diff options
author | Sean McGivern <sean@gitlab.com> | 2018-11-29 11:36:04 +0300 |
---|---|---|
committer | Sean McGivern <sean@gitlab.com> | 2018-11-29 11:36:04 +0300 |
commit | 6852680584a1b22788f451457a6042eabf862a73 (patch) | |
tree | 8619487978bf962708c3f56482ae0f5085af9c8a | |
parent | c07183f0d3ce24e8cfcb93e71ae950d7067a8ce1 (diff) | |
parent | 04ceb69f3eea903d541614f42bbcdd008ad93839 (diff) |
Merge branch '33705-merge-request-rebase-api' into 'master'
Add a rebase API endpoint for merge requests
Closes #33705
See merge request gitlab-org/gitlab-ce!23296
-rw-r--r-- | changelogs/unreleased/33705-merge-request-rebase-api.yml | 5 | ||||
-rw-r--r-- | doc/api/merge_requests.md | 65 | ||||
-rw-r--r-- | lib/api/entities.rb | 4 | ||||
-rw-r--r-- | lib/api/merge_requests.rb | 35 | ||||
-rw-r--r-- | spec/requests/api/merge_requests_spec.rb | 30 |
5 files changed, 137 insertions, 2 deletions
diff --git a/changelogs/unreleased/33705-merge-request-rebase-api.yml b/changelogs/unreleased/33705-merge-request-rebase-api.yml new file mode 100644 index 00000000000..322fe31ce87 --- /dev/null +++ b/changelogs/unreleased/33705-merge-request-rebase-api.yml @@ -0,0 +1,5 @@ +--- +title: Add a rebase API endpoint for merge requests +merge_request: 23296 +author: +type: added diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index da70c74c4ce..fc03cf6cc39 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -408,6 +408,7 @@ Parameters: - `merge_request_iid` (required) - The internal ID of the merge request - `render_html` (optional) - If `true` response includes rendered HTML for title and description - `include_diverged_commits_count` (optional) - If `true` response includes the commits behind the target branch +- `include_rebase_in_progress` (optional) - If `true` response includes whether a rebase operation is in progress ```json { @@ -461,6 +462,7 @@ Parameters: }, "merge_when_pipeline_succeeds": true, "merge_status": "can_be_merged", + "merge_error": null, "sha": "8888888888888888888888888888888888888888", "merge_commit_sha": null, "user_notes_count": 1, @@ -505,7 +507,8 @@ Parameters: "head_sha": "2be7ddb704c7b6b83732fdd5b9f09d5a397b5f8f", "start_sha": "c380d3acebd181f13629a25d2e2acca46ffe1e00" }, - "diverged_commits_count": 2 + "diverged_commits_count": 2, + "rebase_in_progress": false } ``` @@ -773,6 +776,7 @@ POST /projects/:id/merge_requests }, "merge_when_pipeline_succeeds": true, "merge_status": "can_be_merged", + "merge_error": null, "sha": "8888888888888888888888888888888888888888", "merge_commit_sha": null, "user_notes_count": 1, @@ -900,6 +904,7 @@ Must include at least one non-required attribute from above. }, "merge_when_pipeline_succeeds": true, "merge_status": "can_be_merged", + "merge_error": null, "sha": "8888888888888888888888888888888888888888", "merge_commit_sha": null, "user_notes_count": 1, @@ -1043,6 +1048,7 @@ Parameters: }, "merge_when_pipeline_succeeds": true, "merge_status": "can_be_merged", + "merge_error": null, "sha": "8888888888888888888888888888888888888888", "merge_commit_sha": null, "user_notes_count": 1, @@ -1158,6 +1164,7 @@ Parameters: }, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", + "merge_error": null, "sha": "8888888888888888888888888888888888888888", "merge_commit_sha": null, "user_notes_count": 1, @@ -1206,6 +1213,62 @@ Parameters: } ``` +## Rebase a merge request + +Automatically rebase the `source_branch` of the merge request against its +`target_branch`. + +If you don't have permissions to push to the merge request's source branch - +you'll get a `403 Forbidden` response. + +``` +PUT /projects/:id/merge_requests/:merge_request_iid/rebase +``` + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `merge_request_iid` | integer | yes | The internal ID of the merge request | + +```bash +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/76/merge_requests/1/rebase +``` + +This is an asynchronous request. The API will return an empty `202 Accepted` +response if the request is enqueued successfully. + +You can poll the [Get single MR](#get-single-mr) endpoint with the +`include_rebase_in_progress` parameter to check the status of the +asynchronous request. + +If the rebase operation is ongoing, the response will include the following: + +```json +{ + "rebase_in_progress": true + "merge_error": null +} +``` + +Once the rebase operation has completed successfully, the response will include +the following: + +```json +{ + "rebase_in_progress": false, + "merge_error": null, +} +``` + +If the rebase operation fails, the response will include the following: + +```json +{ + "rebase_in_progress": false, + "merge_error": "Rebase failed. Please rebase locally", +} +``` + ## Comments on merge requests Comments are done via the [notes](notes.md) resource. diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 4788b0e16a1..5dbfbb85e9e 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -715,6 +715,10 @@ module API expose :diff_refs, using: Entities::DiffRefs + # Allow the status of a rebase to be determined + expose :merge_error + expose :rebase_in_progress?, as: :rebase_in_progress, if: -> (_, options) { options[:include_rebase_in_progress] } + expose :diverged_commits_count, as: :diverged_commits_count, if: -> (_, options) { options[:include_diverged_commits_count] } def build_available?(options) diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 16f07f16387..595b3641c52 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -74,6 +74,19 @@ module API options end + def authorize_push_to_merge_request!(merge_request) + forbidden!('Source branch does not exist') unless + merge_request.source_branch_exists? + + user_access = Gitlab::UserAccess.new( + current_user, + project: merge_request.source_project + ) + + forbidden!('Cannot push to source branch') unless + user_access.can_push_to_branch?(merge_request.source_branch) + end + params :merge_requests_params do optional :state, type: String, values: %w[opened closed locked merged all], default: 'all', desc: 'Return opened, closed, locked, merged, or all merge requests' @@ -239,6 +252,7 @@ module API requires :merge_request_iid, type: Integer, desc: 'The IID of a merge request' optional :render_html, type: Boolean, desc: 'Returns the description and title rendered HTML' optional :include_diverged_commits_count, type: Boolean, desc: 'Returns the commits count behind the target branch' + optional :include_rebase_in_progress, type: Boolean, desc: 'Returns whether a rebase operation is ongoing ' end desc 'Get a single merge request' do success Entities::MergeRequest @@ -246,7 +260,13 @@ module API get ':id/merge_requests/:merge_request_iid' do merge_request = find_merge_request_with_access(params[:merge_request_iid]) - present merge_request, with: Entities::MergeRequest, current_user: current_user, project: user_project, render_html: params[:render_html], include_diverged_commits_count: params[:include_diverged_commits_count] + present merge_request, + with: Entities::MergeRequest, + current_user: current_user, + project: user_project, + render_html: params[:render_html], + include_diverged_commits_count: params[:include_diverged_commits_count], + include_rebase_in_progress: params[:include_rebase_in_progress] end desc 'Get the participants of a merge request' do @@ -378,6 +398,19 @@ module API .cancel(merge_request) end + desc 'Rebase the merge request against its target branch' do + detail 'This feature was added in GitLab 11.6' + end + put ':id/merge_requests/:merge_request_iid/rebase' do + merge_request = find_project_merge_request(params[:merge_request_iid]) + + authorize_push_to_merge_request!(merge_request) + + RebaseWorker.perform_async(merge_request.id, current_user.id) + + status :accepted + end + desc 'List issues that will be closed on merge' do success Entities::MRNote end diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index e4e0ca285e0..27bcde77860 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -359,6 +359,8 @@ describe API::MergeRequests do expect(json_response['should_close_merge_request']).to be_falsy expect(json_response['force_close_merge_request']).to be_falsy expect(json_response['changes_count']).to eq(merge_request.merge_request_diff.real_size) + expect(json_response['merge_error']).to eq(merge_request.merge_error) + expect(json_response).not_to include('rebase_in_progress') end it 'exposes description and title html when render_html is true' do @@ -369,6 +371,14 @@ describe API::MergeRequests do expect(json_response).to include('title_html', 'description_html') end + it 'exposes rebase_in_progress when include_rebase_in_progress is true' do + get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user), include_rebase_in_progress: true + + expect(response).to have_gitlab_http_status(200) + + expect(json_response).to include('rebase_in_progress') + end + context 'merge_request_metrics' do before do merge_request.metrics.update!(merged_by: user, @@ -1181,6 +1191,26 @@ describe API::MergeRequests do end end + describe 'PUT :id/merge_requests/:merge_request_iid/rebase' do + it 'enqueues a rebase of the merge request against the target branch' do + Sidekiq::Testing.fake! do + put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/rebase", user) + end + + expect(response).to have_gitlab_http_status(202) + expect(RebaseWorker.jobs.size).to eq(1) + 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) + + expect(response).to have_gitlab_http_status(403) + end + end + describe 'Time tracking' do let(:issuable) { merge_request } |