Commit cadf378f authored by Kamil Trzciński's avatar Kamil Trzciński

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
parents 4ebc674a 16a83724
...@@ -40,7 +40,6 @@ module Ci ...@@ -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 ...@@ -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, command = OpenStruct.new(source: source,
ref: ref, origin_ref: params[:ref],
sha: sha, checkout_sha: params[:checkout_sha],
before_sha: before_sha, after_sha: params[:after],
tag: tag_exists?, before_sha: params[:before],
trigger_requests: Array(trigger_request), trigger_request: trigger_request,
user: current_user, schedule: schedule,
pipeline_schedule: schedule, ignore_skip_ci: ignore_skip_ci,
protected: project.protected_for?(ref)
)
command = OpenStruct.new(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 ...@@ -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 ...@@ -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")
......
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
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 ...@@ -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
end
it 'defines source to be unknown' do expect(pipeline).to be_unknown_source
expect(pipeline).to be_unknown_source
end
end end
end
context 'when pipeline contains all needed data' do context 'when pipeline contains all needed data' do
let(:pipeline) do let(:pipeline) do
Ci::Pipeline.new( create(:ci_pipeline, project: project,
project: project, sha: '1234',
sha: '1234', ref: 'master',
ref: 'master', source: :push)
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
context 'when the repository has a config file' do it 'defines source to be from repository' do
before do pipeline.set_config_source
allow(project.repository).to receive(:gitlab_ci_yml_for)
.and_return('config')
end
it 'defines source to be from repository' do expect(pipeline).to be_repository_source
expect(pipeline).to be_repository_source end
end
context 'when loading an object' do context 'when loading an object' do
let(:new_pipeline) { Ci::Pipeline.find(pipeline.id) } let(:new_pipeline) { Ci::Pipeline.find(pipeline.id) }
it 'does not redefine the source' do it 'does not redefine the source' do
# force to overwrite the source # force to overwrite the source
pipeline.unknown_source! pipeline.unknown_source!
expect(new_pipeline).to be_unknown_source expect(new_pipeline).to be_unknown_source
end
end end
end end
end
context 'when the repository does not have a config file' do context 'when the repository does not have a config file' do
let(:implied_yml) { Gitlab::Template::GitlabCiYmlTemplate.find('Auto-DevOps').content } let(:implied_yml) { Gitlab::Template::GitlabCiYmlTemplate.find('Auto-DevOps').content }
context 'auto devops enabled' do context 'auto devops enabled' do
before do before do
stub_application_setting(auto_devops_enabled: true) stub_application_setting(auto_devops_enabled: true)
allow(project).to receive(:ci_config_path) { 'custom' } allow(project).to receive(:ci_config_path) { 'custom' }
end end
it 'defines source to be auto devops' do it 'defines source to be auto devops' do
subject pipeline.set_config_source
expect(pipeline).to be_auto_devops_source expect(pipeline).to be_auto_devops_source
end
end end
end end
end end
......
...@@ -8,7 +8,7 @@ describe Ci::CreatePipelineService do ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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) }
......
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