Add top-level /merge_requests API endpoint

And add support for additional query parameters:
- `author_id`: Returns merge requests created by the given user `id`
- `assignee_id`: Returns merge requests assigned to the given user `id`
- `scope`: Return merge requests for the given scope: `created-by-me`, `assigned-to-me` or `all`
This commit is contained in:
Toon Claes 2017-07-24 22:07:37 +02:00
parent 27df74ad41
commit d7505de8b3
5 changed files with 244 additions and 31 deletions

View file

@ -10,6 +10,7 @@
# group_id: integer
# project_id: integer
# milestone_title: string
# author_id: integer
# assignee_id: integer
# search: string
# label_name: string

View file

@ -0,0 +1,4 @@
---
title: Add top-level merge_requests API endpoint
merge_request: 13060
author:

View file

@ -1,7 +1,99 @@
# Merge requests API
Every API call to merge requests must be authenticated.
## List merge requests
Get all merge requests the authenticated user has access to.
The `state` parameter can be used to get only merge requests with a
given state (`opened`, `closed`, or `merged`) or all of them (`all`).
The pagination parameters `page` and `per_page` can be used to
restrict the list of merge requests.
```
GET /merge_requests
GET /merge_requests?state=opened
GET /merge_requests?state=all
GET /merge_requests?milestone=release
GET /merge_requests?labels=bug,reproduced
GET /merge_requests?author_id=5
GET /merge_requests?scope=assigned-to-me
```
Parameters:
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `state` | string | no | Return all merge requests or just those that are `opened`, `closed`, or `merged`|
| `order_by`| string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` |
| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` |
| `milestone` | string | no | Return merge requests for a specific milestone |
| `view` | string | no | If `simple`, returns the `iid`, URL, title, description, and basic state of merge request |
| `labels` | string | no | Return merge requests matching a comma separated list of labels |
| `created_after` | datetime | no | Return merge requests created after the given time (inclusive) |
| `created_before` | datetime | no | Return merge requests created before the given time (inclusive) |
| `author_id` | integer | no | Returns merge requests created by the given user `id` |
| `assignee_id` | integer | no | Returns merge requests assigned to the given user `id` |
| `scope` | string | no | Return merge requests for the given scope: `created-by-me`, `assigned-to-me` or `all` |
```json
[
{
"id": 1,
"iid": 1,
"target_branch": "master",
"source_branch": "test1",
"project_id": 3,
"title": "test1",
"state": "opened",
"upvotes": 0,
"downvotes": 0,
"author": {
"id": 1,
"username": "admin",
"email": "admin@example.com",
"name": "Administrator",
"state": "active",
"created_at": "2012-04-29T08:46:00Z"
},
"assignee": {
"id": 1,
"username": "admin",
"email": "admin@example.com",
"name": "Administrator",
"state": "active",
"created_at": "2012-04-29T08:46:00Z"
},
"source_project_id": 2,
"target_project_id": 3,
"labels": [ ],
"description": "fixed login page css paddings",
"work_in_progress": false,
"milestone": {
"id": 5,
"iid": 1,
"project_id": 3,
"title": "v2.0",
"description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.",
"state": "closed",
"created_at": "2015-02-02T19:49:26.013Z",
"updated_at": "2015-02-02T19:49:26.013Z",
"due_date": null
},
"merge_when_pipeline_succeeds": true,
"merge_status": "can_be_merged",
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
"user_notes_count": 1,
"should_remove_source_branch": true,
"force_remove_source_branch": false,
"web_url": "http://example.com/example/example/merge_requests/1"
}
]
```
## List project merge requests
Get all merge requests for this project.
The `state` parameter can be used to get only merge requests with a given state (`opened`, `closed`, or `merged`) or all of them (`all`).
The pagination parameters `page` and `per_page` can be used to restrict the list of merge requests.

View file

@ -4,14 +4,75 @@ module API
before { authenticate! }
helpers ::Gitlab::IssuableMetadata
helpers do
def find_merge_requests(args = {})
args = params.merge(args)
args[:milestone_title] = args.delete(:milestone)
args[:label_name] = args.delete(:labels)
merge_requests = MergeRequestsFinder.new(current_user, args).execute
.reorder(args[:order_by] => args[:sort])
merge_requests = paginate(merge_requests)
.preload(:target_project)
return merge_requests if args[:view] == 'simple'
merge_requests
.preload(:notes, :author, :assignee, :milestone, :merge_request_diff, :labels)
end
params :merge_requests_params do
optional :state, type: String, values: %w[opened closed merged all], default: 'all',
desc: 'Return opened, closed, merged, or all merge requests'
optional :order_by, type: String, values: %w[created_at updated_at], default: 'created_at',
desc: 'Return merge requests ordered by `created_at` or `updated_at` fields.'
optional :sort, type: String, values: %w[asc desc], default: 'desc',
desc: 'Return merge requests sorted in `asc` or `desc` order.'
optional :milestone, type: String, desc: 'Return merge requests for a specific milestone'
optional :labels, type: String, desc: 'Comma-separated list of label names'
optional :created_after, type: DateTime, desc: 'Return merge requests created after the specified time'
optional :created_before, type: DateTime, desc: 'Return merge requests created before the specified time'
optional :view, type: String, values: %w[simple], desc: 'If simple, returns the `iid`, URL, title, description, and basic state of merge request'
optional :author_id, type: Integer, desc: 'Return merge requests which are authored by the user with the given ID'
optional :assignee_id, type: Integer, desc: 'Return merge requests which are assigned to the user with the given ID'
optional :scope, type: String, values: %w[created-by-me assigned-to-me all], default: 'all',
desc: 'Return merge requests for the given scope: `created-by-me`, `assigned-to-me` or `all`'
use :pagination
end
end
resource :merge_requests do
desc 'List merge requests' do
success Entities::MergeRequestBasic
end
params do
use :merge_requests_params
end
get do
merge_requests = find_merge_requests
options = { with: Entities::MergeRequestBasic,
current_user: current_user }
if params[:view] == 'simple'
options[:with] = Entities::MergeRequestSimple
else
options[:issuable_metadata] = issuable_meta_data(merge_requests, 'MergeRequest')
end
present merge_requests, options
end
end
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects, requirements: { id: %r{[^/]+} } do
include TimeTrackingEndpoints
helpers ::Gitlab::IssuableMetadata
helpers do
def handle_merge_request_errors!(errors)
if errors[:project_access].any?
@ -29,23 +90,6 @@ module API
render_api_error!(errors, 400)
end
def find_merge_requests(args = {})
args = params.merge(args)
args[:milestone_title] = args.delete(:milestone)
args[:label_name] = args.delete(:labels)
merge_requests = MergeRequestsFinder.new(current_user, args).execute
.reorder(args[:order_by] => args[:sort])
merge_requests = paginate(merge_requests)
.preload(:target_project)
return merge_requests if args[:view] == 'simple'
merge_requests
.preload(:notes, :author, :assignee, :milestone, :merge_request_diff, :labels)
end
params :optional_params_ce do
optional :description, type: String, desc: 'The description of the merge request'
optional :assignee_id, type: Integer, desc: 'The ID of a user to assign the merge request'
@ -63,19 +107,8 @@ module API
success Entities::MergeRequestBasic
end
params do
optional :state, type: String, values: %w[opened closed merged all], default: 'all',
desc: 'Return opened, closed, merged, or all merge requests'
optional :order_by, type: String, values: %w[created_at updated_at], default: 'created_at',
desc: 'Return merge requests ordered by `created_at` or `updated_at` fields.'
optional :sort, type: String, values: %w[asc desc], default: 'desc',
desc: 'Return merge requests sorted in `asc` or `desc` order.'
use :merge_requests_params
optional :iids, type: Array[Integer], desc: 'The IID array of merge requests'
optional :milestone, type: String, desc: 'Return merge requests for a specific milestone'
optional :labels, type: String, desc: 'Comma-separated list of label names'
optional :created_after, type: DateTime, desc: 'Return merge requests created after the specified time'
optional :created_before, type: DateTime, desc: 'Return merge requests created before the specified time'
optional :view, type: String, values: %w[simple], desc: 'If simple, returns the `iid`, URL, title, description, and basic state of merge request'
use :pagination
end
get ":id/merge_requests" do
authorize! :read_merge_request, user_project

View file

@ -26,6 +26,89 @@ describe API::MergeRequests do
project.team << [user, :reporter]
end
describe 'GET /merge_requests' do
context 'when unauthenticated' do
it 'returns authentication error' do
get api('/merge_requests')
expect(response).to have_http_status(401)
end
end
context 'when authenticated' do
let!(:project2) { create(:empty_project, :public, namespace: user.namespace) }
let!(:merge_request2) { create(:merge_request, :simple, author: user, assignee: user, source_project: project2, target_project: project2) }
let(:user2) { create(:user) }
it 'returns an array of all merge requests' do
get api('/merge_requests', user)
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.map { |mr| mr['id'] })
.to contain_exactly(merge_request.id, merge_request_closed.id, merge_request_merged.id, merge_request2.id)
end
it 'does not return unauthorized merge requests' do
private_project = create(:empty_project, :private)
merge_request3 = create(:merge_request, :simple, source_project: private_project, target_project: private_project, source_branch: 'other-branch')
get api('/merge_requests', user)
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.map { |mr| mr['id'] })
.not_to include(merge_request3.id)
end
it 'returns an array of merge requests authored by the given user' do
merge_request3 = create(:merge_request, :simple, author: user2, assignee: user, source_project: project2, target_project: project2, source_branch: 'other-branch')
get api('/merge_requests', user), author_id: user2.id
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
expect(json_response.first['id']).to eq(merge_request3.id)
end
it 'returns an array of merge requests assigned to the given user' do
merge_request3 = create(:merge_request, :simple, author: user, assignee: user2, source_project: project2, target_project: project2, source_branch: 'other-branch')
get api('/merge_requests', user), assignee_id: user2.id
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
expect(json_response.first['id']).to eq(merge_request3.id)
end
it 'returns an array of merge requests assigned to me' do
merge_request3 = create(:merge_request, :simple, author: user, assignee: user2, source_project: project2, target_project: project2, source_branch: 'other-branch')
get api('/merge_requests', user2), scope: 'assigned-to-me'
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
expect(json_response.first['id']).to eq(merge_request3.id)
end
it 'returns an array of merge requests created by me' do
merge_request3 = create(:merge_request, :simple, author: user2, assignee: user, source_project: project2, target_project: project2, source_branch: 'other-branch')
get api('/merge_requests', user2), scope: 'created-by-me'
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
expect(json_response.first['id']).to eq(merge_request3.id)
end
end
end
describe "GET /projects/:id/merge_requests" do
context "when unauthenticated" do
it "returns authentication error" do