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
requires :id , type : String , desc : 'The ID of a project'
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
success Entities :: CommitStatus
end
params do
requires :sha , type : String , desc : 'The commit hash'
optional :ref , type : String , desc : 'The ref'
optional :stage , type : String , desc : 'The stage'
optional :name , type : String , desc : 'The name'
optional :all , type : String , desc : 'Show all statuses, default: false'
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 ] )
2016-06-16 23:09:34 +05:30
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
success Entities :: CommitStatus
end
params do
requires :sha , type : String , desc : 'The commit hash'
requires :state , type : String , desc : 'The state of the status' ,
values : %w( pending running success failed canceled )
optional :ref , type : String , desc : 'The ref'
optional :target_url , type : String , desc : 'The target URL to associate with this status'
optional :description , type : String , desc : 'A short description of the status'
2022-11-25 23:54:43 +05:30
optional :name , type : String , desc : 'A string label to differentiate this status from the status of other systems. Default: "default"' , documentation : { default : 'default' }
optional :context , type : String , desc : 'A string label to differentiate this status from the status of other systems. Default: "default"' , documentation : { default : 'default' }
2017-08-17 22:00:37 +05:30
optional :coverage , type : Float , desc : 'The total code coverage'
2019-10-12 21:52:04 +05:30
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
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 ,
2020-03-13 15:44:24 +05:30
protected : user_project . protected_for? ( ref )
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 ]
pipelines = pipelines . for_id ( params [ :pipeline_id ] ) if params [ :pipeline_id ]
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