summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRémy Coutable <remy@rymai.me>2016-06-24 13:44:47 +0200
committerRémy Coutable <remy@rymai.me>2016-06-24 13:44:47 +0200
commit588244ddd8192512ce04be902226a2fb0b765215 (patch)
tree642179fd9b8ddf8e01dbf9a976d3ad8f68ee343e
parent9babbefe3fadb68b1996951c79d317a0e790f2a3 (diff)
parent6587feba65371a7417a7726b6a19681e99187ecd (diff)
downloadgitlab-ce-588244ddd8192512ce04be902226a2fb0b765215.tar.gz
Merge branch 'mahcsig/gitlab-ce-17818-group-issues-api'
-rw-r--r--CHANGELOG1
-rw-r--r--doc/api/issues.md80
-rw-r--r--lib/api/issues.rb35
-rw-r--r--spec/requests/api/issues_spec.rb142
4 files changed, 256 insertions, 2 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 19782969b85..5e115a8bb17 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -9,6 +9,7 @@ v 8.10.0 (unreleased)
- Fix pagination when sorting by columns with lots of ties (like priority)
- Implement Subresource Integrity for CSS and JavaScript assets. This prevents malicious assets from loading in the case of a CDN compromise.
- Fix user creation with stronger minimum password requirements !4054 (nathan-pmt)
+ - Add API endpoint for a group issues !4520 (mahcsig)
v 8.9.1
- Fix merge requests project settings help link anchor
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 0bc82ef9edb..708fc691f67 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -28,7 +28,7 @@ GET /issues?labels=foo,bar&state=opened
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `state` | string | no | Return all issues or just those that are `opened` or `closed`|
-| `labels` | string | no | Comma-separated list of label names |
+| `labels` | string | no | Comma-separated list of label names, issues with any of the labels will be returned |
| `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` |
@@ -83,6 +83,82 @@ Example response:
]
```
+## List group issues
+
+Get a list of a group's issues.
+
+```
+GET /groups/:id/issues
+GET /groups/:id/issues?state=opened
+GET /groups/:id/issues?state=closed
+GET /groups/:id/issues?labels=foo
+GET /groups/:id/issues?labels=foo,bar
+GET /groups/:id/issues?labels=foo,bar&state=opened
+GET /groups/:id/issues?milestone=1.0.0
+GET /groups/:id/issues?milestone=1.0.0&state=opened
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer | yes | The ID of a group |
+| `state` | string | no | Return all issues or just those that are `opened` or `closed`|
+| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned |
+| `milestone` | string| no | The milestone title |
+| `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` |
+
+
+```bash
+curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/groups/4/issues
+```
+
+Example response:
+
+```json
+[
+ {
+ "project_id" : 4,
+ "milestone" : {
+ "due_date" : null,
+ "project_id" : 4,
+ "state" : "closed",
+ "description" : "Rerum est voluptatem provident consequuntur molestias similique ipsum dolor.",
+ "iid" : 3,
+ "id" : 11,
+ "title" : "v3.0",
+ "created_at" : "2016-01-04T15:31:39.788Z",
+ "updated_at" : "2016-01-04T15:31:39.788Z"
+ },
+ "author" : {
+ "state" : "active",
+ "web_url" : "https://gitlab.example.com/u/root",
+ "avatar_url" : null,
+ "username" : "root",
+ "id" : 1,
+ "name" : "Administrator"
+ },
+ "description" : "Omnis vero earum sunt corporis dolor et placeat.",
+ "state" : "closed",
+ "iid" : 1,
+ "assignee" : {
+ "avatar_url" : null,
+ "web_url" : "https://gitlab.example.com/u/lennie",
+ "state" : "active",
+ "username" : "lennie",
+ "id" : 9,
+ "name" : "Dr. Luella Kovacek"
+ },
+ "labels" : [],
+ "id" : 41,
+ "title" : "Ut commodi ullam eos dolores perferendis nihil sunt.",
+ "updated_at" : "2016-01-04T15:31:46.176Z",
+ "created_at" : "2016-01-04T15:31:46.176Z",
+ "subscribed" : false,
+ "user_notes_count": 1
+ }
+]
+```
+
## List project issues
Get a list of a project's issues.
@@ -104,7 +180,7 @@ GET /projects/:id/issues?iid=42
| `id` | integer | yes | The ID of a project |
| `iid` | integer | no | Return the issue having the given `iid` |
| `state` | string | no | Return all issues or just those that are `opened` or `closed`|
-| `labels` | string | no | Comma-separated list of label names |
+| `labels` | string | no | Comma-separated list of label names, issues with any of the labels will be returned |
| `milestone` | string| no | The milestone title |
| `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` |
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 4c43257c48a..8a03a41e9c5 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -59,6 +59,41 @@ module API
end
end
+ resource :groups do
+ # Get a list of group issues
+ #
+ # Parameters:
+ # id (required) - The ID of a group
+ # state (optional) - Return "opened" or "closed" issues
+ # labels (optional) - Comma-separated list of label names
+ # milestone (optional) - Milestone title
+ # order_by (optional) - Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at`
+ # sort (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
+ #
+ # Example Requests:
+ # GET /groups/:id/issues
+ # GET /groups/:id/issues?state=opened
+ # GET /groups/:id/issues?state=closed
+ # GET /groups/:id/issues?labels=foo
+ # GET /groups/:id/issues?labels=foo,bar
+ # GET /groups/:id/issues?labels=foo,bar&state=opened
+ # GET /groups/:id/issues?milestone=1.0.0
+ # GET /groups/:id/issues?milestone=1.0.0&state=closed
+ get ":id/issues" do
+ group = find_group(params[:id])
+
+ params[:state] ||= 'opened'
+ params[:group_id] = group.id
+ params[:milestone_title] = params.delete(:milestone)
+ params[:label_name] = params.delete(:labels)
+ params[:sort] = "#{params.delete(:order_by)}_#{params.delete(:sort)}" if params[:order_by] && params[:sort]
+
+ issues = IssuesFinder.new(current_user, params).execute
+
+ present paginate(issues), with: Entities::Issue, current_user: current_user
+ end
+ end
+
resource :projects do
# Get a list of project issues
#
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 59e557c5b2a..edec53dad89 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -136,6 +136,148 @@ describe API::API, api: true do
end
end
+ describe "GET /groups/:id/issues" do
+ let!(:group) { create(:group) }
+ let!(:group_project) { create(:project, :public, creator_id: user.id, namespace: group) }
+ let!(:group_closed_issue) do
+ create :closed_issue,
+ author: user,
+ assignee: user,
+ project: group_project,
+ state: :closed,
+ milestone: group_milestone
+ end
+ let!(:group_confidential_issue) do
+ create :issue,
+ :confidential,
+ project: group_project,
+ author: author,
+ assignee: assignee
+ end
+ let!(:group_issue) do
+ create :issue,
+ author: user,
+ assignee: user,
+ project: group_project,
+ milestone: group_milestone
+ end
+ let!(:group_label) do
+ create(:label, title: 'group_lbl', color: '#FFAABB', project: group_project)
+ end
+ let!(:group_label_link) { create(:label_link, label: group_label, target: group_issue) }
+ let!(:group_milestone) { create(:milestone, title: '3.0.0', project: group_project) }
+ let!(:group_empty_milestone) do
+ create(:milestone, title: '4.0.0', project: group_project)
+ end
+ let!(:group_note) { create(:note_on_issue, author: user, project: group_project, noteable: group_issue) }
+
+ before do
+ group_project.team << [user, :reporter]
+ end
+ let(:base_url) { "/groups/#{group.id}/issues" }
+
+ it 'returns group issues without confidential issues for non project members' do
+ get api(base_url, non_member)
+
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['title']).to eq(group_issue.title)
+ end
+
+ it 'returns group confidential issues for author' do
+ get api(base_url, author)
+
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(2)
+ end
+
+ it 'returns group confidential issues for assignee' do
+ get api(base_url, assignee)
+
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(2)
+ end
+
+ it 'returns group issues with confidential issues for project members' do
+ get api(base_url, user)
+
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(2)
+ end
+
+ it 'returns group confidential issues for admin' do
+ get api(base_url, admin)
+
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(2)
+ end
+
+ it 'returns an array of labeled group issues' do
+ get api("#{base_url}?labels=#{group_label.title}", user)
+
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['labels']).to eq([group_label.title])
+ end
+
+ it 'returns an array of labeled group issues where all labels match' do
+ get api("#{base_url}?labels=#{group_label.title},foo,bar", user)
+
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(0)
+ end
+
+ it 'returns an empty array if no group issue matches labels' do
+ get api("#{base_url}?labels=foo,bar", user)
+
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(0)
+ end
+
+ it 'returns an empty array if no issue matches milestone' do
+ get api("#{base_url}?milestone=#{group_empty_milestone.title}", user)
+
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(0)
+ end
+
+ it 'returns an empty array if milestone does not exist' do
+ get api("#{base_url}?milestone=foo", user)
+
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(0)
+ end
+
+ it 'returns an array of issues in given milestone' do
+ get api("#{base_url}?milestone=#{group_milestone.title}", user)
+
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['id']).to eq(group_issue.id)
+ end
+
+ it 'returns an array of issues matching state in milestone' do
+ get api("#{base_url}?milestone=#{group_milestone.title}"\
+ '&state=closed', user)
+
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['id']).to eq(group_closed_issue.id)
+ end
+ end
+
describe "GET /projects/:id/issues" do
let(:base_url) { "/projects/#{project.id}" }
let(:title) { milestone.title }