Commit dc71d79f authored by Mayra Cabrera's avatar Mayra Cabrera

Merge branch '31289-issue-summary-on-release-be-2' into 'master'

Add issue_stats to milestones

See merge request gitlab-org/gitlab!19937
parents ec39a640 36586115
...@@ -70,7 +70,11 @@ Example response: ...@@ -70,7 +70,11 @@ Example response:
"updated_at":"2019-07-12T19:45:44.256Z", "updated_at":"2019-07-12T19:45:44.256Z",
"due_date":"2019-08-16T11:00:00.256Z", "due_date":"2019-08-16T11:00:00.256Z",
"start_date":"2019-07-30T12:00:00.256Z", "start_date":"2019-07-30T12:00:00.256Z",
"web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/1" "web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/1",
"issue_stats": {
"total": 98,
"closed": 76
}
}, },
{ {
"id":52, "id":52,
...@@ -83,7 +87,11 @@ Example response: ...@@ -83,7 +87,11 @@ Example response:
"updated_at":"2019-07-16T14:00:12.256Z", "updated_at":"2019-07-16T14:00:12.256Z",
"due_date":"2019-08-16T11:00:00.256Z", "due_date":"2019-08-16T11:00:00.256Z",
"start_date":"2019-07-30T12:00:00.256Z", "start_date":"2019-07-30T12:00:00.256Z",
"web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/2" "web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/2",
"issue_stats": {
"total": 24,
"closed": 21
}
} }
], ],
"commit_path":"/root/awesome-app/commit/588440f66559714280628a4f9799f0c4eb880a4a", "commit_path":"/root/awesome-app/commit/588440f66559714280628a4f9799f0c4eb880a4a",
...@@ -252,7 +260,11 @@ Example response: ...@@ -252,7 +260,11 @@ Example response:
"updated_at":"2019-07-12T19:45:44.256Z", "updated_at":"2019-07-12T19:45:44.256Z",
"due_date":"2019-08-16T11:00:00.256Z", "due_date":"2019-08-16T11:00:00.256Z",
"start_date":"2019-07-30T12:00:00.256Z", "start_date":"2019-07-30T12:00:00.256Z",
"web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/1" "web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/1",
"issue_stats": {
"total": 98,
"closed": 76
}
}, },
{ {
"id":52, "id":52,
...@@ -265,7 +277,11 @@ Example response: ...@@ -265,7 +277,11 @@ Example response:
"updated_at":"2019-07-16T14:00:12.256Z", "updated_at":"2019-07-16T14:00:12.256Z",
"due_date":"2019-08-16T11:00:00.256Z", "due_date":"2019-08-16T11:00:00.256Z",
"start_date":"2019-07-30T12:00:00.256Z", "start_date":"2019-07-30T12:00:00.256Z",
"web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/2" "web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/2",
"issue_stats": {
"total": 24,
"closed": 21
}
} }
], ],
"commit_path":"/root/awesome-app/commit/588440f66559714280628a4f9799f0c4eb880a4a", "commit_path":"/root/awesome-app/commit/588440f66559714280628a4f9799f0c4eb880a4a",
...@@ -374,7 +390,11 @@ Example response: ...@@ -374,7 +390,11 @@ Example response:
"updated_at":"2019-07-12T19:45:44.256Z", "updated_at":"2019-07-12T19:45:44.256Z",
"due_date":"2019-08-16T11:00:00.256Z", "due_date":"2019-08-16T11:00:00.256Z",
"start_date":"2019-07-30T12:00:00.256Z", "start_date":"2019-07-30T12:00:00.256Z",
"web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/1" "web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/1",
"issue_stats": {
"total": 99,
"closed": 76
}
}, },
{ {
"id":52, "id":52,
...@@ -387,7 +407,11 @@ Example response: ...@@ -387,7 +407,11 @@ Example response:
"updated_at":"2019-07-16T14:00:12.256Z", "updated_at":"2019-07-16T14:00:12.256Z",
"due_date":"2019-08-16T11:00:00.256Z", "due_date":"2019-08-16T11:00:00.256Z",
"start_date":"2019-07-30T12:00:00.256Z", "start_date":"2019-07-30T12:00:00.256Z",
"web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/2" "web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/2",
"issue_stats": {
"total": 24,
"closed": 21
}
} }
], ],
"commit_path":"/root/awesome-app/commit/588440f66559714280628a4f9799f0c4eb880a4a", "commit_path":"/root/awesome-app/commit/588440f66559714280628a4f9799f0c4eb880a4a",
...@@ -495,7 +519,11 @@ Example response: ...@@ -495,7 +519,11 @@ Example response:
"updated_at":"2019-09-01T13:00:00.256Z", "updated_at":"2019-09-01T13:00:00.256Z",
"due_date":"2019-09-20T13:00:00.256Z", "due_date":"2019-09-20T13:00:00.256Z",
"start_date":"2019-09-05T12:00:00.256Z", "start_date":"2019-09-05T12:00:00.256Z",
"web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/3" "web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/3",
"issue_stats": {
"opened": 11,
"closed": 78
}
} }
], ],
"commit_path":"/root/awesome-app/commit/588440f66559714280628a4f9799f0c4eb880a4a", "commit_path":"/root/awesome-app/commit/588440f66559714280628a4f9799f0c4eb880a4a",
......
# frozen_string_literal: true
module API
module Entities
class MilestoneWithStats < Entities::Milestone
expose :issue_stats do
expose :total_issues_count, as: :total
expose :closed_issues_count, as: :closed
end
end
end
end
...@@ -18,7 +18,7 @@ module API ...@@ -18,7 +18,7 @@ module API
expose :author, using: Entities::UserBasic, if: -> (release, _) { release.author.present? } expose :author, using: Entities::UserBasic, if: -> (release, _) { release.author.present? }
expose :commit, using: Entities::Commit, if: ->(_, _) { can_download_code? } expose :commit, using: Entities::Commit, if: ->(_, _) { can_download_code? }
expose :upcoming_release?, as: :upcoming_release expose :upcoming_release?, as: :upcoming_release
expose :milestones, using: Entities::Milestone, if: -> (release, _) { release.milestones.present? && can_read_milestone? } expose :milestones, using: Entities::MilestoneWithStats, if: -> (release, _) { release.milestones.present? && can_read_milestone? }
expose :commit_path, expose_nil: false expose :commit_path, expose_nil: false
expose :tag_path, expose_nil: false expose :tag_path, expose_nil: false
expose :evidence_sha, expose_nil: false, if: ->(_, _) { can_download_code? } expose :evidence_sha, expose_nil: false, if: ->(_, _) { can_download_code? }
......
{
"type": "object",
"properties" : {
"id": { "type": "integer" },
"iid": { "type": "integer" },
"project_id": { "type": ["integer", "null"] },
"group_id": { "type": ["integer", "null"] },
"title": { "type": "string" },
"description": { "type": ["string", "null"] },
"state": { "type": "string" },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"start_date": { "type": "date" },
"due_date": { "type": "date" },
"web_url": { "type": "string" },
"issue_stats": {
"required": ["total", "closed"],
"properties": {
"total": { "type": "integer" },
"closed": { "type": "integer" }
},
"additionalProperties": false
}
},
"required": [
"id", "iid", "title", "description", "state",
"state", "created_at", "updated_at", "start_date", "due_date", "issue_stats"
],
"additionalProperties": false
}
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
}, },
"milestones": { "milestones": {
"type": "array", "type": "array",
"items": { "$ref": "milestone.json" } "items": { "$ref": "milestone_with_stats.json" }
}, },
"commit_path": { "type": "string" }, "commit_path": { "type": "string" },
"tag_path": { "type": "string" }, "tag_path": { "type": "string" },
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
"upcoming_release": { "type": "boolean" }, "upcoming_release": { "type": "boolean" },
"milestones": { "milestones": {
"type": "array", "type": "array",
"items": { "$ref": "../milestone.json" } "items": { "$ref": "../milestone_with_stats.json" }
}, },
"commit_path": { "type": "string" }, "commit_path": { "type": "string" },
"tag_path": { "type": "string" }, "tag_path": { "type": "string" },
......
...@@ -359,12 +359,29 @@ describe API::Releases do ...@@ -359,12 +359,29 @@ describe API::Releases do
let(:milestone) { create(:milestone, project: project) } let(:milestone) { create(:milestone, project: project) }
it 'matches schema' do
get api("/projects/#{project.id}/releases/v0.1", non_project_member)
expect(response).to match_response_schema('public_api/v4/release')
end
it 'exposes milestones' do it 'exposes milestones' do
get api("/projects/#{project.id}/releases/v0.1", non_project_member) get api("/projects/#{project.id}/releases/v0.1", non_project_member)
expect(json_response['milestones'].first['title']).to eq(milestone.title) expect(json_response['milestones'].first['title']).to eq(milestone.title)
end end
it 'returns issue stats for milestone' do
create_list(:issue, 2, milestone: milestone, project: project)
create_list(:issue, 3, :closed, milestone: milestone, project: project)
get api("/projects/#{project.id}/releases/v0.1", non_project_member)
issue_stats = json_response['milestones'].first["issue_stats"]
expect(issue_stats["total"]).to eq(5)
expect(issue_stats["closed"]).to eq(3)
end
context 'when project restricts visibility of issues and merge requests' do context 'when project restricts visibility of issues and merge requests' do
let!(:project) { create(:project, :repository, :public, :issues_private, :merge_requests_private) } let!(:project) { create(:project, :repository, :public, :issues_private, :merge_requests_private) }
......
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