2018-09-29 22:34:47 +00:00
# frozen_string_literal: true
2015-10-06 10:01:16 +00:00
require 'mime/types'
module API
2020-10-15 00:08:42 +00:00
class CommitStatuses < :: API :: Base
2020-10-29 12:08:50 +00:00
feature_category :continuous_integration
2022-04-27 15:10:01 +00:00
urgency :low
2020-10-29 12:08:50 +00:00
2017-03-15 18:09:24 +00:00
params do
2022-11-03 15:11:31 +00:00
requires :id , types : [ String , Integer ] , desc : 'The ID or URL-encoded path of the project'
2017-03-15 18:09:24 +00:00
end
2018-11-08 12:18:17 +00:00
resource :projects , requirements : API :: NAMESPACE_OR_PROJECT_REQUIREMENTS do
2016-12-04 17:11:19 +00:00
include PaginationParams
2015-10-06 10:01:16 +00:00
before { authenticate! }
2016-10-14 08:45:23 +00:00
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'
2016-12-04 17:11:19 +00:00
use :pagination
2016-10-14 08:45:23 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2015-10-06 10:01:16 +00:00
get ':id/repository/commits/:sha/statuses' do
2016-02-29 12:54:33 +00:00
authorize! ( :read_commit_status , user_project )
not_found! ( 'Commit' ) unless user_project . commit ( params [ :sha ] )
2018-12-05 14:39:15 +00:00
pipelines = user_project . ci_pipelines . where ( sha : params [ :sha ] )
2016-06-03 14:27:50 +00:00
statuses = :: CommitStatus . where ( pipeline : pipelines )
2016-07-20 06:55:44 +00:00
statuses = statuses . latest unless to_boolean ( params [ :all ] )
2015-10-06 10:01:16 +00:00
statuses = statuses . where ( ref : params [ :ref ] ) if params [ :ref ] . present?
2015-10-12 13:45:46 +00:00
statuses = statuses . where ( stage : params [ :stage ] ) if params [ :stage ] . present?
2015-10-06 10:01:16 +00:00
statuses = statuses . where ( name : params [ :name ] ) if params [ :name ] . present?
present paginate ( statuses ) , with : Entities :: CommitStatus
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2015-10-06 10:01:16 +00:00
2016-10-14 08:45:23 +00:00
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' ,
2017-02-22 17:46:57 +00:00
values : %w( pending running success failed canceled )
2016-10-14 08:45:23 +00:00
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-10-17 00:10:29 +00:00
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-02-14 02:28:45 +00:00
optional :coverage , type : Float , desc : 'The total code coverage'
2019-07-16 23:36:49 +00:00
optional :pipeline_id , type : Integer , desc : 'An existing pipeline ID, when multiple pipelines on the same commit SHA have been triggered'
2016-10-14 08:45:23 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2015-10-06 10:01:16 +00:00
post ':id/statuses/:sha' do
2015-10-12 19:35:52 +00:00
authorize! :create_commit_status , user_project
2016-10-14 08:45:23 +00:00
2015-10-06 10:01:16 +00:00
not_found! 'Commit' unless commit
2020-06-26 00:09:13 +00:00
# Since the CommitStatus is attached to ::Ci::Pipeline (in the future Pipeline)
2016-04-16 20:43:40 +00:00
# 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-10-18 11:11:44 +00:00
pipeline = all_matching_pipelines . first
2016-04-16 20:43:40 +00:00
ref = params [ :ref ]
2019-10-18 11:11:44 +00:00
ref || = pipeline & . ref
2020-01-03 15:08:33 +00:00
ref || = user_project . repository . branch_names_contains ( commit . sha ) . first
2016-08-25 15:52:09 +00:00
not_found! 'References for commit' unless ref
name = params [ :name ] || params [ :context ] || 'default'
2019-07-16 23:36:49 +00:00
2021-12-02 12:10:10 +00:00
pipeline || = user_project . ci_pipelines . build (
2020-01-27 21:08:47 +00:00
source : :external ,
sha : commit . sha ,
ref : ref ,
user : current_user ,
protected : user_project . protected_for? ( ref ) )
2015-10-06 10:01:16 +00:00
2021-12-02 12:10:10 +00:00
pipeline . ensure_project_iid!
pipeline . save!
2020-01-30 21:08:47 +00:00
authorize! :update_pipeline , pipeline
2016-08-25 15:52:09 +00:00
status = GenericCommitStatus . running_or_pending . find_or_initialize_by (
2020-01-03 15:08:33 +00:00
project : user_project ,
2016-10-20 16:51:03 +00:00
pipeline : pipeline ,
name : name ,
ref : ref ,
2017-09-01 08:54:07 +00:00
user : current_user ,
2020-01-03 15:08:33 +00:00
protected : user_project . protected_for? ( ref )
2016-10-20 16:51:03 +00:00
)
2015-10-06 10:01:16 +00:00
2021-05-19 09:10:19 +00:00
updatable_optional_attributes = %w[ target_url description coverage ]
status . assign_attributes ( attributes_for_keys ( updatable_optional_attributes ) )
2021-03-09 12:08:52 +00:00
2021-07-08 15:10:06 +00:00
render_validation_error! ( status ) unless status . valid?
2017-01-18 11:24:53 +00:00
2021-07-08 15:10:06 +00:00
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-06 10:01:16 +00:00
2021-07-08 15:10:06 +00:00
render_validation_error! ( response . payload [ :job ] ) unless response . success?
2017-06-27 12:08:40 +00:00
2021-07-08 15:10:06 +00:00
if pipeline . latest?
MergeRequest
. where ( source_project : user_project , source_branch : ref )
. update_all ( head_pipeline_id : pipeline . id )
2015-10-06 10:01:16 +00:00
end
2021-07-08 15:10:06 +00:00
present response . payload [ :job ] , with : Entities :: CommitStatus
2015-10-06 10:01:16 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2021-07-08 15:10:06 +00:00
2019-10-18 11:11:44 +00:00
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-07-08 15:10:06 +00:00
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-10-18 11:11:44 +00:00
end
2015-10-06 10:01:16 +00:00
end
end
end