From 1f1f5707244bcf4e69ef0fbe01f93e59386d5087 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 30 May 2017 12:48:05 +0200 Subject: [PATCH 01/22] Implement CI/CD config attributes for persisted stages --- lib/ci/gitlab_ci_yaml_processor.rb | 14 ++++++- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 41 ++++++++++++++++++- .../ci/create_pipeline_service_spec.rb | 2 +- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index b06474cda7f..17a3cdc714c 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -50,10 +50,20 @@ module Ci end end + def stages_for_ref(ref, tag = false, trigger_request = nil) + stages = @stages.map do |stage| + builds = builds_for_stage_and_ref(stage, ref, tag, trigger_request) + + { name: stage, builds_attributes: builds.to_a } if builds.any? + end + + stages.compact.sort_by { |stage| @stages.index(stage[:name]) } + end + def build_attributes(name) job = @jobs[name.to_sym] || {} - { - stage_idx: @stages.index(job[:stage]), + + { stage_idx: @stages.index(job[:stage]), stage: job[:stage], commands: job[:commands], tag_list: job[:tags] || [], diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index fe2c00bb2ca..f98da1916b4 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -1,7 +1,8 @@ require 'spec_helper' module Ci - describe GitlabCiYamlProcessor, lib: true do + describe GitlabCiYamlProcessor, :lib do + subject { described_class.new(config, path) } let(:path) { 'path' } describe 'our current .gitlab-ci.yml' do @@ -82,6 +83,44 @@ module Ci end end + describe '#stages_for_ref' do + context 'when no refs policy is specified' do + let(:config) do + YAML.dump(production: { stage: 'deploy', script: 'cap prod' }, + rspec: { stage: 'test', script: 'rspec' }, + spinach: { stage: 'test', script: 'spinach' }) + end + + it 'returns model attributes for stages with nested jobs' do + attributes = subject.stages_for_ref('master') + + expect(attributes.size).to eq 2 + expect(attributes.dig(0, :name)).to eq 'test' + expect(attributes.dig(1, :name)).to eq 'deploy' + expect(attributes.dig(0, :builds_attributes, 0, :name)).to eq 'rspec' + expect(attributes.dig(0, :builds_attributes, 1, :name)).to eq 'spinach' + expect(attributes.dig(1, :builds_attributes, 0, :name)).to eq 'production' + end + end + + context 'when refs policy is specified' do + let(:config) do + YAML.dump(production: { stage: 'deploy', script: 'cap prod', only: ['master'] }, + spinach: { stage: 'test', script: 'spinach', only: ['tags'] }) + end + + it 'returns stage attributes except of jobs assigned to master' do + # true flag argument means matching jobs for tags + # + attributes = subject.stages_for_ref('feature', true) + + expect(attributes.size).to eq 1 + expect(attributes.dig(0, :name)).to eq 'test' + expect(attributes.dig(0, :builds_attributes, 0, :name)).to eq 'spinach' + end + end + end + describe "#builds_for_ref" do let(:type) { 'test' } diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index b536103ed65..674de2d80c1 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::CreatePipelineService, services: true do +describe Ci::CreatePipelineService, :services do let(:project) { create(:project, :repository) } let(:user) { create(:admin) } From 96cd42287990a67b0ba709b2bb79cb3722230ec4 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 30 May 2017 13:17:42 +0200 Subject: [PATCH 02/22] Rename pipeline service that creates stages and jobs --- app/services/ci/create_pipeline_service.rb | 2 +- ...line_builds_service.rb => create_pipeline_stages_service.rb} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename app/services/ci/{create_pipeline_builds_service.rb => create_pipeline_stages_service.rb} (96%) diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 1f6c1f4a7f6..d42f793e309 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -49,7 +49,7 @@ module Ci Ci::Pipeline.transaction do update_merge_requests_head_pipeline if pipeline.save - Ci::CreatePipelineBuildsService + Ci::CreatePipelineStagesService .new(project, current_user) .execute(pipeline) end diff --git a/app/services/ci/create_pipeline_builds_service.rb b/app/services/ci/create_pipeline_stages_service.rb similarity index 96% rename from app/services/ci/create_pipeline_builds_service.rb rename to app/services/ci/create_pipeline_stages_service.rb index 70fb2c5e38f..5c78cca29df 100644 --- a/app/services/ci/create_pipeline_builds_service.rb +++ b/app/services/ci/create_pipeline_stages_service.rb @@ -1,5 +1,5 @@ module Ci - class CreatePipelineBuildsService < BaseService + class CreatePipelineStagesService < BaseService attr_reader :pipeline def execute(pipeline) From 6113ff992c9a494ea8c657f20fa92f7f7f2365c4 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 30 May 2017 13:27:46 +0200 Subject: [PATCH 03/22] Expose stage model attributes from pipeline object --- app/models/ci/pipeline.rb | 10 ++++++++++ app/services/ci/create_pipeline_service.rb | 4 ++-- spec/models/ci/pipeline_spec.rb | 14 ++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 81c30b0e077..cc165503409 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -292,6 +292,16 @@ module Ci sort_by { |build| build[:stage_idx] } end + def config_stages_attributes + return [] unless config_processor + + config_processor.stages_for_ref(ref, tag?, trigger_requests.first) + end + + def has_stages? + config_stages_attributes.any? + end + def has_warnings? builds.latest.failed_but_allowed.any? end diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index d42f793e309..3f177122180 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -42,8 +42,8 @@ module Ci return pipeline end - unless pipeline.config_builds_attributes.present? - return error('No builds for this pipeline.') + unless pipeline.has_stages? + return error('No stages / jobs for this pipeline.') end Ci::Pipeline.transaction do diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 56b24ce62f3..c4f07c4a693 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -502,6 +502,20 @@ describe Ci::Pipeline, models: true do end end + describe '#has_stages?' do + context 'when pipeline has stages' do + subject { create(:ci_pipeline_with_one_job) } + + it { is_expected.to have_stages } + end + + context 'when pipeline does not have stages' do + subject { create(:ci_pipeline_without_jobs) } + + it { is_expected.not_to have_stages } + end + end + describe '#has_warnings?' do subject { pipeline.has_warnings? } From 325b2d9329ae90748dd0db749f9ebc0800eaea75 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 30 May 2017 14:16:07 +0200 Subject: [PATCH 04/22] Remove legacy method from create build service --- app/models/ci/pipeline.rb | 3 +++ app/services/ci/create_pipeline_stages_service.rb | 10 ++-------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index cc165503409..7298f676a0e 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -284,6 +284,9 @@ module Ci end end + ## + # TODO, phase this method out + # def config_builds_attributes return [] unless config_processor diff --git a/app/services/ci/create_pipeline_stages_service.rb b/app/services/ci/create_pipeline_stages_service.rb index 5c78cca29df..95b55c37ec1 100644 --- a/app/services/ci/create_pipeline_stages_service.rb +++ b/app/services/ci/create_pipeline_stages_service.rb @@ -23,6 +23,7 @@ module Ci user: current_user, trigger_request: trigger_request ) + build = pipeline.builds.create(build_attributes) # Create the environment before the build starts. This sets its slug and @@ -34,17 +35,10 @@ module Ci end def new_builds - @new_builds ||= pipeline.config_builds_attributes. - reject { |build| existing_build_names.include?(build[:name]) } - end - - def existing_build_names - @existing_build_names ||= pipeline.builds.pluck(:name) + @new_builds ||= pipeline.config_builds_attributes end def trigger_request - return @trigger_request if defined?(@trigger_request) - @trigger_request ||= pipeline.trigger_requests.first end end From 805715cc68aabb6992a63356ec7c19940f52c93a Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 30 May 2017 15:30:45 +0200 Subject: [PATCH 05/22] Add stage seed class that represents attributes --- lib/ci/gitlab_ci_yaml_processor.rb | 3 +- lib/gitlab/ci/stage/seed.rb | 38 ++++++++++++++++++++++ spec/lib/gitlab/ci/stage/seed_spec.rb | 47 +++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 lib/gitlab/ci/stage/seed.rb create mode 100644 spec/lib/gitlab/ci/stage/seed_spec.rb diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index 17a3cdc714c..aa6c94f26c8 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -81,8 +81,7 @@ module Ci dependencies: job[:dependencies], after_script: job[:after_script], environment: job[:environment] - }.compact - } + }.compact } end def self.validation_message(content) diff --git a/lib/gitlab/ci/stage/seed.rb b/lib/gitlab/ci/stage/seed.rb new file mode 100644 index 00000000000..95237bff5d7 --- /dev/null +++ b/lib/gitlab/ci/stage/seed.rb @@ -0,0 +1,38 @@ +module Gitlab + module Ci + module Stage + class Seed + attr_reader :name, :builds + + def initialize(name:, builds:) + @name = name + @builds = builds + end + + def pipeline=(pipeline) + trigger_request = pipeline.trigger_requests.first + + @builds.each do |attributes| + attributes.merge!( + pipeline: pipeline, + project: pipeline.project, + ref: pipeline.ref, + tag: pipeline.tag, + trigger_request: trigger_request + ) + end + end + + def user=(current_user) + @builds.each do |attributes| + attributes.merge!(user: current_user) + end + end + + def to_attributes + { name: @name, builds_attributes: @builds } + end + end + end + end +end diff --git a/spec/lib/gitlab/ci/stage/seed_spec.rb b/spec/lib/gitlab/ci/stage/seed_spec.rb new file mode 100644 index 00000000000..a12093b2c7c --- /dev/null +++ b/spec/lib/gitlab/ci/stage/seed_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe Gitlab::Ci::Stage::Seed do + subject do + described_class.new(name: 'test', builds: builds) + end + + let(:builds) do + [{ name: 'rspec' }, { name: 'spinach' }] + end + + describe '#pipeline=' do + let(:pipeline) do + create(:ci_empty_pipeline, ref: 'feature', tag: true) + end + + it 'assignes relevant pipeline attributes' do + trigger_request = pipeline.trigger_requests.first + + subject.pipeline = pipeline + + expect(subject.builds).to all(include(pipeline: pipeline)) + expect(subject.builds).to all(include(project: pipeline.project)) + expect(subject.builds).to all(include(ref: 'feature')) + expect(subject.builds).to all(include(tag: true)) + expect(subject.builds).to all(include(trigger_request: trigger_request)) + end + end + + describe '#user=' do + let(:user) { create(:user) } + + it 'assignes relevant pipeline attributes' do + subject.user = user + + expect(subject.builds).to all(include(user: user)) + end + end + + describe '#to_attributes' do + it 'exposes stage attributes with nested jobs' do + expect(subject.to_attributes).to be_a Hash + expect(subject.to_attributes).to include(name: 'test') + expect(subject.to_attributes).to include(builds_attributes: builds) + end + end +end From c881425b665b9c0b022dc2e213486aecc320ec7e Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 31 May 2017 14:40:50 +0200 Subject: [PATCH 06/22] Refine pipeline stages seeds class --- lib/ci/gitlab_ci_yaml_processor.rb | 2 +- lib/gitlab/ci/stage/seed.rb | 38 ---------------- lib/gitlab/ci/stage/seeds.rb | 58 ++++++++++++++++++++++++ spec/lib/gitlab/ci/stage/seed_spec.rb | 47 ------------------- spec/lib/gitlab/ci/stage/seeds_spec.rb | 62 ++++++++++++++++++++++++++ 5 files changed, 121 insertions(+), 86 deletions(-) delete mode 100644 lib/gitlab/ci/stage/seed.rb create mode 100644 lib/gitlab/ci/stage/seeds.rb delete mode 100644 spec/lib/gitlab/ci/stage/seed_spec.rb create mode 100644 spec/lib/gitlab/ci/stage/seeds_spec.rb diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index aa6c94f26c8..5e6c3d029c6 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -51,7 +51,7 @@ module Ci end def stages_for_ref(ref, tag = false, trigger_request = nil) - stages = @stages.map do |stage| + stages = @stages.uniq.map do |stage| builds = builds_for_stage_and_ref(stage, ref, tag, trigger_request) { name: stage, builds_attributes: builds.to_a } if builds.any? diff --git a/lib/gitlab/ci/stage/seed.rb b/lib/gitlab/ci/stage/seed.rb deleted file mode 100644 index 95237bff5d7..00000000000 --- a/lib/gitlab/ci/stage/seed.rb +++ /dev/null @@ -1,38 +0,0 @@ -module Gitlab - module Ci - module Stage - class Seed - attr_reader :name, :builds - - def initialize(name:, builds:) - @name = name - @builds = builds - end - - def pipeline=(pipeline) - trigger_request = pipeline.trigger_requests.first - - @builds.each do |attributes| - attributes.merge!( - pipeline: pipeline, - project: pipeline.project, - ref: pipeline.ref, - tag: pipeline.tag, - trigger_request: trigger_request - ) - end - end - - def user=(current_user) - @builds.each do |attributes| - attributes.merge!(user: current_user) - end - end - - def to_attributes - { name: @name, builds_attributes: @builds } - end - end - end - end -end diff --git a/lib/gitlab/ci/stage/seeds.rb b/lib/gitlab/ci/stage/seeds.rb new file mode 100644 index 00000000000..16c436b5d4f --- /dev/null +++ b/lib/gitlab/ci/stage/seeds.rb @@ -0,0 +1,58 @@ +module Gitlab + module Ci + module Stage + class Seeds + Seed = Struct.new(:stage, :jobs) + + def initialize + @stages = [] + end + + def stages + @stages.map(&:stage) + end + + def jobs + @stages.map(&:jobs).flatten + end + + def append_stage(stage, jobs) + @stages << Seed.new({ name: stage }, jobs) + end + + def pipeline=(pipeline) + trigger_request = pipeline.trigger_requests.first + + stages.each do |attributes| + attributes.merge!( + pipeline: pipeline, + project: pipeline.project, + ) + end + + jobs.each do |attributes| + attributes.merge!( + pipeline: pipeline, + project: pipeline.project, + ref: pipeline.ref, + tag: pipeline.tag, + trigger_request: trigger_request + ) + end + end + + def user=(current_user) + jobs.each do |attributes| + attributes.merge!(user: current_user) + end + end + + def to_attributes + @stages.map.with_index do |seed| + seed.stage.merge(builds_attributes: seed.jobs) + end + end + end + end + end +end diff --git a/spec/lib/gitlab/ci/stage/seed_spec.rb b/spec/lib/gitlab/ci/stage/seed_spec.rb deleted file mode 100644 index a12093b2c7c..00000000000 --- a/spec/lib/gitlab/ci/stage/seed_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Ci::Stage::Seed do - subject do - described_class.new(name: 'test', builds: builds) - end - - let(:builds) do - [{ name: 'rspec' }, { name: 'spinach' }] - end - - describe '#pipeline=' do - let(:pipeline) do - create(:ci_empty_pipeline, ref: 'feature', tag: true) - end - - it 'assignes relevant pipeline attributes' do - trigger_request = pipeline.trigger_requests.first - - subject.pipeline = pipeline - - expect(subject.builds).to all(include(pipeline: pipeline)) - expect(subject.builds).to all(include(project: pipeline.project)) - expect(subject.builds).to all(include(ref: 'feature')) - expect(subject.builds).to all(include(tag: true)) - expect(subject.builds).to all(include(trigger_request: trigger_request)) - end - end - - describe '#user=' do - let(:user) { create(:user) } - - it 'assignes relevant pipeline attributes' do - subject.user = user - - expect(subject.builds).to all(include(user: user)) - end - end - - describe '#to_attributes' do - it 'exposes stage attributes with nested jobs' do - expect(subject.to_attributes).to be_a Hash - expect(subject.to_attributes).to include(name: 'test') - expect(subject.to_attributes).to include(builds_attributes: builds) - end - end -end diff --git a/spec/lib/gitlab/ci/stage/seeds_spec.rb b/spec/lib/gitlab/ci/stage/seeds_spec.rb new file mode 100644 index 00000000000..cc4f37d236e --- /dev/null +++ b/spec/lib/gitlab/ci/stage/seeds_spec.rb @@ -0,0 +1,62 @@ +require 'spec_helper' + +describe Gitlab::Ci::Stage::Seeds do + before do + subject.append_stage('test', [{ name: 'rspec' }, { name: 'spinach' }]) + subject.append_stage('deploy', [{ name: 'prod', script: 'cap deploy' }]) + end + + describe '#stages' do + it 'returns hashes of all stages' do + expect(subject.stages.size).to eq 2 + expect(subject.stages).to all(be_a Hash) + end + end + + describe '#jobs' do + it 'returns all jobs in all stages' do + expect(subject.jobs.size).to eq 3 + end + end + + describe '#pipeline=' do + let(:pipeline) do + create(:ci_empty_pipeline, ref: 'feature', tag: true) + end + + it 'assignes relevant pipeline attributes' do + trigger_request = pipeline.trigger_requests.first + + subject.pipeline = pipeline + + expect(subject.stages).to all(include(pipeline: pipeline)) + expect(subject.stages).to all(include(project: pipeline.project)) + expect(subject.jobs).to all(include(pipeline: pipeline)) + expect(subject.jobs).to all(include(project: pipeline.project)) + expect(subject.jobs).to all(include(ref: 'feature')) + expect(subject.jobs).to all(include(tag: true)) + expect(subject.jobs).to all(include(trigger_request: trigger_request)) + end + end + + describe '#user=' do + let(:user) { create(:user) } + + it 'assignes relevant pipeline attributes' do + subject.user = user + + expect(subject.jobs).to all(include(user: user)) + end + end + + describe '#to_attributes' do + it 'exposes stage attributes with nested jobs' do + attributes = [{ name: 'test', builds_attributes: + [{ name: 'rspec' }, { name: 'spinach' }] }, + { name: 'deploy', builds_attributes: + [{ name: 'prod', script: 'cap deploy' }] }] + + expect(subject.to_attributes).to eq attributes + end + end +end From c72e21fd9764845a107005562ff8ce1c06cac431 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 31 May 2017 15:13:40 +0200 Subject: [PATCH 07/22] Return stage seeds object from YAML processor --- app/models/ci/pipeline.rb | 8 ++++-- lib/ci/gitlab_ci_yaml_processor.rb | 12 ++++---- lib/gitlab/ci/stage/seeds.rb | 6 +++- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 30 +++++++++----------- spec/lib/gitlab/ci/stage/seeds_spec.rb | 4 +++ 5 files changed, 34 insertions(+), 26 deletions(-) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 7298f676a0e..d5b6da4eee6 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -295,14 +295,16 @@ module Ci sort_by { |build| build[:stage_idx] } end - def config_stages_attributes + def stage_seeds return [] unless config_processor - config_processor.stages_for_ref(ref, tag?, trigger_requests.first) + config_processor.stage_seeds(ref: ref, + tag: tag?, + trigger: trigger_requests.first) end def has_stages? - config_stages_attributes.any? + stage_seeds.has_stages? end def has_warnings? diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index 5e6c3d029c6..4b0e87a945b 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -50,14 +50,14 @@ module Ci end end - def stages_for_ref(ref, tag = false, trigger_request = nil) - stages = @stages.uniq.map do |stage| - builds = builds_for_stage_and_ref(stage, ref, tag, trigger_request) + def stage_seeds(ref:, tag: false, trigger: nil) + Gitlab::Ci::Stage::Seeds.new.tap do |seeds| + @stages.uniq.each do |stage| + builds = builds_for_stage_and_ref(stage, ref, tag, trigger) - { name: stage, builds_attributes: builds.to_a } if builds.any? + seeds.append_stage(stage, builds) if builds.any? + end end - - stages.compact.sort_by { |stage| @stages.index(stage[:name]) } end def build_attributes(name) diff --git a/lib/gitlab/ci/stage/seeds.rb b/lib/gitlab/ci/stage/seeds.rb index 16c436b5d4f..cb5174a166b 100644 --- a/lib/gitlab/ci/stage/seeds.rb +++ b/lib/gitlab/ci/stage/seeds.rb @@ -8,6 +8,10 @@ module Gitlab @stages = [] end + def has_stages? + @stages.any? + end + def stages @stages.map(&:stage) end @@ -48,7 +52,7 @@ module Gitlab end def to_attributes - @stages.map.with_index do |seed| + @stages.map do |seed| seed.stage.merge(builds_attributes: seed.jobs) end end diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index f98da1916b4..7f652c17ed5 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -83,7 +83,7 @@ module Ci end end - describe '#stages_for_ref' do + describe '#stage_seeds' do context 'when no refs policy is specified' do let(:config) do YAML.dump(production: { stage: 'deploy', script: 'cap prod' }, @@ -91,15 +91,15 @@ module Ci spinach: { stage: 'test', script: 'spinach' }) end - it 'returns model attributes for stages with nested jobs' do - attributes = subject.stages_for_ref('master') + it 'returns correctly fabricated stage seeds object' do + seeds = subject.stage_seeds(ref: 'master') - expect(attributes.size).to eq 2 - expect(attributes.dig(0, :name)).to eq 'test' - expect(attributes.dig(1, :name)).to eq 'deploy' - expect(attributes.dig(0, :builds_attributes, 0, :name)).to eq 'rspec' - expect(attributes.dig(0, :builds_attributes, 1, :name)).to eq 'spinach' - expect(attributes.dig(1, :builds_attributes, 0, :name)).to eq 'production' + expect(seeds.stages.size).to eq 2 + expect(seeds.stages.dig(0, :name)).to eq 'test' + expect(seeds.stages.dig(1, :name)).to eq 'deploy' + expect(seeds.jobs.dig(0, :name)).to eq 'rspec' + expect(seeds.jobs.dig(1, :name)).to eq 'spinach' + expect(seeds.jobs.dig(2, :name)).to eq 'production' end end @@ -109,14 +109,12 @@ module Ci spinach: { stage: 'test', script: 'spinach', only: ['tags'] }) end - it 'returns stage attributes except of jobs assigned to master' do - # true flag argument means matching jobs for tags - # - attributes = subject.stages_for_ref('feature', true) + it 'returns stage seeds only assigned to master to master' do + seeds = subject.stage_seeds(ref: 'feature', tag: true) - expect(attributes.size).to eq 1 - expect(attributes.dig(0, :name)).to eq 'test' - expect(attributes.dig(0, :builds_attributes, 0, :name)).to eq 'spinach' + expect(seeds.stages.size).to eq 1 + expect(seeds.stages.dig(0, :name)).to eq 'test' + expect(seeds.jobs.dig(0, :name)).to eq 'spinach' end end end diff --git a/spec/lib/gitlab/ci/stage/seeds_spec.rb b/spec/lib/gitlab/ci/stage/seeds_spec.rb index cc4f37d236e..3824a868fb2 100644 --- a/spec/lib/gitlab/ci/stage/seeds_spec.rb +++ b/spec/lib/gitlab/ci/stage/seeds_spec.rb @@ -6,6 +6,10 @@ describe Gitlab::Ci::Stage::Seeds do subject.append_stage('deploy', [{ name: 'prod', script: 'cap deploy' }]) end + describe '#has_stages?' do + it { is_expected.to have_stages } + end + describe '#stages' do it 'returns hashes of all stages' do expect(subject.stages.size).to eq 2 From 5c2ce44baf5205c038759c4779a74e3381183e8a Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 31 May 2017 15:25:36 +0200 Subject: [PATCH 08/22] Expose pipeline stage seeds from pipeline instance --- app/models/ci/pipeline.rb | 12 +++++++----- spec/models/ci/pipeline_spec.rb | 11 +++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index d5b6da4eee6..155fefcc9c3 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -296,11 +296,13 @@ module Ci end def stage_seeds - return [] unless config_processor + return unless config_processor - config_processor.stage_seeds(ref: ref, - tag: tag?, - trigger: trigger_requests.first) + seeds_scope = { ref: ref, tag: tag?, trigger: trigger_requests.first } + + config_processor.stage_seeds(seeds_scope).tap do |seeds| + seeds.pipeline = self + end end def has_stages? @@ -312,7 +314,7 @@ module Ci end def config_processor - return nil unless ci_yaml_file + return unless ci_yaml_file return @config_processor if defined?(@config_processor) @config_processor ||= begin diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index c4f07c4a693..3a1fe666ff0 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -202,6 +202,17 @@ describe Ci::Pipeline, models: true do status: 'success') end + describe '#stage_seeds' do + let(:pipeline) do + create(:ci_pipeline, config: { rspec: { script: 'rake' } }) + end + + it 'returns preseeded stage seeds object' do + expect(pipeline.stage_seeds).to be_a Gitlab::Ci::Stage::Seeds + expect(pipeline.stage_seeds.stages).to all(include(pipeline: pipeline)) + end + end + describe '#stages' do subject { pipeline.stages } From c00d72b6f33d50b1c5cd6948d54b3addf11f9104 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 1 Jun 2017 11:55:18 +0200 Subject: [PATCH 09/22] Rename pipeline methods related to legacy stages --- .../projects/pipelines_controller.rb | 2 +- app/models/ci/pipeline.rb | 18 +++++++++--------- app/views/projects/builds/_sidebar.html.haml | 2 +- .../projects/commit/_commit_box.html.haml | 4 ++-- .../projects/pipelines/_with_tabs.html.haml | 2 +- .../shared/_mini_pipeline_graph.html.haml | 2 +- lib/gitlab/data_builder/pipeline.rb | 2 +- spec/models/ci/pipeline_spec.rb | 14 +++++++------- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb index 602d3dd8c1c..d351e773cd7 100644 --- a/app/controllers/projects/pipelines_controller.rb +++ b/app/controllers/projects/pipelines_controller.rb @@ -99,7 +99,7 @@ class Projects::PipelinesController < Projects::ApplicationController end def stage - @stage = pipeline.stage(params[:stage]) + @stage = pipeline.legacy_stage(params[:stage]) return not_found unless @stage respond_to do |format| diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 155fefcc9c3..8e687fd5c08 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -151,21 +151,21 @@ module Ci where.not(duration: nil).sum(:duration) end - def stage(name) - stage = Ci::Stage.new(self, name: name) - stage unless stage.statuses_count.zero? - end - def stages_count statuses.select(:stage).distinct.count end - def stages_name + def stages_names statuses.order(:stage_idx).distinct. pluck(:stage, :stage_idx).map(&:first) end - def stages + def legacy_stage(name) + stage = Ci::Stage.new(self, name: name) + stage unless stage.statuses_count.zero? + end + + def legacy_stages # TODO, this needs refactoring, see gitlab-ce#26481. stages_query = statuses @@ -300,13 +300,13 @@ module Ci seeds_scope = { ref: ref, tag: tag?, trigger: trigger_requests.first } - config_processor.stage_seeds(seeds_scope).tap do |seeds| + @seeds ||= config_processor.stage_seeds(seeds_scope).tap do |seeds| seeds.pipeline = self end end def has_stages? - stage_seeds.has_stages? + stage_seeds&.has_stages? end def has_warnings? diff --git a/app/views/projects/builds/_sidebar.html.haml b/app/views/projects/builds/_sidebar.html.haml index 8032d81cd91..a71b6493ce7 100644 --- a/app/views/projects/builds/_sidebar.html.haml +++ b/app/views/projects/builds/_sidebar.html.haml @@ -118,7 +118,7 @@ %span.stage-selection More = icon('chevron-down') %ul.dropdown-menu - - @build.pipeline.stages.each do |stage| + - @build.pipeline.legacy_stages.each do |stage| %li %a.stage-item= stage.name diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml index 0aef5822f81..aab50310234 100644 --- a/app/views/projects/commit/_commit_box.html.haml +++ b/app/views/projects/commit/_commit_box.html.haml @@ -72,8 +72,8 @@ Pipeline = link_to "##{last_pipeline.id}", namespace_project_pipeline_path(@project.namespace, @project, last_pipeline.id) = ci_label_for_status(last_pipeline.status) - - if last_pipeline.stages.any? - with #{"stage".pluralize(last_pipeline.stages.count)} + - if last_pipeline.stages_count.nonzero? + with #{"stage".pluralize(last_pipeline.stages_count)} .mr-widget-pipeline-graph = render 'shared/mini_pipeline_graph', pipeline: last_pipeline, klass: 'js-commit-pipeline-graph' in diff --git a/app/views/projects/pipelines/_with_tabs.html.haml b/app/views/projects/pipelines/_with_tabs.html.haml index 075ddc0025c..a1604ca039e 100644 --- a/app/views/projects/pipelines/_with_tabs.html.haml +++ b/app/views/projects/pipelines/_with_tabs.html.haml @@ -46,7 +46,7 @@ %th %th Coverage %th - = render partial: "projects/stage/stage", collection: pipeline.stages, as: :stage + = render partial: "projects/stage/stage", collection: pipeline.legacy_stages, as: :stage - if failed_builds.present? #js-tab-failures.build-failures.tab-pane - failed_builds.each_with_index do |build, index| diff --git a/app/views/shared/_mini_pipeline_graph.html.haml b/app/views/shared/_mini_pipeline_graph.html.haml index 07970ad9cba..aa93572bf94 100644 --- a/app/views/shared/_mini_pipeline_graph.html.haml +++ b/app/views/shared/_mini_pipeline_graph.html.haml @@ -1,5 +1,5 @@ .stage-cell - - pipeline.stages.each do |stage| + - pipeline.legacy_stages.each do |stage| - if stage.status - detailed_status = stage.detailed_status(current_user) - icon_status = "#{detailed_status.icon}_borderless" diff --git a/lib/gitlab/data_builder/pipeline.rb b/lib/gitlab/data_builder/pipeline.rb index 182a30fd74d..e47fb85b5ee 100644 --- a/lib/gitlab/data_builder/pipeline.rb +++ b/lib/gitlab/data_builder/pipeline.rb @@ -22,7 +22,7 @@ module Gitlab sha: pipeline.sha, before_sha: pipeline.before_sha, status: pipeline.status, - stages: pipeline.stages_name, + stages: pipeline.stages_names, created_at: pipeline.created_at, finished_at: pipeline.finished_at, duration: pipeline.duration diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 3a1fe666ff0..46dfa90218d 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -213,8 +213,8 @@ describe Ci::Pipeline, models: true do end end - describe '#stages' do - subject { pipeline.stages } + describe '#legacy_stages' do + subject { pipeline.legacy_stages } context 'stages list' do it 'returns ordered list of stages' do @@ -263,7 +263,7 @@ describe Ci::Pipeline, models: true do end it 'populates stage with correct number of warnings' do - deploy_stage = pipeline.stages.third + deploy_stage = pipeline.legacy_stages.third expect(deploy_stage).not_to receive(:statuses) expect(deploy_stage).to have_warnings @@ -277,15 +277,15 @@ describe Ci::Pipeline, models: true do end end - describe '#stages_name' do + describe '#stages_names' do it 'returns a valid names of stages' do - expect(pipeline.stages_name).to eq(%w(build test deploy)) + expect(pipeline.stages_names).to eq(%w(build test deploy)) end end end - describe '#stage' do - subject { pipeline.stage('test') } + describe '#legacy_stage' do + subject { pipeline.legacy_stage('test') } context 'with status in stage' do before do From 78b2f65cb5320a6a28c1e26bb6ee792a54e1b674 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 1 Jun 2017 12:00:37 +0200 Subject: [PATCH 10/22] Rename `Ci::Stage` class to `Ci::LegacyStage` --- app/models/ci/{stage.rb => legacy_stage.rb} | 2 +- app/models/ci/pipeline.rb | 4 ++-- spec/factories/ci/stages.rb | 6 ++++-- spec/models/ci/{stage_spec.rb => legacy_stage_spec.rb} | 2 +- spec/models/ci/pipeline_spec.rb | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-) rename app/models/ci/{stage.rb => legacy_stage.rb} (98%) rename spec/models/ci/{stage_spec.rb => legacy_stage_spec.rb} (99%) diff --git a/app/models/ci/stage.rb b/app/models/ci/legacy_stage.rb similarity index 98% rename from app/models/ci/stage.rb rename to app/models/ci/legacy_stage.rb index 9bda3186c30..9b536af672b 100644 --- a/app/models/ci/stage.rb +++ b/app/models/ci/legacy_stage.rb @@ -1,7 +1,7 @@ module Ci # Currently this is artificial object, constructed dynamically # We should migrate this object to actual database record in the future - class Stage + class LegacyStage include StaticModel attr_reader :pipeline, :name diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 8e687fd5c08..e64e16657fe 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -161,7 +161,7 @@ module Ci end def legacy_stage(name) - stage = Ci::Stage.new(self, name: name) + stage = Ci::LegacyStage.new(self, name: name) stage unless stage.statuses_count.zero? end @@ -180,7 +180,7 @@ module Ci .pluck('sg.stage', status_sql, "(#{warnings_sql})") stages_with_statuses.map do |stage| - Ci::Stage.new(self, Hash[%i[name status warnings].zip(stage)]) + Ci::LegacyStage.new(self, Hash[%i[name status warnings].zip(stage)]) end end diff --git a/spec/factories/ci/stages.rb b/spec/factories/ci/stages.rb index 7f557b25ccb..884661e1030 100644 --- a/spec/factories/ci/stages.rb +++ b/spec/factories/ci/stages.rb @@ -1,5 +1,5 @@ FactoryGirl.define do - factory :ci_stage, class: Ci::Stage do + factory :ci_stage, class: Ci::LegacyStage do transient do name 'test' status nil @@ -8,7 +8,9 @@ FactoryGirl.define do end initialize_with do - Ci::Stage.new(pipeline, name: name, status: status, warnings: warnings) + Ci::LegacyStage.new(pipeline, name: name, + status: status, + warnings: warnings) end end end diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/legacy_stage_spec.rb similarity index 99% rename from spec/models/ci/stage_spec.rb rename to spec/models/ci/legacy_stage_spec.rb index 8f6ab908987..48116c7e701 100644 --- a/spec/models/ci/stage_spec.rb +++ b/spec/models/ci/legacy_stage_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::Stage, models: true do +describe Ci::LegacyStage, :models do let(:stage) { build(:ci_stage) } let(:pipeline) { stage.pipeline } let(:stage_name) { stage.name } diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 46dfa90218d..17e10a5322e 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -292,7 +292,7 @@ describe Ci::Pipeline, models: true do create(:commit_status, pipeline: pipeline, stage: 'test') end - it { expect(subject).to be_a Ci::Stage } + it { expect(subject).to be_a Ci::LegacyStage } it { expect(subject.name).to eq 'test' } it { expect(subject.statuses).not_to be_empty } end From 0532883622dde885ec2a120616b31aadaad4c5d2 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 1 Jun 2017 12:57:04 +0200 Subject: [PATCH 11/22] Fix exposing legacy stages in pipeline entity --- app/serializers/pipeline_entity.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/serializers/pipeline_entity.rb b/app/serializers/pipeline_entity.rb index ea57cc97a7e..d03e65b52b4 100644 --- a/app/serializers/pipeline_entity.rb +++ b/app/serializers/pipeline_entity.rb @@ -15,11 +15,11 @@ class PipelineEntity < Grape::Entity expose :details do expose :detailed_status, as: :status, with: StatusEntity - expose :duration - expose :finished_at - expose :stages, using: StageEntity + expose :legacy_stages, as: :stages, using: StageEntity expose :artifacts, using: BuildArtifactEntity expose :manual_actions, using: BuildActionEntity + expose :duration + expose :finished_at end expose :flags do From fe0b2f81c7c9680a11288e0cdffc3e80dc1e8d58 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 2 Jun 2017 12:16:11 +0200 Subject: [PATCH 12/22] Refine implementation of pipeline stage seeds --- app/models/ci/pipeline.rb | 19 +++--- app/models/ci/stage.rb | 11 ++++ app/models/commit_status.rb | 4 +- app/services/ci/create_pipeline_service.rb | 2 +- .../ci/create_pipeline_stages_service.rb | 49 ++++---------- lib/ci/gitlab_ci_yaml_processor.rb | 15 +++-- lib/gitlab/ci/stage/seed.rb | 49 ++++++++++++++ lib/gitlab/ci/stage/seeds.rb | 62 ----------------- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 32 +++++---- spec/lib/gitlab/ci/stage/seed_spec.rb | 54 +++++++++++++++ spec/lib/gitlab/ci/stage/seeds_spec.rb | 66 ------------------- spec/models/ci/pipeline_spec.rb | 14 ++-- 12 files changed, 172 insertions(+), 205 deletions(-) create mode 100644 app/models/ci/stage.rb create mode 100644 lib/gitlab/ci/stage/seed.rb delete mode 100644 lib/gitlab/ci/stage/seeds.rb create mode 100644 spec/lib/gitlab/ci/stage/seed_spec.rb delete mode 100644 spec/lib/gitlab/ci/stage/seeds_spec.rb diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index e64e16657fe..fb1d4720ba8 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -11,9 +11,7 @@ module Ci belongs_to :auto_canceled_by, class_name: 'Ci::Pipeline' belongs_to :pipeline_schedule, class_name: 'Ci::PipelineSchedule' - has_many :auto_canceled_pipelines, class_name: 'Ci::Pipeline', foreign_key: 'auto_canceled_by_id' - has_many :auto_canceled_jobs, class_name: 'CommitStatus', foreign_key: 'auto_canceled_by_id' - + has_many :stages has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id has_many :builds, foreign_key: :commit_id has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id @@ -28,6 +26,9 @@ module Ci has_many :manual_actions, -> { latest.manual_actions }, foreign_key: :commit_id, class_name: 'Ci::Build' has_many :artifacts, -> { latest.with_artifacts_not_expired }, foreign_key: :commit_id, class_name: 'Ci::Build' + has_many :auto_canceled_pipelines, class_name: 'Ci::Pipeline', foreign_key: 'auto_canceled_by_id' + has_many :auto_canceled_jobs, class_name: 'CommitStatus', foreign_key: 'auto_canceled_by_id' + delegate :id, to: :project, prefix: true validates :sha, presence: { unless: :importing? } @@ -296,17 +297,13 @@ module Ci end def stage_seeds - return unless config_processor + return [] unless config_processor - seeds_scope = { ref: ref, tag: tag?, trigger: trigger_requests.first } - - @seeds ||= config_processor.stage_seeds(seeds_scope).tap do |seeds| - seeds.pipeline = self - end + @stage_seeds ||= config_processor.stage_seeds(self) end - def has_stages? - stage_seeds&.has_stages? + def has_stage_seeds? + stage_seeds.any? end def has_warnings? diff --git a/app/models/ci/stage.rb b/app/models/ci/stage.rb new file mode 100644 index 00000000000..59570924c8d --- /dev/null +++ b/app/models/ci/stage.rb @@ -0,0 +1,11 @@ +module Ci + class Stage < ActiveRecord::Base + extend Ci::Model + + belongs_to :project + belongs_to :pipeline + + has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id + has_many :builds, foreign_key: :commit_id + end +end diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index fe63728ea23..82f6ce8e484 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -5,10 +5,10 @@ class CommitStatus < ActiveRecord::Base self.table_name = 'ci_builds' + belongs_to :user belongs_to :project belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id belongs_to :auto_canceled_by, class_name: 'Ci::Pipeline' - belongs_to :user delegate :commit, to: :pipeline delegate :sha, :short_sha, to: :pipeline @@ -18,7 +18,7 @@ class CommitStatus < ActiveRecord::Base validates :name, presence: true alias_attribute :author, :user - + scope :failed_but_allowed, -> do where(allow_failure: true, status: [:failed, :canceled]) end diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 3f177122180..4dd74ebb1bb 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -42,7 +42,7 @@ module Ci return pipeline end - unless pipeline.has_stages? + if pipeline.has_stage_seeds? return error('No stages / jobs for this pipeline.') end diff --git a/app/services/ci/create_pipeline_stages_service.rb b/app/services/ci/create_pipeline_stages_service.rb index 95b55c37ec1..f2c175adee6 100644 --- a/app/services/ci/create_pipeline_stages_service.rb +++ b/app/services/ci/create_pipeline_stages_service.rb @@ -1,45 +1,20 @@ module Ci class CreatePipelineStagesService < BaseService - attr_reader :pipeline - def execute(pipeline) - @pipeline = pipeline + pipeline.stage_seeds.each do |seed| + seed.user = current_user - new_builds.map do |build_attributes| - create_build(build_attributes) + seed.create! do |build| + ## + # Create the environment before the build starts. This sets its slug and + # makes it available as an environment variable + # + if build.has_environment? + environment_name = build.expanded_environment_name + project.environments.find_or_create_by(name: environment_name) + end + end end end - - delegate :project, to: :pipeline - - private - - def create_build(build_attributes) - build_attributes = build_attributes.merge( - pipeline: pipeline, - project: project, - ref: pipeline.ref, - tag: pipeline.tag, - user: current_user, - trigger_request: trigger_request - ) - - build = pipeline.builds.create(build_attributes) - - # Create the environment before the build starts. This sets its slug and - # makes it available as an environment variable - project.environments.find_or_create_by(name: build.expanded_environment_name) if - build.has_environment? - - build - end - - def new_builds - @new_builds ||= pipeline.config_builds_attributes - end - - def trigger_request - @trigger_request ||= pipeline.trigger_requests.first - end end end diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index 4b0e87a945b..22af2671b18 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -50,14 +50,17 @@ module Ci end end - def stage_seeds(ref:, tag: false, trigger: nil) - Gitlab::Ci::Stage::Seeds.new.tap do |seeds| - @stages.uniq.each do |stage| - builds = builds_for_stage_and_ref(stage, ref, tag, trigger) + def stage_seeds(pipeline) + trigger_request = pipeline.trigger_requests.first - seeds.append_stage(stage, builds) if builds.any? - end + seeds = @stages.uniq.map do |stage| + builds = builds_for_stage_and_ref( + stage, pipeline.ref, pipeline.tag?, trigger_request) + + Gitlab::Ci::Stage::Seed.new(pipeline, stage, builds) if builds.any? end + + seeds.compact end def build_attributes(name) diff --git a/lib/gitlab/ci/stage/seed.rb b/lib/gitlab/ci/stage/seed.rb new file mode 100644 index 00000000000..f81f9347b4d --- /dev/null +++ b/lib/gitlab/ci/stage/seed.rb @@ -0,0 +1,49 @@ +module Gitlab + module Ci + module Stage + class Seed + attr_reader :pipeline + delegate :project, to: :pipeline + + def initialize(pipeline, stage, jobs) + @pipeline = pipeline + @stage = { name: stage } + @jobs = jobs.to_a.dup + end + + def user=(current_user) + @jobs.map! do |attributes| + attributes.merge(user: current_user) + end + end + + def stage + @stage.merge(project: project) + end + + def builds + trigger = pipeline.trigger_requests.first + + @jobs.map do |attributes| + attributes.merge(project: project, + ref: pipeline.ref, + tag: pipeline.tag, + trigger_request: trigger) + end + end + + def create! + pipeline.stages.create!(stage).tap do |stage| + builds_attributes = builds.map do |attributes| + attributes.merge(stage_id: stage.id) + end + + pipeline.builds.create!(builds_attributes).each do |build| + yield build if block_given? + end + end + end + end + end + end +end diff --git a/lib/gitlab/ci/stage/seeds.rb b/lib/gitlab/ci/stage/seeds.rb deleted file mode 100644 index cb5174a166b..00000000000 --- a/lib/gitlab/ci/stage/seeds.rb +++ /dev/null @@ -1,62 +0,0 @@ -module Gitlab - module Ci - module Stage - class Seeds - Seed = Struct.new(:stage, :jobs) - - def initialize - @stages = [] - end - - def has_stages? - @stages.any? - end - - def stages - @stages.map(&:stage) - end - - def jobs - @stages.map(&:jobs).flatten - end - - def append_stage(stage, jobs) - @stages << Seed.new({ name: stage }, jobs) - end - - def pipeline=(pipeline) - trigger_request = pipeline.trigger_requests.first - - stages.each do |attributes| - attributes.merge!( - pipeline: pipeline, - project: pipeline.project, - ) - end - - jobs.each do |attributes| - attributes.merge!( - pipeline: pipeline, - project: pipeline.project, - ref: pipeline.ref, - tag: pipeline.tag, - trigger_request: trigger_request - ) - end - end - - def user=(current_user) - jobs.each do |attributes| - attributes.merge!(user: current_user) - end - end - - def to_attributes - @stages.map do |seed| - seed.stage.merge(builds_attributes: seed.jobs) - end - end - end - end - end -end diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 7f652c17ed5..72b9cde10e7 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -91,15 +91,17 @@ module Ci spinach: { stage: 'test', script: 'spinach' }) end - it 'returns correctly fabricated stage seeds object' do - seeds = subject.stage_seeds(ref: 'master') + let(:pipeline) { create(:ci_empty_pipeline) } - expect(seeds.stages.size).to eq 2 - expect(seeds.stages.dig(0, :name)).to eq 'test' - expect(seeds.stages.dig(1, :name)).to eq 'deploy' - expect(seeds.jobs.dig(0, :name)).to eq 'rspec' - expect(seeds.jobs.dig(1, :name)).to eq 'spinach' - expect(seeds.jobs.dig(2, :name)).to eq 'production' + it 'correctly fabricates a stage seeds object' do + seeds = subject.stage_seeds(pipeline) + + expect(seeds.size).to eq 2 + expect(seeds.first.stage[:name]).to eq 'test' + expect(seeds.second.stage[:name]).to eq 'deploy' + expect(seeds.first.builds.dig(0, :name)).to eq 'rspec' + expect(seeds.first.builds.dig(1, :name)).to eq 'spinach' + expect(seeds.second.builds.dig(0, :name)).to eq 'production' end end @@ -109,12 +111,16 @@ module Ci spinach: { stage: 'test', script: 'spinach', only: ['tags'] }) end - it 'returns stage seeds only assigned to master to master' do - seeds = subject.stage_seeds(ref: 'feature', tag: true) + let(:pipeline) do + create(:ci_empty_pipeline, ref: 'feature', tag: true) + end - expect(seeds.stages.size).to eq 1 - expect(seeds.stages.dig(0, :name)).to eq 'test' - expect(seeds.jobs.dig(0, :name)).to eq 'spinach' + it 'returns stage seeds only assigned to master to master' do + seeds = subject.stage_seeds(pipeline) + + expect(seeds.size).to eq 1 + expect(seeds.first.stage[:name]).to eq 'test' + expect(seeds.first.builds.dig(0, :name)).to eq 'spinach' end end end diff --git a/spec/lib/gitlab/ci/stage/seed_spec.rb b/spec/lib/gitlab/ci/stage/seed_spec.rb new file mode 100644 index 00000000000..15bcce04447 --- /dev/null +++ b/spec/lib/gitlab/ci/stage/seed_spec.rb @@ -0,0 +1,54 @@ +require 'spec_helper' + +describe Gitlab::Ci::Stage::Seed do + let(:pipeline) { create(:ci_empty_pipeline) } + + let(:builds) do + [{ name: 'rspec' }, { name: 'spinach' }] + end + + subject do + described_class.new(pipeline, 'test', builds) + end + + describe '#stage' do + it 'returns hash attributes of a stage' do + expect(subject.stage).to be_a Hash + expect(subject.stage).to include(:name, :project) + end + end + + describe '#builds' do + it 'returns hash attributes of all builds' do + expect(subject.builds.size).to eq 2 + expect(subject.builds).to all(include(pipeline: pipeline)) + expect(subject.builds).to all(include(project: pipeline.project)) + expect(subject.builds).to all(include(ref: 'master')) + expect(subject.builds).to all(include(tag: false)) + expect(subject.builds) + .to all(include(trigger_request: pipeline.trigger_requests.first)) + end + end + + describe '#user=' do + let(:user) { create(:user) } + + it 'assignes relevant pipeline attributes' do + subject.user = user + + expect(subject.builds).to all(include(user: user)) + end + end + + describe '#create!' do + it 'creates all stages and builds' do + subject.create! + + expect(pipeline.reload.stages.count).to eq 1 + expect(pipeline.reload.builds.count).to eq 2 + expect(pipeline.builds).to all(satisfy { |job| job.stage_id.present? }) + expect(pipeline.builds).to all(satisfy { |job| job.pipeline.present? }) + expect(pipeline.builds).to all(satisfy { |job| job.project.present? }) + end + end +end diff --git a/spec/lib/gitlab/ci/stage/seeds_spec.rb b/spec/lib/gitlab/ci/stage/seeds_spec.rb deleted file mode 100644 index 3824a868fb2..00000000000 --- a/spec/lib/gitlab/ci/stage/seeds_spec.rb +++ /dev/null @@ -1,66 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Ci::Stage::Seeds do - before do - subject.append_stage('test', [{ name: 'rspec' }, { name: 'spinach' }]) - subject.append_stage('deploy', [{ name: 'prod', script: 'cap deploy' }]) - end - - describe '#has_stages?' do - it { is_expected.to have_stages } - end - - describe '#stages' do - it 'returns hashes of all stages' do - expect(subject.stages.size).to eq 2 - expect(subject.stages).to all(be_a Hash) - end - end - - describe '#jobs' do - it 'returns all jobs in all stages' do - expect(subject.jobs.size).to eq 3 - end - end - - describe '#pipeline=' do - let(:pipeline) do - create(:ci_empty_pipeline, ref: 'feature', tag: true) - end - - it 'assignes relevant pipeline attributes' do - trigger_request = pipeline.trigger_requests.first - - subject.pipeline = pipeline - - expect(subject.stages).to all(include(pipeline: pipeline)) - expect(subject.stages).to all(include(project: pipeline.project)) - expect(subject.jobs).to all(include(pipeline: pipeline)) - expect(subject.jobs).to all(include(project: pipeline.project)) - expect(subject.jobs).to all(include(ref: 'feature')) - expect(subject.jobs).to all(include(tag: true)) - expect(subject.jobs).to all(include(trigger_request: trigger_request)) - end - end - - describe '#user=' do - let(:user) { create(:user) } - - it 'assignes relevant pipeline attributes' do - subject.user = user - - expect(subject.jobs).to all(include(user: user)) - end - end - - describe '#to_attributes' do - it 'exposes stage attributes with nested jobs' do - attributes = [{ name: 'test', builds_attributes: - [{ name: 'rspec' }, { name: 'spinach' }] }, - { name: 'deploy', builds_attributes: - [{ name: 'prod', script: 'cap deploy' }] }] - - expect(subject.to_attributes).to eq attributes - end - end -end diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 17e10a5322e..63dbf1e9d8b 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -208,8 +208,8 @@ describe Ci::Pipeline, models: true do end it 'returns preseeded stage seeds object' do - expect(pipeline.stage_seeds).to be_a Gitlab::Ci::Stage::Seeds - expect(pipeline.stage_seeds.stages).to all(include(pipeline: pipeline)) + expect(pipeline.stage_seeds).to all(be_a Gitlab::Ci::Stage::Seed) + expect(pipeline.stage_seeds.count).to eq 1 end end @@ -513,17 +513,17 @@ describe Ci::Pipeline, models: true do end end - describe '#has_stages?' do - context 'when pipeline has stages' do + describe '#has_stage_seedss?' do + context 'when pipeline has stage seeds' do subject { create(:ci_pipeline_with_one_job) } - it { is_expected.to have_stages } + it { is_expected.to have_stage_seeds } end - context 'when pipeline does not have stages' do + context 'when pipeline does not have stage seeds' do subject { create(:ci_pipeline_without_jobs) } - it { is_expected.not_to have_stages } + it { is_expected.not_to have_stage_seeds } end end From 626cb8edc3f4421fe7e866c51fddc2715875ddda Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 2 Jun 2017 15:05:14 +0200 Subject: [PATCH 13/22] Fix invalid conditional in pipeline create service --- app/services/ci/create_pipeline_service.rb | 2 +- spec/lib/gitlab/ci/stage/seed_spec.rb | 3 +-- spec/services/ci/create_pipeline_service_spec.rb | 5 +++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 4dd74ebb1bb..5ff388c6614 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -42,7 +42,7 @@ module Ci return pipeline end - if pipeline.has_stage_seeds? + unless pipeline.has_stage_seeds? return error('No stages / jobs for this pipeline.') end diff --git a/spec/lib/gitlab/ci/stage/seed_spec.rb b/spec/lib/gitlab/ci/stage/seed_spec.rb index 15bcce04447..f4353040ce6 100644 --- a/spec/lib/gitlab/ci/stage/seed_spec.rb +++ b/spec/lib/gitlab/ci/stage/seed_spec.rb @@ -21,10 +21,9 @@ describe Gitlab::Ci::Stage::Seed do describe '#builds' do it 'returns hash attributes of all builds' do expect(subject.builds.size).to eq 2 - expect(subject.builds).to all(include(pipeline: pipeline)) - expect(subject.builds).to all(include(project: pipeline.project)) expect(subject.builds).to all(include(ref: 'master')) expect(subject.builds).to all(include(tag: false)) + expect(subject.builds).to all(include(project: pipeline.project)) expect(subject.builds) .to all(include(trigger_request: pipeline.trigger_requests.first)) end diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index 674de2d80c1..fe5de2ce227 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -9,10 +9,10 @@ describe Ci::CreatePipelineService, :services do end describe '#execute' do - def execute_service(after: project.commit.id, message: 'Message', ref: 'refs/heads/master') + def execute_service(after_sha: project.commit.id, message: 'Message', ref: 'refs/heads/master') params = { ref: ref, before: '00000000', - after: after, + after: after_sha, commits: [{ message: message }] } described_class.new(project, user, params).execute @@ -30,6 +30,7 @@ describe Ci::CreatePipelineService, :services do it 'creates a pipeline' do expect(pipeline).to be_kind_of(Ci::Pipeline) expect(pipeline).to be_valid + expect(pipeline).to be_persisted expect(pipeline).to eq(project.pipelines.last) expect(pipeline).to have_attributes(user: user) expect(pipeline).to have_attributes(status: 'pending') From bd76cdc97b5883ee801149a6b37a9ad78e79d164 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 5 Jun 2017 10:18:12 +0200 Subject: [PATCH 14/22] Remove legacy method from pipeline class --- app/models/ci/pipeline.rb | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index fb1d4720ba8..e84693bcf3a 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -285,17 +285,6 @@ module Ci end end - ## - # TODO, phase this method out - # - def config_builds_attributes - return [] unless config_processor - - config_processor. - builds_for_ref(ref, tag?, trigger_requests.first). - sort_by { |build| build[:stage_idx] } - end - def stage_seeds return [] unless config_processor From 469975c783d8c90e555b64d069e412a3b062073b Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 5 Jun 2017 10:30:57 +0200 Subject: [PATCH 15/22] Revert invalid changes in new pipeline service specs --- spec/services/ci/create_pipeline_service_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index fe5de2ce227..68242fb4e15 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -9,10 +9,10 @@ describe Ci::CreatePipelineService, :services do end describe '#execute' do - def execute_service(after_sha: project.commit.id, message: 'Message', ref: 'refs/heads/master') + def execute_service(after: project.commit.id, message: 'Message', ref: 'refs/heads/master') params = { ref: ref, before: '00000000', - after: after_sha, + after: after, commits: [{ message: message }] } described_class.new(project, user, params).execute From 3801a0df80306a76dc340ca74427a124a1514dbb Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 5 Jun 2017 10:34:30 +0200 Subject: [PATCH 16/22] Export pipeline stages in import/export feature --- lib/gitlab/import_export/import_export.yml | 1 + lib/gitlab/import_export/relation_factory.rb | 1 + spec/lib/gitlab/import_export/all_models.yml | 7 +++++++ spec/lib/gitlab/import_export/safe_model_attributes.yml | 7 +++++++ 4 files changed, 16 insertions(+) diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml index d0f3cf2b514..ff2b1d08c3c 100644 --- a/lib/gitlab/import_export/import_export.yml +++ b/lib/gitlab/import_export/import_export.yml @@ -38,6 +38,7 @@ project_tree: - notes: - :author - :events + - :stages - :statuses - :triggers - :pipeline_schedules diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb index 19e23a4715f..695852526cb 100644 --- a/lib/gitlab/import_export/relation_factory.rb +++ b/lib/gitlab/import_export/relation_factory.rb @@ -3,6 +3,7 @@ module Gitlab class RelationFactory OVERRIDES = { snippets: :project_snippets, pipelines: 'Ci::Pipeline', + stages: 'Ci::Stage', statuses: 'commit_status', triggers: 'Ci::Trigger', pipeline_schedules: 'Ci::PipelineSchedule', diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 34f617e23a5..6e6e94d0bbb 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -91,6 +91,7 @@ merge_request_diff: pipelines: - project - user +- stages - statuses - builds - trigger_requests @@ -104,9 +105,15 @@ pipelines: - artifacts - pipeline_schedule - merge_requests +stages: +- project +- pipeline +- statuses +- builds statuses: - project - pipeline +- stage - user - auto_canceled_by variables: diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 2388aea24d9..37783f63843 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -191,6 +191,13 @@ Ci::Pipeline: - lock_version - auto_canceled_by_id - pipeline_schedule_id +Ci::Stage: +- id +- name +- project_id +- pipeline_id +- created_at +- updated_at CommitStatus: - id - project_id From 8808e7bcf518e16fa36762a9b01f6cf224233f06 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 5 Jun 2017 12:54:52 +0200 Subject: [PATCH 17/22] Add assertions about new pipeline stage in specs --- spec/lib/gitlab/ci/stage/seed_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/lib/gitlab/ci/stage/seed_spec.rb b/spec/lib/gitlab/ci/stage/seed_spec.rb index f4353040ce6..47a797cfe8f 100644 --- a/spec/lib/gitlab/ci/stage/seed_spec.rb +++ b/spec/lib/gitlab/ci/stage/seed_spec.rb @@ -48,6 +48,10 @@ describe Gitlab::Ci::Stage::Seed do expect(pipeline.builds).to all(satisfy { |job| job.stage_id.present? }) expect(pipeline.builds).to all(satisfy { |job| job.pipeline.present? }) expect(pipeline.builds).to all(satisfy { |job| job.project.present? }) + expect(pipeline.stages) + .to all(satisfy { |stage| stage.pipeline.present? }) + expect(pipeline.stages) + .to all(satisfy { |stage| stage.project.present? }) end end end From 25b26c2f2844178d66a6fde7f728a5e72841e9d2 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 5 Jun 2017 15:01:15 +0200 Subject: [PATCH 18/22] Fix typo in import/export safe model attributes --- spec/lib/gitlab/import_export/safe_model_attributes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 24665645277..34457bf36fe 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -199,7 +199,7 @@ Ci::Stage: - pipeline_id - created_at - updated_at -ommitStatus: +CommitStatus: - id - project_id - status From da0852e08aa07354706be1e0be9251ccf02e85be Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 5 Jun 2017 15:23:09 +0200 Subject: [PATCH 19/22] Improve specs for pipeline and pipeline seeds --- spec/lib/gitlab/ci/stage/seed_spec.rb | 2 +- spec/models/ci/pipeline_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/lib/gitlab/ci/stage/seed_spec.rb b/spec/lib/gitlab/ci/stage/seed_spec.rb index 47a797cfe8f..d7e91a5a62c 100644 --- a/spec/lib/gitlab/ci/stage/seed_spec.rb +++ b/spec/lib/gitlab/ci/stage/seed_spec.rb @@ -30,7 +30,7 @@ describe Gitlab::Ci::Stage::Seed do end describe '#user=' do - let(:user) { create(:user) } + let(:user) { build(:user) } it 'assignes relevant pipeline attributes' do subject.user = user diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index a4392ed073a..b50c7700bd3 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -535,9 +535,9 @@ describe Ci::Pipeline, models: true do end end - describe '#has_stage_seedss?' do + describe '#has_stage_seeds?' do context 'when pipeline has stage seeds' do - subject { create(:ci_pipeline_with_one_job) } + subject { build(:ci_pipeline_with_one_job) } it { is_expected.to have_stage_seeds } end From 602724fcfc9c482d248e512a07fdf0fda6dd0613 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 6 Jun 2017 15:29:02 +0200 Subject: [PATCH 20/22] Clone stage_id when retrying a CI/CD job --- app/services/ci/retry_build_service.rb | 2 +- spec/services/ci/retry_build_service_spec.rb | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/services/ci/retry_build_service.rb b/app/services/ci/retry_build_service.rb index f51e9fd1d54..6372e5755db 100644 --- a/app/services/ci/retry_build_service.rb +++ b/app/services/ci/retry_build_service.rb @@ -1,7 +1,7 @@ module Ci class RetryBuildService < ::BaseService CLONE_ACCESSORS = %i[pipeline project ref tag options commands name - allow_failure stage stage_idx trigger_request + allow_failure stage_id stage stage_idx trigger_request yaml_variables when environment coverage_regex description tag_list].freeze diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index 2bd5af25847..7254e6b357a 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -18,12 +18,11 @@ describe Ci::RetryBuildService, :services do updated_at started_at finished_at queued_at erased_by erased_at auto_canceled_by].freeze - # TODO, move stage_id accessor to CLONE_ACCESSOR in a follow-up MR. IGNORE_ACCESSORS = %i[type lock_version target_url base_tags commit_id deployments erased_by_id last_deployment project_id runner_id tag_taggings taggings tags trigger_request_id - user_id auto_canceled_by_id retried stage_id].freeze + user_id auto_canceled_by_id retried].freeze shared_examples 'build duplication' do let(:build) do From ebce2565ec85f0c3d0b6bdbd427b082283f5c2b0 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 6 Jun 2017 20:55:13 +0200 Subject: [PATCH 21/22] Add changelog for persistent stages improvement --- changelogs/unreleased/feature-gb-persist-pipeline-stages.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelogs/unreleased/feature-gb-persist-pipeline-stages.yml diff --git a/changelogs/unreleased/feature-gb-persist-pipeline-stages.yml b/changelogs/unreleased/feature-gb-persist-pipeline-stages.yml new file mode 100644 index 00000000000..1404b342359 --- /dev/null +++ b/changelogs/unreleased/feature-gb-persist-pipeline-stages.yml @@ -0,0 +1,4 @@ +--- +title: Persist pipeline stages in the database +merge_request: 11790 +author: From 4edde47e7332bf3c29f030dfdac6a017f4ea8b6c Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 7 Jun 2017 10:05:40 +0200 Subject: [PATCH 22/22] Fix retry build service specs related to the stage --- spec/services/ci/retry_build_service_spec.rb | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index 7254e6b357a..ef9927c5969 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -25,12 +25,24 @@ describe Ci::RetryBuildService, :services do user_id auto_canceled_by_id retried].freeze shared_examples 'build duplication' do + let(:stage) do + # TODO, we still do not have factory for new stages, we will need to + # switch existing factory to persist stages, instead of using LegacyStage + # + Ci::Stage.create!(project: project, pipeline: pipeline, name: 'test') + end + let(:build) do create(:ci_build, :failed, :artifacts_expired, :erased, :queued, :coverage, :tags, :allowed_to_fail, :on_tag, - :teardown_environment, :triggered, :trace, - description: 'some build', pipeline: pipeline, - auto_canceled_by: create(:ci_empty_pipeline)) + :triggered, :trace, :teardown_environment, + description: 'my-job', stage: 'test', pipeline: pipeline, + auto_canceled_by: create(:ci_empty_pipeline)) do |build| + ## + # TODO, workaround for FactoryGirl limitation when having both + # stage (text) and stage_id (integer) columns in the table. + build.stage_id = stage.id + end end describe 'clone accessors' do