diff options
author | Luke Duncalfe <lduncalfe@gitlab.com> | 2019-04-05 13:22:58 +0000 |
---|---|---|
committer | Luke Duncalfe <lduncalfe@eml.cc> | 2019-04-09 10:03:26 +1200 |
commit | 68f189ad23d7a384f40caa152d263fdf1465b30a (patch) | |
tree | 36f9b0f177b6238c0a730f23134d80c02e79f982 | |
parent | 1883e320eafa02b332a16eec658f65c4a28def83 (diff) | |
download | gitlab-ce-68f189ad23d7a384f40caa152d263fdf1465b30a.tar.gz |
Support merge on pipeline success w/ push options
MergeRequests::PushOptionsHandlerService has been updated to allow
creating and updating merge requests with the
`merge_when_pipeline_succeeds` set using git push options.
To create a new merge request and set it to merge when the pipeline
succeeds:
git push -u origin -o merge_request.create \
-o merge_request.merge_when_pipeline_succeeds
To update an existing merge request and set it to merge when the
pipeline succeeds:
git push -u origin -o merge_request.merge_when_pipeline_succeeds
Issue https://gitlab.com/gitlab-org/gitlab-ce/issues/53198
5 files changed, 149 insertions, 13 deletions
diff --git a/app/services/merge_requests/push_options_handler_service.rb b/app/services/merge_requests/push_options_handler_service.rb index c810340c636..73b4869cc5d 100644 --- a/app/services/merge_requests/push_options_handler_service.rb +++ b/app/services/merge_requests/push_options_handler_service.rb @@ -7,7 +7,7 @@ module MergeRequests LIMIT = 10 attr_reader :branches, :changes_by_branch, :current_user, :errors, - :project, :push_options, :target + :project, :push_options def initialize(project, current_user, changes, push_options) @project = project @@ -16,7 +16,6 @@ module MergeRequests @push_options = push_options @errors = [] @branches = @changes_by_branch.keys - @target = @push_options[:target] || @project.default_branch raise Error, 'User is required' if @current_user.nil? @@ -28,8 +27,8 @@ module MergeRequests raise Error, "Too many branches pushed (#{@branches.size} were pushed, limit is #{LIMIT})" end - if @push_options[:target] && !@project.repository.branch_exists?(@target) - raise Error, "Branch #{@target} does not exist" + if @push_options[:target] && !@project.repository.branch_exists?(@push_options[:target]) + raise Error, "Branch #{@push_options[:target]} does not exist" end end @@ -93,12 +92,10 @@ module MergeRequests end def update!(merge_request) - return if target == merge_request.target_branch - merge_request = ::MergeRequests::UpdateService.new( project, current_user, - { target_branch: target } + update_params ).execute(merge_request) collect_errors_from_merge_request(merge_request) unless merge_request.valid? @@ -111,13 +108,39 @@ module MergeRequests commits = CommitCollection.new(project, commits) commit = commits.without_merge_commits.first - { + params = { assignee: current_user, source_branch: branch, - target_branch: target, + target_branch: push_options[:target] || project.default_branch, title: commit&.title&.strip || 'New Merge Request', description: commit&.description&.strip } + + if push_options.key?(:merge_when_pipeline_succeeds) + params.merge!( + merge_when_pipeline_succeeds: push_options[:merge_when_pipeline_succeeds], + merge_user: current_user + ) + end + + params + end + + def update_params + params = {} + + if push_options.key?(:merge_when_pipeline_succeeds) + params.merge!( + merge_when_pipeline_succeeds: push_options[:merge_when_pipeline_succeeds], + merge_user: current_user + ) + end + + if push_options.key?(:target) + params[:target_branch] = push_options[:target] + end + + params end def collect_errors_from_merge_request(merge_request) diff --git a/changelogs/unreleased/53198-git-push-option-merge-when-pipeline-succeeds.yml b/changelogs/unreleased/53198-git-push-option-merge-when-pipeline-succeeds.yml new file mode 100644 index 00000000000..6fefd05049c --- /dev/null +++ b/changelogs/unreleased/53198-git-push-option-merge-when-pipeline-succeeds.yml @@ -0,0 +1,6 @@ +--- +title: Allow merge requests to be set to merge when pipeline succeeds via git push + options +merge_request: 26842 +author: +type: added diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md index 678fc3dd196..ba7d05a7ad7 100644 --- a/doc/user/project/merge_requests/index.md +++ b/doc/user/project/merge_requests/index.md @@ -223,9 +223,17 @@ branch already exists, the patches will be applied on top of it. > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/26752) in GitLab 11.10. -GitLab supports using [Git push options](https://git-scm.com/docs/git-push#Documentation/git-push.txt--oltoptiongt) to create merge requests and set the target -branch during a push. Note that git push options are only available with -Git 2.10 or newer. +NOTE: **Note:** +Git push options are only available with Git 2.10 or newer. + +GitLab supports using +[Git push options](https://git-scm.com/docs/git-push#Documentation/git-push.txt--oltoptiongt) +to perform the following actions against merge requests at the same time +as pushing changes: + +- Create a new merge request for the pushed branch. +- Set the target of the merge request to a particular branch. +- Set the merge request to merge when its pipeline succeeds. ### Create a new merge request using git push options @@ -252,6 +260,23 @@ same time using a `-o` flag per push option: git push -o merge_request.create -o merge_request.target=branch_name ``` +### Set merge when pipeline succeeds using git push options + +To set an existing merge request to +[merge when its pipeline succeeds](merge_when_pipeline_succeeds.md), use +the `merge_request.merge_when_pipeline_succeeds` push option: + +```sh +git push -o merge_request.merge_when_pipeline_succeeds +``` + +You can also create a merge request and set it to merge when its +pipeline succeeds at the same time using a `-o` flag per push option: + +```sh +git push -o merge_request.create -o merge_request.merge_when_pipeline_succeeds +``` + ## Find the merge request that introduced a change > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/2383) in GitLab 10.5. diff --git a/lib/gitlab/push_options.rb b/lib/gitlab/push_options.rb index 7c655c12995..810aba436cc 100644 --- a/lib/gitlab/push_options.rb +++ b/lib/gitlab/push_options.rb @@ -4,7 +4,7 @@ module Gitlab class PushOptions VALID_OPTIONS = HashWithIndifferentAccess.new({ merge_request: { - keys: [:create, :target] + keys: [:create, :merge_when_pipeline_succeeds, :target] }, ci: { keys: [:skip] diff --git a/spec/services/merge_requests/push_options_handler_service_spec.rb b/spec/services/merge_requests/push_options_handler_service_spec.rb index 96becfcae26..eafe7a34617 100644 --- a/spec/services/merge_requests/push_options_handler_service_spec.rb +++ b/spec/services/merge_requests/push_options_handler_service_spec.rb @@ -66,6 +66,22 @@ describe MergeRequests::PushOptionsHandlerService do end end + shared_examples_for 'a service that can set the merge request to merge when pipeline succeeds' do + subject(:last_mr) { MergeRequest.last } + + it 'sets merge_when_pipeline_succeeds' do + service.execute + + expect(last_mr.merge_when_pipeline_succeeds).to eq(true) + end + + it 'sets merge_user to the user' do + service.execute + + expect(last_mr.merge_user).to eq(user) + end + end + shared_examples_for 'a service that does not create a merge request' do it do expect { service.execute }.not_to change { MergeRequest.count } @@ -118,6 +134,72 @@ describe MergeRequests::PushOptionsHandlerService do end end + describe '`merge_when_pipeline_succeeds` push option' do + let(:push_options) { { merge_when_pipeline_succeeds: true } } + + context 'with a new branch' do + let(:changes) { new_branch_changes } + + it_behaves_like 'a service that does not create a merge request' + + it 'adds an error to the service' do + error = "A merge_request.create push option is required to create a merge request for branch #{source_branch}" + + service.execute + + expect(service.errors).to include(error) + end + + context 'when coupled with the `create` push option' do + let(:push_options) { { create: true, merge_when_pipeline_succeeds: true } } + + it_behaves_like 'a service that can create a merge request' + it_behaves_like 'a service that can set the merge request to merge when pipeline succeeds' + end + end + + context 'with an existing branch but no open MR' do + let(:changes) { existing_branch_changes } + + it_behaves_like 'a service that does not create a merge request' + + it 'adds an error to the service' do + error = "A merge_request.create push option is required to create a merge request for branch #{source_branch}" + + service.execute + + expect(service.errors).to include(error) + end + + context 'when coupled with the `create` push option' do + let(:push_options) { { create: true, merge_when_pipeline_succeeds: true } } + + it_behaves_like 'a service that can create a merge request' + it_behaves_like 'a service that can set the merge request to merge when pipeline succeeds' + end + end + + context 'with an existing branch that has a merge request open' do + let(:changes) { existing_branch_changes } + let!(:merge_request) { create(:merge_request, source_project: project, source_branch: source_branch)} + + it_behaves_like 'a service that does not create a merge request' + it_behaves_like 'a service that can set the merge request to merge when pipeline succeeds' + end + + context 'with a deleted branch' do + let(:changes) { deleted_branch_changes } + + it_behaves_like 'a service that does nothing' + end + + context 'with the project default branch' do + let(:changes) { default_branch_changes } + + it_behaves_like 'a service that does nothing' + end + end + describe '`target` push option' do let(:push_options) { { target: target_branch } } |