Merge branch 'backstage/gb/build-pipeline-in-a-separate-class' into 'master'
Extract class responsible for building a pipeline Closes #38460 See merge request gitlab-org/gitlab-ce!14762
This commit is contained in:
commit
cadf378f29
|
@ -40,7 +40,6 @@ module Ci
|
||||||
validates :status, presence: { unless: :importing? }
|
validates :status, presence: { unless: :importing? }
|
||||||
validate :valid_commit_sha, unless: :importing?
|
validate :valid_commit_sha, unless: :importing?
|
||||||
|
|
||||||
after_initialize :set_config_source, if: :new_record?
|
|
||||||
after_create :keep_around_commits, unless: :importing?
|
after_create :keep_around_commits, unless: :importing?
|
||||||
|
|
||||||
enum source: {
|
enum source: {
|
||||||
|
|
|
@ -2,27 +2,24 @@ module Ci
|
||||||
class CreatePipelineService < BaseService
|
class CreatePipelineService < BaseService
|
||||||
attr_reader :pipeline
|
attr_reader :pipeline
|
||||||
|
|
||||||
SEQUENCE = [Gitlab::Ci::Pipeline::Chain::Validate::Abilities,
|
SEQUENCE = [Gitlab::Ci::Pipeline::Chain::Build,
|
||||||
|
Gitlab::Ci::Pipeline::Chain::Validate::Abilities,
|
||||||
Gitlab::Ci::Pipeline::Chain::Validate::Repository,
|
Gitlab::Ci::Pipeline::Chain::Validate::Repository,
|
||||||
Gitlab::Ci::Pipeline::Chain::Validate::Config,
|
Gitlab::Ci::Pipeline::Chain::Validate::Config,
|
||||||
Gitlab::Ci::Pipeline::Chain::Skip,
|
Gitlab::Ci::Pipeline::Chain::Skip,
|
||||||
Gitlab::Ci::Pipeline::Chain::Create].freeze
|
Gitlab::Ci::Pipeline::Chain::Create].freeze
|
||||||
|
|
||||||
def execute(source, ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, schedule: nil, &block)
|
def execute(source, ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, schedule: nil, &block)
|
||||||
@pipeline = Ci::Pipeline.new(
|
@pipeline = Ci::Pipeline.new
|
||||||
source: source,
|
|
||||||
project: project,
|
|
||||||
ref: ref,
|
|
||||||
sha: sha,
|
|
||||||
before_sha: before_sha,
|
|
||||||
tag: tag_exists?,
|
|
||||||
trigger_requests: Array(trigger_request),
|
|
||||||
user: current_user,
|
|
||||||
pipeline_schedule: schedule,
|
|
||||||
protected: project.protected_for?(ref)
|
|
||||||
)
|
|
||||||
|
|
||||||
command = OpenStruct.new(ignore_skip_ci: ignore_skip_ci,
|
command = OpenStruct.new(source: source,
|
||||||
|
origin_ref: params[:ref],
|
||||||
|
checkout_sha: params[:checkout_sha],
|
||||||
|
after_sha: params[:after],
|
||||||
|
before_sha: params[:before],
|
||||||
|
trigger_request: trigger_request,
|
||||||
|
schedule: schedule,
|
||||||
|
ignore_skip_ci: ignore_skip_ci,
|
||||||
save_incompleted: save_on_errors,
|
save_incompleted: save_on_errors,
|
||||||
seeds_block: block,
|
seeds_block: block,
|
||||||
project: project,
|
project: project,
|
||||||
|
@ -45,14 +42,6 @@ module Ci
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def commit
|
|
||||||
@commit ||= project.commit(origin_sha || origin_ref)
|
|
||||||
end
|
|
||||||
|
|
||||||
def sha
|
|
||||||
commit.try(:id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def update_merge_requests_head_pipeline
|
def update_merge_requests_head_pipeline
|
||||||
return unless pipeline.latest?
|
return unless pipeline.latest?
|
||||||
|
|
||||||
|
@ -76,26 +65,6 @@ module Ci
|
||||||
.created_or_pending
|
.created_or_pending
|
||||||
end
|
end
|
||||||
|
|
||||||
def before_sha
|
|
||||||
params[:checkout_sha] || params[:before] || Gitlab::Git::BLANK_SHA
|
|
||||||
end
|
|
||||||
|
|
||||||
def origin_sha
|
|
||||||
params[:checkout_sha] || params[:after]
|
|
||||||
end
|
|
||||||
|
|
||||||
def origin_ref
|
|
||||||
params[:ref]
|
|
||||||
end
|
|
||||||
|
|
||||||
def tag_exists?
|
|
||||||
project.repository.tag_exists?(ref)
|
|
||||||
end
|
|
||||||
|
|
||||||
def ref
|
|
||||||
@ref ||= Gitlab::Git.ref_name(origin_ref)
|
|
||||||
end
|
|
||||||
|
|
||||||
def pipeline_created_counter
|
def pipeline_created_counter
|
||||||
@pipeline_created_counter ||= Gitlab::Metrics
|
@pipeline_created_counter ||= Gitlab::Metrics
|
||||||
.counter(:pipelines_created_total, "Counter of pipelines created")
|
.counter(:pipelines_created_total, "Counter of pipelines created")
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
module Gitlab
|
||||||
|
module Ci
|
||||||
|
module Pipeline
|
||||||
|
module Chain
|
||||||
|
class Build < Chain::Base
|
||||||
|
include Chain::Helpers
|
||||||
|
|
||||||
|
def perform!
|
||||||
|
@pipeline.assign_attributes(
|
||||||
|
source: @command.source,
|
||||||
|
project: @project,
|
||||||
|
ref: ref,
|
||||||
|
sha: sha,
|
||||||
|
before_sha: before_sha,
|
||||||
|
tag: tag_exists?,
|
||||||
|
trigger_requests: Array(@command.trigger_request),
|
||||||
|
user: @current_user,
|
||||||
|
pipeline_schedule: @command.schedule,
|
||||||
|
protected: protected_ref?
|
||||||
|
)
|
||||||
|
|
||||||
|
@pipeline.set_config_source
|
||||||
|
end
|
||||||
|
|
||||||
|
def break?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def ref
|
||||||
|
@ref ||= Gitlab::Git.ref_name(origin_ref)
|
||||||
|
end
|
||||||
|
|
||||||
|
def sha
|
||||||
|
@project.commit(origin_sha || origin_ref).try(:id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def origin_ref
|
||||||
|
@command.origin_ref
|
||||||
|
end
|
||||||
|
|
||||||
|
def origin_sha
|
||||||
|
@command.checkout_sha || @command.after_sha
|
||||||
|
end
|
||||||
|
|
||||||
|
def before_sha
|
||||||
|
@command.checkout_sha || @command.before_sha || Gitlab::Git::BLANK_SHA
|
||||||
|
end
|
||||||
|
|
||||||
|
def protected_ref?
|
||||||
|
@project.protected_for?(ref)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,51 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Gitlab::Ci::Pipeline::Chain::Build do
|
||||||
|
set(:project) { create(:project, :repository) }
|
||||||
|
set(:user) { create(:user) }
|
||||||
|
let(:pipeline) { Ci::Pipeline.new }
|
||||||
|
|
||||||
|
let(:command) do
|
||||||
|
double('command', source: :push,
|
||||||
|
origin_ref: 'master',
|
||||||
|
checkout_sha: project.commit.id,
|
||||||
|
after_sha: nil,
|
||||||
|
before_sha: nil,
|
||||||
|
trigger_request: nil,
|
||||||
|
schedule: nil,
|
||||||
|
project: project,
|
||||||
|
current_user: user)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:step) { described_class.new(pipeline, command) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_repository_ci_yaml_file(sha: anything)
|
||||||
|
|
||||||
|
step.perform!
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'never breaks the chain' do
|
||||||
|
expect(step.break?).to be false
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'fills pipeline object with data' do
|
||||||
|
expect(pipeline.sha).not_to be_empty
|
||||||
|
expect(pipeline.sha).to eq project.commit.id
|
||||||
|
expect(pipeline.ref).to eq 'master'
|
||||||
|
expect(pipeline.user).to eq user
|
||||||
|
expect(pipeline.project).to eq project
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sets a valid config source' do
|
||||||
|
expect(pipeline.repository_source?).to be true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a valid pipeline' do
|
||||||
|
expect(pipeline).to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not persist a pipeline' do
|
||||||
|
expect(pipeline).not_to be_persisted
|
||||||
|
end
|
||||||
|
end
|
|
@ -868,62 +868,59 @@ describe Ci::Pipeline, :mailer do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#set_config_source' do
|
describe '#set_config_source' do
|
||||||
context 'on object initialisation' do
|
context 'when pipelines does not contain needed data' do
|
||||||
context 'when pipelines does not contain needed data' do
|
it 'defines source to be unknown' do
|
||||||
let(:pipeline) do
|
pipeline.set_config_source
|
||||||
Ci::Pipeline.new
|
|
||||||
|
expect(pipeline).to be_unknown_source
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when pipeline contains all needed data' do
|
||||||
|
let(:pipeline) do
|
||||||
|
create(:ci_pipeline, project: project,
|
||||||
|
sha: '1234',
|
||||||
|
ref: 'master',
|
||||||
|
source: :push)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the repository has a config file' do
|
||||||
|
before do
|
||||||
|
allow(project.repository).to receive(:gitlab_ci_yml_for)
|
||||||
|
.and_return('config')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'defines source to be unknown' do
|
it 'defines source to be from repository' do
|
||||||
expect(pipeline).to be_unknown_source
|
pipeline.set_config_source
|
||||||
|
|
||||||
|
expect(pipeline).to be_repository_source
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when loading an object' do
|
||||||
|
let(:new_pipeline) { Ci::Pipeline.find(pipeline.id) }
|
||||||
|
|
||||||
|
it 'does not redefine the source' do
|
||||||
|
# force to overwrite the source
|
||||||
|
pipeline.unknown_source!
|
||||||
|
|
||||||
|
expect(new_pipeline).to be_unknown_source
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when pipeline contains all needed data' do
|
context 'when the repository does not have a config file' do
|
||||||
let(:pipeline) do
|
let(:implied_yml) { Gitlab::Template::GitlabCiYmlTemplate.find('Auto-DevOps').content }
|
||||||
Ci::Pipeline.new(
|
|
||||||
project: project,
|
|
||||||
sha: '1234',
|
|
||||||
ref: 'master',
|
|
||||||
source: :push)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the repository has a config file' do
|
context 'auto devops enabled' do
|
||||||
before do
|
before do
|
||||||
allow(project.repository).to receive(:gitlab_ci_yml_for)
|
stub_application_setting(auto_devops_enabled: true)
|
||||||
.and_return('config')
|
allow(project).to receive(:ci_config_path) { 'custom' }
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'defines source to be from repository' do
|
it 'defines source to be auto devops' do
|
||||||
expect(pipeline).to be_repository_source
|
pipeline.set_config_source
|
||||||
end
|
|
||||||
|
|
||||||
context 'when loading an object' do
|
expect(pipeline).to be_auto_devops_source
|
||||||
let(:new_pipeline) { Ci::Pipeline.find(pipeline.id) }
|
|
||||||
|
|
||||||
it 'does not redefine the source' do
|
|
||||||
# force to overwrite the source
|
|
||||||
pipeline.unknown_source!
|
|
||||||
|
|
||||||
expect(new_pipeline).to be_unknown_source
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the repository does not have a config file' do
|
|
||||||
let(:implied_yml) { Gitlab::Template::GitlabCiYmlTemplate.find('Auto-DevOps').content }
|
|
||||||
|
|
||||||
context 'auto devops enabled' do
|
|
||||||
before do
|
|
||||||
stub_application_setting(auto_devops_enabled: true)
|
|
||||||
allow(project).to receive(:ci_config_path) { 'custom' }
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'defines source to be auto devops' do
|
|
||||||
subject
|
|
||||||
|
|
||||||
expect(pipeline).to be_auto_devops_source
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,7 +8,7 @@ describe Ci::CreatePipelineService do
|
||||||
let(:ref_name) { 'refs/heads/master' }
|
let(:ref_name) { 'refs/heads/master' }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_ci_pipeline_to_return_yaml_file
|
stub_repository_ci_yaml_file(sha: anything)
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#execute' do
|
describe '#execute' do
|
||||||
|
@ -44,6 +44,7 @@ describe Ci::CreatePipelineService do
|
||||||
expect(pipeline).to eq(project.pipelines.last)
|
expect(pipeline).to eq(project.pipelines.last)
|
||||||
expect(pipeline).to have_attributes(user: user)
|
expect(pipeline).to have_attributes(user: user)
|
||||||
expect(pipeline).to have_attributes(status: 'pending')
|
expect(pipeline).to have_attributes(status: 'pending')
|
||||||
|
expect(pipeline.repository_source?).to be true
|
||||||
expect(pipeline.builds.first).to be_kind_of(Ci::Build)
|
expect(pipeline.builds.first).to be_kind_of(Ci::Build)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,12 @@ module StubGitlabCalls
|
||||||
allow_any_instance_of(Ci::Pipeline).to receive(:ci_yaml_file) { ci_yaml }
|
allow_any_instance_of(Ci::Pipeline).to receive(:ci_yaml_file) { ci_yaml }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def stub_repository_ci_yaml_file(sha:, path: '.gitlab-ci.yml')
|
||||||
|
allow_any_instance_of(Repository)
|
||||||
|
.to receive(:gitlab_ci_yml_for).with(sha, path)
|
||||||
|
.and_return(gitlab_ci_yaml)
|
||||||
|
end
|
||||||
|
|
||||||
def stub_ci_builds_disabled
|
def stub_ci_builds_disabled
|
||||||
allow_any_instance_of(Project).to receive(:builds_enabled?).and_return(false)
|
allow_any_instance_of(Project).to receive(:builds_enabled?).and_return(false)
|
||||||
end
|
end
|
||||||
|
|
|
@ -66,19 +66,21 @@ describe PostReceive do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "gitlab-ci.yml" do
|
context "gitlab-ci.yml" do
|
||||||
|
let(:changes) { "123456 789012 refs/heads/feature\n654321 210987 refs/tags/tag" }
|
||||||
|
|
||||||
subject { described_class.new.perform(gl_repository, key_id, base64_changes) }
|
subject { described_class.new.perform(gl_repository, key_id, base64_changes) }
|
||||||
|
|
||||||
context "creates a Ci::Pipeline for every change" do
|
context "creates a Ci::Pipeline for every change" do
|
||||||
before do
|
before do
|
||||||
stub_ci_pipeline_to_return_yaml_file
|
stub_ci_pipeline_to_return_yaml_file
|
||||||
|
|
||||||
# TODO, don't stub private methods
|
allow_any_instance_of(Project)
|
||||||
#
|
.to receive(:commit)
|
||||||
allow_any_instance_of(Ci::CreatePipelineService)
|
.and_return(project.commit)
|
||||||
.to receive(:commit).and_return(OpenStruct.new(id: '123456'))
|
|
||||||
|
|
||||||
allow_any_instance_of(Repository)
|
allow_any_instance_of(Repository)
|
||||||
.to receive(:branch_exists?).and_return(true)
|
.to receive(:branch_exists?)
|
||||||
|
.and_return(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
it { expect { subject }.to change { Ci::Pipeline.count }.by(2) }
|
it { expect { subject }.to change { Ci::Pipeline.count }.by(2) }
|
||||||
|
|
Loading…
Reference in New Issue