debian-mirror-gitlab/app/services/ci/create_pipeline_service.rb

194 lines
5 KiB
Ruby
Raw Normal View History

2016-06-02 11:05:42 +05:30
module Ci
class CreatePipelineService < BaseService
2016-09-13 17:45:13 +05:30
attr_reader :pipeline
2016-06-02 11:05:42 +05:30
2017-09-10 17:25:29 +05:30
def execute(source, ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, schedule: nil)
2016-09-13 17:45:13 +05:30
@pipeline = Ci::Pipeline.new(
2017-09-10 17:25:29 +05:30
source: source,
2016-09-13 17:45:13 +05:30
project: project,
ref: ref,
sha: sha,
before_sha: before_sha,
tag: tag?,
trigger_requests: Array(trigger_request),
2017-08-17 22:00:37 +05:30
user: current_user,
pipeline_schedule: schedule
2016-09-13 17:45:13 +05:30
)
2017-09-10 17:25:29 +05:30
result = validate(current_user,
ignore_skip_ci: ignore_skip_ci,
save_on_errors: save_on_errors)
return result if result
begin
Ci::Pipeline.transaction do
pipeline.save!
yield(pipeline) if block_given?
Ci::CreatePipelineStagesService
.new(project, current_user)
.execute(pipeline)
end
rescue ActiveRecord::RecordInvalid => e
return error("Failed to persist the pipeline: #{e}")
end
update_merge_requests_head_pipeline
cancel_pending_pipelines if project.auto_cancel_pending_pipelines?
pipeline_created_counter.increment(source: source)
pipeline.tap(&:process!)
end
private
def validate(triggering_user, ignore_skip_ci:, save_on_errors:)
2016-09-13 17:45:13 +05:30
unless project.builds_enabled?
return error('Pipeline is disabled')
2016-06-02 11:05:42 +05:30
end
2017-09-10 17:25:29 +05:30
unless allowed_to_trigger_pipeline?(triggering_user)
if can?(triggering_user, :create_pipeline, project)
return error("Insufficient permissions for protected ref '#{ref}'")
else
return error('Insufficient permissions to create a new pipeline')
end
2016-06-02 11:05:42 +05:30
end
2016-09-13 17:45:13 +05:30
unless branch? || tag?
return error('Reference not found')
end
unless commit
return error('Commit not found')
2016-06-02 11:05:42 +05:30
end
2016-06-22 15:30:34 +05:30
unless pipeline.config_processor
2016-09-13 17:45:13 +05:30
unless pipeline.ci_yaml_file
2017-09-10 17:25:29 +05:30
return error("Missing #{pipeline.ci_yaml_file_path} file")
2016-09-13 17:45:13 +05:30
end
return error(pipeline.yaml_errors, save: save_on_errors)
2016-06-22 15:30:34 +05:30
end
2016-06-02 11:05:42 +05:30
2016-09-13 17:45:13 +05:30
if !ignore_skip_ci && skip_ci?
pipeline.skip if save_on_errors
return pipeline
end
2016-06-02 11:05:42 +05:30
2017-09-10 17:25:29 +05:30
unless pipeline.has_stage_seeds?
return error('No stages / jobs for this pipeline.')
2016-06-02 11:05:42 +05:30
end
2017-09-10 17:25:29 +05:30
end
2016-06-02 11:05:42 +05:30
2017-09-10 17:25:29 +05:30
def allowed_to_trigger_pipeline?(triggering_user)
if triggering_user
allowed_to_create?(triggering_user)
else # legacy triggers don't have a corresponding user
!project.protected_for?(ref)
2017-08-17 22:00:37 +05:30
end
2017-09-10 17:25:29 +05:30
end
2017-08-17 22:00:37 +05:30
2017-09-10 17:25:29 +05:30
def allowed_to_create?(triggering_user)
access = Gitlab::UserAccess.new(triggering_user, project: project)
2017-08-17 22:00:37 +05:30
2017-09-10 17:25:29 +05:30
can?(triggering_user, :create_pipeline, project) &&
if branch?
access.can_update_branch?(ref)
elsif tag?
access.can_create_tag?(ref)
else
true # Allow it for now and we'll reject when we check ref existence
end
2016-06-02 11:05:42 +05:30
end
2017-09-10 17:25:29 +05:30
def update_merge_requests_head_pipeline
return unless pipeline.latest?
MergeRequest.where(source_project: @pipeline.project, source_branch: @pipeline.ref)
.update_all(head_pipeline_id: @pipeline.id)
end
2016-06-02 11:05:42 +05:30
2016-09-13 17:45:13 +05:30
def skip_ci?
2017-08-17 22:00:37 +05:30
return false unless pipeline.git_commit_message
pipeline.git_commit_message =~ /\[(ci[ _-]skip|skip[ _-]ci)\]/i
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
def auto_cancelable_pipelines
project.pipelines
.where(ref: pipeline.ref)
.where.not(id: pipeline.id)
.where.not(sha: project.repository.sha_from_ref(pipeline.ref))
.created_or_pending
2016-06-02 11:05:42 +05:30
end
def commit
2016-09-13 17:45:13 +05:30
@commit ||= project.commit(origin_sha || origin_ref)
end
def sha
commit.try(:id)
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 branch?
2017-09-10 17:25:29 +05:30
return @is_branch if defined?(@is_branch)
@is_branch =
project.repository.ref_exists?(Gitlab::Git::BRANCH_REF_PREFIX + ref)
2016-09-13 17:45:13 +05:30
end
def tag?
2017-09-10 17:25:29 +05:30
return @is_tag if defined?(@is_tag)
@is_tag =
project.repository.ref_exists?(Gitlab::Git::TAG_REF_PREFIX + ref)
2016-09-13 17:45:13 +05:30
end
def ref
2017-09-10 17:25:29 +05:30
@ref ||= Gitlab::Git.ref_name(origin_ref)
2016-09-13 17:45:13 +05:30
end
def valid_sha?
origin_sha && origin_sha != Gitlab::Git::BLANK_SHA
end
def error(message, save: false)
2017-09-10 17:25:29 +05:30
pipeline.tap do
pipeline.errors.add(:base, message)
if save
pipeline.drop
update_merge_requests_head_pipeline
end
end
end
def pipeline_created_counter
@pipeline_created_counter ||= Gitlab::Metrics.counter(:pipelines_created_total, "Counter of pipelines created")
2016-06-02 11:05:42 +05:30
end
end
end