Skip to content
Snippets Groups Projects
Commit 240a4aa6 authored by Rémy Coutable's avatar Rémy Coutable
Browse files

Merge branch 'api-isssues-due-date' into 'master'

API: Expose due_date for issues

## What does this MR do?

Add support for the `due_date` of issues to the API.

## What are the relevant issue numbers?

Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/18696

## Does this MR meet the acceptance criteria?

- [x] [CHANGELOG](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CHANGELOG) entry added
- [x] [Documentation created/updated](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/doc_styleguide.md)
- [x] API support added
- Tests
  - [x] Added for this feature/bug
  - [x] All builds are passing
- [x] Conform by the [style guides](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#style-guides)
- [x] Branch has no merge conflicts with `master` (if you do - rebase it please)
- [x] [Squashed related commits together](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)

See merge request !5212
parents f1083ba1 e7d9fcc1
Branches
Tags
1 merge request!5212API: Expose due_date for issues
Pipeline #
Loading
@@ -48,6 +48,7 @@ v 8.10.0 (unreleased)
Loading
@@ -48,6 +48,7 @@ v 8.10.0 (unreleased)
- Render inline diffs for multiple changed lines following eachother - Render inline diffs for multiple changed lines following eachother
- Wildcards for protected branches. !4665 - Wildcards for protected branches. !4665
- Allow importing from Github using Personal Access Tokens. (Eric K Idema) - Allow importing from Github using Personal Access Tokens. (Eric K Idema)
- API: Expose `due_date` for issues (Robert Schilling)
- API: Todos !3188 (Robert Schilling) - API: Todos !3188 (Robert Schilling)
- API: Expose shared groups for projects and shared projects for groups !5050 (Robert Schilling) - API: Expose shared groups for projects and shared projects for groups !5050 (Robert Schilling)
- Add "Enabled Git access protocols" to Application Settings - Add "Enabled Git access protocols" to Application Settings
Loading
Loading
Loading
@@ -78,7 +78,8 @@ Example response:
Loading
@@ -78,7 +78,8 @@ Example response:
"iid" : 6, "iid" : 6,
"labels" : [], "labels" : [],
"subscribed" : false, "subscribed" : false,
"user_notes_count": 1 "user_notes_count": 1,
"due_date": "2016-07-22"
} }
] ]
``` ```
Loading
@@ -154,7 +155,8 @@ Example response:
Loading
@@ -154,7 +155,8 @@ Example response:
"updated_at" : "2016-01-04T15:31:46.176Z", "updated_at" : "2016-01-04T15:31:46.176Z",
"created_at" : "2016-01-04T15:31:46.176Z", "created_at" : "2016-01-04T15:31:46.176Z",
"subscribed" : false, "subscribed" : false,
"user_notes_count": 1 "user_notes_count": 1,
"due_date": null
} }
] ]
``` ```
Loading
@@ -232,7 +234,8 @@ Example response:
Loading
@@ -232,7 +234,8 @@ Example response:
"updated_at" : "2016-01-04T15:31:46.176Z", "updated_at" : "2016-01-04T15:31:46.176Z",
"created_at" : "2016-01-04T15:31:46.176Z", "created_at" : "2016-01-04T15:31:46.176Z",
"subscribed" : false, "subscribed" : false,
"user_notes_count": 1 "user_notes_count": 1,
"due_date": "2016-07-22"
} }
] ]
``` ```
Loading
@@ -295,7 +298,8 @@ Example response:
Loading
@@ -295,7 +298,8 @@ Example response:
"updated_at" : "2016-01-04T15:31:46.176Z", "updated_at" : "2016-01-04T15:31:46.176Z",
"created_at" : "2016-01-04T15:31:46.176Z", "created_at" : "2016-01-04T15:31:46.176Z",
"subscribed": false, "subscribed": false,
"user_notes_count": 1 "user_notes_count": 1,
"due_date": null
} }
``` ```
   
Loading
@@ -320,6 +324,7 @@ POST /projects/:id/issues
Loading
@@ -320,6 +324,7 @@ POST /projects/:id/issues
| `milestone_id` | integer | no | The ID of a milestone to assign issue | | `milestone_id` | integer | no | The ID of a milestone to assign issue |
| `labels` | string | no | Comma-separated label names for an issue | | `labels` | string | no | Comma-separated label names for an issue |
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` | | `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` |
| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
   
```bash ```bash
curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues?title=Issues%20with%20auth&labels=bug curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues?title=Issues%20with%20auth&labels=bug
Loading
@@ -351,7 +356,8 @@ Example response:
Loading
@@ -351,7 +356,8 @@ Example response:
"updated_at" : "2016-01-07T12:44:33.959Z", "updated_at" : "2016-01-07T12:44:33.959Z",
"milestone" : null, "milestone" : null,
"subscribed" : true, "subscribed" : true,
"user_notes_count": 0 "user_notes_count": 0,
"due_date": null
} }
``` ```
   
Loading
@@ -379,6 +385,7 @@ PUT /projects/:id/issues/:issue_id
Loading
@@ -379,6 +385,7 @@ PUT /projects/:id/issues/:issue_id
| `labels` | string | no | Comma-separated label names for an issue | | `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 | | `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` | | `updated_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` |
| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
   
```bash ```bash
curl -X PUT -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues/85?state_event=close curl -X PUT -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues/85?state_event=close
Loading
@@ -410,7 +417,8 @@ Example response:
Loading
@@ -410,7 +417,8 @@ Example response:
"assignee" : null, "assignee" : null,
"milestone" : null, "milestone" : null,
"subscribed" : true, "subscribed" : true,
"user_notes_count": 0 "user_notes_count": 0,
"due_date": "2016-07-22"
} }
``` ```
   
Loading
@@ -487,7 +495,8 @@ Example response:
Loading
@@ -487,7 +495,8 @@ Example response:
"state": "active", "state": "active",
"avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon", "avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon",
"web_url": "https://gitlab.example.com/u/solon.cremin" "web_url": "https://gitlab.example.com/u/solon.cremin"
} },
"due_date": null
} }
``` ```
   
Loading
@@ -541,7 +550,8 @@ Example response:
Loading
@@ -541,7 +550,8 @@ Example response:
"state": "active", "state": "active",
"avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon", "avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon",
"web_url": "https://gitlab.example.com/u/solon.cremin" "web_url": "https://gitlab.example.com/u/solon.cremin"
} },
"due_date": null
} }
``` ```
   
Loading
@@ -596,7 +606,8 @@ Example response:
Loading
@@ -596,7 +606,8 @@ Example response:
"avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon", "avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
"web_url": "https://gitlab.example.com/u/orville" "web_url": "https://gitlab.example.com/u/orville"
}, },
"subscribed": false "subscribed": false,
"due_date": null
} }
``` ```
   
Loading
Loading
Loading
@@ -187,6 +187,7 @@ module API
Loading
@@ -187,6 +187,7 @@ module API
end end
expose :user_notes_count expose :user_notes_count
expose :upvotes, :downvotes expose :upvotes, :downvotes
expose :due_date
end end
   
class ExternalIssue < Grape::Entity class ExternalIssue < Grape::Entity
Loading
Loading
Loading
@@ -152,12 +152,13 @@ module API
Loading
@@ -152,12 +152,13 @@ module API
# milestone_id (optional) - The ID of a milestone to assign issue # milestone_id (optional) - The ID of a milestone to assign issue
# labels (optional) - The labels of an issue # labels (optional) - The labels of an issue
# created_at (optional) - Date time string, ISO 8601 formatted # created_at (optional) - Date time string, ISO 8601 formatted
# due_date (optional) - Date time string in the format YEAR-MONTH-DAY
# Example Request: # Example Request:
# POST /projects/:id/issues # POST /projects/:id/issues
post ":id/issues" do post ':id/issues' do
required_attributes! [:title] required_attributes! [:title]
   
keys = [:title, :description, :assignee_id, :milestone_id] keys = [:title, :description, :assignee_id, :milestone_id, :due_date]
keys << :created_at if current_user.admin? || user_project.owner == current_user keys << :created_at if current_user.admin? || user_project.owner == current_user
attrs = attributes_for_keys(keys) attrs = attributes_for_keys(keys)
   
Loading
@@ -201,12 +202,13 @@ module API
Loading
@@ -201,12 +202,13 @@ module API
# labels (optional) - The labels of an issue # labels (optional) - The labels of an issue
# state_event (optional) - The state event of an issue (close|reopen) # state_event (optional) - The state event of an issue (close|reopen)
# updated_at (optional) - Date time string, ISO 8601 formatted # updated_at (optional) - Date time string, ISO 8601 formatted
# due_date (optional) - Date time string in the format YEAR-MONTH-DAY
# Example Request: # Example Request:
# PUT /projects/:id/issues/:issue_id # PUT /projects/:id/issues/:issue_id
put ":id/issues/:issue_id" do put ':id/issues/:issue_id' do
issue = user_project.issues.find(params[:issue_id]) issue = user_project.issues.find(params[:issue_id])
authorize! :update_issue, issue authorize! :update_issue, issue
keys = [:title, :description, :assignee_id, :milestone_id, :state_event] keys = [:title, :description, :assignee_id, :milestone_id, :state_event, :due_date]
keys << :updated_at if current_user.admin? || user_project.owner == current_user keys << :updated_at if current_user.admin? || user_project.owner == current_user
attrs = attributes_for_keys(keys) attrs = attributes_for_keys(keys)
   
Loading
Loading
Loading
@@ -503,6 +503,20 @@ describe API::API, api: true do
Loading
@@ -503,6 +503,20 @@ describe API::API, api: true do
]) ])
end end
   
context 'with due date' do
it 'creates a new project issue' do
due_date = 2.weeks.from_now.strftime('%Y-%m-%d')
post api("/projects/#{project.id}/issues", user),
title: 'new issue', due_date: due_date
expect(response).to have_http_status(201)
expect(json_response['title']).to eq('new issue')
expect(json_response['description']).to be_nil
expect(json_response['due_date']).to eq(due_date)
end
end
context 'when an admin or owner makes the request' do context 'when an admin or owner makes the request' do
it 'accepts the creation date to be set' do it 'accepts the creation date to be set' do
creation_time = 2.weeks.ago creation_time = 2.weeks.ago
Loading
@@ -683,6 +697,17 @@ describe API::API, api: true do
Loading
@@ -683,6 +697,17 @@ describe API::API, api: true do
end end
end end
   
describe 'PUT /projects/:id/issues/:issue_id to update due date' do
it 'creates a new project issue' do
due_date = 2.weeks.from_now.strftime('%Y-%m-%d')
put api("/projects/#{project.id}/issues/#{issue.id}", user), due_date: due_date
expect(response).to have_http_status(200)
expect(json_response['due_date']).to eq(due_date)
end
end
describe "DELETE /projects/:id/issues/:issue_id" do describe "DELETE /projects/:id/issues/:issue_id" do
it "rejects a non member from deleting an issue" do it "rejects a non member from deleting an issue" do
delete api("/projects/#{project.id}/issues/#{issue.id}", non_member) delete api("/projects/#{project.id}/issues/#{issue.id}", non_member)
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment