summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacopo <beschi.jacopo@gmail.com>2018-10-29 10:50:18 +0100
committerJacopo <beschi.jacopo@gmail.com>2018-11-22 10:49:05 +0100
commitf11a54d4a380f17ce17ef42d90be6f0ff9a39c8d (patch)
tree9250ab32a73b177e81decd42f9baf91dfa659156
parentf0630090aaea98daef3582bc95efe3a43736a10f (diff)
downloadgitlab-ce-52371-filter-by-none-any-for-labels-in-issues-mrs-api.tar.gz
Filter by `None`/`Any` for labels in issues/mrs API52371-filter-by-none-any-for-labels-in-issues-mrs-api
By using the parameters `?labels=None|Any` the user can filter issues/mrs from the API that has `none/any` label. Affected endpoints are: - /api/issues - /api/projects/:id/issues - /api/groups/:id/issues - /api/merge_requests - /api/projects/:id/merge_requests - /api/groups/:id/merge_requests
-rw-r--r--app/finders/issuable_finder.rb11
-rw-r--r--app/models/concerns/issuable.rb1
-rw-r--r--app/models/label.rb9
-rw-r--r--changelogs/unreleased/52371-filter-by-none-any-for-labels-in-issues-mrs-api.yml5
-rw-r--r--doc/api/issues.md6
-rw-r--r--doc/api/merge_requests.md6
-rw-r--r--spec/finders/issues_finder_spec.rb36
-rw-r--r--spec/requests/api/issues_spec.rb115
-rw-r--r--spec/support/shared_examples/requests/api/merge_requests_list.rb17
9 files changed, 155 insertions, 51 deletions
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index fdc630cbf72..e04e3a2a7e0 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -210,7 +210,14 @@ class IssuableFinder
end
def filter_by_no_label?
- labels? && params[:label_name].include?(Label::None.title)
+ downcased = label_names.map(&:downcase)
+
+ # Label::NONE is deprecated and should be removed in 12.0
+ downcased.include?(FILTER_NONE) || downcased.include?(Label::NONE)
+ end
+
+ def filter_by_any_label?
+ label_names.map(&:downcase).include?(FILTER_ANY)
end
def labels
@@ -465,6 +472,8 @@ class IssuableFinder
items =
if filter_by_no_label?
items.without_label
+ elsif filter_by_any_label?
+ items.any_label
else
items.with_label(label_names, params[:sort])
end
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 69c5affe142..5080fe03cc8 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -90,6 +90,7 @@ module Issuable
scope :order_milestone_due_asc, -> { left_joins_milestones.reorder('milestones.due_date IS NULL, milestones.id IS NULL, milestones.due_date ASC') }
scope :without_label, -> { joins("LEFT OUTER JOIN label_links ON label_links.target_type = '#{name}' AND label_links.target_id = #{table_name}.id").where(label_links: { id: nil }) }
+ scope :any_label, -> { joins(:label_links).group(:id) }
scope :join_project, -> { joins(:project) }
scope :inc_notes_with_associations, -> { includes(notes: [:project, :author, :award_emoji]) }
scope :references_project, -> { references(:project) }
diff --git a/app/models/label.rb b/app/models/label.rb
index 165e4a8f3e5..5d2d1afd1d9 100644
--- a/app/models/label.rb
+++ b/app/models/label.rb
@@ -9,15 +9,10 @@ class Label < ActiveRecord::Base
include Sortable
include FromUnion
- # Represents a "No Label" state used for filtering Issues and Merge
- # Requests that have no label assigned.
- LabelStruct = Struct.new(:title, :name)
- None = LabelStruct.new('No Label', 'No Label')
- Any = LabelStruct.new('Any Label', '')
-
cache_markdown_field :description, pipeline: :single_line
- DEFAULT_COLOR = '#428BCA'.freeze
+ DEFAULT_COLOR = '#428BCA'
+ NONE = 'no label'
default_value_for :color, DEFAULT_COLOR
diff --git a/changelogs/unreleased/52371-filter-by-none-any-for-labels-in-issues-mrs-api.yml b/changelogs/unreleased/52371-filter-by-none-any-for-labels-in-issues-mrs-api.yml
new file mode 100644
index 00000000000..bb196af3e90
--- /dev/null
+++ b/changelogs/unreleased/52371-filter-by-none-any-for-labels-in-issues-mrs-api.yml
@@ -0,0 +1,5 @@
+---
+title: Filter by None/Any for labels in issues/mrs API
+merge_request: 22622
+author: Jacopo Beschi @jacopo-beschi
+type: added
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 0e97d9ea6f5..9e245f820a3 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -36,7 +36,7 @@ GET /issues?my_reaction_emoji=star
| 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, issues must have all labels to be returned. `No+Label` lists all issues with no labels |
+| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. |
| `milestone` | string | no | The milestone title. `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. |
| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`. Defaults to `created_by_me`<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced][ce-13004] in GitLab 9.5. [Changed to snake_case][ce-18935] in GitLab 11.0)_ |
| `author_id` | integer | no | Return issues created by the given user `id`. Combine with `scope=all` or `scope=assigned_to_me`. _([Introduced][ce-13004] in GitLab 9.5)_ |
@@ -149,7 +149,7 @@ GET /groups/:id/issues?my_reaction_emoji=star
| ------------------- | ---------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
| `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. `No+Label` lists all issues with no labels |
+| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. |
| `iids[]` | Array[integer] | no | Return only the issues having the given `iid` |
| `milestone` | string | no | The milestone title. `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. |
| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`.<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced][ce-13004] in GitLab 9.5. [Changed to snake_case][ce-18935] in GitLab 11.0)_ |
@@ -264,7 +264,7 @@ GET /projects/:id/issues?my_reaction_emoji=star
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `iids[]` | Array[integer] | no | Return only the milestone 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, issues must have all labels to be returned. `No+Label` lists all issues with no labels |
+| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. |
| `milestone` | string | no | The milestone title. `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. |
| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`.<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced][ce-13004] in GitLab 9.5. [Changed to snake_case][ce-18935] in GitLab 11.0)_ |
| `author_id` | integer | no | Return issues created by the given user `id` _([Introduced][ce-13004] in GitLab 9.5)_ |
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 9cb3f0d9c0c..30b31a04475 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -35,7 +35,7 @@ Parameters:
| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` |
| `milestone` | string | no | Return merge requests for a specific milestone. `None` returns merge requests with no milestone. `Any` returns merge requests that have an assigned milestone. |
| `view` | string | no | If `simple`, returns the `iid`, URL, title, description, and basic state of merge request |
-| `labels` | string | no | Return merge requests matching a comma separated list of labels |
+| `labels` | string | no | Return merge requests matching a comma separated list of labels. `None` lists all merge requests with no labels. `Any` lists all merge requests with at least one label. `No+Label` (Deprecated) lists all merge requests with no labels. |
| `created_after` | datetime | no | Return merge requests created on or after the given time |
| `created_before` | datetime | no | Return merge requests created on or before the given time |
| `updated_after` | datetime | no | Return merge requests updated on or after the given time |
@@ -170,7 +170,7 @@ Parameters:
| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` |
| `milestone` | string | no | Return merge requests for a specific milestone. `None` returns merge requests with no milestone. `Any` returns merge requests that have an assigned milestone. |
| `view` | string | no | If `simple`, returns the `iid`, URL, title, description, and basic state of merge request |
-| `labels` | string | no | Return merge requests matching a comma separated list of labels |
+| `labels` | string | no | Return merge requests matching a comma separated list of labels. `None` lists all merge requests with no labels. `Any` lists all merge requests with at least one label. `No+Label` (Deprecated) lists all merge requests with no labels. |
| `created_after` | datetime | no | Return merge requests created on or after the given time |
| `created_before` | datetime | no | Return merge requests created on or before the given time |
| `updated_after` | datetime | no | Return merge requests updated on or after the given time |
@@ -294,7 +294,7 @@ Parameters:
| `sort` | string | no | Return merge requests sorted in `asc` or `desc` order. Default is `desc` |
| `milestone` | string | no | Return merge requests for a specific milestone. `None` returns merge requests with no milestone. `Any` returns merge requests that have an assigned milestone. |
| `view` | string | no | If `simple`, returns the `iid`, URL, title, description, and basic state of merge request |
-| `labels` | string | no | Return merge requests matching a comma separated list of labels |
+| `labels` | string | no | Return merge requests matching a comma separated list of labels. `None` lists all merge requests with no labels. `Any` lists all merge requests with at least one label. `No+Label` (Deprecated) lists all merge requests with no labels. |
| `created_after` | datetime | no | Return merge requests created on or after the given time |
| `created_before` | datetime | no | Return merge requests created on or before the given time |
| `updated_after` | datetime | no | Return merge requests updated on or after the given time |
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index c0488c83bd8..515f6f70b99 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -256,19 +256,51 @@ describe IssuesFinder do
create(:label_link, label: label2, target: issue2)
end
- it 'returns the unique issues with any of those labels' do
+ it 'returns the unique issues with all those labels' do
+ expect(issues).to contain_exactly(issue2)
+ end
+ end
+
+ context 'filtering by a label that includes any or none in the title' do
+ let(:params) { { label_name: [label.title, label2.title].join(',') } }
+ let(:label) { create(:label, title: 'any foo', project: project2) }
+ let(:label2) { create(:label, title: 'bar none', project: project2) }
+
+ it 'returns the unique issues with all those labels' do
+ create(:label_link, label: label2, target: issue2)
+
expect(issues).to contain_exactly(issue2)
end
end
context 'filtering by no label' do
- let(:params) { { label_name: Label::None.title } }
+ let(:params) { { label_name: described_class::FILTER_NONE } }
it 'returns issues with no labels' do
expect(issues).to contain_exactly(issue1, issue3, issue4)
end
end
+ context 'filtering by legacy No+Label' do
+ let(:params) { { label_name: Label::NONE } }
+
+ it 'returns issues with no labels' do
+ expect(issues).to contain_exactly(issue1, issue3, issue4)
+ end
+ end
+
+ context 'filtering by any label' do
+ let(:params) { { label_name: described_class::FILTER_ANY } }
+
+ it 'returns issues that have one or more label' do
+ 2.times do
+ create(:label_link, label: create(:label, project: project2), target: issue3)
+ end
+
+ expect(issues).to contain_exactly(issue2, issue3)
+ end
+ end
+
context 'filtering by issue term' do
let(:params) { { search: 'git' } }
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 3d532dd83c7..1827da61e2d 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -300,17 +300,31 @@ describe API::Issues do
expect(json_response.first['state']).to eq('opened')
end
- it 'returns unlabeled issues for "No Label" label' do
- get api("/issues", user), labels: 'No Label'
+ it 'returns an empty array if no issue matches labels and state filters' do
+ get api("/issues", user), labels: label.title, state: :closed
+
+ expect_paginated_array_response(size: 0)
+ end
+
+ it 'returns an array of issues with any label' do
+ get api("/issues", user), labels: IssuesFinder::FILTER_ANY
expect_paginated_array_response(size: 1)
- expect(json_response.first['labels']).to be_empty
+ expect(json_response.first['id']).to eq(issue.id)
end
- it 'returns an empty array if no issue matches labels and state filters' do
- get api("/issues?labels=#{label.title}&state=closed", user)
+ it 'returns an array of issues with no label' do
+ get api("/issues", user), labels: IssuesFinder::FILTER_NONE
- expect_paginated_array_response(size: 0)
+ expect_paginated_array_response(size: 1)
+ expect(json_response.first['id']).to eq(closed_issue.id)
+ end
+
+ it 'returns an array of issues with no label when using the legacy No+Label filter' do
+ get api("/issues", user), labels: "No Label"
+
+ expect_paginated_array_response(size: 1)
+ expect(json_response.first['id']).to eq(closed_issue.id)
end
it 'returns an empty array if no issue matches milestone' do
@@ -492,58 +506,58 @@ describe API::Issues do
end
it 'returns group issues without confidential issues for non project members' do
- get api("#{base_url}?state=opened", non_member)
+ get api(base_url, non_member), state: :opened
expect_paginated_array_response(size: 1)
expect(json_response.first['title']).to eq(group_issue.title)
end
it 'returns group confidential issues for author' do
- get api("#{base_url}?state=opened", author)
+ get api(base_url, author), state: :opened
expect_paginated_array_response(size: 2)
end
it 'returns group confidential issues for assignee' do
- get api("#{base_url}?state=opened", assignee)
+ get api(base_url, assignee), state: :opened
expect_paginated_array_response(size: 2)
end
it 'returns group issues with confidential issues for project members' do
- get api("#{base_url}?state=opened", user)
+ get api(base_url, user), state: :opened
expect_paginated_array_response(size: 2)
end
it 'returns group confidential issues for admin' do
- get api("#{base_url}?state=opened", admin)
+ get api(base_url, admin), state: :opened
expect_paginated_array_response(size: 2)
end
it 'returns an array of labeled group issues' do
- get api("#{base_url}?labels=#{group_label.title}", user)
+ get api(base_url, user), labels: group_label.title
expect_paginated_array_response(size: 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)
+ get api(base_url, user), labels: "#{group_label.title},foo,bar"
expect_paginated_array_response(size: 0)
end
it 'returns issues matching given search string for title' do
- get api("#{base_url}?search=#{group_issue.title}", user)
+ get api(base_url, user), search: group_issue.title
expect_paginated_array_response(size: 1)
expect(json_response.first['id']).to eq(group_issue.id)
end
it 'returns issues matching given search string for description' do
- get api("#{base_url}?search=#{group_issue.description}", user)
+ get api(base_url, user), search: group_issue.description
expect_paginated_array_response(size: 1)
expect(json_response.first['id']).to eq(group_issue.id)
@@ -556,7 +570,7 @@ describe API::Issues do
create(:label_link, label: label_b, target: group_issue)
create(:label_link, label: label_c, target: group_issue)
- get api("#{base_url}", user), labels: "#{group_label.title},#{label_b.title},#{label_c.title}"
+ get api(base_url, user), labels: "#{group_label.title},#{label_b.title},#{label_c.title}"
expect_paginated_array_response(size: 1)
expect(json_response.first['labels']).to eq([label_c.title, label_b.title, group_label.title])
@@ -576,40 +590,55 @@ describe API::Issues do
end
it 'returns an empty array if no group issue matches labels' do
- get api("#{base_url}?labels=foo,bar", user)
+ get api(base_url, user), labels: 'foo,bar'
expect_paginated_array_response(size: 0)
end
+ it 'returns an array of group issues with any label' do
+ get api(base_url, user), labels: IssuesFinder::FILTER_ANY
+
+ expect_paginated_array_response(size: 1)
+ expect(json_response.first['id']).to eq(group_issue.id)
+ end
+
+ it 'returns an array of group issues with no label' do
+ get api(base_url, user), labels: IssuesFinder::FILTER_NONE
+
+ response_ids = json_response.map { |issue| issue['id'] }
+
+ expect_paginated_array_response(size: 2)
+ expect(response_ids).to contain_exactly(group_closed_issue.id, group_confidential_issue.id)
+ end
+
it 'returns an empty array if no issue matches milestone' do
- get api("#{base_url}?milestone=#{group_empty_milestone.title}", user)
+ get api(base_url, user), milestone: group_empty_milestone.title
expect_paginated_array_response(size: 0)
end
it 'returns an empty array if milestone does not exist' do
- get api("#{base_url}?milestone=foo", user)
+ get api(base_url, user), milestone: 'foo'
expect_paginated_array_response(size: 0)
end
it 'returns an array of issues in given milestone' do
- get api("#{base_url}?state=opened&milestone=#{group_milestone.title}", user)
+ get api(base_url, user), state: :opened, milestone: group_milestone.title
expect_paginated_array_response(size: 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)
+ get api(base_url, user), milestone: group_milestone.title, state: :closed
expect_paginated_array_response(size: 1)
expect(json_response.first['id']).to eq(group_closed_issue.id)
end
it 'returns an array of issues with no milestone' do
- get api("#{base_url}?milestone=#{no_milestone_title}", user)
+ get api(base_url, user), milestone: no_milestone_title
expect(response).to have_gitlab_http_status(200)
@@ -645,7 +674,7 @@ describe API::Issues do
end
it 'sorts by updated_at ascending when requested' do
- get api("#{base_url}?order_by=updated_at&sort=asc", user)
+ get api(base_url, user), order_by: :updated_at, sort: :asc
response_dates = json_response.map { |issue| issue['updated_at'] }
@@ -748,7 +777,7 @@ describe API::Issues do
end
it 'returns an array of labeled project issues' do
- get api("#{base_url}/issues?labels=#{label.title}", user)
+ get api("#{base_url}/issues", user), labels: label.title
expect_paginated_array_response(size: 1)
expect(json_response.first['labels']).to eq([label.title])
@@ -800,26 +829,42 @@ describe API::Issues do
expect_paginated_array_response(size: 0)
end
+ it 'returns an array of project issues with any label' do
+ get api("#{base_url}/issues", user), labels: IssuesFinder::FILTER_ANY
+
+ expect_paginated_array_response(size: 1)
+ expect(json_response.first['id']).to eq(issue.id)
+ end
+
+ it 'returns an array of project issues with no label' do
+ get api("#{base_url}/issues", user), labels: IssuesFinder::FILTER_NONE
+
+ response_ids = json_response.map { |issue| issue['id'] }
+
+ expect_paginated_array_response(size: 2)
+ expect(response_ids).to contain_exactly(closed_issue.id, confidential_issue.id)
+ end
+
it 'returns an empty array if no project issue matches labels' do
- get api("#{base_url}/issues?labels=foo,bar", user)
+ get api("#{base_url}/issues", user), labels: 'foo,bar'
expect_paginated_array_response(size: 0)
end
it 'returns an empty array if no issue matches milestone' do
- get api("#{base_url}/issues?milestone=#{empty_milestone.title}", user)
+ get api("#{base_url}/issues", user), milestone: empty_milestone.title
expect_paginated_array_response(size: 0)
end
it 'returns an empty array if milestone does not exist' do
- get api("#{base_url}/issues?milestone=foo", user)
+ get api("#{base_url}/issues", user), milestone: :foo
expect_paginated_array_response(size: 0)
end
it 'returns an array of issues in given milestone' do
- get api("#{base_url}/issues?milestone=#{milestone.title}", user)
+ get api("#{base_url}/issues", user), milestone: milestone.title
expect_paginated_array_response(size: 2)
expect(json_response.first['id']).to eq(issue.id)
@@ -827,21 +872,21 @@ describe API::Issues do
end
it 'returns an array of issues matching state in milestone' do
- get api("#{base_url}/issues?milestone=#{milestone.title}&state=closed", user)
+ get api("#{base_url}/issues", user), milestone: milestone.title, state: :closed
expect_paginated_array_response(size: 1)
expect(json_response.first['id']).to eq(closed_issue.id)
end
it 'returns an array of issues with no milestone' do
- get api("#{base_url}/issues?milestone=#{no_milestone_title}", user)
+ get api("#{base_url}/issues", user), milestone: no_milestone_title
expect_paginated_array_response(size: 1)
expect(json_response.first['id']).to eq(confidential_issue.id)
end
it 'returns an array of issues with any milestone' do
- get api("#{base_url}/issues?milestone=#{any_milestone_title}", user)
+ get api("#{base_url}/issues", user), milestone: any_milestone_title
response_ids = json_response.map { |issue| issue['id'] }
@@ -859,7 +904,7 @@ describe API::Issues do
end
it 'sorts ascending when requested' do
- get api("#{base_url}/issues?sort=asc", user)
+ get api("#{base_url}/issues", user), sort: :asc
response_dates = json_response.map { |issue| issue['created_at'] }
@@ -868,7 +913,7 @@ describe API::Issues do
end
it 'sorts by updated_at descending when requested' do
- get api("#{base_url}/issues?order_by=updated_at", user)
+ get api("#{base_url}/issues", user), order_by: :updated_at
response_dates = json_response.map { |issue| issue['updated_at'] }
@@ -877,7 +922,7 @@ describe API::Issues do
end
it 'sorts by updated_at ascending when requested' do
- get api("#{base_url}/issues?order_by=updated_at&sort=asc", user)
+ get api("#{base_url}/issues", user), order_by: :updated_at, sort: :asc
response_dates = json_response.map { |issue| issue['updated_at'] }
diff --git a/spec/support/shared_examples/requests/api/merge_requests_list.rb b/spec/support/shared_examples/requests/api/merge_requests_list.rb
index 668a390b5d2..92d4dd598d5 100644
--- a/spec/support/shared_examples/requests/api/merge_requests_list.rb
+++ b/spec/support/shared_examples/requests/api/merge_requests_list.rb
@@ -186,6 +186,23 @@ shared_examples 'merge requests list' do
expect(json_response.length).to eq(0)
end
+ it 'returns an array of merge requests with any label when filtering by any label' do
+ get api(endpoint_path, user), labels: IssuesFinder::FILTER_ANY
+
+ expect_paginated_array_response
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['id']).to eq(merge_request.id)
+ end
+
+ it 'returns an array of merge requests without a label when filtering by no label' do
+ get api(endpoint_path, user), labels: IssuesFinder::FILTER_NONE
+
+ response_ids = json_response.map { |merge_request| merge_request['id'] }
+
+ expect_paginated_array_response
+ expect(response_ids).to contain_exactly(merge_request_closed.id, merge_request_merged.id, merge_request_locked.id)
+ end
+
it 'returns an array of labeled merge requests that are merged for a milestone' do
bug_label = create(:label, title: 'bug', color: '#FFAABB', project: project)