API: Ability to move an issue
This commit is contained in:
parent
8ea6c6d80c
commit
482f67edb4
|
@ -14,6 +14,7 @@ v 8.7.0 (unreleased)
|
||||||
- Expose label description in API (Mariusz Jachimowicz)
|
- Expose label description in API (Mariusz Jachimowicz)
|
||||||
- Allow back dating on issues when created through the API
|
- Allow back dating on issues when created through the API
|
||||||
- API: Ability to update a group (Robert Schilling)
|
- API: Ability to update a group (Robert Schilling)
|
||||||
|
- API: Ability to move issues
|
||||||
- Fix Error 500 after renaming a project path (Stan Hu)
|
- Fix Error 500 after renaming a project path (Stan Hu)
|
||||||
- Fix avatar stretching by providing a cropping feature
|
- Fix avatar stretching by providing a cropping feature
|
||||||
- API: Expose `subscribed` for issues and merge requests (Robert Schilling)
|
- API: Expose `subscribed` for issues and merge requests (Robert Schilling)
|
||||||
|
|
|
@ -351,6 +351,57 @@ DELETE /projects/:id/issues/:issue_id
|
||||||
curl -X DELETE -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues/85
|
curl -X DELETE -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues/85
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Move an issue
|
||||||
|
|
||||||
|
Moves an issue to a different project. If the operation is successful, a status code `200` together with moved issue is returned. If the project, issue, or target project is not found, error `404` is returned. If the target project equals the source project or the user has insufficient permissions to move an issue, error `400` together with an explaining error message is returned.
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /projects/:id/issues/:issue_id/move
|
||||||
|
```
|
||||||
|
|
||||||
|
| Attribute | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `id` | integer | yes | The ID of a project |
|
||||||
|
| `issue_id` | integer | yes | The ID of a project's issue |
|
||||||
|
| `new_project_id` | integer | yes | The ID the new project |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues/85/move
|
||||||
|
```
|
||||||
|
|
||||||
|
Example response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 92,
|
||||||
|
"iid": 11,
|
||||||
|
"project_id": 5,
|
||||||
|
"title": "Sit voluptas tempora quisquam aut doloribus et.",
|
||||||
|
"description": "Repellat voluptas quibusdam voluptatem exercitationem.",
|
||||||
|
"state": "opened",
|
||||||
|
"created_at": "2016-04-05T21:41:45.652Z",
|
||||||
|
"updated_at": "2016-04-07T12:20:17.596Z",
|
||||||
|
"labels": [],
|
||||||
|
"milestone": null,
|
||||||
|
"assignee": {
|
||||||
|
"name": "Miss Monserrate Beier",
|
||||||
|
"username": "axel.block",
|
||||||
|
"id": 12,
|
||||||
|
"state": "active",
|
||||||
|
"avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
|
||||||
|
"web_url": "https://gitlab.example.com/u/axel.block"
|
||||||
|
},
|
||||||
|
"author": {
|
||||||
|
"name": "Kris Steuber",
|
||||||
|
"username": "solon.cremin",
|
||||||
|
"id": 10,
|
||||||
|
"state": "active",
|
||||||
|
"avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon",
|
||||||
|
"web_url": "https://gitlab.example.com/u/solon.cremin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Comments on issues
|
## Comments on issues
|
||||||
|
|
||||||
Comments are done via the [notes](notes.md) resource.
|
Comments are done via the [notes](notes.md) resource.
|
||||||
|
|
|
@ -195,6 +195,29 @@ module API
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Move an existing issue
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
# id (required) - The ID of a project
|
||||||
|
# issue_id (required) - The ID of a project issue
|
||||||
|
# new_project_id (required) - The ID of the new project
|
||||||
|
# Example Request:
|
||||||
|
# POST /projects/:id/issues/:issue_id/move
|
||||||
|
post ":id/issues/:issue_id/move" do
|
||||||
|
required_attributes! [:new_project_id]
|
||||||
|
|
||||||
|
issue = user_project.issues.find(params[:issue_id])
|
||||||
|
new_project = Project.find(params[:new_project_id])
|
||||||
|
|
||||||
|
begin
|
||||||
|
issue = ::Issues::MoveService.new(user_project, current_user).execute(issue, new_project)
|
||||||
|
present issue, with: Entities::Issue
|
||||||
|
rescue ::Issues::MoveService::MoveError => error
|
||||||
|
render_api_error!(error.message, 400)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
# Delete a project issue
|
# Delete a project issue
|
||||||
#
|
#
|
||||||
# Parameters:
|
# Parameters:
|
||||||
|
|
|
@ -7,7 +7,7 @@ describe API::API, api: true do
|
||||||
let(:author) { create(:author) }
|
let(:author) { create(:author) }
|
||||||
let(:assignee) { create(:assignee) }
|
let(:assignee) { create(:assignee) }
|
||||||
let(:admin) { create(:user, :admin) }
|
let(:admin) { create(:user, :admin) }
|
||||||
let!(:project) { create(:project, :public, namespace: user.namespace ) }
|
let!(:project) { create(:project, :public, creator_id: user.id, namespace: user.namespace ) }
|
||||||
let!(:closed_issue) do
|
let!(:closed_issue) do
|
||||||
create :closed_issue,
|
create :closed_issue,
|
||||||
author: user,
|
author: user,
|
||||||
|
@ -501,4 +501,55 @@ describe API::API, api: true do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '/projects/:id/issues/:issue_id/move' do
|
||||||
|
let!(:target_project) { create(:project, path: 'project2', creator_id: user.id, namespace: user.namespace ) }
|
||||||
|
let!(:target_project2) { create(:project, creator_id: non_member.id, namespace: non_member.namespace ) }
|
||||||
|
|
||||||
|
it 'moves an issue' do
|
||||||
|
post api("/projects/#{project.id}/issues/#{issue.id}/move", user),
|
||||||
|
new_project_id: target_project.id
|
||||||
|
|
||||||
|
expect(response.status).to eq(201)
|
||||||
|
expect(json_response['project_id']).to eq(target_project.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns an error if target and source project are the same' do
|
||||||
|
post api("/projects/#{project.id}/issues/#{issue.id}/move", user),
|
||||||
|
new_project_id: project.id
|
||||||
|
|
||||||
|
expect(response.status).to eq(400)
|
||||||
|
expect(json_response['message']).to eq('Cannot move issue to project it originates from!')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns an error if I don't have the permission" do
|
||||||
|
post api("/projects/#{project.id}/issues/#{issue.id}/move", user),
|
||||||
|
new_project_id: target_project2.id
|
||||||
|
|
||||||
|
expect(response.status).to eq(400)
|
||||||
|
expect(json_response['message']).to eq('Cannot move issue due to insufficient permissions!')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'moves the issue to another namespace if I am admin' do
|
||||||
|
post api("/projects/#{project.id}/issues/#{issue.id}/move", admin),
|
||||||
|
new_project_id: target_project2.id
|
||||||
|
|
||||||
|
expect(response.status).to eq(201)
|
||||||
|
expect(json_response['project_id']).to eq(target_project2.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns 404 if the source issue is not found' do
|
||||||
|
post api("/projects/#{project.id}/issues/123/move", user),
|
||||||
|
new_project_id: target_project.id
|
||||||
|
|
||||||
|
expect(response.status).to eq(404)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns 404 if the target project is not found' do
|
||||||
|
post api("/projects/1234/issues/#{issue.id}/move", user),
|
||||||
|
new_project_id: target_project.id
|
||||||
|
|
||||||
|
expect(response.status).to eq(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue