2019-12-26 22:10:19 +05:30
# frozen_string_literal: true
2014-09-02 18:07:02 +05:30
require " spec_helper "
2020-07-28 23:09:34 +05:30
RSpec . describe API :: MergeRequests do
2018-03-17 18:26:18 +05:30
include ProjectForksHelper
2020-11-24 15:15:51 +05:30
let_it_be ( :base_time ) { Time . now }
2020-03-13 15:44:24 +05:30
let_it_be ( :user ) { create ( :user ) }
let_it_be ( :user2 ) { create ( :user ) }
let_it_be ( :admin ) { create ( :user , :admin ) }
2020-11-24 15:15:51 +05:30
let_it_be ( :project ) { create ( :project , :public , :repository , creator : user , namespace : user . namespace , only_allow_merge_if_pipeline_succeeds : false ) }
let ( :milestone1 ) { create ( :milestone , title : '0.9' , project : project ) }
let ( :milestone ) { create ( :milestone , title : '1.0.0' , project : project ) }
2019-07-07 11:18:12 +05:30
let ( :label ) { create ( :label , title : 'label' , color : '#FFAABB' , project : project ) }
let ( :label2 ) { create ( :label , title : 'a-test' , color : '#FFFFFF' , project : project ) }
2015-09-11 14:41:01 +05:30
2020-11-24 15:15:51 +05:30
let ( :merge_request ) { create ( :merge_request , :simple , author : user , assignees : [ user ] , source_project : project , target_project : project , source_branch : 'markdown' , title : " Test " , created_at : base_time ) }
2015-09-11 14:41:01 +05:30
before do
2018-03-17 18:26:18 +05:30
project . add_reporter ( user )
2019-07-31 22:56:46 +05:30
project . add_reporter ( user2 )
stub_licensed_features ( multiple_merge_request_assignees : false )
2015-09-11 14:41:01 +05:30
end
2014-09-02 18:07:02 +05:30
2020-11-24 15:15:51 +05:30
shared_context 'with merge requests' do
let_it_be ( :milestone1 ) { create ( :milestone , title : '0.9' , project : project ) }
let_it_be ( :merge_request ) { create ( :merge_request , :simple , milestone : milestone1 , author : user , assignees : [ user ] , source_project : project , target_project : project , source_branch : 'markdown' , title : " Test " , created_at : base_time ) }
let_it_be ( :merge_request_closed ) { create ( :merge_request , state : " closed " , milestone : milestone1 , author : user , assignees : [ user ] , source_project : project , target_project : project , title : " Closed test " , created_at : base_time + 1 . second ) }
let_it_be ( :merge_request_merged ) { create ( :merge_request , state : " merged " , author : user , assignees : [ user ] , source_project : project , target_project : project , title : " Merged test " , created_at : base_time + 2 . seconds , merge_commit_sha : '9999999999999999999999999999999999999999' ) }
let_it_be ( :merge_request_locked ) { create ( :merge_request , state : " locked " , milestone : milestone1 , author : user , assignees : [ user ] , source_project : project , target_project : project , title : " Locked test " , created_at : base_time + 1 . second ) }
let_it_be ( :note ) { create ( :note_on_merge_request , author : user , project : project , noteable : merge_request , note : " a comment on a MR " ) }
let_it_be ( :note2 ) { create ( :note_on_merge_request , author : user , project : project , noteable : merge_request , note : " another comment on a MR " ) }
end
2019-07-07 11:18:12 +05:30
shared_context 'with labels' do
before do
create ( :label_link , label : label , target : merge_request )
create ( :label_link , label : label2 , target : merge_request )
end
end
shared_examples 'merge requests list' do
context 'when unauthenticated' do
it 'returns merge requests for public projects' do
get api ( endpoint_path )
2020-03-13 15:44:24 +05:30
expect_successful_response_with_paginated_array
2019-07-07 11:18:12 +05:30
end
2021-11-18 22:05:49 +05:30
it_behaves_like 'issuable anonymous search' do
let ( :url ) { endpoint_path }
let ( :issuable ) { merge_request }
let ( :result ) { [ merge_request_merged . id , merge_request_locked . id , merge_request_closed . id , merge_request . id ] }
end
2019-07-07 11:18:12 +05:30
end
context 'when authenticated' do
2021-06-08 01:23:25 +05:30
it 'avoids N+1 queries' , quarantine : 'https://gitlab.com/gitlab-org/gitlab/-/issues/330335' do
2019-07-07 11:18:12 +05:30
control = ActiveRecord :: QueryRecorder . new do
get api ( endpoint_path , user )
end
2019-07-31 22:56:46 +05:30
create ( :merge_request , state : 'closed' , milestone : milestone1 , author : user , assignees : [ user ] , source_project : project , target_project : project , title : 'Test' , created_at : base_time )
2019-07-07 11:18:12 +05:30
2019-07-31 22:56:46 +05:30
merge_request = create ( :merge_request , milestone : milestone1 , author : user , assignees : [ user ] , source_project : project , target_project : project , title : 'Test' , created_at : base_time )
2019-07-07 11:18:12 +05:30
merge_request . metrics . update! ( merged_by : user ,
latest_closed_by : user ,
latest_closed_at : 1 . hour . ago ,
merged_at : 2 . hours . ago )
expect do
get api ( endpoint_path , user )
end . not_to exceed_query_limit ( control )
end
2020-03-13 15:44:24 +05:30
context 'when merge request is unchecked' do
2020-05-24 23:13:21 +05:30
let ( :check_service_class ) { MergeRequests :: MergeabilityCheckService }
let ( :mr_entity ) { json_response . find { | mr | mr [ 'id' ] == merge_request . id } }
2020-11-24 15:15:51 +05:30
let ( :merge_request ) { create ( :merge_request , :simple , author : user , source_project : project , title : " Test " ) }
2020-05-24 23:13:21 +05:30
2020-03-13 15:44:24 +05:30
before do
merge_request . mark_as_unchecked!
end
2020-05-24 23:13:21 +05:30
context 'with merge status recheck projection' do
it 'checks mergeability asynchronously' do
expect_next_instance_of ( check_service_class ) do | service |
expect ( service ) . not_to receive ( :execute )
expect ( service ) . to receive ( :async_execute ) . and_call_original
end
get ( api ( endpoint_path , user ) , params : { with_merge_status_recheck : true } )
expect_successful_response_with_paginated_array
expect ( mr_entity [ 'merge_status' ] ) . to eq ( 'checking' )
2020-03-13 15:44:24 +05:30
end
2020-05-24 23:13:21 +05:30
end
2020-03-13 15:44:24 +05:30
2020-05-24 23:13:21 +05:30
context 'without merge status recheck projection' do
it 'does not enqueue a merge status recheck' do
expect ( check_service_class ) . not_to receive ( :new )
get api ( endpoint_path , user )
expect_successful_response_with_paginated_array
expect ( mr_entity [ 'merge_status' ] ) . to eq ( 'unchecked' )
end
2020-03-13 15:44:24 +05:30
end
end
2019-07-07 11:18:12 +05:30
context 'with labels' do
include_context 'with labels'
it 'returns an array of all merge_requests' do
get api ( endpoint_path , user )
2020-03-13 15:44:24 +05:30
expect_paginated_array_response ( [
merge_request_merged . id , merge_request_locked . id ,
merge_request_closed . id , merge_request . id
] )
2019-07-07 11:18:12 +05:30
expect ( json_response . last [ 'title' ] ) . to eq ( merge_request . title )
expect ( json_response . last ) . to have_key ( 'web_url' )
expect ( json_response . last [ 'sha' ] ) . to eq ( merge_request . diff_head_sha )
expect ( json_response . last [ 'merge_commit_sha' ] ) . to be_nil
expect ( json_response . last [ 'merge_commit_sha' ] ) . to eq ( merge_request . merge_commit_sha )
expect ( json_response . last [ 'downvotes' ] ) . to eq ( 0 )
expect ( json_response . last [ 'upvotes' ] ) . to eq ( 0 )
expect ( json_response . last [ 'labels' ] ) . to eq ( [ label2 . title , label . title ] )
expect ( json_response . first [ 'title' ] ) . to eq ( merge_request_merged . title )
expect ( json_response . first [ 'sha' ] ) . to eq ( merge_request_merged . diff_head_sha )
expect ( json_response . first [ 'merge_commit_sha' ] ) . not_to be_nil
expect ( json_response . first [ 'merge_commit_sha' ] ) . to eq ( merge_request_merged . merge_commit_sha )
end
2020-03-13 15:44:24 +05:30
context 'with labels_details' do
it 'returns labels with details' do
path = endpoint_path + " ?with_labels_details=true "
get api ( path , user )
expect_successful_response_with_paginated_array
expect ( json_response . last [ 'labels' ] . pluck ( 'name' ) ) . to eq ( [ label2 . title , label . title ] )
expect ( json_response . last [ 'labels' ] . first ) . to match_schema ( '/public_api/v4/label_basic' )
end
2021-06-08 01:23:25 +05:30
it 'avoids N+1 queries' , quarantine : 'https://gitlab.com/gitlab-org/gitlab/-/issues/330335' do
2020-03-13 15:44:24 +05:30
path = endpoint_path + " ?with_labels_details=true "
control = ActiveRecord :: QueryRecorder . new do
get api ( path , user )
end . count
mr = create ( :merge_request )
create ( :label_link , label : label , target : mr )
create ( :label_link , label : label2 , target : mr )
expect do
get api ( path , user )
end . not_to exceed_query_limit ( control )
end
end
2019-07-07 11:18:12 +05:30
end
it 'returns an array of all merge_requests using simple mode' do
path = endpoint_path + '?view=simple'
get api ( path , user )
2020-03-13 15:44:24 +05:30
expect_paginated_array_response ( [
merge_request_merged . id , merge_request_locked . id ,
merge_request_closed . id , merge_request . id
] )
2019-07-07 11:18:12 +05:30
expect ( json_response . last . keys ) . to match_array ( %w( id iid title web_url created_at description project_id state updated_at ) )
expect ( json_response . last [ 'iid' ] ) . to eq ( merge_request . iid )
expect ( json_response . last [ 'title' ] ) . to eq ( merge_request . title )
expect ( json_response . last ) . to have_key ( 'web_url' )
expect ( json_response . first [ 'iid' ] ) . to eq ( merge_request_merged . iid )
expect ( json_response . first [ 'title' ] ) . to eq ( merge_request_merged . title )
expect ( json_response . first ) . to have_key ( 'web_url' )
end
it 'returns an array of all merge_requests' do
path = endpoint_path + '?state'
get api ( path , user )
2020-03-13 15:44:24 +05:30
expect_paginated_array_response ( [
merge_request_merged . id , merge_request_locked . id ,
merge_request_closed . id , merge_request . id
] )
2019-07-07 11:18:12 +05:30
expect ( json_response . last [ 'title' ] ) . to eq ( merge_request . title )
end
it 'returns an array of open merge_requests' do
path = endpoint_path + '?state=opened'
get api ( path , user )
2020-03-13 15:44:24 +05:30
expect_paginated_array_response ( [ merge_request . id ] )
2019-07-07 11:18:12 +05:30
expect ( json_response . last [ 'title' ] ) . to eq ( merge_request . title )
end
it 'returns an array of closed merge_requests' do
path = endpoint_path + '?state=closed'
get api ( path , user )
2020-03-13 15:44:24 +05:30
expect_paginated_array_response ( [ merge_request_closed . id ] )
2019-07-07 11:18:12 +05:30
expect ( json_response . first [ 'title' ] ) . to eq ( merge_request_closed . title )
end
it 'returns an array of merged merge_requests' do
path = endpoint_path + '?state=merged'
get api ( path , user )
2020-03-13 15:44:24 +05:30
expect_paginated_array_response ( [ merge_request_merged . id ] )
2019-07-07 11:18:12 +05:30
expect ( json_response . first [ 'title' ] ) . to eq ( merge_request_merged . title )
end
it 'matches V4 response schema' do
get api ( endpoint_path , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-07-07 11:18:12 +05:30
expect ( response ) . to match_response_schema ( 'public_api/v4/merge_requests' )
end
it 'returns an empty array if no issue matches milestone' do
get api ( endpoint_path , user ) , params : { milestone : '1.0.0' }
2020-03-13 15:44:24 +05:30
expect_empty_array_response
2019-07-07 11:18:12 +05:30
end
it 'returns an empty array if milestone does not exist' do
get api ( endpoint_path , user ) , params : { milestone : 'foo' }
2020-03-13 15:44:24 +05:30
expect_empty_array_response
2019-07-07 11:18:12 +05:30
end
it 'returns an array of merge requests in given milestone' do
get api ( endpoint_path , user ) , params : { milestone : '0.9' }
closed_issues = json_response . select { | mr | mr [ 'id' ] == merge_request_closed . id }
expect ( closed_issues . length ) . to eq ( 1 )
expect ( closed_issues . first [ 'title' ] ) . to eq merge_request_closed . title
end
it 'returns an array of merge requests matching state in milestone' do
get api ( endpoint_path , user ) , params : { milestone : '0.9' , state : 'closed' }
2020-03-13 15:44:24 +05:30
expect_paginated_array_response ( [ merge_request_closed . id ] )
2019-07-07 11:18:12 +05:30
expect ( json_response . first [ 'id' ] ) . to eq ( merge_request_closed . id )
end
context 'with labels' do
include_context 'with labels'
it 'returns an array of labeled merge requests' do
path = endpoint_path + " ?labels= #{ label . title } "
get api ( path , user )
2020-03-13 15:44:24 +05:30
expect_successful_response_with_paginated_array
2019-07-07 11:18:12 +05:30
expect ( json_response . length ) . to eq ( 1 )
expect ( json_response . first [ 'labels' ] ) . to eq ( [ label2 . title , label . title ] )
end
it 'returns an array of labeled merge requests where all labels match' do
path = endpoint_path + " ?labels= #{ label . title } ,foo,bar "
get api ( path , user )
2020-03-13 15:44:24 +05:30
expect_empty_array_response
2019-07-07 11:18:12 +05:30
end
it 'returns an empty array if no merge request matches labels' do
path = endpoint_path + '?labels=foo,bar'
get api ( path , user )
2020-03-13 15:44:24 +05:30
expect_empty_array_response
2019-07-07 11:18:12 +05:30
end
it 'returns an array of labeled merge requests where all labels match' do
path = endpoint_path + " ?labels[]= #{ label . title } &labels[]= #{ label2 . title } "
get api ( path , user )
2020-03-13 15:44:24 +05:30
expect_successful_response_with_paginated_array
2019-07-07 11:18:12 +05:30
expect ( json_response . length ) . to eq ( 1 )
expect ( json_response . first [ 'labels' ] ) . to eq ( [ label2 . title , label . title ] )
end
it 'returns an array of merge requests with any label when filtering by any label' do
get api ( endpoint_path , user ) , params : { labels : [ " #{ label . title } " , " #{ label2 . title } " ] }
2020-03-13 15:44:24 +05:30
expect_paginated_array_response ( [ merge_request . id ] )
2019-07-07 11:18:12 +05:30
expect ( json_response . first [ 'labels' ] ) . to eq ( [ label2 . title , label . title ] )
expect ( json_response . first [ 'id' ] ) . to eq ( merge_request . id )
end
it 'returns an array of merge requests with any label when filtering by any label' do
get api ( endpoint_path , user ) , params : { labels : [ " #{ label . title } , #{ label2 . title } " ] }
2020-03-13 15:44:24 +05:30
expect_paginated_array_response ( [ merge_request . id ] )
2019-07-07 11:18:12 +05:30
expect ( json_response . first [ 'labels' ] ) . to eq ( [ label2 . title , label . title ] )
expect ( json_response . first [ 'id' ] ) . to eq ( merge_request . id )
end
it 'returns an array of merge requests with any label when filtering by any label' do
2020-04-22 19:07:51 +05:30
get api ( endpoint_path , user ) , params : { labels : IssuableFinder :: Params :: FILTER_ANY }
2019-07-07 11:18:12 +05:30
2020-03-13 15:44:24 +05:30
expect_paginated_array_response ( [ merge_request . id ] )
2019-07-07 11:18:12 +05:30
expect ( json_response . first [ 'id' ] ) . to eq ( merge_request . id )
end
it 'returns an array of merge requests without a label when filtering by no label' do
2020-04-22 19:07:51 +05:30
get api ( endpoint_path , user ) , params : { labels : IssuableFinder :: Params :: FILTER_NONE }
2019-07-07 11:18:12 +05:30
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly (
merge_request_merged . id , merge_request_locked . id , merge_request_closed . id
)
2019-07-07 11:18:12 +05:30
end
end
it 'returns an array of labeled merge requests that are merged for a milestone' do
bug_label = create ( :label , title : 'bug' , color : '#FFAABB' , project : project )
mr1 = create ( :merge_request , state : 'merged' , source_project : project , target_project : project , milestone : milestone )
mr2 = create ( :merge_request , state : 'merged' , source_project : project , target_project : project , milestone : milestone1 )
mr3 = create ( :merge_request , state : 'closed' , source_project : project , target_project : project , milestone : milestone1 )
_mr = create ( :merge_request , state : 'merged' , source_project : project , target_project : project , milestone : milestone1 )
create ( :label_link , label : bug_label , target : mr1 )
create ( :label_link , label : bug_label , target : mr2 )
create ( :label_link , label : bug_label , target : mr3 )
path = endpoint_path + " ?labels= #{ bug_label . title } &milestone= #{ milestone1 . title } &state=merged "
get api ( path , user )
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly ( mr2 . id )
2019-07-07 11:18:12 +05:30
end
context 'with ordering' do
before do
@mr_later = mr_with_later_created_and_updated_at_time
@mr_earlier = mr_with_earlier_created_and_updated_at_time
end
it 'returns an array of merge_requests in ascending order' do
path = endpoint_path + '?sort=asc'
get api ( path , user )
2020-03-13 15:44:24 +05:30
expect_paginated_array_response ( [
merge_request_closed . id , merge_request_locked . id ,
merge_request_merged . id , merge_request . id
] )
2019-07-07 11:18:12 +05:30
response_dates = json_response . map { | merge_request | merge_request [ 'created_at' ] }
expect ( response_dates ) . to eq ( response_dates . sort )
end
it 'returns an array of merge_requests in descending order' do
path = endpoint_path + '?sort=desc'
get api ( path , user )
2020-03-13 15:44:24 +05:30
expect_paginated_array_response ( [
merge_request . id , merge_request_merged . id ,
merge_request_locked . id , merge_request_closed . id
] )
2019-07-07 11:18:12 +05:30
response_dates = json_response . map { | merge_request | merge_request [ 'created_at' ] }
expect ( response_dates ) . to eq ( response_dates . sort . reverse )
end
context '2 merge requests with equal created_at' do
let! ( :closed_mr2 ) do
create :merge_request ,
state : 'closed' ,
milestone : milestone1 ,
author : user ,
2019-07-31 22:56:46 +05:30
assignees : [ user ] ,
2019-07-07 11:18:12 +05:30
source_project : project ,
target_project : project ,
title : " Test " ,
created_at : @mr_earlier . created_at
end
it 'page breaks first page correctly' do
get api ( " #{ endpoint_path } ?sort=desc&per_page=4 " , user )
response_ids = json_response . map { | merge_request | merge_request [ 'id' ] }
expect ( response_ids ) . to include ( closed_mr2 . id )
expect ( response_ids ) . not_to include ( @mr_earlier . id )
end
it 'page breaks second page correctly' do
get api ( " #{ endpoint_path } ?sort=desc&per_page=4&page=2 " , user )
response_ids = json_response . map { | merge_request | merge_request [ 'id' ] }
expect ( response_ids ) . not_to include ( closed_mr2 . id )
expect ( response_ids ) . to include ( @mr_earlier . id )
end
end
it 'returns an array of merge_requests ordered by updated_at' do
path = endpoint_path + '?order_by=updated_at'
get api ( path , user )
2020-03-13 15:44:24 +05:30
expect_paginated_array_response ( [
merge_request . id , merge_request_locked . id ,
merge_request_merged . id , merge_request_closed . id
] )
2019-07-07 11:18:12 +05:30
response_dates = json_response . map { | merge_request | merge_request [ 'updated_at' ] }
expect ( response_dates ) . to eq ( response_dates . sort . reverse )
end
it 'returns an array of merge_requests ordered by created_at' do
path = endpoint_path + '?order_by=created_at&sort=asc'
get api ( path , user )
2020-03-13 15:44:24 +05:30
expect_paginated_array_response ( [
merge_request_closed . id , merge_request_locked . id ,
merge_request_merged . id , merge_request . id
] )
2019-07-07 11:18:12 +05:30
response_dates = json_response . map { | merge_request | merge_request [ 'created_at' ] }
expect ( response_dates ) . to eq ( response_dates . sort )
end
end
2020-07-28 23:09:34 +05:30
context 'NOT params' do
2020-11-24 15:15:51 +05:30
let! ( :merge_request2 ) do
2020-07-28 23:09:34 +05:30
create (
:merge_request ,
:simple ,
milestone : milestone ,
author : user ,
assignees : [ user ] ,
2021-03-08 18:12:59 +05:30
reviewers : [ user2 ] ,
2020-07-28 23:09:34 +05:30
source_project : project ,
target_project : project ,
source_branch : 'what' ,
title : " What " ,
created_at : base_time
)
end
2020-11-24 15:15:51 +05:30
let! ( :merge_request_context_commit ) { create ( :merge_request_context_commit , merge_request : merge_request2 , message : 'test' ) }
2020-07-28 23:09:34 +05:30
before do
create ( :label_link , label : label , target : merge_request )
create ( :label_link , label : label2 , target : merge_request2 )
end
it 'returns merge requests without any of the labels given' , :aggregate_failures do
get api ( endpoint_path , user ) , params : { not : { labels : [ " #{ label . title } , #{ label2 . title } " ] } }
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response ) . to be_an ( Array )
expect ( json_response . length ) . to eq ( 3 )
json_response . each do | mr |
expect ( mr [ 'labels' ] ) . not_to include ( label2 . title , label . title )
end
end
it 'returns merge requests without any of the milestones given' , :aggregate_failures do
get api ( endpoint_path , user ) , params : { not : { milestone : milestone . title } }
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response ) . to be_an ( Array )
expect ( json_response . length ) . to eq ( 4 )
json_response . each do | mr |
expect ( mr [ 'milestone' ] ) . not_to eq ( milestone . title )
end
end
it 'returns merge requests without the author given' , :aggregate_failures do
get api ( endpoint_path , user ) , params : { not : { author_id : user2 . id } }
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response ) . to be_an ( Array )
expect ( json_response . length ) . to eq ( 5 )
json_response . each do | mr |
expect ( mr [ 'author' ] [ 'id' ] ) . not_to eq ( user2 . id )
end
end
it 'returns merge requests without the assignee given' , :aggregate_failures do
get api ( endpoint_path , user ) , params : { not : { assignee_id : user2 . id } }
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response ) . to be_an ( Array )
expect ( json_response . length ) . to eq ( 5 )
json_response . each do | mr |
expect ( mr [ 'assignee' ] [ 'id' ] ) . not_to eq ( user2 . id )
end
end
2021-03-08 18:12:59 +05:30
context 'filter by reviewer' do
context 'with reviewer_id' do
context 'with an id' do
let ( :params ) { { not : { reviewer_id : user2 . id } } }
it 'returns merge requests that do not have the given reviewer' do
get api ( endpoint_path , user ) , params : { not : { reviewer_id : user2 . id } }
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response ) . to be_an ( Array )
expect ( json_response . length ) . to eq ( 4 )
expect ( json_response . map { | mr | mr [ 'id' ] } ) . not_to include ( merge_request2 )
end
end
context 'with Any' do
let ( :params ) { { not : { reviewer_id : 'Any' } } }
it 'returns a 400' do
# Any is not supported for negated filter
get api ( endpoint_path , user ) , params : params
expect ( response ) . to have_gitlab_http_status ( :bad_request )
expect ( json_response [ 'error' ] ) . to eq ( 'not[reviewer_id] is invalid' )
end
end
context 'with None' do
let ( :params ) { { not : { reviewer_id : 'None' } } }
it 'returns a 400' do
# None is not supported for negated filter
get api ( endpoint_path , user ) , params : params
expect ( response ) . to have_gitlab_http_status ( :bad_request )
expect ( json_response [ 'error' ] ) . to eq ( 'not[reviewer_id] is invalid' )
end
end
end
context 'with reviewer_username' do
let ( :params ) { { not : { reviewer_username : user2 . username } } }
it 'returns merge requests that do not have the given reviewer' do
get api ( endpoint_path , user ) , params : params
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response ) . to be_an ( Array )
expect ( json_response . length ) . to eq ( 4 )
expect ( json_response . map { | mr | mr [ 'id' ] } ) . not_to include ( merge_request2 )
end
end
context 'when both reviewer_id and reviewer_username' do
let ( :params ) { { not : { reviewer_id : user2 . id , reviewer_username : user2 . username } } }
it 'returns a 400' do
get api ( '/merge_requests' , user ) , params : params
expect ( response ) . to have_gitlab_http_status ( :bad_request )
expect ( json_response [ 'error' ] ) . to eq ( 'not[reviewer_id], not[reviewer_username] are mutually exclusive' )
end
end
end
2020-07-28 23:09:34 +05:30
end
2019-07-07 11:18:12 +05:30
context 'source_branch param' do
it 'returns merge requests with the given source branch' do
get api ( endpoint_path , user ) , params : { source_branch : merge_request_closed . source_branch , state : 'all' }
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly (
merge_request_merged . id , merge_request_locked . id , merge_request_closed . id
)
2019-07-07 11:18:12 +05:30
end
end
context 'target_branch param' do
it 'returns merge requests with the given target branch' do
get api ( endpoint_path , user ) , params : { target_branch : merge_request_closed . target_branch , state : 'all' }
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly (
merge_request_merged . id , merge_request_locked . id , merge_request_closed . id
)
2019-07-07 11:18:12 +05:30
end
end
end
end
2018-11-08 19:23:39 +05:30
describe 'route shadowing' do
include GrapePathHelpers :: NamedRouteMatcher
it 'does not occur' do
path = api_v4_projects_merge_requests_path ( id : 1 )
expect ( path ) . to eq ( '/api/v4/projects/1/merge_requests' )
path = api_v4_projects_merge_requests_path ( id : 1 , merge_request_iid : 3 )
expect ( path ) . to eq ( '/api/v4/projects/1/merge_requests/3' )
end
end
2017-09-10 17:25:29 +05:30
describe 'GET /merge_requests' do
2020-11-24 15:15:51 +05:30
include_context 'with merge requests'
2017-09-10 17:25:29 +05:30
context 'when unauthenticated' do
2018-03-17 18:26:18 +05:30
it 'returns an array of all merge requests' do
2019-02-15 15:39:39 +05:30
get api ( '/merge_requests' , user ) , params : { scope : 'all' }
2018-03-17 18:26:18 +05:30
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly (
merge_request_merged . id , merge_request_locked . id ,
merge_request_closed . id , merge_request . id
)
2018-03-17 18:26:18 +05:30
end
2021-11-18 22:05:49 +05:30
it_behaves_like 'issuable anonymous search' do
let ( :url ) { '/merge_requests' }
let ( :issuable ) { merge_request }
let ( :result ) { [ merge_request_merged . id , merge_request_locked . id , merge_request_closed . id , merge_request . id ] }
end
2018-03-17 18:26:18 +05:30
it " returns authentication error without any scope " do
get api ( " /merge_requests " )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
2018-03-17 18:26:18 +05:30
end
it " returns authentication error when scope is assigned-to-me " do
2019-02-15 15:39:39 +05:30
get api ( " /merge_requests " ) , params : { scope : 'assigned-to-me' }
2017-09-10 17:25:29 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
2018-03-17 18:26:18 +05:30
end
2018-11-08 19:23:39 +05:30
it " returns authentication error when scope is assigned_to_me " do
2019-02-15 15:39:39 +05:30
get api ( " /merge_requests " ) , params : { scope : 'assigned_to_me' }
2018-11-08 19:23:39 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
2018-11-08 19:23:39 +05:30
end
2018-03-17 18:26:18 +05:30
it " returns authentication error when scope is created-by-me " do
2019-02-15 15:39:39 +05:30
get api ( " /merge_requests " ) , params : { scope : 'created-by-me' }
2018-03-17 18:26:18 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
2017-09-10 17:25:29 +05:30
end
end
context 'when authenticated' do
2020-11-24 15:15:51 +05:30
let_it_be ( :project2 ) { create ( :project , :public , :repository , namespace : user . namespace ) }
let_it_be ( :merge_request2 ) { create ( :merge_request , :simple , author : user , assignees : [ user ] , source_project : project2 , target_project : project2 ) }
let_it_be ( :user2 ) { create ( :user ) }
2017-09-10 17:25:29 +05:30
2018-11-08 19:23:39 +05:30
it 'returns an array of all merge requests except unauthorized ones' do
2019-02-15 15:39:39 +05:30
get api ( '/merge_requests' , user ) , params : { scope : :all }
2018-12-05 23:21:45 +05:30
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly (
merge_request_merged . id , merge_request2 . id , merge_request_locked . id ,
merge_request_closed . id , merge_request . id
)
2018-12-05 23:21:45 +05:30
end
it " returns an array of no merge_requests when wip=yes " do
2019-02-15 15:39:39 +05:30
get api ( " /merge_requests " , user ) , params : { wip : 'yes' }
2018-12-05 23:21:45 +05:30
2020-03-13 15:44:24 +05:30
expect_empty_array_response
2018-12-05 23:21:45 +05:30
end
it " returns an array of no merge_requests when wip=no " do
2019-02-15 15:39:39 +05:30
get api ( " /merge_requests " , user ) , params : { wip : 'no' }
2018-12-05 23:21:45 +05:30
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly (
merge_request_merged . id , merge_request2 . id , merge_request_locked . id ,
merge_request_closed . id , merge_request . id
)
2018-12-05 23:21:45 +05:30
end
it 'does not return unauthorized merge requests' do
2017-09-10 17:25:29 +05:30
private_project = create ( :project , :private )
merge_request3 = create ( :merge_request , :simple , source_project : private_project , target_project : private_project , source_branch : 'other-branch' )
2019-02-15 15:39:39 +05:30
get api ( '/merge_requests' , user ) , params : { scope : :all }
2017-09-10 17:25:29 +05:30
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly (
merge_request_merged . id , merge_request2 . id , merge_request_locked . id ,
merge_request_closed . id , merge_request . id
)
2018-11-08 19:23:39 +05:30
expect ( json_response . map { | mr | mr [ 'id' ] } ) . not_to include ( merge_request3 . id )
2017-09-10 17:25:29 +05:30
end
it 'returns an array of merge requests created by current user if no scope is given' do
2019-07-31 22:56:46 +05:30
merge_request3 = create ( :merge_request , :simple , author : user2 , assignees : [ user ] , source_project : project2 , target_project : project2 , source_branch : 'other-branch' )
2017-09-10 17:25:29 +05:30
get api ( '/merge_requests' , user2 )
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly ( merge_request3 . id )
2017-09-10 17:25:29 +05:30
end
2020-04-22 19:07:51 +05:30
context 'filter by author' do
let ( :user3 ) { create ( :user ) }
let ( :project ) { create ( :project , :public , :repository , creator : user3 , namespace : user3 . namespace , only_allow_merge_if_pipeline_succeeds : false ) }
let! ( :merge_request3 ) do
create ( :merge_request , :simple , author : user3 , assignees : [ user3 ] , source_project : project , target_project : project , source_branch : 'other-branch' )
end
2017-09-10 17:25:29 +05:30
2020-04-22 19:07:51 +05:30
context 'when only `author_id` is passed' do
it 'returns an array of merge requests authored by the given user' do
get api ( '/merge_requests' , user ) , params : {
author_id : user3 . id ,
scope : :all
}
2017-09-10 17:25:29 +05:30
2020-04-22 19:07:51 +05:30
expect_response_contain_exactly ( merge_request3 . id )
end
end
context 'when only `author_username` is passed' do
it 'returns an array of merge requests authored by the given user(by `author_username`)' do
get api ( '/merge_requests' , user ) , params : {
author_username : user3 . username ,
scope : :all
}
expect_response_contain_exactly ( merge_request3 . id )
end
end
context 'when both `author_id` and `author_username` are passed' do
it 'returns a 400' do
get api ( '/merge_requests' , user ) , params : {
author_id : user . id ,
author_username : user2 . username ,
scope : :all
}
expect ( response ) . to have_gitlab_http_status ( :bad_request )
expect ( json_response [ 'error' ] ) . to eq (
'author_id, author_username are mutually exclusive' )
end
end
2017-09-10 17:25:29 +05:30
end
2021-03-08 18:12:59 +05:30
context 'filter by reviewer' do
let_it_be ( :review_requested_mr1 ) do
create ( :merge_request , :unique_branches , author : user , reviewers : [ user2 ] , source_project : project2 , target_project : project2 )
end
let_it_be ( :review_requested_mr2 ) do
create ( :merge_request , :unique_branches , author : user2 , reviewers : [ user ] , source_project : project2 , target_project : project2 )
end
let ( :params ) { { scope : :all } }
context 'with reviewer_id' do
let ( :params ) { super ( ) . merge ( reviewer_id : reviewer_id ) }
context 'with an id' do
let ( :reviewer_id ) { user2 . id }
it 'returns review requested merge requests for the given user' do
get api ( '/merge_requests' , user ) , params : params
expect_response_contain_exactly ( review_requested_mr1 . id )
end
end
context 'with Any' do
let ( :reviewer_id ) { 'Any' }
it 'returns review requested merge requests for any user' do
get api ( '/merge_requests' , user ) , params : params
expect_response_contain_exactly ( review_requested_mr1 . id , review_requested_mr2 . id )
end
end
context 'with None' do
let ( :reviewer_id ) { 'None' }
it 'returns merge requests that has no assigned reviewers' do
get api ( '/merge_requests' , user ) , params : params
expect_response_contain_exactly (
merge_request . id ,
merge_request_closed . id ,
merge_request_merged . id ,
merge_request_locked . id ,
merge_request2 . id
)
end
end
end
context 'with reviewer_username' do
let ( :params ) { super ( ) . merge ( reviewer_username : user2 . username ) }
it 'returns review requested merge requests for the given user' do
get api ( '/merge_requests' , user ) , params : params
expect_response_contain_exactly ( review_requested_mr1 . id )
end
end
context 'with both reviewer_id and reviewer_username' do
let ( :params ) { super ( ) . merge ( reviewer_id : user2 . id , reviewer_username : user2 . username ) }
it 'returns a 400' do
get api ( '/merge_requests' , user ) , params : params
expect ( response ) . to have_gitlab_http_status ( :bad_request )
expect ( json_response [ 'error' ] ) . to eq ( 'reviewer_id, reviewer_username are mutually exclusive' )
end
end
end
2017-09-10 17:25:29 +05:30
it 'returns an array of merge requests assigned to the given user' do
2019-07-31 22:56:46 +05:30
merge_request3 = create ( :merge_request , :simple , author : user , assignees : [ user2 ] , source_project : project2 , target_project : project2 , source_branch : 'other-branch' )
2017-09-10 17:25:29 +05:30
2019-02-15 15:39:39 +05:30
get api ( '/merge_requests' , user ) , params : { assignee_id : user2 . id , scope : :all }
2017-09-10 17:25:29 +05:30
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly ( merge_request3 . id )
2017-09-10 17:25:29 +05:30
end
2018-12-13 13:39:08 +05:30
it 'returns an array of merge requests with no assignee' do
merge_request3 = create ( :merge_request , :simple , author : user , source_project : project2 , target_project : project2 , source_branch : 'other-branch' )
2019-02-15 15:39:39 +05:30
get api ( '/merge_requests' , user ) , params : { assignee_id : 'None' , scope : :all }
2018-12-13 13:39:08 +05:30
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly ( merge_request3 . id )
2018-12-13 13:39:08 +05:30
end
it 'returns an array of merge requests with any assignee' do
# This MR with no assignee should not be returned
create ( :merge_request , :simple , author : user , source_project : project2 , target_project : project2 , source_branch : 'other-branch' )
2019-02-15 15:39:39 +05:30
get api ( '/merge_requests' , user ) , params : { assignee_id : 'Any' , scope : :all }
2018-12-13 13:39:08 +05:30
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly (
merge_request_merged . id , merge_request2 . id , merge_request_locked . id ,
merge_request_closed . id , merge_request . id
)
2018-12-13 13:39:08 +05:30
end
2017-09-10 17:25:29 +05:30
it 'returns an array of merge requests assigned to me' do
2019-07-31 22:56:46 +05:30
merge_request3 = create ( :merge_request , :simple , author : user , assignees : [ user2 ] , source_project : project2 , target_project : project2 , source_branch : 'other-branch' )
2017-09-10 17:25:29 +05:30
2019-02-15 15:39:39 +05:30
get api ( '/merge_requests' , user2 ) , params : { scope : 'assigned_to_me' }
2018-11-08 19:23:39 +05:30
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly ( merge_request3 . id )
2018-11-08 19:23:39 +05:30
end
it 'returns an array of merge requests assigned to me (kebab-case)' do
2019-07-31 22:56:46 +05:30
merge_request3 = create ( :merge_request , :simple , author : user , assignees : [ user2 ] , source_project : project2 , target_project : project2 , source_branch : 'other-branch' )
2018-11-08 19:23:39 +05:30
2019-02-15 15:39:39 +05:30
get api ( '/merge_requests' , user2 ) , params : { scope : 'assigned-to-me' }
2017-09-10 17:25:29 +05:30
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly ( merge_request3 . id )
2017-09-10 17:25:29 +05:30
end
it 'returns an array of merge requests created by me' do
2019-07-31 22:56:46 +05:30
merge_request3 = create ( :merge_request , :simple , author : user2 , assignees : [ user ] , source_project : project2 , target_project : project2 , source_branch : 'other-branch' )
2017-09-10 17:25:29 +05:30
2019-02-15 15:39:39 +05:30
get api ( '/merge_requests' , user2 ) , params : { scope : 'created_by_me' }
2018-11-08 19:23:39 +05:30
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly ( merge_request3 . id )
2018-11-08 19:23:39 +05:30
end
it 'returns an array of merge requests created by me (kebab-case)' do
2019-07-31 22:56:46 +05:30
merge_request3 = create ( :merge_request , :simple , author : user2 , assignees : [ user ] , source_project : project2 , target_project : project2 , source_branch : 'other-branch' )
2018-11-08 19:23:39 +05:30
2019-02-15 15:39:39 +05:30
get api ( '/merge_requests' , user2 ) , params : { scope : 'created-by-me' }
2017-09-10 17:25:29 +05:30
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly ( merge_request3 . id )
2017-09-10 17:25:29 +05:30
end
2018-03-17 18:26:18 +05:30
it 'returns merge requests reacted by the authenticated user by the given emoji' do
2019-07-31 22:56:46 +05:30
merge_request3 = create ( :merge_request , :simple , author : user , assignees : [ user ] , source_project : project2 , target_project : project2 , source_branch : 'other-branch' )
2018-03-17 18:26:18 +05:30
award_emoji = create ( :award_emoji , awardable : merge_request3 , user : user2 , name : 'star' )
2019-02-15 15:39:39 +05:30
get api ( '/merge_requests' , user2 ) , params : { my_reaction_emoji : award_emoji . name , scope : 'all' }
2018-03-17 18:26:18 +05:30
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly ( merge_request3 . id )
2018-03-17 18:26:18 +05:30
end
2018-03-27 19:54:05 +05:30
context 'source_branch param' do
it 'returns merge requests with the given source branch' do
2019-02-15 15:39:39 +05:30
get api ( '/merge_requests' , user ) , params : { source_branch : merge_request_closed . source_branch , state : 'all' }
2018-03-27 19:54:05 +05:30
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly (
merge_request_merged . id , merge_request_locked . id , merge_request_closed . id
)
2018-03-27 19:54:05 +05:30
end
end
context 'target_branch param' do
it 'returns merge requests with the given target branch' do
2019-02-15 15:39:39 +05:30
get api ( '/merge_requests' , user ) , params : { target_branch : merge_request_closed . target_branch , state : 'all' }
2018-03-27 19:54:05 +05:30
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly (
merge_request_merged . id , merge_request_locked . id , merge_request_closed . id
)
2018-03-27 19:54:05 +05:30
end
end
it 'returns merge requests created before a specific date' do
merge_request2 = create ( :merge_request , :simple , source_project : project , target_project : project , source_branch : 'feature_1' , created_at : Date . new ( 2000 , 1 , 1 ) )
get api ( '/merge_requests?created_before=2000-01-02T00:00:00.060Z' , user )
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly ( merge_request2 . id )
2018-03-27 19:54:05 +05:30
end
it 'returns merge requests created after a specific date' do
merge_request2 = create ( :merge_request , :simple , source_project : project , target_project : project , source_branch : 'feature_1' , created_at : 1 . week . from_now )
get api ( " /merge_requests?created_after= #{ merge_request2 . created_at } " , user )
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly ( merge_request2 . id )
2018-03-27 19:54:05 +05:30
end
it 'returns merge requests updated before a specific date' do
merge_request2 = create ( :merge_request , :simple , source_project : project , target_project : project , source_branch : 'feature_1' , updated_at : Date . new ( 2000 , 1 , 1 ) )
get api ( '/merge_requests?updated_before=2000-01-02T00:00:00.060Z' , user )
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly ( merge_request2 . id )
2018-03-27 19:54:05 +05:30
end
it 'returns merge requests updated after a specific date' do
merge_request2 = create ( :merge_request , :simple , source_project : project , target_project : project , source_branch : 'feature_1' , updated_at : 1 . week . from_now )
get api ( " /merge_requests?updated_after= #{ merge_request2 . updated_at } " , user )
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly ( merge_request2 . id )
2018-03-27 19:54:05 +05:30
end
2018-03-17 18:26:18 +05:30
context 'search params' do
2020-11-24 15:15:51 +05:30
let_it_be ( :merge_request ) do
create ( :merge_request , :simple , author : user , source_project : project , target_project : project , title : 'Search title' , description : 'Search description' )
2018-03-17 18:26:18 +05:30
end
it 'returns merge requests matching given search string for title' do
2019-02-15 15:39:39 +05:30
get api ( " /merge_requests " , user ) , params : { search : merge_request . title }
2018-03-17 18:26:18 +05:30
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly ( merge_request . id )
2018-03-17 18:26:18 +05:30
end
2019-03-02 22:35:43 +05:30
it 'returns merge requests matching given search string for title and scoped in title' do
get api ( " /merge_requests " , user ) , params : { search : merge_request . title , in : 'title' }
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly ( merge_request . id )
2019-03-02 22:35:43 +05:30
end
2020-03-13 15:44:24 +05:30
it 'returns an empty array if no merge request matches given search string for description and scoped in title' do
2019-03-02 22:35:43 +05:30
get api ( " /merge_requests " , user ) , params : { search : merge_request . description , in : 'title' }
2020-03-13 15:44:24 +05:30
expect_empty_array_response
2019-03-02 22:35:43 +05:30
end
2018-03-17 18:26:18 +05:30
it 'returns merge requests for project matching given search string for description' do
2019-02-15 15:39:39 +05:30
get api ( " /merge_requests " , user ) , params : { project_id : project . id , search : merge_request . description }
2018-03-17 18:26:18 +05:30
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly ( merge_request . id )
2018-03-17 18:26:18 +05:30
end
end
2017-08-17 22:00:37 +05:30
2018-11-08 19:23:39 +05:30
context 'state param' do
it 'returns merge requests with the given state' do
2019-02-15 15:39:39 +05:30
get api ( '/merge_requests' , user ) , params : { state : 'locked' }
2014-09-02 18:07:02 +05:30
2020-03-13 15:44:24 +05:30
expect_response_contain_exactly ( merge_request_locked . id )
2018-03-17 18:26:18 +05:30
end
2017-08-17 22:00:37 +05:30
end
2018-11-08 19:23:39 +05:30
end
end
2017-08-17 22:00:37 +05:30
2018-11-08 19:23:39 +05:30
describe " GET /projects/:id/merge_requests " do
2020-11-24 15:15:51 +05:30
include_context 'with merge requests'
2018-11-08 19:23:39 +05:30
let ( :endpoint_path ) { " /projects/ #{ project . id } /merge_requests " }
2017-08-17 22:00:37 +05:30
2018-11-08 19:23:39 +05:30
it_behaves_like 'merge requests list'
2015-04-26 12:48:37 +05:30
2021-06-08 01:23:25 +05:30
context 'when :api_caching_merge_requests is disabled' do
before do
stub_feature_flags ( api_caching_merge_requests : false )
end
it_behaves_like 'merge requests list'
end
2018-11-08 19:23:39 +05:30
it " returns 404 for non public projects " do
project = create ( :project , :private )
2017-08-17 22:00:37 +05:30
2018-11-08 19:23:39 +05:30
get api ( " /projects/ #{ project . id } /merge_requests " )
2015-04-26 12:48:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2018-11-08 19:23:39 +05:30
end
2017-08-17 22:00:37 +05:30
2018-12-05 23:21:45 +05:30
it " returns an array of no merge_requests when wip=yes " do
2019-02-15 15:39:39 +05:30
get api ( " /projects/ #{ project . id } /merge_requests " , user ) , params : { wip : 'yes' }
2018-12-05 23:21:45 +05:30
2020-03-13 15:44:24 +05:30
expect_empty_array_response
2018-12-05 23:21:45 +05:30
end
2018-11-08 19:23:39 +05:30
it 'returns merge_request by "iids" array' do
2019-02-15 15:39:39 +05:30
get api ( endpoint_path , user ) , params : { iids : [ merge_request . iid , merge_request_closed . iid ] }
2015-04-26 12:48:37 +05:30
2020-03-13 15:44:24 +05:30
expect_paginated_array_response ( [ merge_request_closed . id , merge_request . id ] )
2018-11-08 19:23:39 +05:30
expect ( json_response . first [ 'title' ] ) . to eq merge_request_closed . title
expect ( json_response . first [ 'id' ] ) . to eq merge_request_closed . id
end
2019-07-07 11:18:12 +05:30
2021-01-03 14:25:43 +05:30
context 'when filtering by deployments' do
let_it_be ( :mr ) do
create ( :merge_request , :merged , source_project : project , target_project : project )
end
before do
env = create ( :environment , project : project , name : 'staging' )
deploy = create ( :deployment , :success , environment : env , deployable : nil )
deploy . link_merge_requests ( MergeRequest . where ( id : mr . id ) )
end
it 'supports getting merge requests deployed to an environment' do
get api ( endpoint_path , user ) , params : { environment : 'staging' }
expect ( json_response . first [ 'id' ] ) . to eq mr . id
end
it 'does not return merge requests for an environment without deployments' do
get api ( endpoint_path , user ) , params : { environment : 'bla' }
expect_empty_array_response
end
it 'supports getting merge requests deployed after a date' do
get api ( endpoint_path , user ) , params : { deployed_after : '1990-01-01' }
expect ( json_response . first [ 'id' ] ) . to eq mr . id
end
it 'does not return merge requests not deployed after a given date' do
get api ( endpoint_path , user ) , params : { deployed_after : '2100-01-01' }
expect_empty_array_response
end
it 'supports getting merge requests deployed before a date' do
get api ( endpoint_path , user ) , params : { deployed_before : '2100-01-01' }
expect ( json_response . first [ 'id' ] ) . to eq mr . id
end
it 'does not return merge requests not deployed before a given date' do
get api ( endpoint_path , user ) , params : { deployed_before : '1990-01-01' }
expect_empty_array_response
end
end
2019-12-26 22:10:19 +05:30
context 'a project which enforces all discussions to be resolved' do
2020-11-24 15:15:51 +05:30
let_it_be ( :project ) { create ( :project , :repository , only_allow_merge_if_all_discussions_are_resolved : true ) }
include_context 'with merge requests'
2019-07-07 11:18:12 +05:30
2021-06-08 01:23:25 +05:30
it 'avoids N+1 queries' , quarantine : 'https://gitlab.com/gitlab-org/gitlab/-/issues/330335' do
2019-12-26 22:10:19 +05:30
control = ActiveRecord :: QueryRecorder . new do
get api ( " /projects/ #{ project . id } /merge_requests " , user )
end . count
2019-07-07 11:18:12 +05:30
2019-12-26 22:10:19 +05:30
create ( :merge_request , author : user , assignees : [ user ] , source_project : project , target_project : project , created_at : base_time )
expect do
get api ( " /projects/ #{ project . id } /merge_requests " , user )
end . not_to exceed_query_limit ( control )
end
2019-07-07 11:18:12 +05:30
end
2018-11-08 19:23:39 +05:30
end
2017-08-17 22:00:37 +05:30
2018-11-08 19:23:39 +05:30
describe " GET /groups/:id/merge_requests " do
2021-11-11 11:23:49 +05:30
let_it_be ( :group , reload : true ) { create ( :group , :public ) }
2020-05-24 23:13:21 +05:30
let_it_be ( :project ) { create ( :project , :public , :repository , creator : user , namespace : group , only_allow_merge_if_pipeline_succeeds : false ) }
2020-11-24 15:15:51 +05:30
include_context 'with merge requests'
2018-11-08 19:23:39 +05:30
let ( :endpoint_path ) { " /groups/ #{ group . id } /merge_requests " }
2018-03-27 19:54:05 +05:30
2018-11-08 19:23:39 +05:30
before do
group . add_reporter ( user )
end
2018-03-27 19:54:05 +05:30
2018-11-08 19:23:39 +05:30
it_behaves_like 'merge requests list'
2018-03-27 19:54:05 +05:30
2019-10-12 21:52:04 +05:30
context 'when have subgroups' do
2020-05-24 23:13:21 +05:30
let_it_be ( :group ) { create ( :group , :public ) }
let_it_be ( :subgroup ) { create ( :group , parent : group ) }
let_it_be ( :project ) { create ( :project , :public , :repository , creator : user , namespace : subgroup , only_allow_merge_if_pipeline_succeeds : false ) }
2018-03-27 19:54:05 +05:30
2020-11-24 15:15:51 +05:30
include_context 'with merge requests'
2018-11-08 19:23:39 +05:30
it_behaves_like 'merge requests list'
2014-09-02 18:07:02 +05:30
end
2020-03-13 15:44:24 +05:30
describe " # to_reference " do
it 'exposes reference path in context of group' do
get api ( " /groups/ #{ group . id } /merge_requests " , user )
expect ( json_response . first [ 'references' ] [ 'short' ] ) . to eq ( " ! #{ merge_request_merged . iid } " )
expect ( json_response . first [ 'references' ] [ 'relative' ] ) . to eq ( " #{ merge_request_merged . target_project . path } ! #{ merge_request_merged . iid } " )
expect ( json_response . first [ 'references' ] [ 'full' ] ) . to eq ( " #{ merge_request_merged . target_project . full_path } ! #{ merge_request_merged . iid } " )
end
context 'referencing from parent group' do
let ( :parent_group ) { create ( :group ) }
before do
2020-11-24 15:15:51 +05:30
group . update! ( parent_id : parent_group . id )
2020-03-13 15:44:24 +05:30
merge_request_merged . reload
end
it 'exposes reference path in context of parent group' do
get api ( " /groups/ #{ parent_group . id } /merge_requests " )
expect ( json_response . first [ 'references' ] [ 'short' ] ) . to eq ( " ! #{ merge_request_merged . iid } " )
expect ( json_response . first [ 'references' ] [ 'relative' ] ) . to eq ( " #{ merge_request_merged . target_project . full_path } ! #{ merge_request_merged . iid } " )
expect ( json_response . first [ 'references' ] [ 'full' ] ) . to eq ( " #{ merge_request_merged . target_project . full_path } ! #{ merge_request_merged . iid } " )
end
end
end
context 'with archived projects' do
let ( :project2 ) { create ( :project , :public , :archived , namespace : group ) }
let! ( :merge_request_archived ) { create ( :merge_request , title : 'archived mr' , author : user , source_project : project2 , target_project : project2 ) }
it 'returns an array excluding merge_requests from archived projects' do
get api ( endpoint_path , user )
expect_response_contain_exactly (
merge_request_merged . id , merge_request_locked . id ,
merge_request_closed . id , merge_request . id
)
end
context 'with non_archived param set as false' do
it 'returns an array including merge_requests from archived projects' do
path = endpoint_path + '?non_archived=false'
get api ( path , user )
expect_response_contain_exactly (
merge_request_merged . id , merge_request_archived . id , merge_request_locked . id ,
merge_request_closed . id , merge_request . id
)
end
end
end
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
describe " GET /projects/:id/merge_requests/:merge_request_iid " do
2020-11-24 15:15:51 +05:30
let ( :merge_request ) { create ( :merge_request , :simple , author : user , assignees : [ user ] , milestone : milestone , source_project : project , source_branch : 'markdown' , title : " Test " ) }
2019-07-07 11:18:12 +05:30
it 'matches json schema' do
2019-07-31 22:56:46 +05:30
merge_request = create ( :merge_request , :with_test_reports , milestone : milestone1 , author : user , assignees : [ user ] , source_project : project , target_project : project , title : " Test " , created_at : base_time )
2019-07-07 11:18:12 +05:30
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-07-07 11:18:12 +05:30
expect ( response ) . to match_response_schema ( 'public_api/v4/merge_request' )
end
2016-06-02 11:05:42 +05:30
it 'exposes known attributes' do
2019-07-07 11:18:12 +05:30
create ( :award_emoji , :downvote , awardable : merge_request )
create ( :award_emoji , :upvote , awardable : merge_request )
2017-08-17 22:00:37 +05:30
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user )
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2016-06-02 11:05:42 +05:30
expect ( json_response [ 'id' ] ) . to eq ( merge_request . id )
expect ( json_response [ 'iid' ] ) . to eq ( merge_request . iid )
expect ( json_response [ 'project_id' ] ) . to eq ( merge_request . project . id )
expect ( json_response [ 'title' ] ) . to eq ( merge_request . title )
expect ( json_response [ 'description' ] ) . to eq ( merge_request . description )
expect ( json_response [ 'state' ] ) . to eq ( merge_request . state )
expect ( json_response [ 'created_at' ] ) . to be_present
expect ( json_response [ 'updated_at' ] ) . to be_present
expect ( json_response [ 'labels' ] ) . to eq ( merge_request . label_names )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'milestone' ] ) . to be_a Hash
2016-06-02 11:05:42 +05:30
expect ( json_response [ 'assignee' ] ) . to be_a Hash
expect ( json_response [ 'author' ] ) . to be_a Hash
expect ( json_response [ 'target_branch' ] ) . to eq ( merge_request . target_branch )
expect ( json_response [ 'source_branch' ] ) . to eq ( merge_request . source_branch )
2017-09-10 17:25:29 +05:30
expect ( json_response [ 'upvotes' ] ) . to eq ( 1 )
expect ( json_response [ 'downvotes' ] ) . to eq ( 1 )
2016-06-02 11:05:42 +05:30
expect ( json_response [ 'source_project_id' ] ) . to eq ( merge_request . source_project . id )
expect ( json_response [ 'target_project_id' ] ) . to eq ( merge_request . target_project . id )
2021-09-04 01:27:46 +05:30
expect ( json_response [ 'draft' ] ) . to be false
expect ( json_response [ 'work_in_progress' ] ) . to be false
2021-09-30 23:02:18 +05:30
expect ( json_response [ 'merge_when_pipeline_succeeds' ] ) . to be false
2016-06-02 11:05:42 +05:30
expect ( json_response [ 'merge_status' ] ) . to eq ( 'can_be_merged' )
2018-03-17 18:26:18 +05:30
expect ( json_response [ 'changes_count' ] ) . to eq ( merge_request . merge_request_diff . real_size )
2019-02-15 15:39:39 +05:30
expect ( json_response [ 'merge_error' ] ) . to eq ( merge_request . merge_error )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'user' ] [ 'can_merge' ] ) . to be_truthy
2019-02-15 15:39:39 +05:30
expect ( json_response ) . not_to include ( 'rebase_in_progress' )
2021-09-30 23:02:18 +05:30
expect ( json_response [ 'first_contribution' ] ) . to be false
expect ( json_response [ 'has_conflicts' ] ) . to be false
2019-12-26 22:10:19 +05:30
expect ( json_response [ 'blocking_discussions_resolved' ] ) . to be_truthy
2020-03-13 15:44:24 +05:30
expect ( json_response [ 'references' ] [ 'short' ] ) . to eq ( " ! #{ merge_request . iid } " )
expect ( json_response [ 'references' ] [ 'relative' ] ) . to eq ( " ! #{ merge_request . iid } " )
expect ( json_response [ 'references' ] [ 'full' ] ) . to eq ( " #{ merge_request . target_project . full_path } ! #{ merge_request . iid } " )
2014-09-02 18:07:02 +05:30
end
2018-11-08 19:23:39 +05:30
it 'exposes description and title html when render_html is true' do
2019-02-15 15:39:39 +05:30
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : { render_html : true }
2018-11-08 19:23:39 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-11-08 19:23:39 +05:30
expect ( json_response ) . to include ( 'title_html' , 'description_html' )
end
2019-02-15 15:39:39 +05:30
it 'exposes rebase_in_progress when include_rebase_in_progress is true' do
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : { include_rebase_in_progress : true }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-02-15 15:39:39 +05:30
expect ( json_response ) . to include ( 'rebase_in_progress' )
end
2020-04-22 19:07:51 +05:30
context 'when author is not a member without any merged merge requests' do
let ( :non_member ) { create ( :user ) }
before do
2020-11-24 15:15:51 +05:30
merge_request . update! ( author : non_member )
2020-04-22 19:07:51 +05:30
end
it 'exposes first_contribution as true' do
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user )
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'first_contribution' ] ) . to be_truthy
end
end
2021-02-11 23:33:58 +05:30
context 'when merge request author has only guest access' do
it_behaves_like 'rejects user from accessing merge request info' do
let ( :url ) { " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " }
end
end
2018-03-27 19:54:05 +05:30
context 'merge_request_metrics' do
2019-07-07 11:18:12 +05:30
let ( :pipeline ) { create ( :ci_empty_pipeline ) }
2018-03-27 19:54:05 +05:30
before do
merge_request . metrics . update! ( merged_by : user ,
latest_closed_by : user ,
latest_closed_at : 1 . hour . ago ,
merged_at : 2 . hours . ago ,
pipeline : pipeline ,
latest_build_started_at : 3 . hours . ago ,
latest_build_finished_at : 1 . hour . ago ,
first_deployed_to_production_at : 3 . minutes . ago )
end
it 'has fields from merge request metrics' do
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user )
expect ( json_response ) . to include ( 'merged_by' ,
'merged_at' ,
'closed_by' ,
'closed_at' ,
'latest_build_started_at' ,
'latest_build_finished_at' ,
'first_deployed_to_production_at' ,
'pipeline' )
end
it 'returns correct values' do
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . reload . iid } " , user )
expect ( json_response [ 'merged_by' ] [ 'id' ] ) . to eq ( merge_request . metrics . merged_by_id )
2020-04-22 19:07:51 +05:30
expect ( Time . parse ( json_response [ 'merged_at' ] ) ) . to be_like_time ( merge_request . metrics . merged_at )
2018-03-27 19:54:05 +05:30
expect ( json_response [ 'closed_by' ] [ 'id' ] ) . to eq ( merge_request . metrics . latest_closed_by_id )
2020-04-22 19:07:51 +05:30
expect ( Time . parse ( json_response [ 'closed_at' ] ) ) . to be_like_time ( merge_request . metrics . latest_closed_at )
2018-03-27 19:54:05 +05:30
expect ( json_response [ 'pipeline' ] [ 'id' ] ) . to eq ( merge_request . metrics . pipeline_id )
2020-04-22 19:07:51 +05:30
expect ( Time . parse ( json_response [ 'latest_build_started_at' ] ) ) . to be_like_time ( merge_request . metrics . latest_build_started_at )
expect ( Time . parse ( json_response [ 'latest_build_finished_at' ] ) ) . to be_like_time ( merge_request . metrics . latest_build_finished_at )
expect ( Time . parse ( json_response [ 'first_deployed_to_production_at' ] ) ) . to be_like_time ( merge_request . metrics . first_deployed_to_production_at )
2018-03-27 19:54:05 +05:30
end
end
2019-07-07 11:18:12 +05:30
context 'head_pipeline' do
2020-11-24 15:15:51 +05:30
let ( :project ) { create ( :project , :repository ) }
let ( :merge_request ) { create ( :merge_request , :simple , author : user , source_project : project , source_branch : 'markdown' , title : " Test " ) }
2019-07-07 11:18:12 +05:30
before do
2020-11-24 15:15:51 +05:30
merge_request . update! ( head_pipeline : create ( :ci_pipeline ) )
merge_request . project . project_feature . update! ( builds_access_level : 10 )
2019-07-07 11:18:12 +05:30
end
context 'when user can read the pipeline' do
it 'exposes pipeline information' do
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user )
expect ( json_response ) . to include ( 'head_pipeline' )
end
end
context 'when user can not read the pipeline' do
let ( :guest ) { create ( :user ) }
it 'does not expose pipeline information' do
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , guest )
expect ( json_response ) . not_to include ( 'head_pipeline' )
end
end
end
2018-11-20 20:47:30 +05:30
it 'returns the commits behind the target branch when include_diverged_commits_count is present' do
allow_any_instance_of ( merge_request . class ) . to receive ( :diverged_commits_count ) . and_return ( 1 )
2019-02-15 15:39:39 +05:30
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : { include_diverged_commits_count : true }
2018-11-20 20:47:30 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-11-20 20:47:30 +05:30
expect ( json_response [ 'diverged_commits_count' ] ) . to eq ( 1 )
end
2017-08-17 22:00:37 +05:30
it " returns a 404 error if merge_request_iid not found " do
2019-07-07 11:18:12 +05:30
get api ( " /projects/ #{ project . id } /merge_requests/0 " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2015-09-11 14:41:01 +05:30
end
2017-08-17 22:00:37 +05:30
it " returns a 404 error if merge_request `id` is used instead of iid " do
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . id } " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2015-04-26 12:48:37 +05:30
end
2016-06-02 11:05:42 +05:30
2021-09-04 01:27:46 +05:30
context 'Draft' do
let! ( :merge_request_draft ) do
2021-03-11 19:13:27 +05:30
create ( :merge_request ,
author : user ,
assignees : [ user ] ,
source_project : project ,
target_project : project ,
2021-09-04 01:27:46 +05:30
title : " Draft: Test " ,
2021-03-11 19:13:27 +05:30
created_at : base_time + 1 . second
)
end
2016-06-02 11:05:42 +05:30
2018-03-17 18:26:18 +05:30
it " returns merge request " do
2021-09-04 01:27:46 +05:30
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request_draft . iid } " , user )
2018-03-17 18:26:18 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2021-09-04 01:27:46 +05:30
expect ( json_response [ 'draft' ] ) . to eq ( true )
2016-06-02 11:05:42 +05:30
expect ( json_response [ 'work_in_progress' ] ) . to eq ( true )
end
end
2018-03-17 18:26:18 +05:30
context 'when a merge request has more than the changes limit' do
it " returns a string indicating that more changes were made " do
2021-09-04 01:27:46 +05:30
allow ( Commit ) . to receive ( :diff_max_files ) . and_return ( 5 )
2018-03-17 18:26:18 +05:30
merge_request_overflow = create ( :merge_request , :simple ,
author : user ,
2019-07-31 22:56:46 +05:30
assignees : [ user ] ,
2018-03-17 18:26:18 +05:30
source_project : project ,
source_branch : 'expand-collapse-files' ,
target_project : project ,
target_branch : 'master' )
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request_overflow . iid } " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-03-17 18:26:18 +05:30
expect ( json_response [ 'changes_count' ] ) . to eq ( '5+' )
end
end
2018-03-27 19:54:05 +05:30
context 'for forked projects' do
let ( :user2 ) { create ( :user ) }
let ( :project ) { create ( :project , :public , :repository ) }
let ( :forked_project ) { fork_project ( project , user2 , repository : true ) }
let ( :merge_request ) do
create ( :merge_request ,
source_project : forked_project ,
target_project : project ,
source_branch : 'fixes' ,
2018-11-08 19:23:39 +05:30
allow_collaboration : true )
2018-03-27 19:54:05 +05:30
end
2019-12-26 22:10:19 +05:30
it 'includes the `allow_collaboration` field' , :sidekiq_might_not_need_inline do
2018-03-27 19:54:05 +05:30
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user )
2018-11-08 19:23:39 +05:30
expect ( json_response [ 'allow_collaboration' ] ) . to be_truthy
2018-03-27 19:54:05 +05:30
expect ( json_response [ 'allow_maintainer_to_push' ] ) . to be_truthy
end
end
2019-07-07 11:18:12 +05:30
it 'indicates if a user cannot merge the MR' do
user2 = create ( :user )
project . add_reporter ( user2 )
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user2 )
2021-09-30 23:02:18 +05:30
expect ( json_response [ 'user' ] [ 'can_merge' ] ) . to be false
2019-07-07 11:18:12 +05:30
end
2020-03-13 15:44:24 +05:30
2020-04-22 19:07:51 +05:30
it 'returns `checking` as its merge_status instead of `cannot_be_merged_rechecking`' do
merge_request . update! ( merge_status : 'cannot_be_merged_rechecking' )
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user )
expect ( json_response [ 'merge_status' ] ) . to eq 'checking'
end
2020-03-13 15:44:24 +05:30
context 'when merge request is unchecked' do
before do
merge_request . mark_as_unchecked!
end
it 'checks mergeability asynchronously' do
expect_next_instance_of ( MergeRequests :: MergeabilityCheckService ) do | service |
expect ( service ) . not_to receive ( :execute )
expect ( service ) . to receive ( :async_execute )
end
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user )
end
end
2018-03-17 18:26:18 +05:30
end
describe 'GET /projects/:id/merge_requests/:merge_request_iid/participants' do
it_behaves_like 'issuable participants endpoint' do
2020-11-24 15:15:51 +05:30
let ( :entity ) { create ( :merge_request , :simple , milestone : milestone1 , author : user , assignees : [ user ] , source_project : project , target_project : project , source_branch : 'markdown' , title : " Test " , created_at : base_time ) }
2018-03-17 18:26:18 +05:30
end
2021-02-11 23:33:58 +05:30
context 'when merge request author has only guest access' do
it_behaves_like 'rejects user from accessing merge request info' do
let ( :url ) { " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /participants " }
end
end
2015-04-26 12:48:37 +05:30
end
2017-08-17 22:00:37 +05:30
describe 'GET /projects/:id/merge_requests/:merge_request_iid/commits' do
2020-11-24 15:15:51 +05:30
include_context 'with merge requests'
2017-08-17 22:00:37 +05:30
it 'returns a 200 when merge request is valid' do
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /commits " , user )
commit = merge_request . commits . first
2015-12-23 02:04:40 +05:30
2020-03-13 15:44:24 +05:30
expect_successful_response_with_paginated_array
2017-08-17 22:00:37 +05:30
expect ( json_response . size ) . to eq ( merge_request . commits . size )
expect ( json_response . first [ 'id' ] ) . to eq ( commit . id )
expect ( json_response . first [ 'title' ] ) . to eq ( commit . title )
2015-12-23 02:04:40 +05:30
end
2017-08-17 22:00:37 +05:30
it 'returns a 404 when merge_request_iid not found' do
2019-07-07 11:18:12 +05:30
get api ( " /projects/ #{ project . id } /merge_requests/0/commits " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2015-12-23 02:04:40 +05:30
end
2017-08-17 22:00:37 +05:30
it 'returns a 404 when merge_request id is used instead of iid' do
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . id } /commits " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2017-08-17 22:00:37 +05:30
end
2021-02-11 23:33:58 +05:30
context 'when merge request author has only guest access' do
it_behaves_like 'rejects user from accessing merge request info' do
let ( :url ) { " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /commits " }
end
end
2015-12-23 02:04:40 +05:30
end
2020-03-13 15:44:24 +05:30
describe 'GET /projects/:id/merge_requests/:merge_request_iid/:context_commits' do
2020-11-24 15:15:51 +05:30
let_it_be ( :merge_request ) { create ( :merge_request , :simple , author : user , source_project : project , target_project : project , source_branch : 'markdown' , title : " Test " , created_at : base_time ) }
let_it_be ( :merge_request_context_commit ) { create ( :merge_request_context_commit , merge_request : merge_request , message : 'test' ) }
2020-03-13 15:44:24 +05:30
it 'returns a 200 when merge request is valid' do
context_commit = merge_request . context_commits . first
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /context_commits " , user )
expect_successful_response_with_paginated_array
expect ( json_response . size ) . to eq ( merge_request . context_commits . size )
expect ( json_response . first [ 'id' ] ) . to eq ( context_commit . id )
expect ( json_response . first [ 'title' ] ) . to eq ( context_commit . title )
end
it 'returns a 404 when merge_request_iid not found' do
get api ( " /projects/ #{ project . id } /merge_requests/0/context_commits " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2020-03-13 15:44:24 +05:30
end
end
2017-08-17 22:00:37 +05:30
describe 'GET /projects/:id/merge_requests/:merge_request_iid/changes' do
2021-01-29 00:20:46 +05:30
let_it_be ( :merge_request ) do
create (
:merge_request ,
:simple ,
author : user ,
assignees : [ user ] ,
source_project : project ,
target_project : project ,
source_branch : 'markdown' ,
title : " Test " ,
created_at : base_time
)
end
2020-11-24 15:15:51 +05:30
2021-01-29 00:20:46 +05:30
shared_examples 'find an existing merge request' do
it 'returns the change information of the merge_request' do
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /changes " , user )
2017-08-17 22:00:37 +05:30
2021-01-29 00:20:46 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'changes' ] . size ) . to eq ( merge_request . diffs . size )
expect ( json_response [ 'overflow' ] ) . to be_falsy
end
end
shared_examples 'accesses diffs via raw_diffs' do
let ( :params ) { { } }
it 'as expected' do
expect_any_instance_of ( MergeRequest ) do | merge_request |
expect ( merge_request ) . to receive ( :raw_diffs ) . and_call_original
end
expect_any_instance_of ( MergeRequest ) do | merge_request |
expect ( merge_request ) . not_to receive ( :diffs )
end
get ( api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /changes " , user ) , params : params )
end
2015-04-26 12:48:37 +05:30
end
2017-08-17 22:00:37 +05:30
it 'returns a 404 when merge_request_iid not found' do
2019-07-07 11:18:12 +05:30
get api ( " /projects/ #{ project . id } /merge_requests/0/changes " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
it 'returns a 404 when merge_request id is used instead of iid' do
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . id } /changes " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2018-03-17 18:26:18 +05:30
end
2021-01-29 00:20:46 +05:30
2021-02-11 23:33:58 +05:30
context 'when merge request author has only guest access' do
it_behaves_like 'rejects user from accessing merge request info' do
let ( :url ) { " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /changes " }
end
end
2021-01-29 00:20:46 +05:30
it_behaves_like 'find an existing merge request'
it_behaves_like 'accesses diffs via raw_diffs'
it 'returns the overflow status as false' do
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /changes " , user )
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'overflow' ] ) . to be_falsy
end
context 'when using DB-backed diffs via feature flag' do
before do
stub_feature_flags ( mrc_api_use_raw_diffs_from_gitaly : false )
end
it_behaves_like 'find an existing merge request'
it 'accesses diffs via DB-backed diffs.diffs' do
expect_any_instance_of ( MergeRequest ) do | merge_request |
expect ( merge_request ) . to receive ( :diffs ) . and_call_original
end
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /changes " , user )
end
context 'when the diff_collection has overflowed its size limits' do
before do
expect_next_instance_of ( Gitlab :: Git :: DiffCollection ) do | diff_collection |
expect ( diff_collection ) . to receive ( :overflow? ) . and_return ( true )
end
end
it 'returns the overflow status as true' do
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /changes " , user )
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'overflow' ] ) . to be_truthy
end
end
2021-03-11 19:13:27 +05:30
context 'when access_raw_diffs is true' do
2021-01-29 00:20:46 +05:30
it_behaves_like 'accesses diffs via raw_diffs' do
2021-03-11 19:13:27 +05:30
let ( :params ) { { access_raw_diffs : " true " } }
2021-01-29 00:20:46 +05:30
end
end
end
2018-03-17 18:26:18 +05:30
end
describe 'GET /projects/:id/merge_requests/:merge_request_iid/pipelines' do
2020-11-24 15:15:51 +05:30
let_it_be ( :merge_request ) { create ( :merge_request , :simple , author : user , assignees : [ user ] , source_project : project , target_project : project , source_branch : 'markdown' , title : " Test " , created_at : base_time ) }
2018-03-17 18:26:18 +05:30
context 'when authorized' do
let! ( :pipeline ) { create ( :ci_empty_pipeline , project : project , user : user , ref : merge_request . source_branch , sha : merge_request . diff_head_sha ) }
let! ( :pipeline2 ) { create ( :ci_empty_pipeline , project : project ) }
it 'returns a paginated array of corresponding pipelines' do
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /pipelines " )
2020-03-13 15:44:24 +05:30
expect_successful_response_with_paginated_array
2018-03-17 18:26:18 +05:30
expect ( json_response . count ) . to eq ( 1 )
expect ( json_response . first [ 'id' ] ) . to eq ( pipeline . id )
end
it 'exposes basic attributes' do
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /pipelines " )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-03-17 18:26:18 +05:30
expect ( response ) . to match_response_schema ( 'public_api/v4/pipelines' )
end
it 'returns 404 if MR does not exist' do
get api ( " /projects/ #{ project . id } /merge_requests/777/pipelines " )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2018-03-17 18:26:18 +05:30
end
end
context 'when unauthorized' do
it 'returns 403' do
project = create ( :project , public_builds : false )
merge_request = create ( :merge_request , :simple , source_project : project )
guest = create ( :user )
project . add_guest ( guest )
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /pipelines " , guest )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2018-03-17 18:26:18 +05:30
end
2021-02-11 23:33:58 +05:30
end
context 'when merge request author has only guest access' do
it_behaves_like 'rejects user from accessing merge request info' do
let ( :url ) { " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /pipelines " }
end
2017-08-17 22:00:37 +05:30
end
2014-09-02 18:07:02 +05:30
end
2019-12-04 20:38:33 +05:30
describe 'POST /projects/:id/merge_requests/:merge_request_iid/pipelines' do
before do
2020-04-08 14:13:33 +05:30
stub_ci_pipeline_yaml_file ( ci_yaml )
end
let ( :ci_yaml ) do
YAML . dump ( {
2019-12-26 22:10:19 +05:30
rspec : {
script : 'ls' ,
only : [ 'merge_requests' ]
}
2020-04-08 14:13:33 +05:30
} )
2019-12-04 20:38:33 +05:30
end
2020-11-24 15:15:51 +05:30
let_it_be ( :project ) do
2019-12-04 20:38:33 +05:30
create ( :project , :private , :repository ,
creator : user ,
namespace : user . namespace ,
only_allow_merge_if_pipeline_succeeds : false )
end
2020-11-24 15:15:51 +05:30
let_it_be ( :merge_request ) do
2019-12-04 20:38:33 +05:30
create ( :merge_request , :with_detached_merge_request_pipeline ,
author : user ,
assignees : [ user ] ,
source_project : project ,
target_project : project ,
title : 'Test' ,
created_at : base_time )
end
let ( :merge_request_iid ) { merge_request . iid }
let ( :authenticated_user ) { user }
let ( :request ) do
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request_iid } /pipelines " , authenticated_user )
end
context 'when authorized' do
it 'creates and returns the new Pipeline' do
expect { request } . to change ( Ci :: Pipeline , :count ) . by ( 1 )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-12-04 20:38:33 +05:30
expect ( json_response ) . to be_a Hash
end
end
context 'when unauthorized' do
let ( :authenticated_user ) { create ( :user ) }
it 'responds with a blank 404' do
expect { request } . not_to change ( Ci :: Pipeline , :count )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2019-12-04 20:38:33 +05:30
end
end
context 'when the merge request does not exist' do
2020-11-24 15:15:51 +05:30
let ( :merge_request_iid ) { non_existing_record_id }
2019-12-04 20:38:33 +05:30
it 'responds with a blank 404' do
expect { request } . not_to change ( Ci :: Pipeline , :count )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
end
end
context 'when the .gitlab-ci.yml file is invalid' do
let ( :ci_yaml ) { 'invalid yaml file' }
it 'creates a failed pipeline' do
expect { request } . to change ( Ci :: Pipeline , :count ) . by ( 1 )
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response ) . to be_a Hash
expect ( merge_request . pipelines_for_merge_request . last ) . to be_failed
expect ( merge_request . pipelines_for_merge_request . last ) . to be_config_error
2019-12-04 20:38:33 +05:30
end
end
end
2019-07-07 11:18:12 +05:30
describe 'POST /projects/:id/merge_requests' do
2019-07-31 22:56:46 +05:30
context 'support for deprecated assignee_id' do
let ( :params ) do
{
title : 'Test merge request' ,
source_branch : 'feature_conflict' ,
target_branch : 'master' ,
author_id : user . id ,
assignee_id : user2 . id
}
end
it 'creates a new merge request' do
post api ( " /projects/ #{ project . id } /merge_requests " , user ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2019-07-31 22:56:46 +05:30
expect ( json_response [ 'title' ] ) . to eq ( 'Test merge request' )
expect ( json_response [ 'assignee' ] [ 'name' ] ) . to eq ( user2 . name )
expect ( json_response [ 'assignees' ] . first [ 'name' ] ) . to eq ( user2 . name )
end
it 'creates a new merge request when assignee_id is empty' do
params [ :assignee_id ] = ''
post api ( " /projects/ #{ project . id } /merge_requests " , user ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2019-07-31 22:56:46 +05:30
expect ( json_response [ 'title' ] ) . to eq ( 'Test merge request' )
expect ( json_response [ 'assignee' ] ) . to be_nil
end
it 'filters assignee_id of unauthorized user' do
private_project = create ( :project , :private , :repository )
another_user = create ( :user )
private_project . add_maintainer ( user )
params [ :assignee_id ] = another_user . id
post api ( " /projects/ #{ private_project . id } /merge_requests " , user ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2019-07-31 22:56:46 +05:30
expect ( json_response [ 'assignee' ] ) . to be_nil
end
end
context 'single assignee restrictions' do
let ( :params ) do
{
title : 'Test merge request' ,
source_branch : 'feature_conflict' ,
target_branch : 'master' ,
author_id : user . id ,
assignee_ids : [ user . id , user2 . id ]
}
end
it 'creates a new project merge request with no more than one assignee' do
post api ( " /projects/ #{ project . id } /merge_requests " , user ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2019-07-31 22:56:46 +05:30
expect ( json_response [ 'title' ] ) . to eq ( 'Test merge request' )
expect ( json_response [ 'assignees' ] . count ) . to eq ( 1 )
expect ( json_response [ 'assignees' ] . first [ 'name' ] ) . to eq ( user . name )
expect ( json_response . dig ( 'assignee' , 'name' ) ) . to eq ( user . name )
end
end
2021-03-11 19:13:27 +05:30
context 'accepts reviewer_ids' do
let ( :params ) do
{
title : 'Test merge request' ,
source_branch : 'feature_conflict' ,
target_branch : 'master' ,
author_id : user . id ,
reviewer_ids : [ user2 . id ]
}
end
it 'creates a new merge request with a reviewer' do
post api ( " /projects/ #{ project . id } /merge_requests " , user ) , params : params
expect ( response ) . to have_gitlab_http_status ( :created )
expect ( json_response [ 'title' ] ) . to eq ( 'Test merge request' )
expect ( json_response [ 'reviewers' ] . first [ 'name' ] ) . to eq ( user2 . name )
end
it 'creates a new merge request with no reviewer' do
params [ :reviewer_ids ] = [ ]
post api ( " /projects/ #{ project . id } /merge_requests " , user ) , params : params
expect ( response ) . to have_gitlab_http_status ( :created )
expect ( json_response [ 'title' ] ) . to eq ( 'Test merge request' )
expect ( json_response [ 'reviewers' ] ) . to be_empty
end
end
2014-09-02 18:07:02 +05:30
context 'between branches projects' do
2019-07-07 11:18:12 +05:30
context 'different labels' do
let ( :params ) do
{
title : 'Test merge_request' ,
source_branch : 'feature_conflict' ,
target_branch : 'master' ,
author_id : user . id ,
milestone_id : milestone . id ,
squash : true
}
end
2019-05-18 00:54:41 +05:30
2019-07-07 11:18:12 +05:30
shared_examples_for 'creates merge request with labels' do
it 'returns merge_request' do
params [ :labels ] = labels
post api ( " /projects/ #{ project . id } /merge_requests " , user ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'title' ] ) . to eq ( 'Test merge_request' )
expect ( json_response [ 'labels' ] ) . to eq ( %w( label label2 ) )
expect ( json_response [ 'milestone' ] [ 'id' ] ) . to eq ( milestone . id )
expect ( json_response [ 'squash' ] ) . to be_truthy
expect ( json_response [ 'force_remove_source_branch' ] ) . to be_falsy
end
end
it_behaves_like 'creates merge request with labels' do
let ( :labels ) { 'label, label2' }
end
it_behaves_like 'creates merge request with labels' do
let ( :labels ) { %w( label label2 ) }
end
it_behaves_like 'creates merge request with labels' do
let ( :labels ) { %w( label label2 ) }
end
it 'creates merge request with special label names' do
params [ :labels ] = 'label, label?, label&foo, ?, &'
post api ( " /projects/ #{ project . id } /merge_requests " , user ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'labels' ] ) . to include 'label'
expect ( json_response [ 'labels' ] ) . to include 'label?'
expect ( json_response [ 'labels' ] ) . to include 'label&foo'
expect ( json_response [ 'labels' ] ) . to include '?'
expect ( json_response [ 'labels' ] ) . to include '&'
end
it 'creates merge request with special label names as array' do
params [ :labels ] = [ 'label' , 'label?' , 'label&foo, ?, &' , '1, 2' , 3 , 4 ]
post api ( " /projects/ #{ project . id } /merge_requests " , user ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'labels' ] ) . to include 'label'
expect ( json_response [ 'labels' ] ) . to include 'label?'
expect ( json_response [ 'labels' ] ) . to include 'label&foo'
expect ( json_response [ 'labels' ] ) . to include '?'
expect ( json_response [ 'labels' ] ) . to include '&'
expect ( json_response [ 'labels' ] ) . to include '1'
expect ( json_response [ 'labels' ] ) . to include '2'
expect ( json_response [ 'labels' ] ) . to include '3'
expect ( json_response [ 'labels' ] ) . to include '4'
end
it 'empty label param does not add any labels' do
params [ :labels ] = ''
post api ( " /projects/ #{ project . id } /merge_requests " , user ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'labels' ] ) . to eq ( [ ] )
end
it 'empty label param as array does not add any labels, but only explicitly as json' do
params [ :labels ] = [ ]
post api ( " /projects/ #{ project . id } /merge_requests " , user ) ,
params : params . to_json ,
headers : { 'Content-Type' : 'application/json' }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'labels' ] ) . to eq ( [ ] )
end
2020-03-13 15:44:24 +05:30
it 'empty label param as array, does not add any labels' do
2019-07-07 11:18:12 +05:30
params [ :labels ] = [ ]
post api ( " /projects/ #{ project . id } /merge_requests " , user ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'labels' ] ) . to eq ( [ ] )
end
it 'array with one empty string element does not add labels' do
params [ :labels ] = [ '' ]
post api ( " /projects/ #{ project . id } /merge_requests " , user ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'labels' ] ) . to eq ( [ ] )
end
it 'array with multiple empty string elements, does not add labels' do
params [ :labels ] = [ '' , '' , '' ]
post api ( " /projects/ #{ project . id } /merge_requests " , user ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'labels' ] ) . to eq ( [ ] )
end
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it " returns 422 when source_branch equals target_branch " do
2014-09-02 18:07:02 +05:30
post api ( " /projects/ #{ project . id } /merge_requests " , user ) ,
2019-02-15 15:39:39 +05:30
params : { title : " Test merge_request " , source_branch : " master " , target_branch : " master " , author : user }
2020-10-24 23:57:45 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :unprocessable_entity )
2020-10-24 23:57:45 +05:30
expect ( json_response [ 'message' ] ) . to eq ( [ " You can't use same project/branch for source and target " ] )
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it " returns 400 when source_branch is missing " do
2014-09-02 18:07:02 +05:30
post api ( " /projects/ #{ project . id } /merge_requests " , user ) ,
2019-02-15 15:39:39 +05:30
params : { title : " Test merge_request " , target_branch : " master " , author : user }
2020-10-24 23:57:45 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2020-10-24 23:57:45 +05:30
expect ( json_response [ 'error' ] ) . to eq ( 'source_branch is missing' )
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it " returns 400 when target_branch is missing " do
2014-09-02 18:07:02 +05:30
post api ( " /projects/ #{ project . id } /merge_requests " , user ) ,
2019-02-15 15:39:39 +05:30
params : { title : " Test merge_request " , source_branch : " markdown " , author : user }
2020-10-24 23:57:45 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2020-10-24 23:57:45 +05:30
expect ( json_response [ 'error' ] ) . to eq ( 'target_branch is missing' )
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it " returns 400 when title is missing " do
2014-09-02 18:07:02 +05:30
post api ( " /projects/ #{ project . id } /merge_requests " , user ) ,
2019-02-15 15:39:39 +05:30
params : { target_branch : 'master' , source_branch : 'markdown' }
2020-10-24 23:57:45 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2020-10-24 23:57:45 +05:30
expect ( json_response [ 'error' ] ) . to eq ( 'title is missing' )
2014-09-02 18:07:02 +05:30
end
2015-04-26 12:48:37 +05:30
context 'with existing MR' do
before do
post api ( " /projects/ #{ project . id } /merge_requests " , user ) ,
2019-02-15 15:39:39 +05:30
params : {
title : 'Test merge_request' ,
source_branch : 'feature_conflict' ,
target_branch : 'master' ,
author : user
}
2015-04-26 12:48:37 +05:30
@mr = MergeRequest . all . last
end
2016-09-13 17:45:13 +05:30
it 'returns 409 when MR already exists for source/target' do
2015-04-26 12:48:37 +05:30
expect do
post api ( " /projects/ #{ project . id } /merge_requests " , user ) ,
2019-02-15 15:39:39 +05:30
params : {
title : 'New test merge_request' ,
source_branch : 'feature_conflict' ,
target_branch : 'master' ,
author : user
}
2015-04-26 12:48:37 +05:30
end . to change { MergeRequest . count } . by ( 0 )
2020-10-24 23:57:45 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :conflict )
2020-11-24 15:15:51 +05:30
expect ( json_response [ 'message' ] ) . to eq ( [ " Another open merge request already exists for this source branch: !1 " ] )
2015-04-26 12:48:37 +05:30
end
2014-09-02 18:07:02 +05:30
end
2017-09-10 17:25:29 +05:30
context 'accepts remove_source_branch parameter' do
let ( :params ) do
{ title : 'Test merge_request' ,
2019-12-26 22:10:19 +05:30
source_branch : 'feature_conflict' ,
2017-09-10 17:25:29 +05:30
target_branch : 'master' ,
author : user }
end
it 'sets force_remove_source_branch to false' do
2019-02-15 15:39:39 +05:30
post api ( " /projects/ #{ project . id } /merge_requests " , user ) , params : params . merge ( remove_source_branch : false )
2017-09-10 17:25:29 +05:30
expect ( json_response [ 'force_remove_source_branch' ] ) . to be_falsy
end
it 'sets force_remove_source_branch to true' do
2019-02-15 15:39:39 +05:30
post api ( " /projects/ #{ project . id } /merge_requests " , user ) , params : params . merge ( remove_source_branch : true )
2017-09-10 17:25:29 +05:30
expect ( json_response [ 'force_remove_source_branch' ] ) . to be_truthy
end
end
2014-09-02 18:07:02 +05:30
end
2020-03-13 15:44:24 +05:30
context 'forked projects' , :sidekiq_might_not_need_inline do
2020-05-24 23:13:21 +05:30
let_it_be ( :user2 ) { create ( :user ) }
2021-09-30 23:02:18 +05:30
2018-03-27 19:54:05 +05:30
let ( :project ) { create ( :project , :public , :repository ) }
2018-03-17 18:26:18 +05:30
let! ( :forked_project ) { fork_project ( project , user2 , repository : true ) }
2019-03-02 22:35:43 +05:30
let! ( :unrelated_project ) { create ( :project , namespace : create ( :user ) . namespace , creator_id : user2 . id ) }
2014-09-02 18:07:02 +05:30
2018-03-17 18:26:18 +05:30
before do
forked_project . add_reporter ( user2 )
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it " returns merge_request " do
2018-03-17 18:26:18 +05:30
post api ( " /projects/ #{ forked_project . id } /merge_requests " , user2 ) ,
2019-02-15 15:39:39 +05:30
params : { title : 'Test merge_request' , source_branch : " feature_conflict " , target_branch : " master " , author : user2 , target_project_id : project . id , description : 'Test description for Test merge_request' }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2015-04-26 12:48:37 +05:30
expect ( json_response [ 'title' ] ) . to eq ( 'Test merge_request' )
expect ( json_response [ 'description' ] ) . to eq ( 'Test description for Test merge_request' )
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it " does not return 422 when source_branch equals target_branch " do
2018-03-17 18:26:18 +05:30
expect ( project . id ) . not_to eq ( forked_project . id )
expect ( forked_project . forked? ) . to be_truthy
expect ( forked_project . forked_from_project ) . to eq ( project )
post api ( " /projects/ #{ forked_project . id } /merge_requests " , user2 ) ,
2019-02-15 15:39:39 +05:30
params : { title : 'Test merge_request' , source_branch : " master " , target_branch : " master " , author : user2 , target_project_id : project . id }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2015-04-26 12:48:37 +05:30
expect ( json_response [ 'title' ] ) . to eq ( 'Test merge_request' )
2014-09-02 18:07:02 +05:30
end
2018-05-09 12:01:36 +05:30
it 'returns 403 when target project has disabled merge requests' do
2020-11-24 15:15:51 +05:30
project . project_feature . update! ( merge_requests_access_level : 0 )
2017-08-17 22:00:37 +05:30
2018-03-17 18:26:18 +05:30
post api ( " /projects/ #{ forked_project . id } /merge_requests " , user2 ) ,
2019-02-15 15:39:39 +05:30
params : {
title : 'Test' ,
target_branch : 'master' ,
source_branch : 'markdown' ,
author : user2 ,
target_project_id : project . id
}
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2017-08-17 22:00:37 +05:30
end
2016-09-13 17:45:13 +05:30
it " returns 400 when source_branch is missing " do
2018-03-17 18:26:18 +05:30
post api ( " /projects/ #{ forked_project . id } /merge_requests " , user2 ) ,
2019-02-15 15:39:39 +05:30
params : { title : 'Test merge_request' , target_branch : " master " , author : user2 , target_project_id : project . id }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it " returns 400 when target_branch is missing " do
2018-03-17 18:26:18 +05:30
post api ( " /projects/ #{ forked_project . id } /merge_requests " , user2 ) ,
2020-04-22 19:07:51 +05:30
params : { title : 'Test merge_request' , source_branch : " master " , author : user2 , target_project_id : project . id }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it " returns 400 when title is missing " do
2018-03-17 18:26:18 +05:30
post api ( " /projects/ #{ forked_project . id } /merge_requests " , user2 ) ,
2019-02-15 15:39:39 +05:30
params : { target_branch : 'master' , source_branch : 'markdown' , author : user2 , target_project_id : project . id }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2014-09-02 18:07:02 +05:30
end
2019-12-26 22:10:19 +05:30
it 'allows setting `allow_collaboration`' , :sidekiq_might_not_need_inline do
2018-03-27 19:54:05 +05:30
post api ( " /projects/ #{ forked_project . id } /merge_requests " , user2 ) ,
2019-02-15 15:39:39 +05:30
params : { title : 'Test merge_request' , source_branch : " feature_conflict " , target_branch : " master " , author : user2 , target_project_id : project . id , allow_collaboration : true }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2018-11-08 19:23:39 +05:30
expect ( json_response [ 'allow_collaboration' ] ) . to be_truthy
2018-03-27 19:54:05 +05:30
expect ( json_response [ 'allow_maintainer_to_push' ] ) . to be_truthy
end
2018-03-17 18:26:18 +05:30
context 'when target_branch and target_project_id is specified' do
let ( :params ) do
{ title : 'Test merge_request' ,
target_branch : 'master' ,
source_branch : 'markdown' ,
author : user2 ,
target_project_id : unrelated_project . id }
2015-04-26 12:48:37 +05:30
end
2016-09-13 17:45:13 +05:30
it 'returns 422 if targeting a different fork' do
2018-03-17 18:26:18 +05:30
unrelated_project . add_developer ( user2 )
2019-02-15 15:39:39 +05:30
post api ( " /projects/ #{ forked_project . id } /merge_requests " , user2 ) , params : params
2018-03-17 18:26:18 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :unprocessable_entity )
2018-03-17 18:26:18 +05:30
end
it 'returns 403 if targeting a different fork which user can not access' do
2019-02-15 15:39:39 +05:30
post api ( " /projects/ #{ forked_project . id } /merge_requests " , user2 ) , params : params
2018-03-17 18:26:18 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2015-04-26 12:48:37 +05:30
end
2014-09-02 18:07:02 +05:30
end
2019-12-26 22:10:19 +05:30
it " returns 201 when target_branch is specified and for the same project " , :sidekiq_might_not_need_inline do
2018-03-17 18:26:18 +05:30
post api ( " /projects/ #{ forked_project . id } /merge_requests " , user2 ) ,
2019-02-15 15:39:39 +05:30
params : { title : 'Test merge_request' , target_branch : 'master' , source_branch : 'markdown' , author : user2 , target_project_id : forked_project . id }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2014-09-02 18:07:02 +05:30
end
end
2021-02-22 17:27:13 +05:30
describe 'SSE counter' do
let ( :headers ) { { } }
let ( :params ) do
{
title : 'Test merge_request' ,
source_branch : 'feature_conflict' ,
target_branch : 'master' ,
author_id : user . id ,
milestone_id : milestone . id ,
squash : true
}
end
subject { post api ( " /projects/ #{ project . id } /merge_requests " , user ) , params : params , headers : headers }
it 'does not increase the SSE counter by default' do
expect ( Gitlab :: UsageDataCounters :: EditorUniqueCounter ) . not_to receive ( :track_sse_edit_action )
subject
expect ( response ) . to have_gitlab_http_status ( :created )
end
context 'when referer is not the SSE' do
let ( :headers ) { { 'HTTP_REFERER' = > 'https://gitlab.com' } }
it 'does not increase the SSE counter by default' do
expect ( Gitlab :: UsageDataCounters :: EditorUniqueCounter ) . not_to receive ( :track_sse_edit_action )
subject
expect ( response ) . to have_gitlab_http_status ( :created )
end
end
context 'when referer is the SSE' do
let ( :headers ) { { 'HTTP_REFERER' = > project_show_sse_url ( project , 'master/README.md' ) } }
it 'increases the SSE counter by default' do
expect ( Gitlab :: UsageDataCounters :: EditorUniqueCounter ) . to receive ( :track_sse_edit_action ) . with ( author : user )
subject
expect ( response ) . to have_gitlab_http_status ( :created )
end
end
end
2014-09-02 18:07:02 +05:30
end
2021-06-08 01:23:25 +05:30
describe 'PUT /projects/:id/merge_requests/:merge_request_iid' do
2020-06-23 00:09:42 +05:30
it_behaves_like 'issuable update endpoint' do
let ( :entity ) { merge_request }
end
2021-03-11 19:13:27 +05:30
2021-04-29 21:17:54 +05:30
context 'when only assignee_ids are provided' do
let ( :params ) do
{
assignee_ids : [ user2 . id ]
}
end
it 'sets the assignees' do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : params
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'assignees' ] ) . to contain_exactly (
a_hash_including ( 'name' = > user2 . name )
)
end
2021-09-04 01:27:46 +05:30
it 'creates appropriate system notes' , :sidekiq_inline do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : params
expect ( merge_request . notes . system . last . note ) . to include ( " assigned to #{ user2 . to_reference } " )
end
2021-04-29 21:17:54 +05:30
end
2021-06-08 01:23:25 +05:30
context 'when assignee_id=user2.id' do
let ( :params ) do
{
assignee_id : user2 . id
}
end
it 'sets the assignees' do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : params
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'assignees' ] ) . to contain_exactly (
a_hash_including ( 'name' = > user2 . name )
)
end
end
2021-09-04 01:27:46 +05:30
context 'when assignee_id=0' do
let ( :params ) do
{
assignee_id : 0
}
end
it 'clears the assignees' do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : params
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'assignees' ] ) . to be_empty
end
it 'creates appropriate system notes' , :sidekiq_inline do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : params
expect ( merge_request . notes . system . last . note ) . to include ( " unassigned #{ user . to_reference } " )
end
end
2021-06-08 01:23:25 +05:30
context 'when only assignee_ids are provided, and the list is empty' do
let ( :params ) do
{
assignee_ids : [ ]
}
end
it 'clears the assignees' do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : params
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'assignees' ] ) . to be_empty
end
end
context 'when only assignee_ids are provided, and the list contains the sentinel value' do
let ( :params ) do
{
assignee_ids : [ 0 ]
}
end
it 'clears the assignees' do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : params
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'assignees' ] ) . to be_empty
end
end
context 'when only assignee_id=0' do
let ( :params ) do
{
assignee_id : 0
}
end
it 'clears the assignees' do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : params
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'assignees' ] ) . to be_empty
end
end
2021-03-11 19:13:27 +05:30
context 'accepts reviewer_ids' do
let ( :params ) do
{
title : 'Updated merge request' ,
reviewer_ids : [ user2 . id ]
}
end
it 'adds a reviewer to the existing merge request' do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : params
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'title' ] ) . to eq ( 'Updated merge request' )
expect ( json_response [ 'reviewers' ] . first [ 'name' ] ) . to eq ( user2 . name )
end
it 'removes a reviewer from the existing merge request' do
merge_request . reviewers = [ user2 ]
params [ :reviewer_ids ] = [ ]
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : params
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'title' ] ) . to eq ( 'Updated merge request' )
expect ( json_response [ 'reviewers' ] ) . to be_empty
end
end
2020-06-23 00:09:42 +05:30
end
2020-03-13 15:44:24 +05:30
describe " POST /projects/:id/merge_requests/:merge_request_iid/context_commits " do
let ( :merge_request_iid ) { merge_request . iid }
let ( :authenticated_user ) { user }
let ( :commit ) { project . repository . commit }
let ( :params ) do
{
commits : [ commit . id ]
}
end
let ( :params_empty_commits ) do
{
commits : [ ]
}
end
let ( :params_invalid_shas ) do
{
commits : [ 'invalid' ]
}
end
describe 'when authenticated' do
it 'creates and returns the new context commit' do
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request_iid } /context_commits " , authenticated_user ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2020-03-13 15:44:24 +05:30
expect ( json_response ) . to be_an Array
expect ( json_response . first [ 'short_id' ] ) . to eq ( commit . short_id )
expect ( json_response . first [ 'title' ] ) . to eq ( commit . title )
expect ( json_response . first [ 'message' ] ) . to eq ( commit . message )
expect ( json_response . first [ 'author_name' ] ) . to eq ( commit . author_name )
expect ( json_response . first [ 'author_email' ] ) . to eq ( commit . author_email )
expect ( json_response . first [ 'committer_name' ] ) . to eq ( commit . committer_name )
expect ( json_response . first [ 'committer_email' ] ) . to eq ( commit . committer_email )
end
context 'doesnt create when its already created' do
before do
create ( :merge_request_context_commit , merge_request : merge_request , sha : commit . id )
end
2020-11-24 15:15:51 +05:30
2020-03-13 15:44:24 +05:30
it 'returns 400 when the context commit is already created' do
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request_iid } /context_commits " , authenticated_user ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2020-03-13 15:44:24 +05:30
expect ( json_response [ 'message' ] ) . to eq ( " Context commits: [ \" #{ commit . id } \" ] are already created " )
end
end
it 'returns 400 when one or more shas are invalid' do
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request_iid } /context_commits " , authenticated_user ) , params : params_invalid_shas
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2020-03-13 15:44:24 +05:30
expect ( json_response [ 'message' ] ) . to eq ( 'One or more context commits\' sha is not valid.' )
end
it 'returns 400 when the commits are empty' do
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request_iid } /context_commits " , authenticated_user ) , params : params_empty_commits
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2020-03-13 15:44:24 +05:30
end
it 'returns 400 when params is empty' do
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request_iid } /context_commits " , authenticated_user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2020-03-13 15:44:24 +05:30
end
it 'returns 403 when creating new context commit for guest role' do
guest = create ( :user )
project . add_guest ( guest )
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request_iid } /context_commits " , guest ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2020-03-13 15:44:24 +05:30
end
it 'returns 403 when creating new context commit for reporter role' do
reporter = create ( :user )
project . add_reporter ( reporter )
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request_iid } /context_commits " , reporter ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2020-03-13 15:44:24 +05:30
end
end
context 'when unauthenticated' do
it 'returns 401 if user tries to create context commits' do
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request_iid } /context_commits " ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
2020-03-13 15:44:24 +05:30
end
end
end
2017-08-17 22:00:37 +05:30
describe " DELETE /projects/:id/merge_requests/:merge_request_iid " do
2016-06-02 11:05:42 +05:30
context " when the user is developer " do
let ( :developer ) { create ( :user ) }
before do
2018-03-17 18:26:18 +05:30
project . add_developer ( developer )
2016-06-02 11:05:42 +05:30
end
it " denies the deletion of the merge request " do
2017-08-17 22:00:37 +05:30
delete api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , developer )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2016-06-02 11:05:42 +05:30
end
end
context " when the user is project owner " do
it " destroys the merge request owners can destroy " do
2017-08-17 22:00:37 +05:30
delete api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :no_content )
2017-08-17 22:00:37 +05:30
end
it " returns 404 for an invalid merge request IID " do
2020-04-22 19:07:51 +05:30
delete api ( " /projects/ #{ project . id } /merge_requests/ #{ non_existing_record_iid } " , user )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2017-08-17 22:00:37 +05:30
end
it " returns 404 if the merge request id is used instead of iid " do
2016-06-02 11:05:42 +05:30
delete api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . id } " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2018-03-17 18:26:18 +05:30
end
it_behaves_like '412 response' do
let ( :request ) { api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) }
2016-06-02 11:05:42 +05:30
end
end
end
2020-03-13 15:44:24 +05:30
describe " DELETE /projects/:id/merge_requests/:merge_request_iid/context_commits " do
let ( :merge_request_iid ) { merge_request . iid }
let ( :authenticated_user ) { user }
let ( :commit ) { project . repository . commit }
context " when authenticated " do
let ( :params ) do
{
commits : [ commit . id ]
}
end
let ( :params_invalid_shas ) do
{
commits : [ " invalid " ]
}
end
let ( :params_empty_commits ) do
{
commits : [ ]
}
end
it " deletes context commit " do
delete api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /context_commits " , authenticated_user ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :no_content )
2020-03-13 15:44:24 +05:30
end
it " returns 400 when invalid commit sha is passed " do
delete api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /context_commits " , authenticated_user ) , params : params_invalid_shas
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2020-03-13 15:44:24 +05:30
expect ( json_response [ " message " ] ) . to eq ( 'One or more context commits\' sha is not valid.' )
end
it " returns 400 when commits is empty " do
delete api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /context_commits " , authenticated_user ) , params : params_empty_commits
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2020-03-13 15:44:24 +05:30
end
it " returns 400 when no params is passed " do
delete api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /context_commits " , authenticated_user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2020-03-13 15:44:24 +05:30
end
it 'returns 403 when deleting existing context commit for guest role' do
guest = create ( :user )
project . add_guest ( guest )
delete api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request_iid } /context_commits " , guest ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2020-03-13 15:44:24 +05:30
end
it 'returns 403 when deleting existing context commit for reporter role' do
reporter = create ( :user )
project . add_reporter ( reporter )
delete api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request_iid } /context_commits " , reporter ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2020-03-13 15:44:24 +05:30
end
end
context " when unauthenticated " do
it " returns 401, unauthorised error " do
delete api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /context_commits " )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
2020-03-13 15:44:24 +05:30
end
end
end
describe " PUT /projects/:id/merge_requests/:merge_request_iid/merge " , :clean_gitlab_redis_cache do
2020-11-24 15:15:51 +05:30
let ( :project ) { create ( :project , :repository , namespace : user . namespace ) }
let ( :merge_request ) { create ( :merge_request , :simple , author : user , source_project : project , source_branch : 'markdown' , title : 'Test' ) }
let ( :pipeline ) { create ( :ci_pipeline , project : project ) }
2015-12-23 02:04:40 +05:30
2016-09-13 17:45:13 +05:30
it " returns merge_request in case of success " do
2017-08-17 22:00:37 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user )
2015-09-11 14:41:01 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it " returns 406 if branch can't be merged " do
2017-09-10 17:25:29 +05:30
allow_any_instance_of ( MergeRequest )
. to receive ( :can_be_merged? ) . and_return ( false )
2015-09-11 14:41:01 +05:30
2017-08-17 22:00:37 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user )
2015-09-11 14:41:01 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_acceptable )
2015-04-26 12:48:37 +05:30
expect ( json_response [ 'message' ] ) . to eq ( 'Branch cannot be merged' )
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it " returns 405 if merge_request is not open " do
2014-09-02 18:07:02 +05:30
merge_request . close
2017-08-17 22:00:37 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :method_not_allowed )
2015-04-26 12:48:37 +05:30
expect ( json_response [ 'message' ] ) . to eq ( '405 Method Not Allowed' )
2014-09-02 18:07:02 +05:30
end
2021-09-04 01:27:46 +05:30
it " returns 405 if merge_request is a draft " do
merge_request . update_attribute ( :title , " Draft: #{ merge_request . title } " )
2017-08-17 22:00:37 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :method_not_allowed )
2015-09-11 14:41:01 +05:30
expect ( json_response [ 'message' ] ) . to eq ( '405 Method Not Allowed' )
end
2016-06-16 23:09:34 +05:30
it 'returns 405 if the build failed for a merge request that requires success' do
2019-07-07 11:18:12 +05:30
project . update! ( only_allow_merge_if_pipeline_succeeds : true )
create ( :ci_pipeline ,
:failed ,
sha : merge_request . diff_head_sha ,
merge_requests_as_head_pipeline : [ merge_request ] )
2016-06-16 23:09:34 +05:30
2017-08-17 22:00:37 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user )
2016-06-16 23:09:34 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :method_not_allowed )
2016-06-16 23:09:34 +05:30
expect ( json_response [ 'message' ] ) . to eq ( '405 Method Not Allowed' )
end
2016-09-13 17:45:13 +05:30
it " returns 401 if user has no permissions to merge " do
2014-09-02 18:07:02 +05:30
user2 = create ( :user )
2018-03-17 18:26:18 +05:30
project . add_reporter ( user2 )
2017-08-17 22:00:37 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user2 )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
2015-04-26 12:48:37 +05:30
expect ( json_response [ 'message' ] ) . to eq ( '401 Unauthorized' )
2014-09-02 18:07:02 +05:30
end
2015-12-23 02:04:40 +05:30
2016-06-16 23:09:34 +05:30
it " returns 409 if the SHA parameter doesn't match " do
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user ) , params : { sha : merge_request . diff_head_sha . reverse }
2016-06-16 23:09:34 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :conflict )
2016-06-16 23:09:34 +05:30
expect ( json_response [ 'message' ] ) . to start_with ( 'SHA does not match HEAD of source branch' )
end
it " succeeds if the SHA parameter matches " do
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user ) , params : { sha : merge_request . diff_head_sha }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
end
2018-11-08 19:23:39 +05:30
it " updates the MR's squash attribute " do
expect do
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user ) , params : { squash : true }
2020-07-28 23:09:34 +05:30
end . to change { merge_request . reload . squash_on_merge? }
2018-11-08 19:23:39 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-11-08 19:23:39 +05:30
end
2020-01-01 13:55:28 +05:30
it 'does not merge if merge_when_pipeline_succeeds is passed and the pipeline has failed' do
create ( :ci_pipeline ,
:failed ,
sha : merge_request . diff_head_sha ,
merge_requests_as_head_pipeline : [ merge_request ] )
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user ) , params : { merge_when_pipeline_succeeds : true }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :method_not_allowed )
2020-01-01 13:55:28 +05:30
expect ( merge_request . reload . state ) . to eq ( 'opened' )
end
2020-03-13 15:44:24 +05:30
it 'merges if the head pipeline already succeeded and `merge_when_pipeline_succeeds` is passed' do
create ( :ci_pipeline , :success , sha : merge_request . diff_head_sha , merge_requests_as_head_pipeline : [ merge_request ] )
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user ) , params : { merge_when_pipeline_succeeds : true }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2020-03-13 15:44:24 +05:30
expect ( json_response [ 'state' ] ) . to eq ( 'merged' )
end
2017-08-17 22:00:37 +05:30
it " enables merge when pipeline succeeds if the pipeline is active " do
2019-09-04 21:01:54 +05:30
allow_any_instance_of ( MergeRequest ) . to receive_messages ( head_pipeline : pipeline , actual_head_pipeline : pipeline )
2017-08-17 22:00:37 +05:30
allow ( pipeline ) . to receive ( :active? ) . and_return ( true )
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user ) , params : { merge_when_pipeline_succeeds : true }
2016-06-16 23:09:34 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'title' ] ) . to eq ( 'Test' )
expect ( json_response [ 'merge_when_pipeline_succeeds' ] ) . to eq ( true )
2016-06-16 23:09:34 +05:30
end
2017-08-17 22:00:37 +05:30
it " enables merge when pipeline succeeds if the pipeline is active and only_allow_merge_if_pipeline_succeeds is true " do
2019-09-04 21:01:54 +05:30
allow_any_instance_of ( MergeRequest ) . to receive_messages ( head_pipeline : pipeline , actual_head_pipeline : pipeline )
2016-06-16 23:09:34 +05:30
allow ( pipeline ) . to receive ( :active? ) . and_return ( true )
2017-08-17 22:00:37 +05:30
project . update_attribute ( :only_allow_merge_if_pipeline_succeeds , true )
2015-12-23 02:04:40 +05:30
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user ) , params : { merge_when_pipeline_succeeds : true }
2015-12-23 02:04:40 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2015-12-23 02:04:40 +05:30
expect ( json_response [ 'title' ] ) . to eq ( 'Test' )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'merge_when_pipeline_succeeds' ] ) . to eq ( true )
end
it " returns 404 for an invalid merge request IID " do
2020-04-22 19:07:51 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ non_existing_record_iid } /merge " , user )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2017-08-17 22:00:37 +05:30
end
it " returns 404 if the merge request id is used instead of iid " do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . id } /merge " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2015-12-23 02:04:40 +05:30
end
2019-03-02 22:35:43 +05:30
describe " the squash_commit_message param " do
let ( :squash_commit ) do
project . repository . commits_between ( json_response [ 'diff_refs' ] [ 'start_sha' ] , json_response [ 'merge_commit_sha' ] ) . first
end
it " results in a specific squash commit message when set " do
squash_commit_message = 'My custom squash commit message'
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user ) , params : {
squash : true ,
squash_commit_message : squash_commit_message
}
expect ( squash_commit . message . chomp ) . to eq ( squash_commit_message )
end
it " results in a default squash commit message when not set " do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user ) , params : { squash : true }
2021-04-29 21:17:54 +05:30
expect ( squash_commit . message . chomp ) . to eq ( merge_request . default_squash_commit_message . chomp )
2019-03-02 22:35:43 +05:30
end
end
2019-07-07 11:18:12 +05:30
2021-04-17 20:07:23 +05:30
describe " the should_remove_source_branch param " , :sidekiq_inline do
2019-07-07 11:18:12 +05:30
let ( :source_repository ) { merge_request . source_project . repository }
let ( :source_branch ) { merge_request . source_branch }
it 'removes the source branch when set' do
put (
api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user ) ,
params : { should_remove_source_branch : true }
)
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2021-09-30 23:02:18 +05:30
expect ( source_repository . branch_exists? ( source_branch ) ) . to be false
2019-07-07 11:18:12 +05:30
end
end
2019-12-26 22:10:19 +05:30
2021-04-17 20:07:23 +05:30
context " with a merge request that has force_remove_source_branch enabled " , :sidekiq_inline do
2020-06-23 00:09:42 +05:30
let ( :source_repository ) { merge_request . source_project . repository }
let ( :source_branch ) { merge_request . source_branch }
before do
2020-11-24 15:15:51 +05:30
merge_request . update! ( merge_params : { 'force_remove_source_branch' = > true } )
2020-06-23 00:09:42 +05:30
end
it 'removes the source branch' do
put (
api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user )
)
expect ( response ) . to have_gitlab_http_status ( :ok )
2021-09-30 23:02:18 +05:30
expect ( source_repository . branch_exists? ( source_branch ) ) . to be false
2020-06-23 00:09:42 +05:30
end
it 'does not remove the source branch' do
put (
api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user ) ,
params : { should_remove_source_branch : false }
)
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( source_repository . branch_exists? ( source_branch ) ) . to be_truthy
end
end
2019-12-26 22:10:19 +05:30
context " performing a ff-merge with squash " do
let ( :merge_request ) { create ( :merge_request , :rebased , source_project : project , squash : true ) }
before do
2020-11-24 15:15:51 +05:30
project . update! ( merge_requests_ff_only_enabled : true )
2019-12-26 22:10:19 +05:30
end
it " records the squash commit SHA and returns it in the response " do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /merge " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-12-26 22:10:19 +05:30
expect ( json_response [ 'squash_commit_sha' ] . length ) . to eq ( 40 )
end
end
2019-07-07 11:18:12 +05:30
end
2019-09-30 21:07:59 +05:30
describe " GET /projects/:id/merge_requests/:merge_request_iid/merge_ref " , :clean_gitlab_redis_shared_state do
before do
merge_request . mark_as_unchecked!
end
let ( :merge_request_iid ) { merge_request . iid }
2019-07-07 11:18:12 +05:30
let ( :url ) do
2019-09-30 21:07:59 +05:30
" /projects/ #{ project . id } /merge_requests/ #{ merge_request_iid } /merge_ref "
2019-07-07 11:18:12 +05:30
end
it 'returns the generated ID from the merge service in case of success' do
2019-09-30 21:07:59 +05:30
get api ( url , user )
2019-07-07 11:18:12 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-09-30 21:07:59 +05:30
expect ( json_response [ 'commit_id' ] ) . to eq ( merge_request . merge_ref_head . sha )
2019-07-07 11:18:12 +05:30
end
2019-09-30 21:07:59 +05:30
context 'when merge-ref is not synced with merge status' do
2020-11-24 15:15:51 +05:30
let ( :merge_request ) { create ( :merge_request , :simple , author : user , source_project : project , source_branch : 'markdown' , merge_status : 'cannot_be_merged' ) }
2019-07-07 11:18:12 +05:30
2019-09-30 21:07:59 +05:30
it 'returns 200 if MR can be merged' do
get api ( url , user )
2019-07-07 11:18:12 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-09-30 21:07:59 +05:30
expect ( json_response [ 'commit_id' ] ) . to eq ( merge_request . merge_ref_head . sha )
end
it 'returns 400 if MR cannot be merged' do
expect_next_instance_of ( MergeRequests :: MergeToRefService ) do | merge_request |
expect ( merge_request ) . to receive ( :execute ) { { status : :failed } }
end
get api ( url , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2019-09-30 21:07:59 +05:30
expect ( json_response [ 'message' ] ) . to eq ( 'Merge request is not mergeable' )
end
2019-07-07 11:18:12 +05:30
end
2019-09-30 21:07:59 +05:30
context 'when user has no access to the MR' do
let ( :project ) { create ( :project , :private ) }
let ( :merge_request ) { create ( :merge_request , source_project : project , target_project : project ) }
2019-07-07 11:18:12 +05:30
2019-09-30 21:07:59 +05:30
it 'returns 404' do
project . add_guest ( user )
2019-07-07 11:18:12 +05:30
2019-09-30 21:07:59 +05:30
get api ( url , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2019-09-30 21:07:59 +05:30
expect ( json_response [ 'message' ] ) . to eq ( '404 Not found' )
end
2019-07-07 11:18:12 +05:30
end
2019-09-30 21:07:59 +05:30
context 'when invalid merge request IID' do
2020-04-22 19:07:51 +05:30
let ( :merge_request_iid ) { non_existing_record_iid }
2019-07-07 11:18:12 +05:30
2019-09-30 21:07:59 +05:30
it 'returns 404' do
get api ( url , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2019-09-30 21:07:59 +05:30
end
2019-07-07 11:18:12 +05:30
end
2019-09-30 21:07:59 +05:30
context 'when merge request ID is used instead IID' do
let ( :merge_request_iid ) { merge_request . id }
2019-07-07 11:18:12 +05:30
2019-09-30 21:07:59 +05:30
it 'returns 404' do
get api ( url , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2019-09-30 21:07:59 +05:30
end
2019-07-07 11:18:12 +05:30
end
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
describe " PUT /projects/:id/merge_requests/:merge_request_iid " do
2019-07-07 11:18:12 +05:30
context 'updates force_remove_source_branch properly' do
it 'sets to false' do
2020-11-24 15:15:51 +05:30
merge_request . update! ( merge_params : { 'force_remove_source_branch' = > true } )
2019-07-07 11:18:12 +05:30
expect ( merge_request . force_remove_source_branch? ) . to be_truthy
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : { state_event : " close " , remove_source_branch : false }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'state' ] ) . to eq ( 'closed' )
expect ( json_response [ 'force_remove_source_branch' ] ) . to be_falsey
end
it 'sets to true' do
2020-11-24 15:15:51 +05:30
merge_request . update! ( merge_params : { 'force_remove_source_branch' = > false } )
2019-07-07 11:18:12 +05:30
2021-09-30 23:02:18 +05:30
expect ( merge_request . force_remove_source_branch? ) . to be false
2019-07-07 11:18:12 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : { state_event : " close " , remove_source_branch : true }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'state' ] ) . to eq ( 'closed' )
expect ( json_response [ 'force_remove_source_branch' ] ) . to be_truthy
end
2019-10-31 01:37:42 +05:30
context 'with a merge request across forks' do
2020-11-24 15:15:51 +05:30
let ( :project ) { create ( :project , :public , :repository , creator : user , namespace : user . namespace , only_allow_merge_if_pipeline_succeeds : false ) }
2019-10-31 01:37:42 +05:30
let ( :fork_owner ) { create ( :user ) }
let ( :source_project ) { fork_project ( project , fork_owner ) }
let ( :target_project ) { project }
let ( :merge_request ) do
create ( :merge_request ,
source_project : source_project ,
target_project : target_project ,
source_branch : 'fixes' ,
merge_params : { 'force_remove_source_branch' = > false } )
end
it 'is true for an authorized user' do
put api ( " /projects/ #{ target_project . id } /merge_requests/ #{ merge_request . iid } " , fork_owner ) , params : { state_event : 'close' , remove_source_branch : true }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-10-31 01:37:42 +05:30
expect ( json_response [ 'state' ] ) . to eq ( 'closed' )
expect ( json_response [ 'force_remove_source_branch' ] ) . to be true
end
it 'is false for an unauthorized user' do
expect do
put api ( " /projects/ #{ target_project . id } /merge_requests/ #{ merge_request . iid } " , target_project . owner ) , params : { state_event : 'close' , remove_source_branch : true }
end . not_to change { merge_request . reload . merge_params }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-10-31 01:37:42 +05:30
expect ( json_response [ 'state' ] ) . to eq ( 'closed' )
expect ( json_response [ 'force_remove_source_branch' ] ) . to be false
end
end
2019-07-07 11:18:12 +05:30
end
2017-01-15 13:20:01 +05:30
context " to close a MR " do
it " returns merge_request " do
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : { state_event : " close " }
2017-01-15 13:20:01 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-01-15 13:20:01 +05:30
expect ( json_response [ 'state' ] ) . to eq ( 'closed' )
end
end
2016-04-02 18:10:28 +05:30
it " updates title and returns merge_request " do
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : { title : " New title " }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2015-04-26 12:48:37 +05:30
expect ( json_response [ 'title' ] ) . to eq ( 'New title' )
2014-09-02 18:07:02 +05:30
end
2016-04-02 18:10:28 +05:30
it " updates description and returns merge_request " do
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : { description : " New description " }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2015-04-26 12:48:37 +05:30
expect ( json_response [ 'description' ] ) . to eq ( 'New description' )
2014-09-02 18:07:02 +05:30
end
2016-04-02 18:10:28 +05:30
it " updates milestone_id and returns merge_request " do
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : { milestone_id : milestone . id }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2016-04-02 18:10:28 +05:30
expect ( json_response [ 'milestone' ] [ 'id' ] ) . to eq ( milestone . id )
end
2018-11-08 19:23:39 +05:30
it " updates squash and returns merge_request " do
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : { squash : true }
2018-11-08 19:23:39 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-11-08 19:23:39 +05:30
expect ( json_response [ 'squash' ] ) . to be_truthy
end
2020-11-24 15:15:51 +05:30
it " updates target_branch and returns merge_request " do
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : { target_branch : " wiki " }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2015-04-26 12:48:37 +05:30
expect ( json_response [ 'target_branch' ] ) . to eq ( 'wiki' )
2014-09-02 18:07:02 +05:30
end
2020-11-24 15:15:51 +05:30
context " forked projects " do
let_it_be ( :user2 ) { create ( :user ) }
2021-09-30 23:02:18 +05:30
2020-11-24 15:15:51 +05:30
let ( :project ) { create ( :project , :public , :repository ) }
let! ( :forked_project ) { fork_project ( project , user2 , repository : true ) }
let ( :merge_request ) do
create ( :merge_request ,
source_project : forked_project ,
target_project : project ,
source_branch : " fixes " )
end
shared_examples " update of allow_collaboration and allow_maintainer_to_push " do | request_value , expected_value |
%w[ allow_collaboration allow_maintainer_to_push ] . each do | attr |
it " attempts to update #{ attr } to #{ request_value } and returns #{ expected_value } for `allow_collaboration` " do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user2 ) , params : { attr = > request_value }
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ " allow_collaboration " ] ) . to eq ( expected_value )
expect ( json_response [ " allow_maintainer_to_push " ] ) . to eq ( expected_value )
end
end
end
context " when source project is public (i.e. MergeRequest # collaborative_push_possible? == true) " do
it_behaves_like " update of allow_collaboration and allow_maintainer_to_push " , true , true
end
context " when source project is private (i.e. MergeRequest # collaborative_push_possible? == false) " do
let ( :project ) { create ( :project , :private , :repository ) }
it_behaves_like " update of allow_collaboration and allow_maintainer_to_push " , true , false
end
end
2017-08-17 22:00:37 +05:30
it " returns merge_request that removes the source branch " do
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : { remove_source_branch : true }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'force_remove_source_branch' ] ) . to be_truthy
end
2019-07-31 22:56:46 +05:30
it 'filters assignee_id of unauthorized user' do
private_project = create ( :project , :private , :repository )
mr = create ( :merge_request , source_project : private_project , target_project : private_project )
another_user = create ( :user )
private_project . add_maintainer ( user )
params = { assignee_id : another_user . id }
put api ( " /projects/ #{ private_project . id } /merge_requests/ #{ mr . iid } " , user ) , params : params
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-07-31 22:56:46 +05:30
expect ( json_response [ 'assignee' ] ) . to be_nil
end
2019-07-07 11:18:12 +05:30
context 'when updating labels' do
it 'allows special label names' do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) ,
params : {
title : 'new issue' ,
labels : 'label, label?, label&foo, ?, &'
}
2020-04-22 19:07:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'labels' ] ) . to include 'label'
expect ( json_response [ 'labels' ] ) . to include 'label?'
expect ( json_response [ 'labels' ] ) . to include 'label&foo'
expect ( json_response [ 'labels' ] ) . to include '?'
expect ( json_response [ 'labels' ] ) . to include '&'
end
2019-05-18 00:54:41 +05:30
2019-07-07 11:18:12 +05:30
it 'also accepts labels as an array' do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) ,
params : {
title : 'new issue' ,
labels : [ 'label' , 'label?' , 'label&foo, ?, &' , '1, 2' , 3 , 4 ]
}
2020-04-22 19:07:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'labels' ] ) . to include 'label'
expect ( json_response [ 'labels' ] ) . to include 'label?'
expect ( json_response [ 'labels' ] ) . to include 'label&foo'
expect ( json_response [ 'labels' ] ) . to include '?'
expect ( json_response [ 'labels' ] ) . to include '&'
expect ( json_response [ 'labels' ] ) . to include '1'
expect ( json_response [ 'labels' ] ) . to include '2'
expect ( json_response [ 'labels' ] ) . to include '3'
expect ( json_response [ 'labels' ] ) . to include '4'
end
it 'empty label param removes labels' do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) ,
params : {
title : 'new issue' ,
labels : ''
}
2020-04-22 19:07:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'labels' ] ) . to eq [ ]
end
it 'label param as empty array, but only explicitly as json, removes labels' do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) ,
params : {
title : 'new issue' ,
labels : [ ]
} . to_json ,
headers : { 'Content-Type' = > 'application/json' }
2020-04-22 19:07:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'labels' ] ) . to eq [ ]
end
2020-03-13 15:44:24 +05:30
it 'empty label as array, removes labels' do
2019-07-07 11:18:12 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) ,
params : {
title : 'new issue' ,
labels : [ ]
}
2020-04-22 19:07:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'labels' ] ) . to eq [ ]
end
it 'array with one empty string element removes labels' do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) ,
params : {
title : 'new issue' ,
labels : [ '' ]
}
2020-04-22 19:07:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'labels' ] ) . to eq [ ]
end
it 'array with multiple empty string elements, removes labels' do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) ,
params : {
title : 'new issue' ,
labels : [ '' , '' , '' ]
}
2020-04-22 19:07:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'labels' ] ) . to eq [ ]
end
2014-09-02 18:07:02 +05:30
end
2020-05-24 23:13:21 +05:30
context 'with labels' do
include_context 'with labels'
let ( :api_base ) { api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) }
it 'when adding labels, keeps existing labels and adds new' do
put api_base , params : { add_labels : '1, 2' }
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'labels' ] ) . to contain_exactly ( label . title , label2 . title , '1' , '2' )
end
it 'when removing labels, only removes those specified' do
put api_base , params : { remove_labels : " #{ label . title } " }
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'labels' ] ) . to eq ( [ label2 . title ] )
end
it 'when removing all labels, keeps no labels' do
put api_base , params : { remove_labels : " #{ label . title } , #{ label2 . title } " }
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'labels' ] ) . to be_empty
end
end
2017-08-17 22:00:37 +05:30
it 'does not update state when title is empty' do
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : { state_event : 'close' , title : nil }
2015-10-24 18:46:33 +05:30
2017-08-17 22:00:37 +05:30
merge_request . reload
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2017-08-17 22:00:37 +05:30
expect ( merge_request . state ) . to eq ( 'opened' )
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
it 'does not update state when target_branch is empty' do
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } " , user ) , params : { state_event : 'close' , target_branch : nil }
2017-08-17 22:00:37 +05:30
merge_request . reload
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2017-08-17 22:00:37 +05:30
expect ( merge_request . state ) . to eq ( 'opened' )
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
it " returns 404 for an invalid merge request IID " do
2020-04-22 19:07:51 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ non_existing_record_iid } " , user ) , params : { state_event : " close " }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
it " returns 404 if the merge request id is used instead of iid " do
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . id } " , user ) , params : { state_event : " close " }
2014-09-02 18:07:02 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2014-09-02 18:07:02 +05:30
end
end
2015-04-26 12:48:37 +05:30
2017-08-17 22:00:37 +05:30
describe 'GET :id/merge_requests/:merge_request_iid/closes_issues' do
2016-04-02 18:10:28 +05:30
it 'returns the issue that will be closed on merge' do
issue = create ( :issue , project : project )
mr = merge_request . tap do | mr |
mr . update_attribute ( :description , " Closes #{ issue . to_reference ( mr . project ) } " )
2018-11-18 11:00:15 +05:30
mr . cache_merge_request_closes_issues!
2016-04-02 18:10:28 +05:30
end
2017-08-17 22:00:37 +05:30
get api ( " /projects/ #{ project . id } /merge_requests/ #{ mr . iid } /closes_issues " , user )
2020-03-13 15:44:24 +05:30
expect_successful_response_with_paginated_array
2016-04-02 18:10:28 +05:30
expect ( json_response . length ) . to eq ( 1 )
expect ( json_response . first [ 'id' ] ) . to eq ( issue . id )
end
it 'returns an empty array when there are no issues to be closed' do
2017-08-17 22:00:37 +05:30
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /closes_issues " , user )
2020-03-13 15:44:24 +05:30
expect_empty_array_response
2016-04-02 18:10:28 +05:30
end
2016-06-16 23:09:34 +05:30
it 'handles external issues' do
2017-09-10 17:25:29 +05:30
jira_project = create ( :jira_project , :public , :repository , name : 'JIR_EXT1' )
ext_issue = ExternalIssue . new ( " #{ jira_project . name } -123 " , jira_project )
issue = create ( :issue , project : jira_project )
description = " Closes #{ ext_issue . to_reference ( jira_project ) } \n closes #{ issue . to_reference } "
merge_request = create ( :merge_request ,
2019-07-31 22:56:46 +05:30
:simple , author : user , assignees : [ user ] , source_project : jira_project , description : description )
2016-06-16 23:09:34 +05:30
2017-08-17 22:00:37 +05:30
get api ( " /projects/ #{ jira_project . id } /merge_requests/ #{ merge_request . iid } /closes_issues " , user )
2016-06-16 23:09:34 +05:30
2020-03-13 15:44:24 +05:30
expect_successful_response_with_paginated_array
2017-09-10 17:25:29 +05:30
expect ( json_response . length ) . to eq ( 2 )
expect ( json_response . second [ 'title' ] ) . to eq ( ext_issue . title )
expect ( json_response . second [ 'id' ] ) . to eq ( ext_issue . id )
expect ( json_response . second [ 'confidential' ] ) . to be_nil
2016-06-16 23:09:34 +05:30
expect ( json_response . first [ 'title' ] ) . to eq ( issue . title )
expect ( json_response . first [ 'id' ] ) . to eq ( issue . id )
2017-09-10 17:25:29 +05:30
expect ( json_response . first [ 'confidential' ] ) . not_to be_nil
2016-06-16 23:09:34 +05:30
end
2017-08-17 22:00:37 +05:30
it 'returns 403 if the user has no access to the merge request' do
2017-09-10 17:25:29 +05:30
project = create ( :project , :private )
2017-08-17 22:00:37 +05:30
merge_request = create ( :merge_request , :simple , source_project : project )
guest = create ( :user )
2018-03-17 18:26:18 +05:30
project . add_guest ( guest )
2017-08-17 22:00:37 +05:30
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /closes_issues " , guest )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2017-08-17 22:00:37 +05:30
end
it " returns 404 for an invalid merge request IID " do
2020-04-22 19:07:51 +05:30
get api ( " /projects/ #{ project . id } /merge_requests/ #{ non_existing_record_iid } /closes_issues " , user )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2017-08-17 22:00:37 +05:30
end
it " returns 404 if the merge request id is used instead of iid " do
get api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . id } /closes_issues " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2017-08-17 22:00:37 +05:30
end
2016-04-02 18:10:28 +05:30
end
2017-08-17 22:00:37 +05:30
describe 'POST :id/merge_requests/:merge_request_iid/subscribe' do
2016-06-02 11:05:42 +05:30
it 'subscribes to a merge request' do
2017-08-17 22:00:37 +05:30
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /subscribe " , admin )
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2016-06-02 11:05:42 +05:30
expect ( json_response [ 'subscribed' ] ) . to eq ( true )
end
it 'returns 304 if already subscribed' do
2017-08-17 22:00:37 +05:30
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /subscribe " , user )
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_modified )
2016-06-02 11:05:42 +05:30
end
it 'returns 404 if the merge request is not found' do
2017-08-17 22:00:37 +05:30
post api ( " /projects/ #{ project . id } /merge_requests/123/subscribe " , user )
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2016-06-02 11:05:42 +05:30
end
2017-08-17 22:00:37 +05:30
it 'returns 404 if the merge request id is used instead of iid' do
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . id } /subscribe " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2017-08-17 22:00:37 +05:30
end
it 'returns 403 if user has no access to read code' do
guest = create ( :user )
2018-03-17 18:26:18 +05:30
project . add_guest ( guest )
2017-08-17 22:00:37 +05:30
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /subscribe " , guest )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2017-08-17 22:00:37 +05:30
end
2016-06-02 11:05:42 +05:30
end
2017-08-17 22:00:37 +05:30
describe 'POST :id/merge_requests/:merge_request_iid/unsubscribe' do
2016-06-02 11:05:42 +05:30
it 'unsubscribes from a merge request' do
2017-08-17 22:00:37 +05:30
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /unsubscribe " , user )
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2016-06-02 11:05:42 +05:30
expect ( json_response [ 'subscribed' ] ) . to eq ( false )
end
it 'returns 304 if not subscribed' do
2017-08-17 22:00:37 +05:30
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /unsubscribe " , admin )
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_modified )
2016-06-02 11:05:42 +05:30
end
it 'returns 404 if the merge request is not found' do
2017-08-17 22:00:37 +05:30
post api ( " /projects/ #{ project . id } /merge_requests/123/unsubscribe " , user )
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2016-06-02 11:05:42 +05:30
end
2017-08-17 22:00:37 +05:30
it 'returns 404 if the merge request id is used instead of iid' do
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . id } /unsubscribe " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2017-08-17 22:00:37 +05:30
end
it 'returns 403 if user has no access to read code' do
guest = create ( :user )
2018-03-17 18:26:18 +05:30
project . add_guest ( guest )
2017-08-17 22:00:37 +05:30
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /unsubscribe " , guest )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2018-03-17 18:26:18 +05:30
end
end
describe 'POST :id/merge_requests/:merge_request_iid/cancel_merge_when_pipeline_succeeds' do
before do
2019-09-04 21:01:54 +05:30
:: AutoMergeService . new ( merge_request . target_project , user ) . execute ( merge_request , AutoMergeService :: STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS )
2018-03-17 18:26:18 +05:30
end
it 'removes the merge_when_pipeline_succeeds status' do
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /cancel_merge_when_pipeline_succeeds " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2018-03-17 18:26:18 +05:30
end
it 'returns 404 if the merge request is not found' do
2019-03-02 22:35:43 +05:30
post api ( " /projects/ #{ project . id } /merge_requests/123/cancel_merge_when_pipeline_succeeds " , user )
2018-03-17 18:26:18 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2018-03-17 18:26:18 +05:30
end
it 'returns 404 if the merge request id is used instead of iid' do
2019-03-02 22:35:43 +05:30
post api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . id } /cancel_merge_when_pipeline_succeeds " , user )
2018-03-17 18:26:18 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2017-08-17 22:00:37 +05:30
end
end
2019-02-15 15:39:39 +05:30
describe 'PUT :id/merge_requests/:merge_request_iid/rebase' do
2020-03-13 15:44:24 +05:30
context 'when rebase can be performed' do
it 'enqueues a rebase of the merge request against the target branch' do
Sidekiq :: Testing . fake! do
expect do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /rebase " , user )
end . to change { RebaseWorker . jobs . size } . by ( 1 )
end
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :accepted )
2020-03-13 15:44:24 +05:30
expect ( merge_request . reload ) . to be_rebase_in_progress
expect ( json_response [ 'rebase_in_progress' ] ) . to be ( true )
2019-02-15 15:39:39 +05:30
end
2020-03-13 15:44:24 +05:30
context 'when skip_ci parameter is set' do
it 'enqueues a rebase of the merge request with skip_ci flag set' do
2021-12-11 22:18:48 +05:30
allow ( RebaseWorker ) . to receive ( :with_status ) . and_return ( RebaseWorker )
2020-03-13 15:44:24 +05:30
expect ( RebaseWorker ) . to receive ( :perform_async ) . with ( merge_request . id , user . id , true ) . and_call_original
2019-09-30 21:07:59 +05:30
2020-03-13 15:44:24 +05:30
Sidekiq :: Testing . fake! do
expect do
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /rebase " , user ) , params : { skip_ci : true }
end . to change { RebaseWorker . jobs . size } . by ( 1 )
end
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :accepted )
2020-03-13 15:44:24 +05:30
expect ( merge_request . reload ) . to be_rebase_in_progress
expect ( json_response [ 'rebase_in_progress' ] ) . to be ( true )
end
end
2019-02-15 15:39:39 +05:30
end
it 'returns 403 if the user cannot push to the branch' do
guest = create ( :user )
project . add_guest ( guest )
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /rebase " , guest )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2019-02-15 15:39:39 +05:30
end
2019-09-30 21:07:59 +05:30
it 'returns 409 if a rebase is already in progress' do
Sidekiq :: Testing . fake! do
merge_request . rebase_async ( user . id )
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /rebase " , user )
end
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :conflict )
2019-09-30 21:07:59 +05:30
end
2019-12-26 22:10:19 +05:30
it " returns 409 if rebase can't lock the row " do
allow_any_instance_of ( MergeRequest ) . to receive ( :with_lock ) . and_raise ( ActiveRecord :: LockWaitTimeout )
expect ( RebaseWorker ) . not_to receive ( :perform_async )
put api ( " /projects/ #{ project . id } /merge_requests/ #{ merge_request . iid } /rebase " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :conflict )
2020-03-13 15:44:24 +05:30
expect ( json_response [ 'message' ] ) . to eq ( 'Failed to enqueue the rebase operation, possibly due to a long-lived transaction. Try again later.' )
2019-12-26 22:10:19 +05:30
end
2019-02-15 15:39:39 +05:30
end
2017-08-17 22:00:37 +05:30
describe 'Time tracking' do
2020-11-24 15:15:51 +05:30
let! ( :issuable ) { create ( :merge_request , :simple , author : user , assignees : [ user ] , source_project : project , target_project : project , source_branch : 'markdown' , title : " Test " , created_at : base_time ) }
2017-08-17 22:00:37 +05:30
include_examples 'time tracking endpoints' , 'merge_request'
2016-06-02 11:05:42 +05:30
end
2015-04-26 12:48:37 +05:30
def mr_with_later_created_and_updated_at_time
merge_request
merge_request . created_at += 1 . hour
merge_request . updated_at += 30 . minutes
2020-11-24 15:15:51 +05:30
merge_request . save!
2015-04-26 12:48:37 +05:30
merge_request
end
def mr_with_earlier_created_and_updated_at_time
merge_request_closed
merge_request_closed . created_at -= 1 . hour
merge_request_closed . updated_at -= 30 . minutes
2020-11-24 15:15:51 +05:30
merge_request_closed . save!
2015-04-26 12:48:37 +05:30
merge_request_closed
end
2014-09-02 18:07:02 +05:30
end