debian-mirror-gitlab/lib/api/commit_statuses.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

190 lines
7.5 KiB
Ruby
Raw Permalink Normal View History

2018-12-05 23:21:45 +05:30
# frozen_string_literal: true
2015-10-24 18:46:33 +05:30
require 'mime/types'
module API
2021-01-03 14:25:43 +05:30
class CommitStatuses < ::API::Base
2021-01-29 00:20:46 +05:30
feature_category :continuous_integration
2022-07-16 23:28:13 +05:30
urgency :low
2021-01-29 00:20:46 +05:30
2017-08-17 22:00:37 +05:30
params do
2023-01-13 00:05:48 +05:30
requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
2017-08-17 22:00:37 +05:30
end
2019-02-15 15:39:39 +05:30
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
2017-08-17 22:00:37 +05:30
include PaginationParams
2015-10-24 18:46:33 +05:30
before { authenticate! }
2017-08-17 22:00:37 +05:30
desc "Get a commit's statuses" do
2023-01-13 00:05:48 +05:30
success code: 200, model: Entities::CommitStatus
failure [
{ code: 401, message: 'Unauthorized' },
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not found' }
]
is_array true
2017-08-17 22:00:37 +05:30
end
params do
2023-01-13 00:05:48 +05:30
requires :sha, type: String, desc: 'The commit hash', documentation: { example: '18f3e63d05582537db6d183d9d557be09e1f90c8' }
optional :ref, type: String, desc: 'The ref', documentation: { example: 'develop' }
optional :stage, type: String, desc: 'The stage', documentation: { example: 'test' }
optional :name, type: String, desc: 'The name', documentation: { example: 'bundler:audit' }
optional :all, type: Boolean, desc: 'Show all statuses', documentation: { default: false }
2017-08-17 22:00:37 +05:30
use :pagination
end
2018-12-05 23:21:45 +05:30
# rubocop: disable CodeReuse/ActiveRecord
2015-10-24 18:46:33 +05:30
get ':id/repository/commits/:sha/statuses' do
2016-06-02 11:05:42 +05:30
authorize!(:read_commit_status, user_project)
not_found!('Commit') unless user_project.commit(params[:sha])
2019-02-15 15:39:39 +05:30
pipelines = user_project.ci_pipelines.where(sha: params[:sha])
statuses = ::CommitStatus.where(pipeline: pipelines)
2016-09-13 17:45:13 +05:30
statuses = statuses.latest unless to_boolean(params[:all])
2015-10-24 18:46:33 +05:30
statuses = statuses.where(ref: params[:ref]) if params[:ref].present?
statuses = statuses.where(stage: params[:stage]) if params[:stage].present?
statuses = statuses.where(name: params[:name]) if params[:name].present?
present paginate(statuses), with: Entities::CommitStatus
end
2018-12-05 23:21:45 +05:30
# rubocop: enable CodeReuse/ActiveRecord
2015-10-24 18:46:33 +05:30
2017-08-17 22:00:37 +05:30
desc 'Post status to a commit' do
2023-01-13 00:05:48 +05:30
success code: 200, model: Entities::CommitStatus
failure [
{ code: 400, message: 'Bad request' },
{ code: 401, message: 'Unauthorized' },
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not found' }
]
2017-08-17 22:00:37 +05:30
end
params do
2023-01-13 00:05:48 +05:30
requires :sha, type: String, desc: 'The commit hash',
documentation: { example: '18f3e63d05582537db6d183d9d557be09e1f90c8' }
requires :state, type: String, desc: 'The state of the status',
values: %w(pending running success failed canceled),
documentation: { example: 'pending' }
optional :ref, type: String, desc: 'The ref',
documentation: { example: 'develop' }
optional :target_url, type: String, desc: 'The target URL to associate with this status',
documentation: { example: 'https://gitlab.example.com/janedoe/gitlab-foss/builds/91' }
optional :description, type: String, desc: 'A short description of the status'
optional :name, type: String, desc: 'A string label to differentiate this status from the status of other systems',
documentation: { example: 'coverage', default: 'default' }
optional :context, type: String, desc: 'A string label to differentiate this status from the status of other systems',
documentation: { example: 'coverage', default: 'default' }
optional :coverage, type: Float, desc: 'The total code coverage',
documentation: { example: 100.0 }
optional :pipeline_id, type: Integer, desc: 'An existing pipeline ID, when multiple pipelines on the same commit SHA have been triggered'
2017-08-17 22:00:37 +05:30
end
2018-12-05 23:21:45 +05:30
# rubocop: disable CodeReuse/ActiveRecord
2015-10-24 18:46:33 +05:30
post ':id/statuses/:sha' do
authorize! :create_commit_status, user_project
2017-08-17 22:00:37 +05:30
2015-10-24 18:46:33 +05:30
not_found! 'Commit' unless commit
2020-07-28 23:09:34 +05:30
# Since the CommitStatus is attached to ::Ci::Pipeline (in the future Pipeline)
2016-06-02 11:05:42 +05:30
# We need to always have the pipeline object
# To have a valid pipeline object that can be attached to specific MR
# Other CI service needs to send `ref`
# If we don't receive it, we will attach the CommitStatus to
# the first found branch on that commit
2019-12-21 20:55:43 +05:30
pipeline = all_matching_pipelines.first
2016-06-02 11:05:42 +05:30
ref = params[:ref]
2019-12-21 20:55:43 +05:30
ref ||= pipeline&.ref
2020-03-13 15:44:24 +05:30
ref ||= user_project.repository.branch_names_contains(commit.sha).first
2016-09-29 09:46:39 +05:30
not_found! 'References for commit' unless ref
2016-06-02 11:05:42 +05:30
2016-09-29 09:46:39 +05:30
name = params[:name] || params[:context] || 'default'
2015-10-24 18:46:33 +05:30
2022-01-26 12:08:38 +05:30
pipeline ||= user_project.ci_pipelines.build(
2020-03-13 15:44:24 +05:30
source: :external,
sha: commit.sha,
ref: ref,
user: current_user,
protected: user_project.protected_for?(ref))
2015-10-24 18:46:33 +05:30
2022-01-26 12:08:38 +05:30
pipeline.ensure_project_iid!
pipeline.save!
2020-02-01 01:16:34 +05:30
authorize! :update_pipeline, pipeline
2023-03-04 22:38:38 +05:30
# rubocop: disable Performance/ActiveRecordSubtransactionMethods
stage = pipeline.stages.safe_find_or_create_by!(name: 'external') do |stage|
stage.position = GenericCommitStatus::EXTERNAL_STAGE_IDX
stage.project = pipeline.project
end
# rubocop: enable Performance/ActiveRecordSubtransactionMethods
2016-09-29 09:46:39 +05:30
status = GenericCommitStatus.running_or_pending.find_or_initialize_by(
2020-03-13 15:44:24 +05:30
project: user_project,
2017-08-17 22:00:37 +05:30
pipeline: pipeline,
name: name,
ref: ref,
2018-03-17 18:26:18 +05:30
user: current_user,
2023-03-04 22:38:38 +05:30
protected: user_project.protected_for?(ref),
ci_stage: stage,
stage_idx: stage.position,
stage: 'external'
2017-08-17 22:00:37 +05:30
)
2021-09-04 01:27:46 +05:30
updatable_optional_attributes = %w[target_url description coverage]
status.assign_attributes(attributes_for_keys(updatable_optional_attributes))
2021-04-17 20:07:23 +05:30
2021-09-30 23:02:18 +05:30
render_validation_error!(status) unless status.valid?
2016-09-29 09:46:39 +05:30
2021-09-30 23:02:18 +05:30
response = ::Ci::Pipelines::AddJobService.new(pipeline).execute!(status) do |job|
apply_job_state!(job)
rescue ::StateMachines::InvalidTransition => e
render_api_error!(e.message, 400)
end
2015-10-24 18:46:33 +05:30
2021-09-30 23:02:18 +05:30
render_validation_error!(response.payload[:job]) unless response.success?
2017-09-10 17:25:29 +05:30
2021-09-30 23:02:18 +05:30
if pipeline.latest?
MergeRequest
.where(source_project: user_project, source_branch: ref)
.update_all(head_pipeline_id: pipeline.id)
2015-10-24 18:46:33 +05:30
end
2021-09-30 23:02:18 +05:30
present response.payload[:job], with: Entities::CommitStatus
2015-10-24 18:46:33 +05:30
end
2018-12-05 23:21:45 +05:30
# rubocop: enable CodeReuse/ActiveRecord
2021-09-30 23:02:18 +05:30
2019-12-21 20:55:43 +05:30
helpers do
def commit
strong_memoize(:commit) do
user_project.commit(params[:sha])
end
end
def all_matching_pipelines
pipelines = user_project.ci_pipelines.newest_first(sha: commit.sha)
pipelines = pipelines.for_ref(params[:ref]) if params[:ref]
2023-03-04 22:38:38 +05:30
pipelines = pipelines.id_in(params[:pipeline_id]) if params[:pipeline_id]
2019-12-21 20:55:43 +05:30
pipelines
end
2021-09-30 23:02:18 +05:30
def apply_job_state!(job)
case params[:state]
when 'pending'
job.enqueue!
when 'running'
job.enqueue
job.run!
when 'success'
job.success!
when 'failed'
job.drop!(:api_failure)
when 'canceled'
job.cancel!
else
render_api_error!('invalid state', 400)
end
end
2019-12-21 20:55:43 +05:30
end
2015-10-24 18:46:33 +05:30
end
end
end