diff --git a/changelogs/unreleased/add_closed_at_attribute.yml b/changelogs/unreleased/add_closed_at_attribute.yml new file mode 100644 index 00000000000..3afb75e8915 --- /dev/null +++ b/changelogs/unreleased/add_closed_at_attribute.yml @@ -0,0 +1,5 @@ +--- +title: Add 'closed_at' attribute to Issues API +merge_request: 14316 +author: Vitaliy @blackst0ne Klachkov +type: added diff --git a/doc/api/issues.md b/doc/api/issues.md index 8ca66049d31..cd2cfe8e430 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -95,6 +95,7 @@ Example response: "username" : "root" }, "updated_at" : "2016-01-04T15:31:51.081Z", + "closed_at" : null, "id" : 76, "title" : "Consequatur vero maxime deserunt laboriosam est voluptas dolorem.", "created_at" : "2016-01-04T15:31:51.081Z", @@ -205,6 +206,7 @@ Example response: "title" : "Ut commodi ullam eos dolores perferendis nihil sunt.", "updated_at" : "2016-01-04T15:31:46.176Z", "created_at" : "2016-01-04T15:31:46.176Z", + "closed_at" : null, "user_notes_count": 1, "due_date": null, "web_url": "http://example.com/example/example/issues/1", @@ -311,6 +313,7 @@ Example response: "title" : "Ut commodi ullam eos dolores perferendis nihil sunt.", "updated_at" : "2016-01-04T15:31:46.176Z", "created_at" : "2016-01-04T15:31:46.176Z", + "closed_at" : "2016-01-05T15:31:46.176Z", "user_notes_count": 1, "due_date": "2016-07-22", "web_url": "http://example.com/example/example/issues/1", @@ -358,7 +361,8 @@ Example response: "id" : 11, "title" : "v3.0", "created_at" : "2016-01-04T15:31:39.788Z", - "updated_at" : "2016-01-04T15:31:39.788Z" + "updated_at" : "2016-01-04T15:31:39.788Z", + "closed_at" : "2016-01-05T15:31:46.176Z" }, "author" : { "state" : "active", @@ -465,6 +469,7 @@ Example response: }, "description" : null, "updated_at" : "2016-01-07T12:44:33.959Z", + "closed_at" : null, "milestone" : null, "subscribed" : true, "user_notes_count": 0, @@ -533,6 +538,7 @@ Example response: "project_id" : 4, "description" : null, "updated_at" : "2016-01-07T12:55:16.213Z", + "closed_at" : "2016-01-08T12:55:16.213Z", "iid" : 15, "labels" : [ "bug" @@ -615,6 +621,7 @@ Example response: "state": "opened", "created_at": "2016-04-05T21:41:45.652Z", "updated_at": "2016-04-07T12:20:17.596Z", + "closed_at": null, "labels": [], "milestone": null, "assignees": [{ @@ -692,6 +699,7 @@ Example response: "state": "opened", "created_at": "2016-04-05T21:41:45.652Z", "updated_at": "2016-04-07T12:20:17.596Z", + "closed_at": null, "labels": [], "milestone": null, "assignees": [{ diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 52c49e5caa9..30b115b1b56 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -332,6 +332,7 @@ module API end class IssueBasic < ProjectEntity + expose :closed_at expose :labels do |issue, options| # Avoids an N+1 query since labels are preloaded issue.labels.map(&:title).sort diff --git a/spec/fixtures/api/schemas/public_api/v4/issues.json b/spec/fixtures/api/schemas/public_api/v4/issues.json index 8acd9488215..03c422ab023 100644 --- a/spec/fixtures/api/schemas/public_api/v4/issues.json +++ b/spec/fixtures/api/schemas/public_api/v4/issues.json @@ -9,6 +9,7 @@ "title": { "type": "string" }, "description": { "type": ["string", "null"] }, "state": { "type": "string" }, + "closed_at": { "type": "date" }, "created_at": { "type": "date" }, "updated_at": { "type": "date" }, "labels": { diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 1583d1c2435..972e57bc373 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -22,7 +22,8 @@ describe API::Issues, :mailer do state: :closed, milestone: milestone, created_at: generate(:past_time), - updated_at: 3.hours.ago + updated_at: 3.hours.ago, + closed_at: 1.hour.ago end let!(:confidential_issue) do create :issue, @@ -738,6 +739,7 @@ describe API::Issues, :mailer do expect(json_response['title']).to eq(issue.title) expect(json_response['description']).to eq(issue.description) expect(json_response['state']).to eq(issue.state) + expect(json_response['closed_at']).to be_falsy expect(json_response['created_at']).to be_present expect(json_response['updated_at']).to be_present expect(json_response['labels']).to eq(issue.label_names) @@ -748,6 +750,13 @@ describe API::Issues, :mailer do expect(json_response['confidential']).to be_falsy end + it "exposes the 'closed_at' attribute" do + get api("/projects/#{project.id}/issues/#{closed_issue.iid}", user) + + expect(response).to have_http_status(200) + expect(json_response['closed_at']).to be_present + end + context 'links exposure' do it 'exposes related resources full URIs' do get api("/projects/#{project.id}/issues/#{issue.iid}", user)