Commit df708442 authored by Robert Speicher's avatar Robert Speicher 🇲🇽 Committed by Yorick Peterse

ComponentVersions.get takes a commit ID String

Also adds a VERSION entry with the commit ID to represent the
`gitlab-rails` version string.
parent a3726b6c
......@@ -65,7 +65,6 @@ require 'release_tools/omnibus_gitlab_version'
require 'release_tools/packages/publish_service'
require 'release_tools/passing_build'
require 'release_tools/patch_issue'
require 'release_tools/pipeline'
require 'release_tools/pick_into_label'
require 'release_tools/preparation_merge_request'
require 'release_tools/project/base_project'
......
......@@ -2,19 +2,40 @@
module ReleaseTools
class ComponentVersions
FILES = %w[GITALY_SERVER GITLAB_PAGES GITLAB_SHELL GITLAB_WORKHORSE].freeze
FILES = %w[
GITALY_SERVER_VERSION
GITLAB_PAGES_VERSION
GITLAB_SHELL_VERSION
GITLAB_WORKHORSE_VERSION
].freeze
def self.get(project, commit)
versions = {}
FILES.each do |x|
versions["#{x}_VERSION"] = ReleaseTools::GitlabClient.file_contents(
project.path,
"#{x}_VERSION",
commit.id
).chomp
def self.get(project, commit_id)
versions = { 'VERSION' => commit_id }
FILES.each_with_object(versions) do |file, memo|
memo[file] = ReleaseTools::GitlabClient
.file_contents(project.path, file, commit_id)
.chomp
end
end
def self.update_omnibus(target_branch, version_map)
return if SharedStatus.dry_run?
actions = version_map.map do |filename, contents|
{
action: 'update',
file_path: "/#{filename}",
content: "#{contents}\n"
}
end
versions
ReleaseTools::GitlabClient.create_commit(
ReleaseTools::Project::OmnibusGitlab,
target_branch,
'Update component versions',
actions
)
end
end
end
......@@ -17,6 +17,8 @@ module ReleaseTools
def_delegator :client, :create_merge_request_comment
def_delegator :client, :create_variable
def_delegator :client, :update_variable
def_delegator :client, :create_commit
end
class MissingMilestone
......
......@@ -17,38 +17,29 @@ module ReleaseTools
raise "Unable to find a passing #{project} build for `#{ref}` on dev"
end
$stdout.puts "Found at #{commit.id}".indent(4)
versions = ReleaseTools::ComponentVersions.get(project, commit)
versions = ReleaseTools::ComponentVersions.get(project, commit.id)
versions.each do |component, version|
$stdout.puts "#{component}: #{version}".indent(6)
$stdout.puts "#{component}: #{version}".indent(4)
end
trigger_build(commit, versions) if args.trigger_build
trigger_build(versions) if args.trigger_build
end
def trigger_build(commit, versions)
pipeline_id = ENV.fetch('CI_PIPELINE_ID', 'pipeline_id_unset')
branch_name = "nightly-#{pipeline_id}"
def trigger_build(version_map)
commit = ReleaseTools::ComponentVersions.update_omnibus(ref, version_map)
$stdout.puts "Creating branch #{branch_name}"
dev_client.create_branch(branch_name, commit.id, project)
url = commit_url(ReleaseTools::Project::OmnibusGitlab, commit.short_id)
ReleaseTools::Pipeline.new(
project,
commit.id,
versions
).trigger
$stdout.puts "Updated Omnibus versions at #{url}".indent(4)
$stdout.puts "Deleting branch #{branch_name}"
dev_client.delete_branch(branch_name, project)
# TODO: Tagging
end
private
def dev_client
ReleaseTools::GitlabDevClient
def commit_url(project, id)
"https://gitlab.com/#{project.path}/commit/#{id}"
end
end
end
module ReleaseTools
class Pipeline
attr_reader :project, :sha
def initialize(project, sha, versions)
@project = project
@sha = sha
@token = ENV.fetch('OMNIBUS_BUILD_TRIGGER_TOKEN') { |name| raise "Missing environment variable `#{name}`" }
@versions = versions
end
def trigger
$stdout.puts "trigger build: #{sha} for #{project.path}"
trigger = ReleaseTools::GitlabDevClient.run_trigger(
ReleaseTools::Project::OmnibusGitlab,
@token,
'master',
build_variables
)
$stdout.puts "Pipeline triggered: #{trigger.web_url}"
wait(trigger.id)
end
def status(id)
ReleaseTools::GitlabDevClient.pipeline(ReleaseTools::Project::OmnibusGitlab, id).status
end
def wait(id)
interval = 60 # seconds
max_duration = 3600 * 3 # 3 hours
start = Time.now.to_i
loop do
if ReleaseTools::TimeUtil.timeout?(start, max_duration)
raise "Pipeline timeout after waiting for #{max_duration} seconds."
end
case status(id)
when 'created', 'pending', 'running'
print '.'
sleep interval
when 'success'
$stdout.puts "Pipeline succeeded in #{max_duration} seconds."
break
else
raise 'Pipeline did not suceed.'
end
$stdout.flush
end
end
private
def build_variables
@versions.merge(
'GITLAB_VERSION' => @sha,
'NIGHTLY' => 'true',
'ee' => @project == ReleaseTools::Project::GitlabEe
)
end
end
end
......@@ -5,13 +5,6 @@ require 'spec_helper'
describe ReleaseTools::Commits do
let(:project) { ReleaseTools::Project::GitlabCe }
# Simulate an error class from the `gitlab` gem
def api_error(klass, message)
error = double(parsed_response: double(message: message)).as_null_object
klass.new(error)
end
before do
# Reduce our fixture payload
stub_const('ReleaseTools::Commits::MAX_COMMITS_TO_CHECK', 5)
......@@ -33,7 +26,7 @@ describe ReleaseTools::Commits do
it 'handles a missing commit on dev' do
allow(ReleaseTools::GitlabDevClient)
.to receive(:commit)
.and_raise(api_error(Gitlab::Error::NotFound, 'foo'))
.and_raise(gitlab_error(:NotFound))
instance = described_class.new(project)
......
# frozen_string_literal: true
require 'spec_helper'
describe ReleaseTools::ComponentVersions do
let(:fake_client) { spy }
before do
stub_const('ReleaseTools::GitlabClient', fake_client)
end
describe '.get' do
it 'returns a Hash of component versions' do
project = ReleaseTools::Project::GitlabEe
commit_id = 'abcdefg'
file = described_class::FILES.sample
expect(fake_client).to receive(:file_contents)
.with(project.path, file, commit_id)
.and_return("1.2.3\n")
expect(described_class.get(project, commit_id)).to match(
a_hash_including(
'VERSION' => commit_id,
file => '1.2.3'
)
)
end
end
describe '.update_omnibus' do
it 'commits version updates for the specified ref' do
map = {
'GITALY_SERVER_VERSION' => '1.33.0',
'GITLAB_PAGES_VERSION' => '1.5.0',
'GITLAB_SHELL_VERSION' => '9.0.0',
'GITLAB_WORKHORSE_VERSION' => '8.6.0',
'VERSION' => '0cfa69752d82b8e134bdb8e473c185bdae26ccc2'
}
without_dry_run do
described_class.update_omnibus('foo-branch', map)
end
expect(fake_client).to have_received(:create_commit).with(
ReleaseTools::Project::OmnibusGitlab,
'foo-branch',
anything,
array_including(
action: 'update',
file_path: '/VERSION',
content: "#{map['VERSION']}\n"
)
)
end
end
end
......@@ -5,6 +5,7 @@ require 'spec_helper'
describe ReleaseTools::PassingBuild do
let(:project) { ReleaseTools::Project::GitlabCe }
let(:fake_commit) { double('Commit', id: '1234') }
let(:version_map) { { 'VERSION' => '1.2.3' } }
subject(:service) { described_class.new(project, 'master') }
......@@ -28,8 +29,8 @@ describe ReleaseTools::PassingBuild do
.and_return(fake_commit)
expect(ReleaseTools::ComponentVersions)
.to receive(:get).with(project, fake_commit)
.and_return({})
.to receive(:get).with(project, fake_commit.id)
.and_return(version_map)
expect(service).not_to receive(:trigger_build)
......@@ -41,52 +42,24 @@ describe ReleaseTools::PassingBuild do
.and_return(fake_commit)
expect(ReleaseTools::ComponentVersions)
.to receive(:get).with(project, fake_commit)
.and_return({})
.to receive(:get).with(project, fake_commit.id)
.and_return(version_map)
expect(service).to receive(:trigger_build).with(fake_commit, {})
expect(service).to receive(:trigger_build).with(version_map)
service.execute(double(trigger_build: true))
end
end
describe '#trigger_build', :silence_stdout do
describe '#trigger_build' do
let(:fake_client) { spy }
let(:fake_pipeline) { spy }
before do
# Ensure we don't actually perform branch creation or deletion
allow(service).to receive(:dev_client).and_return(fake_client)
stub_const('ReleaseTools::Pipeline', fake_pipeline)
end
it 'creates a temporary branch' do
ClimateControl.modify(CI_PIPELINE_ID: 'fake_pipeline_id') do
service.trigger_build(fake_commit, spy)
end
expect(fake_client).to have_received(:create_branch)
.with('nightly-fake_pipeline_id', fake_commit.id, project)
end
it 'triggers a pipeline' do
versions = { foo: 'foo', bar: 'bar' }
service.trigger_build(fake_commit, versions)
expect(fake_pipeline).to have_received(:new)
.with(project, fake_commit.id, versions)
expect(fake_pipeline).to have_received(:trigger)
end
it 'deletes the temporary branch' do
ClimateControl.modify(CI_PIPELINE_ID: 'fake_pipeline_id') do
service.trigger_build(fake_commit, spy)
end
it 'updates Omnibus versions', :silence_stdout do
expect(ReleaseTools::ComponentVersions)
.to receive(:update_omnibus).with('master', version_map)
.and_return(double('Commit', short_id: 'abcdefg'))
expect(fake_client).to have_received(:delete_branch)
.with('nightly-fake_pipeline_id', project)
service.trigger_build(version_map)
end
end
end
......@@ -3,13 +3,6 @@
require 'spec_helper'
describe ReleaseTools::Services::AutoDeployBranchService do
# Unset the `TEST` environment variable that gets set by default
def without_dry_run(&block)
ClimateControl.modify(TEST: nil) do
yield
end
end
let(:internal_client) { double('ReleaseTools::GitlabClient', current_milestone: double(title: '11.10'), update_variable: double) }
let(:internal_client_ops) { spy('ReleaseTools::GitlabOpsClient') }
let(:branch_commit) { double(latest_successful: double(id: '1234')) }
......
......@@ -12,20 +12,6 @@ describe ReleaseTools::Services::MonthlyPreparationService do
allow(service).to receive(:gitlab_client).and_return(internal_client)
end
# Simulate an error class from the `gitlab` gem
def api_error(klass, message)
error = double(parsed_response: double(message: message)).as_null_object
klass.new(error)
end
# Unset the `TEST` environment variable that gets set by default
def without_dry_run(&block)
ClimateControl.modify(TEST: nil) do
yield
end
end
describe '#create_label', :silence_stdout do
it 'does nothing on a dry run' do
expect(ReleaseTools::PickIntoLabel).not_to receive(:create)
......@@ -37,7 +23,7 @@ describe ReleaseTools::Services::MonthlyPreparationService do
allow(ReleaseTools::PickIntoLabel).to receive(:create)
allow(internal_client).to receive(:create_branch)
.and_raise(api_error(Gitlab::Error::BadRequest, 'Label already exists'))
.and_raise(gitlab_error(:BadRequest, message: 'Label already exists'))
without_dry_run do
expect { service.create_label }.not_to raise_error
......@@ -65,7 +51,7 @@ describe ReleaseTools::Services::MonthlyPreparationService do
it 'is idempotent' do
allow(internal_client).to receive(:create_branch)
.and_raise(api_error(Gitlab::Error::Conflict, 'Branch already exists'))
.and_raise(gitlab_error(:Conflict, message: 'Branch already exists'))
without_dry_run do
expect { service.create_stable_branches }.not_to raise_error
......
# frozen_string_literal: true
# Helpers for working with the `gitlab` client gem
module GitlabHelper
# Simulate a `Gitlab::Error::Error` class
#
# klass - Gitlab::Error::Error class object, or a Symbol of an Error class
# code - Status code (default: 500)
# message - Status message: (default: 'Something went wrong')
def gitlab_error(klass, code: 500, message: 'Something went wrong')
error = double(
response: double(
code: code
),
parsed_response: double(
message: message
)
).as_null_object
if klass.is_a?(Gitlab::Error::Error)
klass.new(error)
else
Object.const_get("Gitlab::Error::#{klass}").new(error)
end
end
end
RSpec.configure do |config|
config.include GitlabHelper
end
# frozen_string_literal: true
module WithoutDryRun
# Unset the `TEST` environment variable that gets set by default
def without_dry_run
ClimateControl.modify(TEST: nil) do
yield
end
end
end
RSpec.configure do |config|
config.include WithoutDryRun
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment