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:
Kamil Trzciński 2017-12-01 12:02:04 +00:00
commit cadf378f29
8 changed files with 178 additions and 95 deletions

View File

@ -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: {

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) }