Commit 9a48952a authored by Savas Vedova's avatar Savas Vedova

Merge branch 'nfriend-migrate-deployment-frequency-charts-to-new-endpoints' into 'master'

Update Deployment Frequency to use new API

See merge request gitlab-org/gitlab!57860
parents d5811e5f 96fa5c90
import { buildApiUrl } from '~/api/api_utils';
import axios from '~/lib/utils/axios_utils';
export const DEPLOYMENT_FREQUENCY_METRIC_TYPE = 'deployment_frequency';
export const LEAD_TIME_FOR_CHANGES = 'lead_time_for_changes';
export const ALL_METRIC_TYPES = Object.freeze([
DEPLOYMENT_FREQUENCY_METRIC_TYPE,
LEAD_TIME_FOR_CHANGES,
]);
const PROJECTS_DORA_METRICS_PATH = '/api/:version/projects/:id/dora/metrics';
/**
* Gets DORA 4 metrics data from a project
* See https://docs.gitlab.com/ee/api/dora/metrics.html
*
* @param {String|Number} projectId The ID or path of the project
* @param {String} metric The name of the metric to fetch. Must be one of:
* `["deployment_frequency", "lead_time_for_changes"]`
* @param {Object} params Any additional query parameters that should be
* included with the request. These parameters are optional. See
* https://docs.gitlab.com/ee/api/dora/metrics.html for a list of available options.
*
* @returns {Promise} A `Promise` that resolves to an array of data points.
*/
export function getProjectDoraMetrics(projectId, metric, params = {}) {
if (!ALL_METRIC_TYPES.includes(metric)) {
throw new Error(`Unsupported metric type provided to getProjectDoraMetrics(): "${metric}"`);
}
const url = buildApiUrl(PROJECTS_DORA_METRICS_PATH).replace(':id', encodeURIComponent(projectId));
return axios.get(url, {
params: {
metric,
...params,
},
});
}
<script>
import { GlLink, GlSprintf } from '@gitlab/ui';
import * as Sentry from '@sentry/browser';
import Api from 'ee/api';
import * as DoraApi from 'ee/api/dora_api';
import createFlash from '~/flash';
import { s__ } from '~/locale';
import CiCdAnalyticsCharts from '~/projects/pipelines/charts/components/ci_cd_analytics_charts.vue';
......@@ -47,7 +47,11 @@ export default {
async mounted() {
const results = await Promise.allSettled(
allChartDefinitions.map(async ({ id, requestParams, startDate, endDate }) => {
const { data: apiData } = await Api.deploymentFrequencies(this.projectPath, requestParams);
const { data: apiData } = await DoraApi.getProjectDoraMetrics(
this.projectPath,
DoraApi.DEPLOYMENT_FREQUENCY_METRIC_TYPE,
requestParams,
);
this.chartData[id] = apiDataToChartSeries(apiData, startDate, endDate);
}),
......
......@@ -19,8 +19,8 @@ const last90Days = nDaysBefore(startOfTomorrow, 90, { utc: true });
const apiDateFormatString = 'isoDateTime';
const titleDateFormatString = 'mmm d';
const sharedRequestParams = {
environment: 'production',
interval: 'daily',
end_date: dateFormat(startOfTomorrow, apiDateFormatString, true),
// We will never have more than 91 records (1 record per day), so we
// don't have to worry about making multiple requests to get all the results
......@@ -39,8 +39,7 @@ export const allChartDefinitions = [
endDate: startOfTomorrow,
requestParams: {
...sharedRequestParams,
from: dateFormat(lastWeek, apiDateFormatString, true),
to: dateFormat(startOfTomorrow, apiDateFormatString, true),
start_date: dateFormat(lastWeek, apiDateFormatString, true),
},
},
{
......@@ -54,8 +53,7 @@ export const allChartDefinitions = [
endDate: startOfTomorrow,
requestParams: {
...sharedRequestParams,
from: dateFormat(lastMonth, apiDateFormatString, true),
to: dateFormat(startOfTomorrow, apiDateFormatString, true),
start_date: dateFormat(lastMonth, apiDateFormatString, true),
},
},
{
......@@ -69,8 +67,7 @@ export const allChartDefinitions = [
endDate: startOfTomorrow,
requestParams: {
...sharedRequestParams,
from: dateFormat(last90Days, apiDateFormatString, true),
to: dateFormat(startOfTomorrow, apiDateFormatString, true),
start_date: dateFormat(last90Days, apiDateFormatString, true),
},
},
];
......
......@@ -24,7 +24,7 @@ export const apiDataToChartSeries = (apiData, startDate, endDate) => {
// The timestamps are explicitly set to the _beginning_ of the day (in UTC)
// so that we can confidently compare dates by value below.
const timestampToApiValue = apiData.reduce((acc, curr) => {
const apiTimestamp = getStartOfDay(new Date(curr.from), { utc: true }).getTime();
const apiTimestamp = getStartOfDay(new Date(curr.date), { utc: true }).getTime();
acc[apiTimestamp] = curr.value;
return acc;
}, {});
......
export * from './api/groups_api';
export * from './api/subscriptions_api';
export * from './api/dora_api';
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Project Analytics (JavaScript fixtures)' do
include ApiHelpers
include JavaScriptFixturesHelpers
let_it_be(:reporter) { create(:user) }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:environment) { create(:environment, project: project, name: 'production') }
let!(:deployments) do
[
1.minute.ago,
2.days.ago,
3.days.ago,
3.days.ago,
3.days.ago,
8.days.ago,
32.days.ago,
91.days.ago
].map do |finished_at|
create(:deployment,
:success,
project: project,
environment: environment,
finished_at: finished_at)
end
end
before do
stub_licensed_features(dora4_analytics: true)
project.add_reporter(reporter)
sign_in(reporter)
end
after(:all) do
remove_repository(project)
end
describe API::Analytics::ProjectDeploymentFrequency, type: :request do
before(:all) do
clean_frontend_fixtures('api/project_analytics/')
end
let(:shared_params) do
{
environment: environment.name,
interval: 'daily',
to: Date.tomorrow.beginning_of_day
}
end
def make_request(additional_query_params:)
params = shared_params.merge(additional_query_params)
get api("/projects/#{project.id}/analytics/deployment_frequency?#{params.to_query}", reporter)
end
it 'api/project_analytics/daily_deployment_frequencies_for_last_week.json' do
make_request(additional_query_params: { from: 1.week.ago })
expect(response).to be_successful
end
it 'api/project_analytics/daily_deployment_frequencies_for_last_month.json' do
make_request(additional_query_params: { from: 1.month.ago })
expect(response).to be_successful
end
it 'api/project_analytics/daily_deployment_frequencies_for_last_90_days.json' do
make_request(additional_query_params: { from: 90.days.ago })
expect(response).to be_successful
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'DORA Metrics (JavaScript fixtures)' do
include ApiHelpers
include JavaScriptFixturesHelpers
let_it_be(:project) { create(:project, :repository) }
let_it_be(:reporter) { create(:user).tap { |u| project.add_reporter(u) } }
let_it_be(:environment) { create(:environment, project: project, name: 'production') }
before_all do
[
{ date: '2015-06-01', value: 1 },
{ date: '2015-06-25', value: 1 },
{ date: '2015-06-30', value: 3 },
{ date: '2015-07-01', value: 1 },
{ date: '2015-07-03', value: 1 }
].each do |data_point|
create(:dora_daily_metrics, deployment_frequency: data_point[:value], environment: environment, date: data_point[:date])
end
end
before do
stub_licensed_features(dora4_analytics: true)
sign_in(reporter)
end
after(:all) do
remove_repository(project)
end
describe API::Dora::Metrics, type: :request do
before(:all) do
clean_frontend_fixtures('api/dora/metrics')
end
describe 'deployment frequency' do
let(:shared_params) do
{
metric: 'deployment_frequency',
end_date: Date.tomorrow.beginning_of_day,
interval: 'daily'
}
end
def make_request(additional_query_params:)
params = shared_params.merge(additional_query_params)
get api("/projects/#{project.id}/dora/metrics?#{params.to_query}", reporter)
end
it 'api/dora/metrics/daily_deployment_frequencies_for_last_week.json' do
make_request(additional_query_params: { start_date: 1.week.ago })
expect(response).to be_successful
end
it 'api/dora/metrics/daily_deployment_frequencies_for_last_month.json' do
make_request(additional_query_params: { start_date: 1.month.ago })
expect(response).to be_successful
end
it 'api/dora/metrics/daily_deployment_frequencies_for_last_90_days.json' do
make_request(additional_query_params: { start_date: 90.days.ago })
expect(response).to be_successful
end
end
end
end
......@@ -42,11 +42,10 @@ Array [
"id": "LAST_WEEK",
"range": "Jun 27 - Jul 3",
"requestParams": Object {
"environment": "production",
"from": "2015-06-27T00:00:00+0000",
"end_date": "2015-07-04T00:00:00+0000",
"interval": "daily",
"per_page": 100,
"to": "2015-07-04T00:00:00+0000",
"start_date": "2015-06-27T00:00:00+0000",
},
"startDate": 2015-06-27T00:00:00.000Z,
"title": "Last week",
......@@ -183,11 +182,10 @@ Array [
"id": "LAST_MONTH",
"range": "Jun 4 - Jul 3",
"requestParams": Object {
"environment": "production",
"from": "2015-06-04T00:00:00+0000",
"end_date": "2015-07-04T00:00:00+0000",
"interval": "daily",
"per_page": 100,
"to": "2015-07-04T00:00:00+0000",
"start_date": "2015-06-04T00:00:00+0000",
},
"startDate": 2015-06-04T00:00:00.000Z,
"title": "Last month",
......@@ -564,11 +562,10 @@ Array [
"id": "LAST_90_DAYS",
"range": "Apr 5 - Jul 3",
"requestParams": Object {
"environment": "production",
"from": "2015-04-05T00:00:00+0000",
"end_date": "2015-07-04T00:00:00+0000",
"interval": "daily",
"per_page": 100,
"to": "2015-07-04T00:00:00+0000",
"start_date": "2015-04-05T00:00:00+0000",
},
"startDate": 2015-04-05T00:00:00.000Z,
"title": "Last 90 days",
......
......@@ -11,13 +11,13 @@ import CiCdAnalyticsCharts from '~/projects/pipelines/charts/components/ci_cd_an
jest.mock('~/flash');
const lastWeekData = getJSONFixture(
'api/project_analytics/daily_deployment_frequencies_for_last_week.json',
'api/dora/metrics/daily_deployment_frequencies_for_last_week.json',
);
const lastMonthData = getJSONFixture(
'api/project_analytics/daily_deployment_frequencies_for_last_month.json',
'api/dora/metrics/daily_deployment_frequencies_for_last_month.json',
);
const last90DaysData = getJSONFixture(
'api/project_analytics/daily_deployment_frequencies_for_last_90_days.json',
'api/dora/metrics/daily_deployment_frequencies_for_last_90_days.json',
);
describe('ee_component/projects/pipelines/charts/components/deployment_frequency_charts.vue', () => {
......@@ -49,15 +49,15 @@ describe('ee_component/projects/pipelines/charts/components/deployment_frequency
// Initializes the mock endpoint to return a specific set of deployment
// frequency data for a given "from" date.
const setUpMockDeploymentFrequencies = ({ from, data }) => {
const setUpMockDeploymentFrequencies = ({ start_date, data }) => {
mock
.onGet(/projects\/test%2Fproject\/analytics\/deployment_frequency/, {
.onGet(/projects\/test%2Fproject\/dora\/metrics/, {
params: {
environment: 'production',
metric: 'deployment_frequency',
interval: 'daily',
per_page: 100,
to: '2015-07-04T00:00:00+0000',
from,
end_date: '2015-07-04T00:00:00+0000',
start_date,
},
})
.replyOnce(httpStatus.OK, data);
......@@ -77,15 +77,15 @@ describe('ee_component/projects/pipelines/charts/components/deployment_frequency
mock = new MockAdapter(axios);
setUpMockDeploymentFrequencies({
from: '2015-06-27T00:00:00+0000',
start_date: '2015-06-27T00:00:00+0000',
data: lastWeekData,
});
setUpMockDeploymentFrequencies({
from: '2015-06-04T00:00:00+0000',
start_date: '2015-06-04T00:00:00+0000',
data: lastMonthData,
});
setUpMockDeploymentFrequencies({
from: '2015-04-05T00:00:00+0000',
start_date: '2015-04-05T00:00:00+0000',
data: last90DaysData,
});
......
......@@ -5,11 +5,11 @@ describe('ee/projects/pipelines/charts/components/util.js', () => {
it('transforms the data from the API into data the chart component can use', () => {
const apiData = [
// This is the date format we expect from the API
{ value: 5, from: '2015-06-28T00:00:00.000Z', to: '2015-06-29T00:00:00.000Z' },
{ value: 5, date: '2015-06-28' },
// But we should support _any_ date format
{ value: 1, from: '2015-06-28T20:00:00.000-0400', to: '2015-06-19T20:00:00.000-0400' },
{ value: 8, from: '2015-07-01', to: '2015-07-02' },
{ value: 1, date: '2015-06-28T20:00:00.000-0400' },
{ value: 8, date: '2015-07-01T00:00:00.000Z' },
];
const startDate = new Date(2015, 5, 26, 10);
......
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