ba781484c7
gitlab-org/gitlab-shell!166 added support for collecting push options from the environment, and passing them along to the /internal/post_receive API endpoint. This change handles the new push_options JSON element in the payload, and passes them on through to the GitPushService and GitTagPushService services. Futhermore, it adds support for the first push option, ci.skip. With this change, one can use 'git push -o ci.skip' to skip CI pipe execution. Note that the pipeline is still created, but in the "skipped" state, just like with the 'ci skip' commit message text. Implements #18667
107 lines
3.2 KiB
Ruby
107 lines
3.2 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Ci
|
|
class CreatePipelineService < BaseService
|
|
attr_reader :pipeline
|
|
|
|
CreateError = Class.new(StandardError)
|
|
|
|
SEQUENCE = [Gitlab::Ci::Pipeline::Chain::Build,
|
|
Gitlab::Ci::Pipeline::Chain::Validate::Abilities,
|
|
Gitlab::Ci::Pipeline::Chain::Validate::Repository,
|
|
Gitlab::Ci::Pipeline::Chain::Validate::Config,
|
|
Gitlab::Ci::Pipeline::Chain::Skip,
|
|
Gitlab::Ci::Pipeline::Chain::Populate,
|
|
Gitlab::Ci::Pipeline::Chain::Create].freeze
|
|
|
|
def execute(source, ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, schedule: nil, merge_request: nil, &block)
|
|
@pipeline = Ci::Pipeline.new
|
|
|
|
command = Gitlab::Ci::Pipeline::Chain::Command.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,
|
|
merge_request: merge_request,
|
|
ignore_skip_ci: ignore_skip_ci,
|
|
save_incompleted: save_on_errors,
|
|
seeds_block: block,
|
|
variables_attributes: params[:variables_attributes],
|
|
project: project,
|
|
current_user: current_user,
|
|
push_options: params[:push_options])
|
|
|
|
sequence = Gitlab::Ci::Pipeline::Chain::Sequence
|
|
.new(pipeline, command, SEQUENCE)
|
|
|
|
sequence.build! do |pipeline, sequence|
|
|
schedule_head_pipeline_update
|
|
|
|
if sequence.complete?
|
|
cancel_pending_pipelines if project.auto_cancel_pending_pipelines?
|
|
pipeline_created_counter.increment(source: source)
|
|
|
|
pipeline.process!
|
|
end
|
|
end
|
|
|
|
pipeline
|
|
end
|
|
|
|
def execute!(*args, &block)
|
|
execute(*args, &block).tap do |pipeline|
|
|
unless pipeline.persisted?
|
|
raise CreateError, pipeline.errors.full_messages.join(',')
|
|
end
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def commit
|
|
@commit ||= project.commit(origin_sha || origin_ref)
|
|
end
|
|
|
|
def sha
|
|
commit.try(:id)
|
|
end
|
|
|
|
def cancel_pending_pipelines
|
|
Gitlab::OptimisticLocking.retry_lock(auto_cancelable_pipelines) do |cancelables|
|
|
cancelables.find_each do |cancelable|
|
|
cancelable.auto_cancel_running(pipeline)
|
|
end
|
|
end
|
|
end
|
|
|
|
# rubocop: disable CodeReuse/ActiveRecord
|
|
def auto_cancelable_pipelines
|
|
project.ci_pipelines
|
|
.where(ref: pipeline.ref)
|
|
.where.not(id: pipeline.id)
|
|
.where.not(sha: project.commit(pipeline.ref).try(:id))
|
|
.created_or_pending
|
|
end
|
|
# rubocop: enable CodeReuse/ActiveRecord
|
|
|
|
def pipeline_created_counter
|
|
@pipeline_created_counter ||= Gitlab::Metrics
|
|
.counter(:pipelines_created_total, "Counter of pipelines created")
|
|
end
|
|
|
|
def schedule_head_pipeline_update
|
|
related_merge_requests.each do |merge_request|
|
|
UpdateHeadPipelineForMergeRequestWorker.perform_async(merge_request.id)
|
|
end
|
|
end
|
|
|
|
# rubocop: disable CodeReuse/ActiveRecord
|
|
def related_merge_requests
|
|
pipeline.project.source_of_merge_requests.opened.where(source_branch: pipeline.ref)
|
|
end
|
|
# rubocop: enable CodeReuse/ActiveRecord
|
|
end
|
|
end
|