Commit f258a59e authored by jubianchi's avatar jubianchi
Browse files

Filters issues by milestone via API

parent fd338d67
......@@ -5,6 +5,7 @@ v 7.4.0
- Refactor test coverage tools usage. Use SIMPLECOV=true to generate it locally
- Increase unicorn timeout to 60 seconds
- Sort search autocomplete projects by stars count so most popular go first
- API: filter project issues by milestone (Julien Bianchi)
v 7.3.1
- Fix ref parsing in Gitlab::GitAccess
......
......@@ -95,6 +95,8 @@ GET /projects/:id/issues?state=closed
GET /projects/:id/issues?labels=foo
GET /projects/:id/issues?labels=foo,bar
GET /projects/:id/issues?labels=foo,bar&state=opened
GET /projects/:id/issues?milestone=1.0.0
GET /projects/:id/issues?milestone=1.0.0&state=opened
```
Parameters:
......@@ -102,6 +104,7 @@ Parameters:
- `id` (required) - The ID of a project
- `state` (optional) - Return `all` issues or just those that are `opened` or `closed`
- `labels` (optional) - Comma-separated list of label names
- `milestone` (optional) - Milestone title
## Single issue
......
......@@ -4,7 +4,7 @@ class Issues < Grape::API
before { authenticate! }
helpers do
def filter_issues_state(issues, state = nil)
def filter_issues_state(issues, state)
case state
when 'opened' then issues.opened
when 'closed' then issues.closed
......@@ -13,7 +13,11 @@ def filter_issues_state(issues, state = nil)
end
def filter_issues_labels(issues, labels)
issues.includes(:labels).where("labels.title" => labels.split(','))
issues.includes(:labels).where('labels.title' => labels.split(','))
end
def filter_issues_milestone(issues, milestone)
issues.includes(:milestone).where('milestones.title' => milestone)
end
end
......@@ -48,19 +52,24 @@ def filter_issues_labels(issues, labels)
# id (required) - The ID of a project
# state (optional) - Return "opened" or "closed" issues
# labels (optional) - Comma-separated list of label names
# milestone (optional) - Milestone title
#
# Example Requests:
# GET /projects/:id/issues
# GET /projects/:id/issues?state=opened
# GET /projects/:id/issues?state=closed
# GET /projects/:id/issues
# GET /projects/:id/issues?labels=foo
# GET /projects/:id/issues?labels=foo,bar
# GET /projects/:id/issues?labels=foo,bar&state=opened
# GET /projects/:id/issues?milestone=1.0.0
# GET /projects/:id/issues?milestone=1.0.0&state=closed
get ":id/issues" do
issues = user_project.issues
issues = filter_issues_state(issues, params[:state]) unless params[:state].nil?
issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
unless params[:milestone].nil?
issues = filter_issues_milestone(issues, params[:milestone])
end
issues = issues.order('issues.id DESC')
present paginate(issues), with: Entities::Issue
......
......@@ -4,12 +4,29 @@
include ApiHelpers
let(:user) { create(:user) }
let!(:project) { create(:project, namespace: user.namespace ) }
let!(:closed_issue) { create(:closed_issue, author: user, assignee: user, project: project, state: :closed) }
let!(:issue) { create(:issue, author: user, assignee: user, project: project) }
let!(:closed_issue) do
create :closed_issue,
author: user,
assignee: user,
project: project,
state: :closed,
milestone: milestone
end
let!(:issue) do
create :issue,
author: user,
assignee: user,
project: project,
milestone: milestone
end
let!(:label) do
create(:label, title: 'label', color: '#FFAABB', project: project)
end
let!(:label_link) { create(:label_link, label: label, target: issue) }
let!(:milestone) { create(:milestone, title: '1.0.0', project: project) }
let!(:empty_milestone) do
create(:milestone, title: '2.0.0', project: project)
end
before { project.team << [user, :reporter] }
......@@ -102,15 +119,18 @@
end
describe "GET /projects/:id/issues" do
let(:base_url) { "/projects/#{project.id}" }
let(:title) { milestone.title }
it "should return project issues" do
get api("/projects/#{project.id}/issues", user)
get api("#{base_url}/issues", user)
response.status.should == 200
json_response.should be_an Array
json_response.first['title'].should == issue.title
end
it 'should return an array of labeled project issues' do
get api("/projects/#{project.id}/issues?labels=#{label.title}", user)
get api("#{base_url}/issues?labels=#{label.title}", user)
response.status.should == 200
json_response.should be_an Array
json_response.length.should == 1
......@@ -118,7 +138,7 @@
end
it 'should return an array of labeled project issues when at least one label matches' do
get api("/projects/#{project.id}/issues?labels=#{label.title},foo,bar", user)
get api("#{base_url}/issues?labels=#{label.title},foo,bar", user)
response.status.should == 200
json_response.should be_an Array
json_response.length.should == 1
......@@ -126,11 +146,43 @@
end
it 'should return an empty array if no project issue matches labels' do
get api("/projects/#{project.id}/issues?labels=foo,bar", user)
get api("#{base_url}/issues?labels=foo,bar", user)
response.status.should == 200
json_response.should be_an Array
json_response.length.should == 0
end
it 'should return an empty array if no issue matches milestone' do
get api("#{base_url}/issues?milestone=#{empty_milestone.title}", user)
response.status.should == 200
json_response.should be_an Array
json_response.length.should == 0
end
it 'should return an empty array if milestone does not exist' do
get api("#{base_url}/issues?milestone=foo", user)
response.status.should == 200
json_response.should be_an Array
json_response.length.should == 0
end
it 'should return an array of issues in given milestone' do
get api("#{base_url}/issues?milestone=#{title}", user)
response.status.should == 200
json_response.should be_an Array
json_response.length.should == 2
json_response.first['id'].should == issue.id
json_response.second['id'].should == closed_issue.id
end
it 'should return an array of issues matching state in milestone' do
get api("#{base_url}/issues?milestone=#{milestone.title}"\
'&state=closed', user)
response.status.should == 200
json_response.should be_an Array
json_response.length.should == 1
json_response.first['id'].should == closed_issue.id
end
end
describe "GET /projects/:id/issues/:issue_id" do
......
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