Commit 3946e937 authored by Scott Hampton's avatar Scott Hampton

Graph group average code coverage

Add a graph to the group repo analytics page to
represent the average coverage of all projects
in the group over the past 30 days.
parent 2fc1ffff
...@@ -24,7 +24,7 @@ export default { ...@@ -24,7 +24,7 @@ export default {
<h4 data-testid="test-coverage-header"> <h4 data-testid="test-coverage-header">
{{ $options.text.codeCoverageHeader }} {{ $options.text.codeCoverageHeader }}
</h4> </h4>
<test-coverage-summary /> <test-coverage-summary class="gl-mb-5" />
<test-coverage-table class="gl-mb-5" /> <test-coverage-table class="gl-mb-5" />
<download-test-coverage /> <download-test-coverage />
</div> </div>
......
<script> <script>
import { GlAreaChart } from '@gitlab/ui/dist/charts';
import { GlCard, GlSprintf } from '@gitlab/ui';
import { __, s__ } from '~/locale'; import { __, s__ } from '~/locale';
import MetricCard from '~/analytics/shared/components/metric_card.vue'; import MetricCard from '~/analytics/shared/components/metric_card.vue';
import { formatDate } from '~/lib/utils/datetime_utility';
import ChartSkeletonLoader from '~/vue_shared/components/resizable_chart/skeleton_loader.vue';
import getGroupTestCoverage from '../graphql/queries/get_group_test_coverage.query.graphql'; import getGroupTestCoverage from '../graphql/queries/get_group_test_coverage.query.graphql';
export default { export default {
name: 'TestCoverageSummary', name: 'TestCoverageSummary',
components: { components: {
ChartSkeletonLoader,
GlAreaChart,
GlCard,
GlSprintf,
MetricCard, MetricCard,
}, },
inject: { inject: {
...@@ -17,26 +25,37 @@ export default { ...@@ -17,26 +25,37 @@ export default {
group: { group: {
query: getGroupTestCoverage, query: getGroupTestCoverage,
variables() { variables() {
const ONE_WEEK = 7 * 24 * 60 * 60 * 1000; // milliseconds const THIRTY_DAYS = 30 * 24 * 60 * 60 * 1000; // milliseconds
return { return {
groupFullPath: this.groupFullPath, groupFullPath: this.groupFullPath,
startDate: new Date(Date.now() - ONE_WEEK), startDate: new Date(Date.now() - THIRTY_DAYS),
}; };
}, },
result(res) { result(res) {
const groupCoverage = res.data?.group?.codeCoverageActivities?.nodes;
const { projectCount, averageCoverage, coverageCount } = const { projectCount, averageCoverage, coverageCount } =
res.data?.group?.codeCoverageActivities?.nodes?.[0] || {}; groupCoverage?.[groupCoverage.length - 1] || {};
this.projectCount = projectCount; this.projectCount = projectCount;
this.averageCoverage = averageCoverage; this.averageCoverage = averageCoverage;
this.coverageCount = coverageCount; this.coverageCount = coverageCount;
this.groupCoverageChartData = [
{
name: this.$options.text.graphName,
data: groupCoverage.map((coverage) => [
formatDate(coverage.date, 'mmm dd'),
coverage.averageCoverage,
]),
},
];
}, },
error() { error() {
this.hasError = true; this.hasError = true;
this.projectCount = null; this.projectCount = null;
this.averageCoverage = null; this.averageCoverage = null;
this.coverageCount = null; this.coverageCount = null;
this.groupCoverageChartData = [];
}, },
watchLoading(isLoading) { watchLoading(isLoading) {
this.isLoading = isLoading; this.isLoading = isLoading;
...@@ -48,6 +67,9 @@ export default { ...@@ -48,6 +67,9 @@ export default {
projectCount: null, projectCount: null,
averageCoverage: null, averageCoverage: null,
coverageCount: null, coverageCount: null,
groupCoverageChartData: [],
coveragePercentage: null,
tooltipTitle: null,
hasError: false, hasError: false,
isLoading: false, isLoading: false,
}; };
...@@ -76,9 +98,68 @@ export default { ...@@ -76,9 +98,68 @@ export default {
}, },
]; ];
}, },
chartOptions() {
return {
xAxis: {
name: this.$options.text.xAxisName,
type: 'category',
},
yAxis: {
name: this.$options.text.yAxisName,
type: 'value',
min: 0,
max: 100,
axisLabel: {
formatter: (value) => `${value}%`,
},
},
};
},
},
methods: {
formatTooltipText(params) {
this.tooltipTitle = params.value;
this.coveragePercentage = params.seriesData?.[0]?.data?.[1];
},
},
text: {
graphCardHeader: s__('RepositoriesAnalytics|Average test coverage last 30 days'),
yAxisName: __('Coverage'),
xAxisName: __('Date'),
graphName: s__('RepositoriesAnalytics|Average coverage'),
}, },
}; };
</script> </script>
<template> <template>
<metric-card :title="$options.i18n.cardTitle" :metrics="metrics" :is-loading="isLoading" /> <div>
<metric-card :title="$options.i18n.cardTitle" :metrics="metrics" :is-loading="isLoading" />
<gl-card>
<template #header>
<h5>{{ $options.text.graphCardHeader }}</h5>
</template>
<chart-skeleton-loader v-if="isLoading" />
<gl-area-chart
v-else
:data="groupCoverageChartData"
:option="chartOptions"
:include-legend-avg-max="false"
:format-tooltip-text="formatTooltipText"
>
<template #tooltip-title>
{{ tooltipTitle }}
</template>
<template #tooltip-content>
<gl-sprintf :message="__('Code Coverage: %{coveragePercentage}%{percentSymbol}')">
<template #coveragePercentage>
{{ coveragePercentage }}
</template>
<template #percentSymbol>%</template>
</gl-sprintf>
</template>
</gl-area-chart>
</gl-card>
</div>
</template> </template>
query getGroupTestCoverage($groupFullPath: ID!, $startDate: Date!, $last: Int = 1) { query getGroupTestCoverage($groupFullPath: ID!, $startDate: Date!) {
group(fullPath: $groupFullPath) { group(fullPath: $groupFullPath) {
codeCoverageActivities(startDate: $startDate, last: $last) { fullPath
codeCoverageActivities(startDate: $startDate) {
nodes { nodes {
projectCount projectCount
averageCoverage averageCoverage
......
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