Skip to content
Snippets Groups Projects
Commit 7a774d1a authored by Douwe Maan's avatar Douwe Maan
Browse files

Merge branch '28251-mr-and-issue-iids-for-api-v4' into 'master'

API routes referencing a specific issue should use the issue `iid`

Closes #28251

See merge request !9530
parents bec5c370 6384bf7a
No related branches found
No related tags found
1 merge request!9530API routes referencing a specific issue should use the issue `iid`
Pipeline #
Showing
with 799 additions and 435 deletions
Loading
Loading
@@ -14,17 +14,17 @@ requests, snippets, and notes/comments. Issues, merge requests, snippets, and no
Gets a list of all award emoji
 
```
GET /projects/:id/issues/:issue_id/award_emoji
GET /projects/:id/merge_requests/:merge_request_id/award_emoji
GET /projects/:id/issues/:issue_iid/award_emoji
GET /projects/:id/merge_requests/:merge_request_iid/award_emoji
GET /projects/:id/snippets/:snippet_id/award_emoji
```
 
Parameters:
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `awardable_id` | integer | yes | The ID of an awardable |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `awardable_id` | integer | yes | The ID (`iid` for merge requests/issues, `id` for snippets) of an awardable |
 
```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji
Loading
Loading
@@ -74,18 +74,18 @@ Example Response:
Gets a single award emoji from an issue, snippet, or merge request.
 
```
GET /projects/:id/issues/:issue_id/award_emoji/:award_id
GET /projects/:id/merge_requests/:merge_request_id/award_emoji/:award_id
GET /projects/:id/issues/:issue_iid/award_emoji/:award_id
GET /projects/:id/merge_requests/:merge_request_iid/award_emoji/:award_id
GET /projects/:id/snippets/:snippet_id/award_emoji/:award_id
```
 
Parameters:
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `awardable_id` | integer | yes | The ID of an awardable |
| `award_id` | integer | yes | The ID of the award emoji |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `awardable_id` | integer | yes | The ID (`iid` for merge requests/issues, `id` for snippets) of an awardable |
| `award_id` | integer | yes | The ID of the award emoji |
 
```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji/1
Loading
Loading
@@ -117,18 +117,18 @@ Example Response:
This end point creates an award emoji on the specified resource
 
```
POST /projects/:id/issues/:issue_id/award_emoji
POST /projects/:id/merge_requests/:merge_request_id/award_emoji
POST /projects/:id/issues/:issue_iid/award_emoji
POST /projects/:id/merge_requests/:merge_request_iid/award_emoji
POST /projects/:id/snippets/:snippet_id/award_emoji
```
 
Parameters:
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `awardable_id` | integer | yes | The ID of an awardable |
| `name` | string | yes | The name of the emoji, without colons |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `awardable_id` | integer | yes | The ID (`iid` for merge requests/issues, `id` for snippets) of an awardable |
| `name` | string | yes | The name of the emoji, without colons |
 
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji?name=blowfish
Loading
Loading
@@ -161,18 +161,18 @@ Sometimes its just not meant to be, and you'll have to remove your award. Only a
admins or the author of the award.
 
```
DELETE /projects/:id/issues/:issue_id/award_emoji/:award_id
DELETE /projects/:id/merge_requests/:merge_request_id/award_emoji/:award_id
DELETE /projects/:id/issues/:issue_iid/award_emoji/:award_id
DELETE /projects/:id/merge_requests/:merge_request_iid/award_emoji/:award_id
DELETE /projects/:id/snippets/:snippet_id/award_emoji/:award_id
```
 
Parameters:
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_id` | integer | yes | The ID of an issue |
| `award_id` | integer | yes | The ID of a award_emoji |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_iid` | integer | yes | The internal ID of an issue |
| `award_id` | integer | yes | The ID of a award_emoji |
 
```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji/344
Loading
Loading
@@ -188,16 +188,16 @@ easily adapted for notes on a Merge Request.
### List a note's award emoji
 
```
GET /projects/:id/issues/:issue_id/notes/:note_id/award_emoji
GET /projects/:id/issues/:issue_iid/notes/:note_id/award_emoji
```
 
Parameters:
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_id` | integer | yes | The ID of an issue |
| `note_id` | integer | yes | The ID of an note |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_iid` | integer | yes | The internal ID of an issue |
| `note_id` | integer | yes | The ID of an note |
 
 
```bash
Loading
Loading
@@ -230,17 +230,17 @@ Example Response:
### Get single note's award emoji
 
```
GET /projects/:id/issues/:issue_id/notes/:note_id/award_emoji/:award_id
GET /projects/:id/issues/:issue_iid/notes/:note_id/award_emoji/:award_id
```
 
Parameters:
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_id` | integer | yes | The ID of an issue |
| `note_id` | integer | yes | The ID of a note |
| `award_id` | integer | yes | The ID of the award emoji |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_iid` | integer | yes | The internal ID of an issue |
| `note_id` | integer | yes | The ID of a note |
| `award_id` | integer | yes | The ID of the award emoji |
 
```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/notes/1/award_emoji/2
Loading
Loading
@@ -270,17 +270,17 @@ Example Response:
### Award a new emoji on a note
 
```
POST /projects/:id/issues/:issue_id/notes/:note_id/award_emoji
POST /projects/:id/issues/:issue_iid/notes/:note_id/award_emoji
```
 
Parameters:
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_id` | integer | yes | The ID of an issue |
| `note_id` | integer | yes | The ID of a note |
| `name` | string | yes | The name of the emoji, without colons |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_iid` | integer | yes | The internal ID of an issue |
| `note_id` | integer | yes | The ID of a note |
| `name` | string | yes | The name of the emoji, without colons |
 
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/notes/1/award_emoji?name=rocket
Loading
Loading
@@ -313,17 +313,17 @@ Sometimes its just not meant to be, and you'll have to remove your award. Only a
admins or the author of the award.
 
```
DELETE /projects/:id/issues/:issue_id/notes/:note_id/award_emoji/:award_id
DELETE /projects/:id/issues/:issue_iid/notes/:note_id/award_emoji/:award_id
```
 
Parameters:
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_id` | integer | yes | The ID of an issue |
| `note_id` | integer | yes | The ID of a note |
| `award_id` | integer | yes | The ID of a award_emoji |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_iid` | integer | yes | The internal ID of an issue |
| `note_id` | integer | yes | The ID of a note |
| `award_id` | integer | yes | The ID of a award_emoji |
 
```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji/345
Loading
Loading
Loading
Loading
@@ -261,13 +261,13 @@ Example response:
Get a single project issue.
 
```
GET /projects/:id/issues/:issue_id
GET /projects/:id/issues/:issue_iid
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_id`| integer | yes | The ID of a project's issue |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
 
```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/4/issues/41
Loading
Loading
@@ -385,22 +385,22 @@ Updates an existing project issue. This call is also used to mark an issue as
closed.
 
```
PUT /projects/:id/issues/:issue_id
PUT /projects/:id/issues/:issue_iid
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_id` | integer | yes | The ID of a project's issue |
| `title` | string | no | The title of an issue |
| `description` | string | no | The description of an issue |
| `confidential` | boolean | no | Updates an issue to be confidential |
| `assignee_id` | integer | no | The ID of a user to assign the issue to |
| `milestone_id` | integer | no | The ID of a milestone to assign the issue to |
| `labels` | string | no | Comma-separated label names for an issue |
| `state_event` | string | no | The state event of an issue. Set `close` to close the issue and `reopen` to reopen it |
| `updated_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights) |
| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
| `title` | string | no | The title of an issue |
| `description` | string | no | The description of an issue |
| `confidential` | boolean | no | Updates an issue to be confidential |
| `assignee_id` | integer | no | The ID of a user to assign the issue to |
| `milestone_id` | integer | no | The ID of a milestone to assign the issue to |
| `labels` | string | no | Comma-separated label names for an issue |
| `state_event` | string | no | The state event of an issue. Set `close` to close the issue and `reopen` to reopen it |
| `updated_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights) |
| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
 
```bash
curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/4/issues/85?state_event=close
Loading
Loading
@@ -444,13 +444,13 @@ Example response:
Only for admins and project owners. Soft deletes the issue in question.
 
```
DELETE /projects/:id/issues/:issue_id
DELETE /projects/:id/issues/:issue_iid
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_id` | integer | yes | The ID of a project's issue |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
 
```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/4/issues/85
Loading
Loading
@@ -466,14 +466,14 @@ If a given label and/or milestone with the same name also exists in the target
project, it will then be assigned to the issue that is being moved.
 
```
POST /projects/:id/issues/:issue_id/move
POST /projects/:id/issues/:issue_iid/move
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_id` | integer | yes | The ID of a project's issue |
| `to_project_id` | integer | yes | The ID of the new project |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
| `to_project_id` | integer | yes | The ID of the new project |
 
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/4/issues/85/move
Loading
Loading
@@ -522,13 +522,13 @@ If the user is already subscribed to the issue, the status code `304`
is returned.
 
```
POST /projects/:id/issues/:issue_id/subscribe
POST /projects/:id/issues/:issue_iid/subscribe
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_id` | integer | yes | The ID of a project's issue |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
 
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/subscribe
Loading
Loading
@@ -577,13 +577,13 @@ from it. If the user is not subscribed to the issue, the
status code `304` is returned.
 
```
POST /projects/:id/issues/:issue_id/unsubscribe
POST /projects/:id/issues/:issue_iid/unsubscribe
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_id` | integer | yes | The ID of a project's issue |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
 
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/unsubscribe
Loading
Loading
@@ -596,13 +596,13 @@ there already exists a todo for the user on that issue, status code `304` is
returned.
 
```
POST /projects/:id/issues/:issue_id/todo
POST /projects/:id/issues/:issue_iid/todo
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_id` | integer | yes | The ID of a project's issue |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
 
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/todo
Loading
Loading
@@ -687,14 +687,14 @@ Example response:
Sets an estimated time of work for this issue.
 
```
POST /projects/:id/issues/:issue_id/time_estimate
POST /projects/:id/issues/:issue_iid/time_estimate
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_id` | integer | yes | The ID of a project's issue |
| `duration` | string | yes | The duration in human format. e.g: 3h30m |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
| `duration` | string | yes | The duration in human format. e.g: 3h30m |
 
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/time_estimate?duration=3h30m
Loading
Loading
@@ -716,13 +716,13 @@ Example response:
Resets the estimated time for this issue to 0 seconds.
 
```
POST /projects/:id/issues/:issue_id/reset_time_estimate
POST /projects/:id/issues/:issue_iid/reset_time_estimate
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_id` | integer | yes | The ID of a project's issue |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
 
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/reset_time_estimate
Loading
Loading
@@ -744,14 +744,14 @@ Example response:
Adds spent time for this issue
 
```
POST /projects/:id/issues/:issue_id/add_spent_time
POST /projects/:id/issues/:issue_iid/add_spent_time
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_id` | integer | yes | The ID of a project's issue |
| `duration` | string | yes | The duration in human format. e.g: 3h30m |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
| `duration` | string | yes | The duration in human format. e.g: 3h30m |
 
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/add_spent_time?duration=1h
Loading
Loading
@@ -773,13 +773,13 @@ Example response:
Resets the total spent time for this issue to 0 seconds.
 
```
POST /projects/:id/issues/:issue_id/reset_spent_time
POST /projects/:id/issues/:issue_iid/reset_spent_time
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_id` | integer | yes | The ID of a project's issue |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
 
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/reset_spent_time
Loading
Loading
@@ -799,13 +799,13 @@ Example response:
## Get time tracking stats
 
```
GET /projects/:id/issues/:issue_id/time_stats
GET /projects/:id/issues/:issue_iid/time_stats
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_id` | integer | yes | The ID of a project's issue |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
 
```bash
curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/time_stats
Loading
Loading
Loading
Loading
@@ -82,13 +82,13 @@ Parameters:
Shows information about a single merge request.
 
```
GET /projects/:id/merge_requests/:merge_request_id
GET /projects/:id/merge_requests/:merge_request_iid
```
 
Parameters:
 
- `id` (required) - The ID of a project
- `merge_request_id` (required) - The ID of MR
- `merge_request_iid` (required) - The internal ID of the merge request
 
```json
{
Loading
Loading
@@ -150,13 +150,13 @@ Parameters:
Get a list of merge request commits.
 
```
GET /projects/:id/merge_requests/:merge_request_id/commits
GET /projects/:id/merge_requests/:merge_request_iid/commits
```
 
Parameters:
 
- `id` (required) - The ID of a project
- `merge_request_id` (required) - The ID of MR
- `merge_request_iid` (required) - The internal ID of the merge request
 
 
```json
Loading
Loading
@@ -187,13 +187,13 @@ Parameters:
Shows information about the merge request including its files and changes.
 
```
GET /projects/:id/merge_requests/:merge_request_id/changes
GET /projects/:id/merge_requests/:merge_request_iid/changes
```
 
Parameters:
 
- `id` (required) - The ID of a project
- `merge_request_id` (required) - The ID of MR
- `merge_request_iid` (required) - The internal ID of the merge request
 
```json
{
Loading
Loading
@@ -269,18 +269,18 @@ Creates a new merge request.
POST /projects/:id/merge_requests
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | string | yes | The ID of a project |
| `source_branch` | string | yes | The source branch |
| `target_branch` | string | yes | The target branch |
| `title` | string | yes | Title of MR |
| `assignee_id` | integer | no | Assignee user ID |
| `description` | string | no | Description of MR |
| `target_project_id` | integer | no | The target project (numeric id) |
| `labels` | string | no | Labels for MR as a comma-separated list |
| `milestone_id` | integer | no | The ID of a milestone |
| `remove_source_branch` | boolean | no | Flag indicating if a merge request should remove the source branch when merging |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | string | yes | The ID of a project |
| `source_branch` | string | yes | The source branch |
| `target_branch` | string | yes | The target branch |
| `title` | string | yes | Title of MR |
| `assignee_id` | integer | no | Assignee user ID |
| `description` | string | no | Description of MR |
| `target_project_id` | integer | no | The target project (numeric id) |
| `labels` | string | no | Labels for MR as a comma-separated list |
| `milestone_id` | integer | no | The ID of a milestone |
| `remove_source_branch` | boolean | no | Flag indicating if a merge request should remove the source branch when merging |
 
```json
{
Loading
Loading
@@ -342,21 +342,21 @@ POST /projects/:id/merge_requests
Updates an existing merge request. You can change the target branch, title, or even close the MR.
 
```
PUT /projects/:id/merge_requests/:merge_request_id
PUT /projects/:id/merge_requests/:merge_request_iid
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | string | yes | The ID of a project |
| `merge_request_id` | integer | yes | The ID of a merge request |
| `target_branch` | string | no | The target branch |
| `title` | string | no | Title of MR |
| `assignee_id` | integer | no | Assignee user ID |
| `description` | string | no | Description of MR |
| `state_event` | string | no | New state (close/reopen) |
| `labels` | string | no | Labels for MR as a comma-separated list |
| `milestone_id` | integer | no | The ID of a milestone |
| `remove_source_branch` | boolean | no | Flag indicating if a merge request should remove the source branch when merging |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | string | yes | The ID of a project |
| `merge_request_iid` | integer | yes | The ID of a merge request |
| `target_branch` | string | no | The target branch |
| `title` | string | no | Title of MR |
| `assignee_id` | integer | no | Assignee user ID |
| `description` | string | no | Description of MR |
| `state_event` | string | no | New state (close/reopen) |
| `labels` | string | no | Labels for MR as a comma-separated list |
| `milestone_id` | integer | no | The ID of a milestone |
| `remove_source_branch` | boolean | no | Flag indicating if a merge request should remove the source branch when merging |
 
Must include at least one non-required attribute from above.
 
Loading
Loading
@@ -419,13 +419,13 @@ Must include at least one non-required attribute from above.
Only for admins and project owners. Soft deletes the merge request in question.
 
```
DELETE /projects/:id/merge_requests/:merge_request_id
DELETE /projects/:id/merge_requests/:merge_request_iid
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_id` | integer | yes | The ID of a project's merge request |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_iid` | integer | yes | The internal ID of the merge request |
 
```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/4/merge_requests/85
Loading
Loading
@@ -445,13 +445,13 @@ If the `sha` parameter is passed and does not match the HEAD of the source - you
If you don't have permissions to accept this merge request - you'll get a `401`
 
```
PUT /projects/:id/merge_requests/:merge_request_id/merge
PUT /projects/:id/merge_requests/:merge_request_iid/merge
```
 
Parameters:
 
- `id` (required) - The ID of a project
- `merge_request_id` (required) - ID of MR
- `merge_request_iid` (required) - Internal ID of MR
- `merge_commit_message` (optional) - Custom merge commit message
- `should_remove_source_branch` (optional) - if `true` removes the source branch
- `merge_when_pipeline_succeeds` (optional) - if `true` the MR is merged when the pipeline succeeds
Loading
Loading
@@ -520,12 +520,12 @@ If the merge request is already merged or closed - you get `405` and error messa
 
In case the merge request is not set to be merged when the pipeline succeeds, you'll also get a `406` error.
```
PUT /projects/:id/merge_requests/:merge_request_id/cancel_merge_when_pipeline_succeeds
PUT /projects/:id/merge_requests/:merge_request_iid/cancel_merge_when_pipeline_succeeds
```
Parameters:
 
- `id` (required) - The ID of a project
- `merge_request_id` (required) - ID of MR
- `merge_request_iid` (required) - Internal ID of MR
 
```json
{
Loading
Loading
@@ -591,13 +591,13 @@ Comments are done via the [notes](notes.md) resource.
Get all the issues that would be closed by merging the provided merge request.
 
```
GET /projects/:id/merge_requests/:merge_request_id/closes_issues
GET /projects/:id/merge_requests/:merge_request_iid/closes_issues
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_id` | integer | yes | The ID of the merge request |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `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/closes_issues
Loading
Loading
@@ -666,13 +666,13 @@ Subscribes the authenticated user to a merge request to receive notification. If
status code `304` is returned.
 
```
POST /projects/:id/merge_requests/:merge_request_id/subscribe
POST /projects/:id/merge_requests/:merge_request_iid/subscribe
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_id` | integer | yes | The ID of the merge request |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_iid` | integer | yes | The internal ID of the merge request |
 
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/17/subscribe
Loading
Loading
@@ -740,13 +740,13 @@ notifications from that merge request. If the user is
not subscribed to the merge request, the status code `304` is returned.
 
```
POST /projects/:id/merge_requests/:merge_request_id/unsubscribe
POST /projects/:id/merge_requests/:merge_request_iid/unsubscribe
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_id` | integer | yes | The ID of the merge request |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_iid` | integer | yes | The internal ID of the merge request |
 
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/17/unsubscribe
Loading
Loading
@@ -814,13 +814,13 @@ If there already exists a todo for the user on that merge request,
status code `304` is returned.
 
```
POST /projects/:id/merge_requests/:merge_request_id/todo
POST /projects/:id/merge_requests/:merge_request_iid/todo
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_id` | integer | yes | The ID of the merge request |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_iid` | integer | yes | The internal ID of the merge request |
 
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/27/todo
Loading
Loading
@@ -914,13 +914,13 @@ Example response:
Get a list of merge request diff versions.
 
```
GET /projects/:id/merge_requests/:merge_request_id/versions
GET /projects/:id/merge_requests/:merge_request_iid/versions
```
 
| Attribute | Type | Required | Description |
| --------- | ------- | -------- | --------------------- |
| `id` | String | yes | The ID of the project |
| `merge_request_id` | integer | yes | The ID of the merge request |
| Attribute | Type | Required | Description |
| --------- | ------- | -------- | --------------------- |
| `id` | String | yes | The ID of the project |
| `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/1/merge_requests/1/versions
Loading
Loading
@@ -955,14 +955,14 @@ Example response:
Get a single merge request diff version.
 
```
GET /projects/:id/merge_requests/:merge_request_id/versions/:version_id
GET /projects/:id/merge_requests/:merge_request_iid/versions/:version_id
```
 
| Attribute | Type | Required | Description |
| --------- | ------- | -------- | --------------------- |
| `id` | String | yes | The ID of the project |
| `merge_request_id` | integer | yes | The ID of the merge request |
| `version_id` | integer | yes | The ID of the merge request diff version |
| Attribute | Type | Required | Description |
| --------- | ------- | -------- | --------------------- |
| `id` | String | yes | The ID of the project |
| `merge_request_iid` | integer | yes | The internal ID of the merge request |
| `version_id` | integer | yes | The ID of the merge request diff version |
 
```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/merge_requests/1/versions/1
Loading
Loading
@@ -1022,14 +1022,14 @@ Example response:
Sets an estimated time of work for this merge request.
 
```
POST /projects/:id/merge_requests/:merge_request_id/time_estimate
POST /projects/:id/merge_requests/:merge_request_iid/time_estimate
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_id` | integer | yes | The ID of a project's merge request |
| `duration` | string | yes | The duration in human format. e.g: 3h30m |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_iid` | integer | yes | The internal ID of the merge request |
| `duration` | string | yes | The duration in human format. e.g: 3h30m |
 
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/93/time_estimate?duration=3h30m
Loading
Loading
@@ -1051,13 +1051,13 @@ Example response:
Resets the estimated time for this merge request to 0 seconds.
 
```
POST /projects/:id/merge_requests/:merge_request_id/reset_time_estimate
POST /projects/:id/merge_requests/:merge_request_iid/reset_time_estimate
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_id` | integer | yes | The ID of a project's merge_request |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_iid` | integer | yes | The internal ID of a project's merge_request |
 
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/93/reset_time_estimate
Loading
Loading
@@ -1079,14 +1079,14 @@ Example response:
Adds spent time for this merge request
 
```
POST /projects/:id/merge_requests/:merge_request_id/add_spent_time
POST /projects/:id/merge_requests/:merge_request_iid/add_spent_time
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_id` | integer | yes | The ID of a project's merge request |
| `duration` | string | yes | The duration in human format. e.g: 3h30m |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_iid` | integer | yes | The internal ID of the merge request |
| `duration` | string | yes | The duration in human format. e.g: 3h30m |
 
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/93/add_spent_time?duration=1h
Loading
Loading
@@ -1108,13 +1108,13 @@ Example response:
Resets the total spent time for this merge request to 0 seconds.
 
```
POST /projects/:id/merge_requests/:merge_request_id/reset_spent_time
POST /projects/:id/merge_requests/:merge_request_iid/reset_spent_time
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_id` | integer | yes | The ID of a project's merge_request |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_iid` | integer | yes | The internal ID of a project's merge_request |
 
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/93/reset_spent_time
Loading
Loading
@@ -1134,13 +1134,13 @@ Example response:
## Get time tracking stats
 
```
GET /projects/:id/merge_requests/:merge_request_id/time_stats
GET /projects/:id/merge_requests/:merge_request_iid/time_stats
```
 
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_id` | integer | yes | The ID of a project's merge request |
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `merge_request_iid` | integer | yes | The internal ID of the merge request |
 
```bash
curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/93/time_stats
Loading
Loading
Loading
Loading
@@ -69,4 +69,5 @@ changes are in V4:
- `POST /projects/:id/trigger/builds` to `POST /projects/:id/trigger/pipeline`
- Require description when creating a new trigger `POST /projects/:id/triggers`
- Simplify project payload exposed on Environment endpoints [!9675](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9675)
- API uses merge request `IID`s (internal ID, as in the web UI) rather than `ID`s. This affects the merge requests, award emoji, todos, and time tracking APIs. [!9530](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9530)
- API uses issue `IID`s (internal ID, as in the web UI) rather than `ID`s. This affects the issues, award emoji, todos, and time tracking APIs. [!9530](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9530)
Loading
Loading
@@ -5,6 +5,8 @@ module API
version %w(v3 v4), using: :path
 
version 'v3', using: :path do
helpers ::API::V3::Helpers
mount ::API::V3::AwardEmoji
mount ::API::V3::Boards
mount ::API::V3::Branches
Loading
Loading
Loading
Loading
@@ -3,12 +3,16 @@ module API
include PaginationParams
 
before { authenticate! }
AWARDABLES = %w[issue merge_request snippet].freeze
AWARDABLES = [
{ type: 'issue', find_by: :iid },
{ type: 'merge_request', find_by: :iid },
{ type: 'snippet', find_by: :id }
].freeze
 
resource :projects do
AWARDABLES.each do |awardable_type|
awardable_string = awardable_type.pluralize
awardable_id_string = "#{awardable_type}_id"
AWARDABLES.each do |awardable_params|
awardable_string = awardable_params[:type].pluralize
awardable_id_string = "#{awardable_params[:type]}_#{awardable_params[:find_by]}"
 
params do
requires :id, type: String, desc: 'The ID of a project'
Loading
Loading
@@ -104,10 +108,10 @@ module API
note_id = params.delete(:note_id)
 
awardable.notes.find(note_id)
elsif params.include?(:issue_id)
user_project.issues.find(params[:issue_id])
elsif params.include?(:merge_request_id)
user_project.merge_requests.find(params[:merge_request_id])
elsif params.include?(:issue_iid)
user_project.issues.find_by!(iid: params[:issue_iid])
elsif params.include?(:merge_request_iid)
user_project.merge_requests.find_by!(iid: params[:merge_request_iid])
else
user_project.snippets.find(params[:snippet_id])
end
Loading
Loading
Loading
Loading
@@ -82,16 +82,16 @@ module API
label || not_found!('Label')
end
 
def find_project_issue(id)
IssuesFinder.new(current_user, project_id: user_project.id).find(id)
def find_project_issue(iid)
IssuesFinder.new(current_user, project_id: user_project.id).find_by!(iid: iid)
end
 
def find_project_merge_request(id)
MergeRequestsFinder.new(current_user, project_id: user_project.id).find(id)
def find_project_merge_request(iid)
MergeRequestsFinder.new(current_user, project_id: user_project.id).find_by!(iid: iid)
end
 
def find_merge_request_with_access(id, access_level = :read_merge_request)
merge_request = user_project.merge_requests.find(id)
def find_merge_request_with_access(iid, access_level = :read_merge_request)
merge_request = user_project.merge_requests.find_by!(iid: iid)
authorize! access_level, merge_request
merge_request
end
Loading
Loading
Loading
Loading
@@ -102,10 +102,10 @@ module API
success Entities::Issue
end
params do
requires :issue_id, type: Integer, desc: 'The ID of a project issue'
requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue'
end
get ":id/issues/:issue_id" do
issue = find_project_issue(params[:issue_id])
get ":id/issues/:issue_iid" do
issue = find_project_issue(params[:issue_iid])
present issue, with: Entities::Issue, current_user: current_user, project: user_project
end
 
Loading
Loading
@@ -152,7 +152,7 @@ module API
success Entities::Issue
end
params do
requires :issue_id, type: Integer, desc: 'The ID of a project issue'
requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue'
optional :title, type: String, desc: 'The title of an issue'
optional :updated_at, type: DateTime,
desc: 'Date time when the issue was updated. Available only for admins and project owners.'
Loading
Loading
@@ -161,8 +161,8 @@ module API
at_least_one_of :title, :description, :assignee_id, :milestone_id,
:labels, :created_at, :due_date, :confidential, :state_event
end
put ':id/issues/:issue_id' do
issue = user_project.issues.find(params.delete(:issue_id))
put ':id/issues/:issue_iid' do
issue = user_project.issues.find_by!(iid: params.delete(:issue_iid))
authorize! :update_issue, issue
 
# Setting created_at time only allowed for admins and project owners
Loading
Loading
@@ -189,11 +189,11 @@ module API
success Entities::Issue
end
params do
requires :issue_id, type: Integer, desc: 'The ID of a project issue'
requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue'
requires :to_project_id, type: Integer, desc: 'The ID of the new project'
end
post ':id/issues/:issue_id/move' do
issue = user_project.issues.find_by(id: params[:issue_id])
post ':id/issues/:issue_iid/move' do
issue = user_project.issues.find_by(iid: params[:issue_iid])
not_found!('Issue') unless issue
 
new_project = Project.find_by(id: params[:to_project_id])
Loading
Loading
@@ -209,10 +209,10 @@ module API
 
desc 'Delete a project issue'
params do
requires :issue_id, type: Integer, desc: 'The ID of a project issue'
requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue'
end
delete ":id/issues/:issue_id" do
issue = user_project.issues.find_by(id: params[:issue_id])
delete ":id/issues/:issue_iid" do
issue = user_project.issues.find_by(iid: params[:issue_iid])
not_found!('Issue') unless issue
 
authorize!(:destroy_issue, issue)
Loading
Loading
Loading
Loading
@@ -13,11 +13,11 @@ module API
 
params do
requires :id, type: String, desc: 'The ID of a project'
requires :merge_request_id, type: Integer, desc: 'The ID of a merge request'
requires :merge_request_iid, type: Integer, desc: 'The IID of a merge request'
use :pagination
end
get ":id/merge_requests/:merge_request_id/versions" do
merge_request = find_merge_request_with_access(params[:merge_request_id])
get ":id/merge_requests/:merge_request_iid/versions" do
merge_request = find_merge_request_with_access(params[:merge_request_iid])
 
present paginate(merge_request.merge_request_diffs), with: Entities::MergeRequestDiff
end
Loading
Loading
@@ -29,12 +29,12 @@ module API
 
params do
requires :id, type: String, desc: 'The ID of a project'
requires :merge_request_id, type: Integer, desc: 'The ID of a merge request'
requires :merge_request_iid, type: Integer, desc: 'The IID of a merge request'
requires :version_id, type: Integer, desc: 'The ID of a merge request diff version'
end
 
get ":id/merge_requests/:merge_request_id/versions/:version_id" do
merge_request = find_merge_request_with_access(params[:merge_request_id])
get ":id/merge_requests/:merge_request_iid/versions/:version_id" do
merge_request = find_merge_request_with_access(params[:merge_request_iid])
 
present merge_request.merge_request_diffs.find(params[:version_id]), with: Entities::MergeRequestDiffFull
end
Loading
Loading
Loading
Loading
@@ -101,23 +101,23 @@ module API
 
desc 'Delete a merge request'
params do
requires :merge_request_id, type: Integer, desc: 'The ID of a merge request'
requires :merge_request_iid, type: Integer, desc: 'The IID of a merge request'
end
delete ":id/merge_requests/:merge_request_id" do
merge_request = find_project_merge_request(params[:merge_request_id])
delete ":id/merge_requests/:merge_request_iid" do
merge_request = find_project_merge_request(params[:merge_request_iid])
 
authorize!(:destroy_merge_request, merge_request)
merge_request.destroy
end
 
params do
requires :merge_request_id, type: Integer, desc: 'The ID of a merge request'
requires :merge_request_iid, type: Integer, desc: 'The IID of a merge request'
end
desc 'Get a single merge request' do
success Entities::MergeRequest
end
get ':id/merge_requests/:merge_request_id' do
merge_request = find_merge_request_with_access(params[:merge_request_id])
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
end
Loading
Loading
@@ -125,8 +125,8 @@ module API
desc 'Get the commits of a merge request' do
success Entities::RepoCommit
end
get ':id/merge_requests/:merge_request_id/commits' do
merge_request = find_merge_request_with_access(params[:merge_request_id])
get ':id/merge_requests/:merge_request_iid/commits' do
merge_request = find_merge_request_with_access(params[:merge_request_iid])
commits = ::Kaminari.paginate_array(merge_request.commits)
 
present paginate(commits), with: Entities::RepoCommit
Loading
Loading
@@ -135,8 +135,8 @@ module API
desc 'Show the merge request changes' do
success Entities::MergeRequestChanges
end
get ':id/merge_requests/:merge_request_id/changes' do
merge_request = find_merge_request_with_access(params[:merge_request_id])
get ':id/merge_requests/:merge_request_iid/changes' do
merge_request = find_merge_request_with_access(params[:merge_request_iid])
 
present merge_request, with: Entities::MergeRequestChanges, current_user: current_user
end
Loading
Loading
@@ -154,8 +154,8 @@ module API
:milestone_id, :labels, :state_event,
:remove_source_branch
end
put ':id/merge_requests/:merge_request_id' do
merge_request = find_merge_request_with_access(params.delete(:merge_request_id), :update_merge_request)
put ':id/merge_requests/:merge_request_iid' do
merge_request = find_merge_request_with_access(params.delete(:merge_request_iid), :update_merge_request)
 
mr_params = declared_params(include_missing: false)
mr_params[:force_remove_source_branch] = mr_params.delete(:remove_source_branch) if mr_params[:remove_source_branch].present?
Loading
Loading
@@ -180,8 +180,8 @@ module API
desc: 'When true, this merge request will be merged when the pipeline succeeds'
optional :sha, type: String, desc: 'When present, must have the HEAD SHA of the source branch'
end
put ':id/merge_requests/:merge_request_id/merge' do
merge_request = find_project_merge_request(params[:merge_request_id])
put ':id/merge_requests/:merge_request_iid/merge' do
merge_request = find_project_merge_request(params[:merge_request_iid])
 
# Merge request can not be merged
# because user dont have permissions to push into target branch
Loading
Loading
@@ -216,8 +216,8 @@ module API
desc 'Cancel merge if "Merge When Pipeline Succeeds" is enabled' do
success Entities::MergeRequest
end
post ':id/merge_requests/:merge_request_id/cancel_merge_when_pipeline_succeeds' do
merge_request = find_project_merge_request(params[:merge_request_id])
post ':id/merge_requests/:merge_request_iid/cancel_merge_when_pipeline_succeeds' do
merge_request = find_project_merge_request(params[:merge_request_iid])
 
unauthorized! unless merge_request.can_cancel_merge_when_pipeline_succeeds?(current_user)
 
Loading
Loading
@@ -232,8 +232,8 @@ module API
params do
use :pagination
end
get ':id/merge_requests/:merge_request_id/comments' do
merge_request = find_merge_request_with_access(params[:merge_request_id])
get ':id/merge_requests/:merge_request_iid/comments' do
merge_request = find_merge_request_with_access(params[:merge_request_iid])
present paginate(merge_request.notes.fresh), with: Entities::MRNote
end
 
Loading
Loading
@@ -243,8 +243,8 @@ module API
params do
requires :note, type: String, desc: 'The text of the comment'
end
post ':id/merge_requests/:merge_request_id/comments' do
merge_request = find_merge_request_with_access(params[:merge_request_id], :create_note)
post ':id/merge_requests/:merge_request_iid/comments' do
merge_request = find_merge_request_with_access(params[:merge_request_iid], :create_note)
 
opts = {
note: params[:note],
Loading
Loading
@@ -267,8 +267,8 @@ module API
params do
use :pagination
end
get ':id/merge_requests/:merge_request_id/closes_issues' do
merge_request = find_merge_request_with_access(params[:merge_request_id])
get ':id/merge_requests/:merge_request_iid/closes_issues' do
merge_request = find_merge_request_with_access(params[:merge_request_iid])
issues = ::Kaminari.paginate_array(merge_request.closes_issues(current_user))
present paginate(issues), with: issue_entity(user_project), current_user: current_user
end
Loading
Loading
Loading
Loading
@@ -5,11 +5,11 @@ module API
included do
helpers do
def issuable_name
declared_params.has_key?(:issue_id) ? 'issue' : 'merge_request'
declared_params.has_key?(:issue_iid) ? 'issue' : 'merge_request'
end
 
def issuable_key
"#{issuable_name}_id".to_sym
"#{issuable_name}_iid".to_sym
end
 
def update_issuable_key
Loading
Loading
@@ -50,7 +50,7 @@ module API
 
issuable_name = name.end_with?('Issues') ? 'issue' : 'merge_request'
issuable_collection_name = issuable_name.pluralize
issuable_key = "#{issuable_name}_id".to_sym
issuable_key = "#{issuable_name}_iid".to_sym
 
desc "Set a time estimate for a project #{issuable_name}"
params do
Loading
Loading
Loading
Loading
@@ -5,8 +5,8 @@ module API
before { authenticate! }
 
ISSUABLE_TYPES = {
'merge_requests' => ->(id) { find_merge_request_with_access(id) },
'issues' => ->(id) { find_project_issue(id) }
'merge_requests' => ->(iid) { find_merge_request_with_access(iid) },
'issues' => ->(iid) { find_project_issue(iid) }
}.freeze
 
params do
Loading
Loading
@@ -14,13 +14,13 @@ module API
end
resource :projects do
ISSUABLE_TYPES.each do |type, finder|
type_id_str = "#{type.singularize}_id".to_sym
type_id_str = "#{type.singularize}_iid".to_sym
 
desc 'Create a todo on an issuable' do
success Entities::Todo
end
params do
requires type_id_str, type: Integer, desc: 'The ID of an issuable'
requires type_id_str, type: Integer, desc: 'The IID of an issuable'
end
post ":id/#{type}/:#{type_id_str}/todo" do
issuable = instance_exec(params[type_id_str], &finder)
Loading
Loading
Loading
Loading
@@ -16,11 +16,64 @@ module API
requires :"#{awardable_id_string}", type: Integer, desc: "The ID of an Issue, Merge Request or Snippet"
end
 
[":id/#{awardable_string}/:#{awardable_id_string}/award_emoji",
":id/#{awardable_string}/:#{awardable_id_string}/notes/:note_id/award_emoji"].each do |endpoint|
[
":id/#{awardable_string}/:#{awardable_id_string}/award_emoji",
":id/#{awardable_string}/:#{awardable_id_string}/notes/:note_id/award_emoji"
].each do |endpoint|
desc 'Get a list of project +awardable+ award emoji' do
detail 'This feature was introduced in 8.9'
success Entities::AwardEmoji
end
params do
use :pagination
end
get endpoint do
if can_read_awardable?
awards = awardable.award_emoji
present paginate(awards), with: Entities::AwardEmoji
else
not_found!("Award Emoji")
end
end
desc 'Get a specific award emoji' do
detail 'This feature was introduced in 8.9'
success Entities::AwardEmoji
end
params do
requires :award_id, type: Integer, desc: 'The ID of the award'
end
get "#{endpoint}/:award_id" do
if can_read_awardable?
present awardable.award_emoji.find(params[:award_id]), with: Entities::AwardEmoji
else
not_found!("Award Emoji")
end
end
desc 'Award a new Emoji' do
detail 'This feature was introduced in 8.9'
success Entities::AwardEmoji
end
params do
requires :name, type: String, desc: 'The name of a award_emoji (without colons)'
end
post endpoint do
not_found!('Award Emoji') unless can_read_awardable? && can_award_awardable?
award = awardable.create_award_emoji(params[:name], current_user)
if award.persisted?
present award, with: Entities::AwardEmoji
else
not_found!("Award Emoji #{award.errors.messages}")
end
end
desc 'Delete a +awardables+ award emoji' do
detail 'This feature was introduced in 8.9'
success ::API::Entities::AwardEmoji
success Entities::AwardEmoji
end
params do
requires :award_id, type: Integer, desc: 'The ID of an award emoji'
Loading
Loading
@@ -30,13 +83,22 @@ module API
 
unauthorized! unless award.user == current_user || current_user.admin?
 
present award.destroy, with: ::API::Entities::AwardEmoji
award.destroy
present award, with: Entities::AwardEmoji
end
end
end
end
 
helpers do
def can_read_awardable?
can?(current_user, read_ability(awardable), awardable)
end
def can_award_awardable?
awardable.user_can_award?(current_user, params[:name])
end
def awardable
@awardable ||=
begin
Loading
Loading
@@ -53,6 +115,15 @@ module API
end
end
end
def read_ability(awardable)
case awardable
when Note
read_ability(awardable.noteable)
else
:"read_#{awardable.class.to_s.underscore}"
end
end
end
end
end
Loading
Loading
module API
module V3
module Helpers
def find_project_issue(id)
IssuesFinder.new(current_user, project_id: user_project.id).find(id)
end
def find_project_merge_request(id)
MergeRequestsFinder.new(current_user, project_id: user_project.id).find(id)
end
def find_merge_request_with_access(id, access_level = :read_merge_request)
merge_request = user_project.merge_requests.find(id)
authorize! access_level, merge_request
merge_request
end
end
end
end
module API
module V3
module TimeTrackingEndpoints
extend ActiveSupport::Concern
included do
helpers do
def issuable_name
declared_params.has_key?(:issue_id) ? 'issue' : 'merge_request'
end
def issuable_key
"#{issuable_name}_id".to_sym
end
def update_issuable_key
"update_#{issuable_name}".to_sym
end
def read_issuable_key
"read_#{issuable_name}".to_sym
end
def load_issuable
@issuable ||= begin
case issuable_name
when 'issue'
find_project_issue(params.delete(issuable_key))
when 'merge_request'
find_project_merge_request(params.delete(issuable_key))
end
end
end
def update_issuable(attrs)
custom_params = declared_params(include_missing: false)
custom_params.merge!(attrs)
issuable = update_service.new(user_project, current_user, custom_params).execute(load_issuable)
if issuable.valid?
present issuable, with: ::API::Entities::IssuableTimeStats
else
render_validation_error!(issuable)
end
end
def update_service
issuable_name == 'issue' ? ::Issues::UpdateService : ::MergeRequests::UpdateService
end
end
issuable_name = name.end_with?('Issues') ? 'issue' : 'merge_request'
issuable_collection_name = issuable_name.pluralize
issuable_key = "#{issuable_name}_id".to_sym
desc "Set a time estimate for a project #{issuable_name}"
params do
requires issuable_key, type: Integer, desc: "The ID of a project #{issuable_name}"
requires :duration, type: String, desc: 'The duration to be parsed'
end
post ":id/#{issuable_collection_name}/:#{issuable_key}/time_estimate" do
authorize! update_issuable_key, load_issuable
status :ok
update_issuable(time_estimate: Gitlab::TimeTrackingFormatter.parse(params.delete(:duration)))
end
desc "Reset the time estimate for a project #{issuable_name}"
params do
requires issuable_key, type: Integer, desc: "The ID of a project #{issuable_name}"
end
post ":id/#{issuable_collection_name}/:#{issuable_key}/reset_time_estimate" do
authorize! update_issuable_key, load_issuable
status :ok
update_issuable(time_estimate: 0)
end
desc "Add spent time for a project #{issuable_name}"
params do
requires issuable_key, type: Integer, desc: "The ID of a project #{issuable_name}"
requires :duration, type: String, desc: 'The duration to be parsed'
end
post ":id/#{issuable_collection_name}/:#{issuable_key}/add_spent_time" do
authorize! update_issuable_key, load_issuable
update_issuable(spend_time: {
duration: Gitlab::TimeTrackingFormatter.parse(params.delete(:duration)),
user: current_user
})
end
desc "Reset spent time for a project #{issuable_name}"
params do
requires issuable_key, type: Integer, desc: "The ID of a project #{issuable_name}"
end
post ":id/#{issuable_collection_name}/:#{issuable_key}/reset_spent_time" do
authorize! update_issuable_key, load_issuable
status :ok
update_issuable(spend_time: { duration: :reset, user: current_user })
end
desc "Show time stats for a project #{issuable_name}"
params do
requires issuable_key, type: Integer, desc: "The ID of a project #{issuable_name}"
end
get ":id/#{issuable_collection_name}/:#{issuable_key}/time_stats" do
authorize! read_issuable_key, load_issuable
present load_issuable, with: ::API::Entities::IssuableTimeStats
end
end
end
end
end
Loading
Loading
@@ -15,7 +15,7 @@ describe API::AwardEmoji, api: true do
describe "GET /projects/:id/awardable/:awardable_id/award_emoji" do
context 'on an issue' do
it "returns an array of award_emoji" do
get api("/projects/#{project.id}/issues/#{issue.id}/award_emoji", user)
get api("/projects/#{project.id}/issues/#{issue.iid}/award_emoji", user)
 
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
Loading
Loading
@@ -31,7 +31,7 @@ describe API::AwardEmoji, api: true do
 
context 'on a merge request' do
it "returns an array of award_emoji" do
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/award_emoji", user)
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/award_emoji", user)
 
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
Loading
Loading
@@ -57,7 +57,7 @@ describe API::AwardEmoji, api: true do
it 'returns a status code 404' do
user1 = create(:user)
 
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/award_emoji", user1)
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/award_emoji", user1)
 
expect(response).to have_http_status(404)
end
Loading
Loading
@@ -68,7 +68,7 @@ describe API::AwardEmoji, api: true do
let!(:rocket) { create(:award_emoji, awardable: note, name: 'rocket') }
 
it 'returns an array of award emoji' do
get api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji", user)
get api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{note.id}/award_emoji", user)
 
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
Loading
Loading
@@ -79,7 +79,7 @@ describe API::AwardEmoji, api: true do
describe "GET /projects/:id/awardable/:awardable_id/award_emoji/:award_id" do
context 'on an issue' do
it "returns the award emoji" do
get api("/projects/#{project.id}/issues/#{issue.id}/award_emoji/#{award_emoji.id}", user)
get api("/projects/#{project.id}/issues/#{issue.iid}/award_emoji/#{award_emoji.id}", user)
 
expect(response).to have_http_status(200)
expect(json_response['name']).to eq(award_emoji.name)
Loading
Loading
@@ -88,7 +88,7 @@ describe API::AwardEmoji, api: true do
end
 
it "returns a 404 error if the award is not found" do
get api("/projects/#{project.id}/issues/#{issue.id}/award_emoji/12345", user)
get api("/projects/#{project.id}/issues/#{issue.iid}/award_emoji/12345", user)
 
expect(response).to have_http_status(404)
end
Loading
Loading
@@ -96,7 +96,7 @@ describe API::AwardEmoji, api: true do
 
context 'on a merge request' do
it 'returns the award emoji' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/award_emoji/#{downvote.id}", user)
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/award_emoji/#{downvote.id}", user)
 
expect(response).to have_http_status(200)
expect(json_response['name']).to eq(downvote.name)
Loading
Loading
@@ -123,7 +123,7 @@ describe API::AwardEmoji, api: true do
it 'returns a status code 404' do
user1 = create(:user)
 
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/award_emoji/#{downvote.id}", user1)
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/award_emoji/#{downvote.id}", user1)
 
expect(response).to have_http_status(404)
end
Loading
Loading
@@ -134,7 +134,7 @@ describe API::AwardEmoji, api: true do
let!(:rocket) { create(:award_emoji, awardable: note, name: 'rocket') }
 
it 'returns an award emoji' do
get api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji/#{rocket.id}", user)
get api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{note.id}/award_emoji/#{rocket.id}", user)
 
expect(response).to have_http_status(200)
expect(json_response).not_to be_an Array
Loading
Loading
@@ -147,7 +147,7 @@ describe API::AwardEmoji, api: true do
 
context "on an issue" do
it "creates a new award emoji" do
post api("/projects/#{project.id}/issues/#{issue.id}/award_emoji", user), name: 'blowfish'
post api("/projects/#{project.id}/issues/#{issue.iid}/award_emoji", user), name: 'blowfish'
 
expect(response).to have_http_status(201)
expect(json_response['name']).to eq('blowfish')
Loading
Loading
@@ -155,13 +155,13 @@ describe API::AwardEmoji, api: true do
end
 
it "returns a 400 bad request error if the name is not given" do
post api("/projects/#{project.id}/issues/#{issue.id}/award_emoji", user)
post api("/projects/#{project.id}/issues/#{issue.iid}/award_emoji", user)
 
expect(response).to have_http_status(400)
end
 
it "returns a 401 unauthorized error if the user is not authenticated" do
post api("/projects/#{project.id}/issues/#{issue.id}/award_emoji"), name: 'thumbsup'
post api("/projects/#{project.id}/issues/#{issue.iid}/award_emoji"), name: 'thumbsup'
 
expect(response).to have_http_status(401)
end
Loading
Loading
@@ -173,15 +173,15 @@ describe API::AwardEmoji, api: true do
end
 
it "normalizes +1 as thumbsup award" do
post api("/projects/#{project.id}/issues/#{issue.id}/award_emoji", user), name: '+1'
post api("/projects/#{project.id}/issues/#{issue.iid}/award_emoji", user), name: '+1'
 
expect(issue.award_emoji.last.name).to eq("thumbsup")
end
 
context 'when the emoji already has been awarded' do
it 'returns a 404 status code' do
post api("/projects/#{project.id}/issues/#{issue.id}/award_emoji", user), name: 'thumbsup'
post api("/projects/#{project.id}/issues/#{issue.id}/award_emoji", user), name: 'thumbsup'
post api("/projects/#{project.id}/issues/#{issue.iid}/award_emoji", user), name: 'thumbsup'
post api("/projects/#{project.id}/issues/#{issue.iid}/award_emoji", user), name: 'thumbsup'
 
expect(response).to have_http_status(404)
expect(json_response["message"]).to match("has already been taken")
Loading
Loading
@@ -207,7 +207,7 @@ describe API::AwardEmoji, api: true do
 
it 'creates a new award emoji' do
expect do
post api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji", user), name: 'rocket'
post api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{note.id}/award_emoji", user), name: 'rocket'
end.to change { note.award_emoji.count }.from(0).to(1)
 
expect(response).to have_http_status(201)
Loading
Loading
@@ -215,21 +215,21 @@ describe API::AwardEmoji, api: true do
end
 
it "it returns 404 error when user authored note" do
post api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note2.id}/award_emoji", user), name: 'thumbsup'
post api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{note2.id}/award_emoji", user), name: 'thumbsup'
 
expect(response).to have_http_status(404)
end
 
it "normalizes +1 as thumbsup award" do
post api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji", user), name: '+1'
post api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{note.id}/award_emoji", user), name: '+1'
 
expect(note.award_emoji.last.name).to eq("thumbsup")
end
 
context 'when the emoji already has been awarded' do
it 'returns a 404 status code' do
post api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji", user), name: 'rocket'
post api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji", user), name: 'rocket'
post api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{note.id}/award_emoji", user), name: 'rocket'
post api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{note.id}/award_emoji", user), name: 'rocket'
 
expect(response).to have_http_status(404)
expect(json_response["message"]).to match("has already been taken")
Loading
Loading
@@ -241,14 +241,14 @@ describe API::AwardEmoji, api: true do
context 'when the awardable is an Issue' do
it 'deletes the award' do
expect do
delete api("/projects/#{project.id}/issues/#{issue.id}/award_emoji/#{award_emoji.id}", user)
delete api("/projects/#{project.id}/issues/#{issue.iid}/award_emoji/#{award_emoji.id}", user)
 
expect(response).to have_http_status(204)
end.to change { issue.award_emoji.count }.from(1).to(0)
end
 
it 'returns a 404 error when the award emoji can not be found' do
delete api("/projects/#{project.id}/issues/#{issue.id}/award_emoji/12345", user)
delete api("/projects/#{project.id}/issues/#{issue.iid}/award_emoji/12345", user)
 
expect(response).to have_http_status(404)
end
Loading
Loading
@@ -257,14 +257,14 @@ describe API::AwardEmoji, api: true do
context 'when the awardable is a Merge Request' do
it 'deletes the award' do
expect do
delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}/award_emoji/#{downvote.id}", user)
delete api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/award_emoji/#{downvote.id}", user)
 
expect(response).to have_http_status(204)
end.to change { merge_request.award_emoji.count }.from(1).to(0)
end
 
it 'returns a 404 error when note id not found' do
delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}/notes/12345", user)
delete api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes/12345", user)
 
expect(response).to have_http_status(404)
end
Loading
Loading
@@ -289,7 +289,7 @@ describe API::AwardEmoji, api: true do
 
it 'deletes the award' do
expect do
delete api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji/#{rocket.id}", user)
delete api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{note.id}/award_emoji/#{rocket.id}", user)
 
expect(response).to have_http_status(204)
end.to change { note.award_emoji.count }.from(1).to(0)
Loading
Loading
This diff is collapsed.
Loading
Loading
@@ -13,9 +13,9 @@ describe API::MergeRequestDiffs, 'MergeRequestDiffs', api: true do
project.team << [user, :master]
end
 
describe 'GET /projects/:id/merge_requests/:merge_request_id/versions' do
describe 'GET /projects/:id/merge_requests/:merge_request_iid/versions' do
it 'returns 200 for a valid merge request' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions", user)
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/versions", user)
merge_request_diff = merge_request.merge_request_diffs.first
 
expect(response.status).to eq 200
Loading
Loading
@@ -26,16 +26,22 @@ describe API::MergeRequestDiffs, 'MergeRequestDiffs', api: true do
expect(json_response.first['head_commit_sha']).to eq(merge_request_diff.head_commit_sha)
end
 
it 'returns a 404 when merge_request_id not found' do
it 'returns a 404 when merge_request id is used instead of the iid' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions", user)
expect(response).to have_http_status(404)
end
it 'returns a 404 when merge_request_iid not found' do
get api("/projects/#{project.id}/merge_requests/999/versions", user)
expect(response).to have_http_status(404)
end
end
 
describe 'GET /projects/:id/merge_requests/:merge_request_id/versions/:version_id' do
describe 'GET /projects/:id/merge_requests/:merge_request_iid/versions/:version_id' do
let(:merge_request_diff) { merge_request.merge_request_diffs.first }
it 'returns a 200 for a valid merge request' do
merge_request_diff = merge_request.merge_request_diffs.first
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions/#{merge_request_diff.id}", user)
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/versions/#{merge_request_diff.id}", user)
 
expect(response.status).to eq 200
expect(json_response['id']).to eq(merge_request_diff.id)
Loading
Loading
@@ -43,8 +49,18 @@ describe API::MergeRequestDiffs, 'MergeRequestDiffs', api: true do
expect(json_response['diffs'].size).to eq(merge_request_diff.diffs.size)
end
 
it 'returns a 404 when merge_request_id not found' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions/999", user)
it 'returns a 404 when merge_request id is used instead of the iid' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions/#{merge_request_diff.id}", user)
expect(response).to have_http_status(404)
end
it 'returns a 404 when merge_request version_id is not found' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/versions/999", user)
expect(response).to have_http_status(404)
end
it 'returns a 404 when merge_request_iid is not found' do
get api("/projects/#{project.id}/merge_requests/12345/versions/#{merge_request_diff.id}", user)
expect(response).to have_http_status(404)
end
end
Loading
Loading
This diff is collapsed.
Loading
Loading
@@ -163,7 +163,7 @@ describe API::Todos, api: true do
 
shared_examples 'an issuable' do |issuable_type|
it 'creates a todo on an issuable' do
post api("/projects/#{project_1.id}/#{issuable_type}/#{issuable.id}/todo", john_doe)
post api("/projects/#{project_1.id}/#{issuable_type}/#{issuable.iid}/todo", john_doe)
 
expect(response.status).to eq(201)
expect(json_response['project']).to be_a Hash
Loading
Loading
@@ -180,7 +180,7 @@ describe API::Todos, api: true do
it 'returns 304 there already exist a todo on that issuable' do
create(:todo, project: project_1, author: author_1, user: john_doe, target: issuable)
 
post api("/projects/#{project_1.id}/#{issuable_type}/#{issuable.id}/todo", john_doe)
post api("/projects/#{project_1.id}/#{issuable_type}/#{issuable.iid}/todo", john_doe)
 
expect(response.status).to eq(304)
end
Loading
Loading
@@ -195,7 +195,7 @@ describe API::Todos, api: true do
guest = create(:user)
project_1.team << [guest, :guest]
 
post api("/projects/#{project_1.id}/#{issuable_type}/#{issuable.id}/todo", guest)
post api("/projects/#{project_1.id}/#{issuable_type}/#{issuable.iid}/todo", guest)
 
if issuable_type == 'merge_requests'
expect(response).to have_http_status(403)
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment