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