Commit 44065b01 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'speed-up-labels-api' into 'master'

Remove label issue and MR counts from default API responses

See merge request gitlab-org/gitlab-ce!31543
parents 6e33ec17 e6dc5168
---
title: Remove counts from default labels API responses
merge_request: 31543
author:
type: changed
...@@ -15,9 +15,10 @@ GET /groups/:id/labels ...@@ -15,9 +15,10 @@ GET /groups/:id/labels
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- | | --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user. | | `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user. |
| `with_counts` | boolean | no | Whether or not to include issue and merge request counts. Defaults to `false`. _([Introduced in GitLab 12.2](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/31543))_ |
```bash ```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/labels curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/labels?with_counts=true
``` ```
Example response: Example response:
......
...@@ -11,9 +11,10 @@ GET /projects/:id/labels ...@@ -11,9 +11,10 @@ GET /projects/:id/labels
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| --------- | ------- | -------- | --------------------- | | --------- | ------- | -------- | --------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `with_counts` | boolean | no | Whether or not to include issue and merge request counts. Defaults to `false`. _([Introduced in GitLab 12.2](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/31543))_ |
```bash ```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/labels curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/labels?with_counts=true
``` ```
Example response: Example response:
......
...@@ -1090,6 +1090,7 @@ module API ...@@ -1090,6 +1090,7 @@ module API
end end
class Label < LabelBasic class Label < LabelBasic
with_options if: lambda { |_, options| options[:with_counts] } do
expose :open_issues_count do |label, options| expose :open_issues_count do |label, options|
label.open_issues_count(options[:current_user]) label.open_issues_count(options[:current_user])
end end
...@@ -1101,6 +1102,7 @@ module API ...@@ -1101,6 +1102,7 @@ module API
expose :open_merge_requests_count do |label, options| expose :open_merge_requests_count do |label, options|
label.open_merge_requests_count(options[:current_user]) label.open_merge_requests_count(options[:current_user])
end end
end
expose :subscribed do |label, options| expose :subscribed do |label, options|
label.subscribed?(options[:current_user], options[:parent]) label.subscribed?(options[:current_user], options[:parent])
......
...@@ -16,6 +16,8 @@ module API ...@@ -16,6 +16,8 @@ module API
success Entities::GroupLabel success Entities::GroupLabel
end end
params do params do
optional :with_counts, type: Boolean, default: false,
desc: 'Include issue and merge request counts'
use :pagination use :pagination
end end
get ':id/labels' do get ':id/labels' do
......
...@@ -19,7 +19,11 @@ module API ...@@ -19,7 +19,11 @@ module API
end end
def get_labels(parent, entity) def get_labels(parent, entity)
present paginate(available_labels_for(parent)), with: entity, current_user: current_user, parent: parent present paginate(available_labels_for(parent)),
with: entity,
current_user: current_user,
parent: parent,
with_counts: params[:with_counts]
end end
def create_label(parent, entity) def create_label(parent, entity)
......
...@@ -15,6 +15,8 @@ module API ...@@ -15,6 +15,8 @@ module API
success Entities::ProjectLabel success Entities::ProjectLabel
end end
params do params do
optional :with_counts, type: Boolean, default: false,
desc: 'Include issue and merge request counts'
use :pagination use :pagination
end end
get ':id/labels' do get ':id/labels' do
......
{
"type": "array",
"items": {
"type": "object",
"properties" : {
"id" : { "type": "integer" },
"name" : { "type": "string "},
"color" : { "type": "string "},
"text_color" : { "type": "string "},
"description" : { "type": "string "},
"open_issues_count" : { "type": "integer "},
"closed_issues_count" : { "type": "integer "},
"open_merge_requests_count" : { "type": "integer "},
"subscribed" : { "type": "boolean" },
"priority" : { "type": "null" }
},
"additionalProperties": false
}
}
{
"type": "object",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"color": { "type": "string" },
"text_color": { "type": "string" },
"description": { "type": ["string", "null"] },
"subscribed": { "type": "boolean" }
}
}
{
"type": "object",
"properties": {
"allOf": [
{ "$ref": "label.json" },
{
"type": "object",
"properties": {
"open_issues_count": { "type": "integer" },
"closed_issues_count": { "type": "integer" },
"open_merge_requests_count": { "type": "integer" }
}
}
]
}
}
{
"type": "object",
"properties": {
"allOf": [
{ "$ref": "label.json" },
{
"type": "object",
"properties": {
"priority": { "type": ["integer", "null"] },
"is_project_label": { "type": "boolean" }
}
}
]
}
}
{
"type": "object",
"properties": {
"allOf": [
{ "$ref": "project_label.json" },
{ "$ref": "label_with_counts.json" }
]
}
}
...@@ -14,12 +14,25 @@ describe API::GroupLabels do ...@@ -14,12 +14,25 @@ describe API::GroupLabels do
get api("/groups/#{group.id}/labels", user) get api("/groups/#{group.id}/labels", user)
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/group_labels')
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response).to all(match_schema('public_api/v4/labels/label'))
expect(json_response.size).to eq(2) expect(json_response.size).to eq(2)
expect(json_response.map {|r| r['name'] }).to contain_exactly('feature', 'bug') expect(json_response.map {|r| r['name'] }).to contain_exactly('feature', 'bug')
end end
context 'when the with_counts parameter is set' do
it 'includes counts in the response' do
get api("/groups/#{group.id}/labels", user), params: { with_counts: true }
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response).to all(match_schema('public_api/v4/labels/label_with_counts'))
expect(json_response.size).to eq(2)
expect(json_response.map { |r| r['open_issues_count'] }).to contain_exactly(0, 0)
end
end
end end
describe 'POST /groups/:id/labels' do describe 'POST /groups/:id/labels' do
......
...@@ -11,65 +11,76 @@ describe API::Labels do ...@@ -11,65 +11,76 @@ describe API::Labels do
end end
describe 'GET /projects/:id/labels' do describe 'GET /projects/:id/labels' do
let(:group) { create(:group) }
let!(:group_label) { create(:group_label, title: 'feature', group: group) }
before do
project.update!(group: group)
end
it 'returns all available labels to the project' do it 'returns all available labels to the project' do
group = create(:group) get api("/projects/#{project.id}/labels", user)
group_label = create(:group_label, title: 'feature', group: group)
project.update(group: group) expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to all(match_schema('public_api/v4/labels/project_label'))
expect(json_response.size).to eq(3)
expect(json_response.map { |l| l['name'] }).to match_array([group_label.name, priority_label.name, label1.name])
end
context 'when the with_counts parameter is set' do
before do
create(:labeled_issue, project: project, labels: [group_label], author: user) create(:labeled_issue, project: project, labels: [group_label], author: user)
create(:labeled_issue, project: project, labels: [label1], author: user, state: :closed) create(:labeled_issue, project: project, labels: [label1], author: user, state: :closed)
create(:labeled_merge_request, labels: [priority_label], author: user, source_project: project ) create(:labeled_merge_request, labels: [priority_label], author: user, source_project: project )
end
expected_keys = %w( it 'includes counts in the response' do
id name color text_color description get api("/projects/#{project.id}/labels", user), params: { with_counts: true }
open_issues_count closed_issues_count open_merge_requests_count
subscribed priority is_project_label
)
get api("/projects/#{project.id}/labels", user)
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(json_response).to be_an Array expect(json_response).to all(match_schema('public_api/v4/labels/project_label_with_counts'))
expect(json_response.size).to eq(3) expect(json_response.size).to eq(3)
expect(json_response.first.keys).to match_array expected_keys
expect(json_response.map { |l| l['name'] }).to match_array([group_label.name, priority_label.name, label1.name]) expect(json_response.map { |l| l['name'] }).to match_array([group_label.name, priority_label.name, label1.name])
label1_response = json_response.find { |l| l['name'] == label1.title } label1_response = json_response.find { |l| l['name'] == label1.title }
group_label_response = json_response.find { |l| l['name'] == group_label.title } group_label_response = json_response.find { |l| l['name'] == group_label.title }
priority_label_response = json_response.find { |l| l['name'] == priority_label.title } priority_label_response = json_response.find { |l| l['name'] == priority_label.title }
expect(label1_response['open_issues_count']).to eq(0) expect(label1_response).to include('open_issues_count' => 0,
expect(label1_response['closed_issues_count']).to eq(1) 'closed_issues_count' => 1,
expect(label1_response['open_merge_requests_count']).to eq(0) 'open_merge_requests_count' => 0,
expect(label1_response['name']).to eq(label1.name) 'name' => label1.name,
expect(label1_response['color']).to be_present 'description' => nil,
expect(label1_response['text_color']).to be_present 'color' => a_string_matching(/^#\h{6}$/),
expect(label1_response['description']).to be_nil 'text_color' => a_string_matching(/^#\h{6}$/),
expect(label1_response['priority']).to be_nil 'priority' => nil,
expect(label1_response['subscribed']).to be_falsey 'subscribed' => false,
expect(label1_response['is_project_label']).to be_truthy 'is_project_label' => true)
expect(group_label_response['open_issues_count']).to eq(1) expect(group_label_response).to include('open_issues_count' => 1,
expect(group_label_response['closed_issues_count']).to eq(0) 'closed_issues_count' => 0,
expect(group_label_response['open_merge_requests_count']).to eq(0) 'open_merge_requests_count' => 0,
expect(group_label_response['name']).to eq(group_label.name) 'name' => group_label.name,
expect(group_label_response['color']).to be_present 'description' => nil,
expect(group_label_response['text_color']).to be_present 'color' => a_string_matching(/^#\h{6}$/),
expect(group_label_response['description']).to be_nil 'text_color' => a_string_matching(/^#\h{6}$/),
expect(group_label_response['priority']).to be_nil 'priority' => nil,
expect(group_label_response['subscribed']).to be_falsey 'subscribed' => false,
expect(group_label_response['is_project_label']).to be_falsey 'is_project_label' => false)
expect(priority_label_response['open_issues_count']).to eq(0) expect(priority_label_response).to include('open_issues_count' => 0,
expect(priority_label_response['closed_issues_count']).to eq(0) 'closed_issues_count' => 0,
expect(priority_label_response['open_merge_requests_count']).to eq(1) 'open_merge_requests_count' => 1,
expect(priority_label_response['name']).to eq(priority_label.name) 'name' => priority_label.name,
expect(priority_label_response['color']).to be_present 'description' => nil,
expect(priority_label_response['text_color']).to be_present 'color' => a_string_matching(/^#\h{6}$/),
expect(priority_label_response['description']).to be_nil 'text_color' => a_string_matching(/^#\h{6}$/),
expect(priority_label_response['priority']).to eq(3) 'priority' => 3,
expect(priority_label_response['subscribed']).to be_falsey 'subscribed' => false,
expect(priority_label_response['is_project_label']).to be_truthy 'is_project_label' => true)
end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment