Commit e17d8ad8 authored by Sean McGivern's avatar Sean McGivern

Merge branch '41905_merge_request_and_issue_metrics' into 'master'

expose metrics in merge request api

Closes #41905

See merge request gitlab-org/gitlab-ce!16589
parents 29356cfe bb89412f
---
title: expose more metrics in merge requests api
merge_request: 16589
author: haseebeqx
type: added
...@@ -261,20 +261,20 @@ Parameters: ...@@ -261,20 +261,20 @@ Parameters:
"upvotes": 0, "upvotes": 0,
"downvotes": 0, "downvotes": 0,
"author": { "author": {
"id": 1, "state" : "active",
"username": "admin", "web_url" : "https://gitlab.example.com/root",
"email": "admin@example.com", "avatar_url" : null,
"name": "Administrator", "username" : "root",
"state": "active", "id" : 1,
"created_at": "2012-04-29T08:46:00Z" "name" : "Administrator"
}, },
"assignee": { "assignee": {
"id": 1, "state" : "active",
"username": "admin", "web_url" : "https://gitlab.example.com/root",
"email": "admin@example.com", "avatar_url" : null,
"name": "Administrator", "username" : "root",
"state": "active", "id" : 1,
"created_at": "2012-04-29T08:46:00Z" "name" : "Administrator"
}, },
"source_project_id": 2, "source_project_id": 2,
"target_project_id": 3, "target_project_id": 3,
...@@ -308,6 +308,26 @@ Parameters: ...@@ -308,6 +308,26 @@ Parameters:
"total_time_spent": 0, "total_time_spent": 0,
"human_time_estimate": null, "human_time_estimate": null,
"human_total_time_spent": null "human_total_time_spent": null
},
"closed_at": "2018-01-19T14:36:11.086Z",
"latest_build_started_at": null,
"latest_build_finished_at": null,
"first_deployed_to_production_at": null,
"pipeline": {
"id": 8,
"ref": "master",
"sha": "2dc6aa325a317eda67812f05600bdf0fcdc70ab0",
"status": "created"
},
"merged_by": null,
"merged_at": null,
"closed_by": {
"state" : "active",
"web_url" : "https://gitlab.example.com/root",
"avatar_url" : null,
"username" : "root",
"id" : 1,
"name" : "Administrator"
} }
} }
``` ```
......
...@@ -481,6 +481,10 @@ module API ...@@ -481,6 +481,10 @@ module API
expose :id expose :id
end end
class PipelineBasic < Grape::Entity
expose :id, :sha, :ref, :status
end
class MergeRequestSimple < ProjectEntity class MergeRequestSimple < ProjectEntity
expose :title expose :title
expose :web_url do |merge_request, options| expose :web_url do |merge_request, options|
...@@ -546,6 +550,42 @@ module API ...@@ -546,6 +550,42 @@ module API
expose :changes_count do |merge_request, _options| expose :changes_count do |merge_request, _options|
merge_request.merge_request_diff.real_size merge_request.merge_request_diff.real_size
end end
expose :merged_by, using: Entities::UserBasic do |merge_request, _options|
merge_request.metrics&.merged_by
end
expose :merged_at do |merge_request, _options|
merge_request.metrics&.merged_at
end
expose :closed_by, using: Entities::UserBasic do |merge_request, _options|
merge_request.metrics&.latest_closed_by
end
expose :closed_at do |merge_request, _options|
merge_request.metrics&.latest_closed_at
end
expose :latest_build_started_at, if: -> (_, options) { build_available?(options) } do |merge_request, _options|
merge_request.metrics&.latest_build_started_at
end
expose :latest_build_finished_at, if: -> (_, options) { build_available?(options) } do |merge_request, _options|
merge_request.metrics&.latest_build_finished_at
end
expose :first_deployed_to_production_at, if: -> (_, options) { build_available?(options) } do |merge_request, _options|
merge_request.metrics&.first_deployed_to_production_at
end
expose :pipeline, using: Entities::PipelineBasic, if: -> (_, options) { build_available?(options) } do |merge_request, _options|
merge_request.metrics&.pipeline
end
def build_available?(options)
options[:project]&.feature_available?(:builds, options[:current_user])
end
end end
class MergeRequestChanges < MergeRequest class MergeRequestChanges < MergeRequest
...@@ -909,10 +949,6 @@ module API ...@@ -909,10 +949,6 @@ module API
expose :filename, :size expose :filename, :size
end end
class PipelineBasic < Grape::Entity
expose :id, :sha, :ref, :status
end
class JobBasic < Grape::Entity class JobBasic < Grape::Entity
expose :id, :status, :stage, :name, :ref, :tag, :coverage expose :id, :status, :stage, :name, :ref, :tag, :coverage
expose :created_at, :started_at, :finished_at expose :created_at, :started_at, :finished_at
......
...@@ -222,7 +222,7 @@ module API ...@@ -222,7 +222,7 @@ module API
get ':id/merge_requests/:merge_request_iid/changes' do get ':id/merge_requests/:merge_request_iid/changes' do
merge_request = find_merge_request_with_access(params[:merge_request_iid]) merge_request = find_merge_request_with_access(params[:merge_request_iid])
present merge_request, with: Entities::MergeRequestChanges, current_user: current_user present merge_request, with: Entities::MergeRequestChanges, current_user: current_user, project: user_project
end end
desc 'Get the merge request pipelines' do desc 'Get the merge request pipelines' do
......
...@@ -9,6 +9,7 @@ describe API::MergeRequests do ...@@ -9,6 +9,7 @@ describe API::MergeRequests do
let(:non_member) { create(:user) } let(:non_member) { create(:user) }
let!(:project) { create(:project, :public, :repository, creator: user, namespace: user.namespace, only_allow_merge_if_pipeline_succeeds: false) } let!(:project) { create(:project, :public, :repository, creator: user, namespace: user.namespace, only_allow_merge_if_pipeline_succeeds: false) }
let(:milestone) { create(:milestone, title: '1.0.0', project: project) } let(:milestone) { create(:milestone, title: '1.0.0', project: project) }
let(:pipeline) { create(:ci_empty_pipeline) }
let(:milestone1) { create(:milestone, title: '0.9', project: project) } let(:milestone1) { create(:milestone, title: '0.9', project: project) }
let!(:merge_request) { create(:merge_request, :simple, milestone: milestone1, author: user, assignee: user, source_project: project, target_project: project, title: "Test", created_at: base_time) } let!(:merge_request) { create(:merge_request, :simple, milestone: milestone1, author: user, assignee: user, source_project: project, target_project: project, title: "Test", created_at: base_time) }
let!(:merge_request_closed) { create(:merge_request, state: "closed", milestone: milestone1, author: user, assignee: user, source_project: project, target_project: project, title: "Closed test", created_at: base_time + 1.second) } let!(:merge_request_closed) { create(:merge_request, state: "closed", milestone: milestone1, author: user, assignee: user, source_project: project, target_project: project, title: "Closed test", created_at: base_time + 1.second) }
...@@ -500,6 +501,45 @@ describe API::MergeRequests do ...@@ -500,6 +501,45 @@ describe API::MergeRequests do
expect(json_response['changes_count']).to eq(merge_request.merge_request_diff.real_size) expect(json_response['changes_count']).to eq(merge_request.merge_request_diff.real_size)
end end
context 'merge_request_metrics' do
before do
merge_request.metrics.update!(merged_by: user,
latest_closed_by: user,
latest_closed_at: 1.hour.ago,
merged_at: 2.hours.ago,
pipeline: pipeline,
latest_build_started_at: 3.hours.ago,
latest_build_finished_at: 1.hour.ago,
first_deployed_to_production_at: 3.minutes.ago)
end
it 'has fields from merge request metrics' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user)
expect(json_response).to include('merged_by',
'merged_at',
'closed_by',
'closed_at',
'latest_build_started_at',
'latest_build_finished_at',
'first_deployed_to_production_at',
'pipeline')
end
it 'returns correct values' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.reload.iid}", user)
expect(json_response['merged_by']['id']).to eq(merge_request.metrics.merged_by_id)
expect(Time.parse json_response['merged_at']).to be_like_time(merge_request.metrics.merged_at)
expect(json_response['closed_by']['id']).to eq(merge_request.metrics.latest_closed_by_id)
expect(Time.parse json_response['closed_at']).to be_like_time(merge_request.metrics.latest_closed_at)
expect(json_response['pipeline']['id']).to eq(merge_request.metrics.pipeline_id)
expect(Time.parse json_response['latest_build_started_at']).to be_like_time(merge_request.metrics.latest_build_started_at)
expect(Time.parse json_response['latest_build_finished_at']).to be_like_time(merge_request.metrics.latest_build_finished_at)
expect(Time.parse json_response['first_deployed_to_production_at']).to be_like_time(merge_request.metrics.first_deployed_to_production_at)
end
end
it "returns a 404 error if merge_request_iid not found" do it "returns a 404 error if merge_request_iid not found" do
get api("/projects/#{project.id}/merge_requests/999", user) get api("/projects/#{project.id}/merge_requests/999", user)
expect(response).to have_gitlab_http_status(404) expect(response).to have_gitlab_http_status(404)
......
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