summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2014-09-30 12:18:07 +0300
committerDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2014-09-30 12:18:07 +0300
commit0c29cb3451414d21346894c140a17c53de6e1567 (patch)
treef838215f9f04264e0325988f67823188e0bd46b6
parentc20c2c83859bf7ba699c085a1baf0ee1f1a6da7a (diff)
parent4c52ff51844f4c55e8c4a0f46a0b6aeacc7d42d5 (diff)
downloadgitlab-ce-0c29cb3451414d21346894c140a17c53de6e1567.tar.gz
Merge branch 'jubianchi-api/issues-filter-milestone'
-rw-r--r--CHANGELOG1
-rw-r--r--doc/api/issues.md3
-rw-r--r--lib/api/issues.rb15
-rw-r--r--spec/requests/api/issues_spec.rb64
4 files changed, 74 insertions, 9 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 15942e396d7..5c57b14ad15 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -9,6 +9,7 @@ v 7.4.0
- Do not delete tmp/repositories itself during clean-up, only its contents
- Support for backup uploads to remote storage
- Prevent notes polling when there are not notes
+ - API: filter project issues by milestone (Julien Bianchi)
v 7.3.1
- Fix ref parsing in Gitlab::GitAccess
diff --git a/doc/api/issues.md b/doc/api/issues.md
index a935b146d37..ceeb683a6bf 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -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
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 30170c657ba..d2828b24c36 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -4,7 +4,7 @@ module 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 @@ module API
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 @@ module API
# 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
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 9876452f81d..775d7b4e18d 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -4,12 +4,29 @@ describe API::API, api: true do
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 @@ describe API::API, api: true do
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 @@ describe API::API, api: true do
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 @@ describe API::API, api: true do
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