Commit be3578d2 authored by Alexandru Croitor's avatar Alexandru Croitor

Add array support for labels

* Support label parameter as comma separated and array of strings
for merge requests and issues api endpoints
parent ee8cb2d1
...@@ -89,7 +89,7 @@ class IssuableBaseService < BaseService ...@@ -89,7 +89,7 @@ class IssuableBaseService < BaseService
return unless labels return unless labels
params[:label_ids] = labels.split(",").map do |label_name| params[:label_ids] = labels.map do |label_name|
label = Labels::FindOrCreateService.new( label = Labels::FindOrCreateService.new(
current_user, current_user,
parent, parent,
......
...@@ -34,7 +34,7 @@ module API ...@@ -34,7 +34,7 @@ module API
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
params :issues_params do params :issues_params do
optional :labels, type: String, desc: 'Comma-separated list of label names' optional :labels, type: Array[String], coerce_with: Validations::Types::LabelsList.coerce, desc: 'Comma-separated list of label names'
optional :milestone, type: String, desc: 'Milestone title' optional :milestone, type: String, desc: 'Milestone title'
optional :order_by, type: String, values: %w[created_at updated_at], default: 'created_at', optional :order_by, type: String, values: %w[created_at updated_at], default: 'created_at',
desc: 'Return issues ordered by `created_at` or `updated_at` fields.' desc: 'Return issues ordered by `created_at` or `updated_at` fields.'
...@@ -65,7 +65,7 @@ module API ...@@ -65,7 +65,7 @@ module API
optional :assignee_ids, type: Array[Integer], desc: 'The array of user IDs to assign issue' optional :assignee_ids, type: Array[Integer], desc: 'The array of user IDs to assign issue'
optional :assignee_id, type: Integer, desc: '[Deprecated] The ID of a user to assign issue' optional :assignee_id, type: Integer, desc: '[Deprecated] The ID of a user to assign issue'
optional :milestone_id, type: Integer, desc: 'The ID of a milestone to assign issue' optional :milestone_id, type: Integer, desc: 'The ID of a milestone to assign issue'
optional :labels, type: String, desc: 'Comma-separated list of label names' optional :labels, type: Array[String], coerce_with: Validations::Types::LabelsList.coerce, desc: 'Comma-separated list of label names'
optional :due_date, type: String, desc: 'Date string in the format YEAR-MONTH-DAY' optional :due_date, type: String, desc: 'Date string in the format YEAR-MONTH-DAY'
optional :confidential, type: Boolean, desc: 'Boolean parameter if the issue should be confidential' optional :confidential, type: Boolean, desc: 'Boolean parameter if the issue should be confidential'
optional :discussion_locked, type: Boolean, desc: " Boolean parameter indicating if the issue's discussion is locked" optional :discussion_locked, type: Boolean, desc: " Boolean parameter indicating if the issue's discussion is locked"
......
...@@ -95,7 +95,7 @@ module API ...@@ -95,7 +95,7 @@ module API
optional :sort, type: String, values: %w[asc desc], default: 'desc', optional :sort, type: String, values: %w[asc desc], default: 'desc',
desc: 'Return merge requests sorted in `asc` or `desc` order.' desc: 'Return merge requests sorted in `asc` or `desc` order.'
optional :milestone, type: String, desc: 'Return merge requests for a specific milestone' optional :milestone, type: String, desc: 'Return merge requests for a specific milestone'
optional :labels, type: String, desc: 'Comma-separated list of label names' optional :labels, type: Array[String], coerce_with: Validations::Types::LabelsList.coerce, desc: 'Comma-separated list of label names'
optional :created_after, type: DateTime, desc: 'Return merge requests created after the specified time' optional :created_after, type: DateTime, desc: 'Return merge requests created after the specified time'
optional :created_before, type: DateTime, desc: 'Return merge requests created before the specified time' optional :created_before, type: DateTime, desc: 'Return merge requests created before the specified time'
optional :updated_after, type: DateTime, desc: 'Return merge requests updated after the specified time' optional :updated_after, type: DateTime, desc: 'Return merge requests updated after the specified time'
...@@ -179,7 +179,7 @@ module API ...@@ -179,7 +179,7 @@ module API
optional :description, type: String, desc: 'The description of the merge request' optional :description, type: String, desc: 'The description of the merge request'
optional :assignee_id, type: Integer, desc: 'The ID of a user to assign the merge request' optional :assignee_id, type: Integer, desc: 'The ID of a user to assign the merge request'
optional :milestone_id, type: Integer, desc: 'The ID of a milestone to assign the merge request' optional :milestone_id, type: Integer, desc: 'The ID of a milestone to assign the merge request'
optional :labels, type: String, coerce_with: ->(val) { val.is_a?(Array) ? val.join(', ') : val }, desc: 'Comma-separated list of label names' optional :labels, type: Array[String], coerce_with: Validations::Types::LabelsList.coerce, desc: 'Comma-separated list of label names'
optional :remove_source_branch, type: Boolean, desc: 'Remove source branch when merging' optional :remove_source_branch, type: Boolean, desc: 'Remove source branch when merging'
optional :allow_collaboration, type: Boolean, desc: 'Allow commits from members who can merge to the target branch' optional :allow_collaboration, type: Boolean, desc: 'Allow commits from members who can merge to the target branch'
optional :allow_maintainer_to_push, type: Boolean, as: :allow_collaboration, desc: '[deprecated] See allow_collaboration' optional :allow_maintainer_to_push, type: Boolean, as: :allow_collaboration, desc: '[deprecated] See allow_collaboration'
......
# frozen_string_literal: true
module API
module Validations
module Types
class LabelsList
def self.coerce
lambda do |value|
case value
when String
value.split(',').map(&:strip)
when Array
value.map { |v| v.to_s.split(',').map(&:strip) }.flatten
when LabelsList
value
else
[]
end
end
end
end
end
end
end
...@@ -271,7 +271,14 @@ describe API::Issues do ...@@ -271,7 +271,14 @@ describe API::Issues do
end end
it 'returns an array of labeled issues' do it 'returns an array of labeled issues' do
get api("/issues", user), params: { labels: label.title } get api('/issues', user), params: { labels: label.title }
expect_paginated_array_response(issue.id)
expect(json_response.first['labels']).to eq([label.title])
end
it 'returns an array of labeled issues with labels param as array' do
get api('/issues', user), params: { labels: [label.title] }
expect_paginated_array_response(issue.id) expect_paginated_array_response(issue.id)
expect(json_response.first['labels']).to eq([label.title]) expect(json_response.first['labels']).to eq([label.title])
...@@ -284,7 +291,20 @@ describe API::Issues do ...@@ -284,7 +291,20 @@ describe API::Issues do
create(:label_link, label: label_b, target: issue) create(:label_link, label: label_b, target: issue)
create(:label_link, label: label_c, target: issue) create(:label_link, label: label_c, target: issue)
get api("/issues", user), params: { labels: "#{label.title},#{label_b.title},#{label_c.title}" } get api('/issues', user), params: { labels: "#{label.title},#{label_b.title},#{label_c.title}" }
expect_paginated_array_response(issue.id)
expect(json_response.first['labels']).to eq([label_c.title, label_b.title, label.title])
end
it 'returns an array of labeled issues when all labels matches with labels param as array' do
label_b = create(:label, title: 'foo', project: project)
label_c = create(:label, title: 'bar', project: project)
create(:label_link, label: label_b, target: issue)
create(:label_link, label: label_c, target: issue)
get api('/issues', user), params: { labels: [label.title, label_b.title, label_c.title] }
expect_paginated_array_response(issue.id) expect_paginated_array_response(issue.id)
expect(json_response.first['labels']).to eq([label_c.title, label_b.title, label.title]) expect(json_response.first['labels']).to eq([label_c.title, label_b.title, label.title])
...@@ -296,8 +316,22 @@ describe API::Issues do ...@@ -296,8 +316,22 @@ describe API::Issues do
expect_paginated_array_response([]) expect_paginated_array_response([])
end end
it 'returns an empty array if no issue matches labels with labels param as array' do
get api('/issues', user), params: { labels: %w(foo bar) }
expect_paginated_array_response([])
end
it 'returns an array of labeled issues matching given state' do it 'returns an array of labeled issues matching given state' do
get api("/issues", user), params: { labels: label.title, state: :opened } get api('/issues', user), params: { labels: label.title, state: :opened }
expect_paginated_array_response(issue.id)
expect(json_response.first['labels']).to eq([label.title])
expect(json_response.first['state']).to eq('opened')
end
it 'returns an array of labeled issues matching given state with labels param as array' do
get api('/issues', user), params: { labels: [label.title], state: :opened }
expect_paginated_array_response(issue.id) expect_paginated_array_response(issue.id)
expect(json_response.first['labels']).to eq([label.title]) expect(json_response.first['labels']).to eq([label.title])
...@@ -305,25 +339,43 @@ describe API::Issues do ...@@ -305,25 +339,43 @@ describe API::Issues do
end end
it 'returns an empty array if no issue matches labels and state filters' do it 'returns an empty array if no issue matches labels and state filters' do
get api("/issues", user), params: { labels: label.title, state: :closed } get api('/issues', user), params: { labels: label.title, state: :closed }
expect_paginated_array_response([]) expect_paginated_array_response([])
end end
it 'returns an array of issues with any label' do it 'returns an array of issues with any label' do
get api("/issues", user), params: { labels: IssuesFinder::FILTER_ANY } get api('/issues', user), params: { labels: IssuesFinder::FILTER_ANY }
expect_paginated_array_response(issue.id)
end
it 'returns an array of issues with any label with labels param as array' do
get api('/issues', user), params: { labels: [IssuesFinder::FILTER_ANY] }
expect_paginated_array_response(issue.id) expect_paginated_array_response(issue.id)
end end
it 'returns an array of issues with no label' do it 'returns an array of issues with no label' do
get api("/issues", user), params: { labels: IssuesFinder::FILTER_NONE } get api('/issues', user), params: { labels: IssuesFinder::FILTER_NONE }
expect_paginated_array_response(closed_issue.id)
end
it 'returns an array of issues with no label with labels param as array' do
get api('/issues', user), params: { labels: [IssuesFinder::FILTER_NONE] }
expect_paginated_array_response(closed_issue.id) expect_paginated_array_response(closed_issue.id)
end end
it 'returns an array of issues with no label when using the legacy No+Label filter' do it 'returns an array of issues with no label when using the legacy No+Label filter' do
get api("/issues", user), params: { labels: "No Label" } get api('/issues', user), params: { labels: 'No Label' }
expect_paginated_array_response(closed_issue.id)
end
it 'returns an array of issues with no label when using the legacy No+Label filter with labels param as array' do
get api('/issues', user), params: { labels: ['No Label'] }
expect_paginated_array_response(closed_issue.id) expect_paginated_array_response(closed_issue.id)
end end
...@@ -588,12 +640,25 @@ describe API::Issues do ...@@ -588,12 +640,25 @@ describe API::Issues do
expect(json_response.first['labels']).to eq([group_label.title]) expect(json_response.first['labels']).to eq([group_label.title])
end end
it 'returns an array of labeled group issues with labels param as array' do
get api(base_url, user), params: { labels: [group_label.title] }
expect_paginated_array_response(group_issue.id)
expect(json_response.first['labels']).to eq([group_label.title])
end
it 'returns an array of labeled group issues where all labels match' do it 'returns an array of labeled group issues where all labels match' do
get api(base_url, user), params: { labels: "#{group_label.title},foo,bar" } get api(base_url, user), params: { labels: "#{group_label.title},foo,bar" }
expect_paginated_array_response([]) expect_paginated_array_response([])
end end
it 'returns an array of labeled group issues where all labels match with labels param as array' do
get api(base_url, user), params: { labels: [group_label.title, 'foo', 'bar'] }
expect_paginated_array_response([])
end
it 'returns issues matching given search string for title' do it 'returns issues matching given search string for title' do
get api(base_url, user), params: { search: group_issue.title } get api(base_url, user), params: { search: group_issue.title }
...@@ -619,6 +684,19 @@ describe API::Issues do ...@@ -619,6 +684,19 @@ describe API::Issues do
expect(json_response.first['labels']).to eq([label_c.title, label_b.title, group_label.title]) expect(json_response.first['labels']).to eq([label_c.title, label_b.title, group_label.title])
end end
it 'returns an array of labeled issues when all labels matches with labels param as array' do
label_b = create(:label, title: 'foo', project: group_project)
label_c = create(:label, title: 'bar', project: group_project)
create(:label_link, label: label_b, target: group_issue)
create(:label_link, label: label_c, target: group_issue)
get api(base_url, user), params: { labels: [group_label.title, label_b.title, label_c.title] }
expect_paginated_array_response(group_issue.id)
expect(json_response.first['labels']).to eq([label_c.title, label_b.title, group_label.title])
end
it 'returns an array of issues found by iids' do it 'returns an array of issues found by iids' do
get api(base_url, user), params: { iids: [group_issue.iid] } get api(base_url, user), params: { iids: [group_issue.iid] }
...@@ -645,12 +723,25 @@ describe API::Issues do ...@@ -645,12 +723,25 @@ describe API::Issues do
expect(json_response.first['id']).to eq(group_issue.id) expect(json_response.first['id']).to eq(group_issue.id)
end end
it 'returns an array of group issues with any label with labels param as array' do
get api(base_url, user), params: { labels: [IssuesFinder::FILTER_ANY] }
expect_paginated_array_response(group_issue.id)
expect(json_response.first['id']).to eq(group_issue.id)
end
it 'returns an array of group issues with no label' do it 'returns an array of group issues with no label' do
get api(base_url, user), params: { labels: IssuesFinder::FILTER_NONE } get api(base_url, user), params: { labels: IssuesFinder::FILTER_NONE }
expect_paginated_array_response([group_closed_issue.id, group_confidential_issue.id]) expect_paginated_array_response([group_closed_issue.id, group_confidential_issue.id])
end end
it 'returns an array of group issues with no label with labels param as array' do
get api(base_url, user), params: { labels: [IssuesFinder::FILTER_NONE] }
expect_paginated_array_response([group_closed_issue.id, group_confidential_issue.id])
end
it 'returns an empty array if no issue matches milestone' do it 'returns an empty array if no issue matches milestone' do
get api(base_url, user), params: { milestone: group_empty_milestone.title } get api(base_url, user), params: { milestone: group_empty_milestone.title }
...@@ -842,6 +933,12 @@ describe API::Issues do ...@@ -842,6 +933,12 @@ describe API::Issues do
expect_paginated_array_response(issue.id) expect_paginated_array_response(issue.id)
end end
it 'returns an array of labeled project issues with labels param as array' do
get api("#{base_url}/issues", user), params: { labels: [label.title] }
expect_paginated_array_response(issue.id)
end
it 'returns an array of labeled issues when all labels matches' do it 'returns an array of labeled issues when all labels matches' do
label_b = create(:label, title: 'foo', project: project) label_b = create(:label, title: 'foo', project: project)
label_c = create(:label, title: 'bar', project: project) label_c = create(:label, title: 'bar', project: project)
...@@ -854,6 +951,18 @@ describe API::Issues do ...@@ -854,6 +951,18 @@ describe API::Issues do
expect_paginated_array_response(issue.id) expect_paginated_array_response(issue.id)
end end
it 'returns an array of labeled issues when all labels matches with labels param as array' do
label_b = create(:label, title: 'foo', project: project)
label_c = create(:label, title: 'bar', project: project)
create(:label_link, label: label_b, target: issue)
create(:label_link, label: label_c, target: issue)
get api("#{base_url}/issues", user), params: { labels: [label.title, label_b.title, label_c.title] }
expect_paginated_array_response(issue.id)
end
it 'returns issues matching given search string for title' do it 'returns issues matching given search string for title' do
get api("#{base_url}/issues?search=#{issue.title}", user) get api("#{base_url}/issues?search=#{issue.title}", user)
...@@ -890,12 +999,24 @@ describe API::Issues do ...@@ -890,12 +999,24 @@ describe API::Issues do
expect_paginated_array_response(issue.id) expect_paginated_array_response(issue.id)
end end
it 'returns an array of project issues with any label with labels param as array' do
get api("#{base_url}/issues", user), params: { labels: [IssuesFinder::FILTER_ANY] }
expect_paginated_array_response(issue.id)
end
it 'returns an array of project issues with no label' do it 'returns an array of project issues with no label' do
get api("#{base_url}/issues", user), params: { labels: IssuesFinder::FILTER_NONE } get api("#{base_url}/issues", user), params: { labels: IssuesFinder::FILTER_NONE }
expect_paginated_array_response([confidential_issue.id, closed_issue.id]) expect_paginated_array_response([confidential_issue.id, closed_issue.id])
end end
it 'returns an array of project issues with no label with labels param as array' do
get api("#{base_url}/issues", user), params: { labels: [IssuesFinder::FILTER_NONE] }
expect_paginated_array_response([confidential_issue.id, closed_issue.id])
end
it 'returns an empty array if no project issue matches labels' do it 'returns an empty array if no project issue matches labels' do
get api("#{base_url}/issues", user), params: { labels: 'foo,bar' } get api("#{base_url}/issues", user), params: { labels: 'foo,bar' }
...@@ -1215,6 +1336,19 @@ describe API::Issues do ...@@ -1215,6 +1336,19 @@ describe API::Issues do
expect(json_response['assignees'].first['name']).to eq(user2.name) expect(json_response['assignees'].first['name']).to eq(user2.name)
end end
it 'creates a new project issue with labels param as array' do
post api("/projects/#{project.id}/issues", user),
params: { title: 'new issue', labels: %w(label label2), weight: 3, assignee_ids: [user2.id] }
expect(response).to have_gitlab_http_status(201)
expect(json_response['title']).to eq('new issue')
expect(json_response['description']).to be_nil
expect(json_response['labels']).to eq(%w(label label2))
expect(json_response['confidential']).to be_falsy
expect(json_response['assignee']['name']).to eq(user2.name)
expect(json_response['assignees'].first['name']).to eq(user2.name)
end
it 'creates a new confidential project issue' do it 'creates a new confidential project issue' do
post api("/projects/#{project.id}/issues", user), post api("/projects/#{project.id}/issues", user),
params: { title: 'new issue', confidential: true } params: { title: 'new issue', confidential: true }
...@@ -1269,6 +1403,20 @@ describe API::Issues do ...@@ -1269,6 +1403,20 @@ describe API::Issues do
expect(json_response['labels']).to include '&' expect(json_response['labels']).to include '&'
end end
it 'allows special label names with labels param as array' do
post api("/projects/#{project.id}/issues", user),
params: {
title: 'new issue',
labels: ['label', 'label?', 'label&foo, ?, &']
}
expect(response.status).to eq(201)
expect(json_response['labels']).to include 'label'
expect(json_response['labels']).to include 'label?'
expect(json_response['labels']).to include 'label&foo'
expect(json_response['labels']).to include '?'
expect(json_response['labels']).to include '&'
end
it 'returns 400 if title is too long' do it 'returns 400 if title is too long' do
post api("/projects/#{project.id}/issues", user), post api("/projects/#{project.id}/issues", user),
params: { title: 'g' * 256 } params: { title: 'g' * 256 }
...@@ -1377,6 +1525,12 @@ describe API::Issues do ...@@ -1377,6 +1525,12 @@ describe API::Issues do
post api("/projects/#{project.id}/issues", non_member), params: { title: 'new issue', labels: 'label, label2' } post api("/projects/#{project.id}/issues", non_member), params: { title: 'new issue', labels: 'label, label2' }
end.not_to change { project.labels.count } end.not_to change { project.labels.count }
end end
it 'cannot create new labels with labels param as array' do
expect do
post api("/projects/#{project.id}/issues", non_member), params: { title: 'new issue', labels: %w(label label2) }
end.not_to change { project.labels.count }
end
end end
end end
...@@ -1444,6 +1598,21 @@ describe API::Issues do ...@@ -1444,6 +1598,21 @@ describe API::Issues do
expect(json_response['labels']).to include '&' expect(json_response['labels']).to include '&'
end end
it 'allows special label names with labels param as array' do
put api("/projects/#{project.id}/issues/#{issue.iid}", user),
params: {
title: 'updated title',
labels: ['label', 'label?', 'label&foo, ?, &']
}
expect(response.status).to eq(200)
expect(json_response['labels']).to include 'label'
expect(json_response['labels']).to include 'label?'
expect(json_response['labels']).to include 'label&foo'
expect(json_response['labels']).to include '?'
expect(json_response['labels']).to include '&'
end
context 'confidential issues' do context 'confidential issues' do
it "returns 403 for non project members" do it "returns 403 for non project members" do
put api("/projects/#{project.id}/issues/#{confidential_issue.iid}", non_member), put api("/projects/#{project.id}/issues/#{confidential_issue.iid}", non_member),
...@@ -1603,6 +1772,16 @@ describe API::Issues do ...@@ -1603,6 +1772,16 @@ describe API::Issues do
expect(json_response['updated_at']).to be > Time.now expect(json_response['updated_at']).to be > Time.now
end end
it 'removes all labels and touches the record with labels param as array' do
Timecop.travel(1.minute.from_now) do
put api("/projects/#{project.id}/issues/#{issue.iid}", user), params: { labels: [''] }
end
expect(response).to have_gitlab_http_status(200)
expect(json_response['labels']).to eq([])
expect(json_response['updated_at']).to be > Time.now
end
it 'updates labels and touches the record' do it 'updates labels and touches the record' do
Timecop.travel(1.minute.from_now) do Timecop.travel(1.minute.from_now) do
put api("/projects/#{project.id}/issues/#{issue.iid}", user), put api("/projects/#{project.id}/issues/#{issue.iid}", user),
...@@ -1614,6 +1793,17 @@ describe API::Issues do ...@@ -1614,6 +1793,17 @@ describe API::Issues do
expect(json_response['updated_at']).to be > Time.now expect(json_response['updated_at']).to be > Time.now
end end
it 'updates labels and touches the record with labels param as array' do
Timecop.travel(1.minute.from_now) do
put api("/projects/#{project.id}/issues/#{issue.iid}", user),
params: { labels: %w(foo bar) }
end
expect(response).to have_gitlab_http_status(200)
expect(json_response['labels']).to include 'foo'
expect(json_response['labels']).to include 'bar'
expect(json_response['updated_at']).to be > Time.now
end
it 'allows special label names' do it 'allows special label names' do
put api("/projects/#{project.id}/issues/#{issue.iid}", user), put api("/projects/#{project.id}/issues/#{issue.iid}", user),
params: { labels: 'label:foo, label-bar,label_bar,label/bar,label?bar,label&bar,?,&' } params: { labels: 'label:foo, label-bar,label_bar,label/bar,label?bar,label&bar,?,&' }
...@@ -1628,6 +1818,20 @@ describe API::Issues do ...@@ -1628,6 +1818,20 @@ describe API::Issues do
expect(json_response['labels']).to include '&' expect(json_response['labels']).to include '&'
end end
it 'allows special label names with labels param as array' do
put api("/projects/#{project.id}/issues/#{issue.iid}", user),
params: { labels: ['label:foo', 'label-bar', 'label_bar', 'label/bar,label?bar,label&bar,?,&'] }
expect(response.status).to eq(200)
expect(json_response['labels']).to include 'label:foo'
expect(json_response['labels']).to include 'label-bar'
expect(json_response['labels']).to include 'label_bar'
expect(json_response['labels']).to include 'label/bar'
expect(json_response['labels']).to include 'label?bar'
expect(json_response['labels']).to include 'label&bar'
expect(json_response['labels']).to include '?'
expect(json_response['labels']).to include '&'
end
it 'returns 400 if title is too long' do it 'returns 400 if title is too long' do
put api("/projects/#{project.id}/issues/#{issue.iid}", user), put api("/projects/#{project.id}/issues/#{issue.iid}", user),
params: { title: 'g' * 256 } params: { title: 'g' * 256 }
......
...@@ -617,26 +617,115 @@ describe API::MergeRequests do ...@@ -617,26 +617,115 @@ describe API::MergeRequests do
end end
end end
describe "POST /projects/:id/merge_requests" do describe 'POST /projects/:id/merge_requests' do
context 'between branches projects' do context 'between branches projects' do
it "returns merge_request" do context 'different labels' do
post api("/projects/#{project.id}/merge_requests", user), let(:params) do
params: { {
title: 'Test merge_request', title: 'Test merge_request',
source_branch: 'feature_conflict', source_branch: 'feature_conflict',
target_branch: 'master', target_branch: 'master',
author: user, author_id: user.id,
labels: 'label, label2', milestone_id: milestone.id,
milestone_id: milestone.id, squash: true
squash: true }
} end
expect(response).to have_gitlab_http_status(201) shared_examples_for 'creates merge request with labels' do
expect(json_response['title']).to eq('Test merge_request') it 'returns merge_request' do
expect(json_response['labels']).to eq(%w(label label2)) params[:labels] = labels
expect(json_response['milestone']['id']).to eq(milestone.id) post api("/projects/#{project.id}/merge_requests", user), params: params
expect(json_response['squash']).to be_truthy
expect(json_response['force_remove_source_branch']).to be_falsy expect(response).to have_gitlab_http_status(201)
expect(json_response['title']).to eq('Test merge_request')
expect(json_response['labels']).to eq(%w(label label2))
expect(json_response['milestone']['id']).to eq(milestone.id)
expect(json_response['squash']).to be_truthy
expect(json_response['force_remove_source_branch']).to be_falsy
end
end
it_behaves_like 'creates merge request with labels' do
let(:labels) { 'label, label2' }
end
it_behaves_like 'creates merge request with labels' do
let(:labels) { %w(label label2) }
end
it_behaves_like 'creates merge request with labels' do
let(:labels) { %w(label label2) }
end
it 'creates merge request with special label names' do
params[:labels] = 'label, label?, label&foo, ?, &'
post api("/projects/#{project.id}/merge_requests", user), params: params
expect(response).to have_gitlab_http_status(201)
expect(json_response['labels']).to include 'label'
expect(json_response['labels']).to include 'label?'
expect(json_response['labels']).to include 'label&foo'
expect(json_response['labels']).to include '?'
expect(json_response['labels']).to include '&'
end
it 'creates merge request with special label names as array' do
params[:labels] = ['label', 'label?', 'label&foo, ?, &', '1, 2', 3, 4]
post api("/projects/#{project.id}/merge_requests", user), params: params
expect(response).to have_gitlab_http_status(201)
expect(json_response['labels']).to include 'label'
expect(json_response['labels']).to include 'label?'
expect(json_response['labels']).to include 'label&foo'
expect(json_response['labels']).to include '?'
expect(json_response['labels']).to include '&'
expect(json_response['labels']).to include '1'
expect(json_response['labels']).to include '2'
expect(json_response['labels']).to include '3'
expect(json_response['labels']).to include '4'
end
it 'empty label param does not add any labels' do
params[:labels] = ''
post api("/projects/#{project.id}/merge_requests", user), params: params
expect(response).to have_gitlab_http_status(201)
expect(json_response['labels']).to eq([])
end
it 'empty label param as array does not add any labels, but only explicitly as json' do
params[:labels] = []
post api("/projects/#{project.id}/merge_requests", user),
params: params.to_json,
headers: { 'Content-Type': 'application/json' }
expect(response).to have_gitlab_http_status(201)
expect(json_response['labels']).to eq([])
end
xit 'empty label param as array, does not add any labels' do
params[:labels] = []
post api("/projects/#{project.id}/merge_requests", user), params: params
expect(response).to have_gitlab_http_status(201)
expect(json_response['labels']).to eq([])
end
it 'array with one empty string element does not add labels' do
params[:labels] = ['']
post api("/projects/#{project.id}/merge_requests", user), params: params
expect(response).to have_gitlab_http_status(201)
expect(json_response['labels']).to eq([])
end
it 'array with multiple empty string elements, does not add labels' do
params[:labels] = ['', '', '']
post api("/projects/#{project.id}/merge_requests", user), params: params
expect(response).to have_gitlab_http_status(201)
expect(json_response['labels']).to eq([])
end
end end
it "returns 422 when source_branch equals target_branch" do it "returns 422 when source_branch equals target_branch" do
...@@ -663,23 +752,6 @@ describe API::MergeRequests do ...@@ -663,23 +752,6 @@ describe API::MergeRequests do
expect(response).to have_gitlab_http_status(400) expect(response).to have_gitlab_http_status(400)
end end
it 'allows special label names' do
post api("/projects/#{project.id}/merge_requests", user),
params: {
title: 'Test merge_request',
source_branch: 'markdown',
target_branch: 'master',
author: user,
labels: 'label, label?, label&foo, ?, &'
}
expect(response).to have_gitlab_http_status(201)
expect(json_response['labels']).to include 'label'
expect(json_response['labels']).to include 'label?'
expect(json_response['labels']).to include 'label&foo'
expect(json_response['labels']).to include '?'
expect(json_response['labels']).to include '&'
end
context 'with existing MR' do context 'with existing MR' do
before do before do
post api("/projects/#{project.id}/merge_requests", user), post api("/projects/#{project.id}/merge_requests", user),
...@@ -1122,32 +1194,97 @@ describe API::MergeRequests do ...@@ -1122,32 +1194,97 @@ describe API::MergeRequests do
expect(json_response['force_remove_source_branch']).to be_truthy expect(json_response['force_remove_source_branch']).to be_truthy
end end
it 'allows special label names' do context 'when updating labels' do
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user), it 'allows special label names' do
params: { put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user),
title: 'new issue', params: {
labels: 'label, label?, label&foo, ?, &' title: 'new issue',
} labels: 'label, label?, label&foo, ?, &'
}
expect(response.status).to eq(200)
expect(json_response['labels']).to include 'label'
expect(json_response['labels']).to include 'label?'
expect(json_response['labels']).to include 'label&foo'
expect(json_response['labels']).to include '?'
expect(json_response['labels']).to include '&'
end
expect(response.status).to eq(200) it 'also accepts labels as an array' do
expect(json_response['labels']).to include 'label' put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user),
expect(json_response['labels']).to include 'label?' params: {
expect(json_response['labels']).to include 'label&foo' title: 'new issue',
expect(json_response['labels']).to include '?' labels: ['label', 'label?', 'label&foo, ?, &', '1, 2', 3, 4]
expect(json_response['labels']).to include '&' }
end
expect(response.status).to eq(200)
it 'also accepts labels as an array' do expect(json_response['labels']).to include 'label'
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user), expect(json_response['labels']).to include 'label?'
title: 'new issue', expect(json_response['labels']).to include 'label&foo'
labels: ['label', 'label?', 'label&foo', '?', '&'] expect(json_response['labels']).to include '?'
expect(json_response['labels']).to include '&'
expect(response.status).to eq(200) expect(json_response['labels']).to include '1'
expect(json_response['labels']).to include 'label' expect(json_response['labels']).to include '2'
expect(json_response['labels']).to include 'label?' expect(json_response['labels']).to include '3'
expect(json_response['labels']).to include 'label&foo' expect(json_response['labels']).to include '4'
expect(json_response['labels']).to include '?' end
expect(json_response['labels']).to include '&'
it 'empty label param removes labels' do
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user),
params: {
title: 'new issue',
labels: ''
}
expect(response.status).to eq(200)
expect(json_response['labels']).to eq []
end
it 'label param as empty array, but only explicitly as json, removes labels' do
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user),
params: {
title: 'new issue',
labels: []
}.to_json,
headers: { 'Content-Type' => 'application/json' }
expect(response.status).to eq(200)
expect(json_response['labels']).to eq []
end
xit 'empty label as array, removes labels' do
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user),
params: {
title: 'new issue',
labels: []
}
expect(response.status).to eq(200)
# fails, as grape ommits for some reason empty array as optional param value, so nothing it passed along
expect(json_response['labels']).to eq []
end
it 'array with one empty string element removes labels' do
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user),
params: {
title: 'new issue',
labels: ['']
}
expect(response.status).to eq(200)
expect(json_response['labels']).to eq []
end
it 'array with multiple empty string elements, removes labels' do
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user),
params: {
title: 'new issue',
labels: ['', '', '']
}
expect(response.status).to eq(200)
expect(json_response['labels']).to eq []
end
end end
it 'does not update state when title is empty' do it 'does not update state when title is empty' do
......
...@@ -186,6 +186,37 @@ shared_examples 'merge requests list' do ...@@ -186,6 +186,37 @@ shared_examples 'merge requests list' do
expect(json_response.length).to eq(0) expect(json_response.length).to eq(0)
end end
it 'returns an array of labeled merge requests where all labels match' do
path = endpoint_path + "?labels[]=#{label.title}&labels[]=#{label2.title}"
get api(path, user)
expect(response).to have_gitlab_http_status(200)
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
expect(json_response.first['labels']).to eq([label2.title, label.title])
end
it 'returns an array of merge requests with any label when filtering by any label' do
get api(endpoint_path, user), params: { labels: [" #{label.title} ", " #{label2.title} "] }
expect_paginated_array_response
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
expect(json_response.first['labels']).to eq([label2.title, label.title])
expect(json_response.first['id']).to eq(merge_request.id)
end
it 'returns an array of merge requests with any label when filtering by any label' do
get api(endpoint_path, user), params: { labels: ["#{label.title} , #{label2.title}"] }
expect_paginated_array_response
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
expect(json_response.first['labels']).to eq([label2.title, label.title])
expect(json_response.first['id']).to eq(merge_request.id)
end
it 'returns an array of merge requests with any label when filtering by any label' do it 'returns an array of merge requests with any label when filtering by any label' do
get api(endpoint_path, user), params: { labels: IssuesFinder::FILTER_ANY } get api(endpoint_path, user), params: { labels: IssuesFinder::FILTER_ANY }
......
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