Skip to content

Commit a0dca3e

Browse files
bnjjjsguiheux
authored andcommitted
feat(ui): add graph for code coverage on the overview app page (#3653)
1 parent 558f97f commit a0dca3e

File tree

7 files changed

+100
-23
lines changed

7 files changed

+100
-23
lines changed

engine/api/metrics/elasticsearch.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"time"
77

88
"github.com/go-gorp/gorp"
9+
coverage "github.com/sguiheux/go-coverage"
910
"gopkg.in/olivere/elastic.v5"
1011

1112
"github.com/ovh/cds/engine/api/services"
@@ -108,3 +109,24 @@ func PushUnitTests(projKey string, appID int64, workflowID int64, num int64, tes
108109

109110
metricsChan <- m
110111
}
112+
113+
// PushCoverage Create metrics from coverage and send them
114+
func PushCoverage(projKey string, appID int64, workflowID int64, num int64, cover coverage.Report) {
115+
m := sdk.Metric{
116+
Date: time.Now(),
117+
ProjectKey: projKey,
118+
ApplicationID: appID,
119+
WorkflowID: workflowID,
120+
Key: sdk.MetricKeyCoverage,
121+
Num: num,
122+
}
123+
124+
summary := make(map[string]float64, 3)
125+
summary["covered_lines"] = float64(cover.CoveredLines)
126+
summary["total_lines"] = float64(cover.TotalLines)
127+
summary["percent"] = (summary["covered_lines"] / summary["total_lines"]) * 100
128+
129+
m.Value = summary
130+
131+
metricsChan <- m
132+
}

engine/api/ui.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,30 +31,31 @@ func (api *API) getApplicationOverviewHandler() service.Handler {
3131
vars := mux.Vars(r)
3232
key := vars["key"]
3333
appName := vars["permApplicationName"]
34+
db := api.mustDB()
3435

35-
p, errP := project.Load(api.mustDB(), api.Cache, key, getUser(ctx))
36+
p, errP := project.Load(db, api.Cache, key, getUser(ctx))
3637
if errP != nil {
3738
return sdk.WrapError(errP, "getApplicationOverviewHandler> unable to load project")
3839
}
3940

40-
app, errA := application.LoadByName(api.mustDB(), api.Cache, key, appName, getUser(ctx))
41+
app, errA := application.LoadByName(db, api.Cache, key, appName, getUser(ctx))
4142
if errA != nil {
4243
return sdk.WrapError(errA, "getApplicationOverviewHandler> unable to load application")
4344
}
4445

45-
usage, errU := loadApplicationUsage(api.mustDB(), key, appName)
46+
usage, errU := loadApplicationUsage(db, key, appName)
4647
if errU != nil {
4748
return sdk.WrapError(errU, "getApplicationOverviewHandler> Cannot load application usage")
4849
}
4950
app.Usage = &usage
5051

5152
appOverview := sdk.ApplicationOverview{
52-
Graphs: make([]sdk.ApplicationOverviewGraph, 0, 2),
53+
Graphs: make([]sdk.ApplicationOverviewGraph, 0, 3),
5354
History: make(map[string][]sdk.WorkflowRun, len(app.Usage.Workflows)),
5455
}
5556

5657
// GET METRICS
57-
m1, errMV := metrics.GetMetrics(api.mustDB(), key, app.ID, sdk.MetricKeyVulnerability)
58+
m1, errMV := metrics.GetMetrics(db, key, app.ID, sdk.MetricKeyVulnerability)
5859
if errMV != nil {
5960
return sdk.WrapError(errMV, "getApplicationOverviewHandler> Cannot list vulnerability metrics")
6061
}
@@ -63,7 +64,7 @@ func (api *API) getApplicationOverviewHandler() service.Handler {
6364
Datas: m1,
6465
})
6566

66-
m2, errUT := metrics.GetMetrics(api.mustDB(), key, app.ID, sdk.MetricKeyUnitTest)
67+
m2, errUT := metrics.GetMetrics(db, key, app.ID, sdk.MetricKeyUnitTest)
6768
if errUT != nil {
6869
return sdk.WrapError(errUT, "getApplicationOverviewHandler> Cannot list Unit test metrics")
6970
}
@@ -72,10 +73,19 @@ func (api *API) getApplicationOverviewHandler() service.Handler {
7273
Datas: m2,
7374
})
7475

76+
mCov, errCov := metrics.GetMetrics(db, key, app.ID, sdk.MetricKeyCoverage)
77+
if errCov != nil {
78+
return sdk.WrapError(errCov, "getApplicationOverviewHandler> Cannot list coverage metrics")
79+
}
80+
appOverview.Graphs = append(appOverview.Graphs, sdk.ApplicationOverviewGraph{
81+
Type: sdk.MetricKeyCoverage,
82+
Datas: mCov,
83+
})
84+
7585
// GET VCS URL
7686
// Get vcs info to known if we are on the default branch or not
7787
if projectVCSServer := repositoriesmanager.GetProjectVCSServer(p, app.VCSServer); projectVCSServer != nil {
78-
client, erra := repositoriesmanager.AuthorizedClient(ctx, api.mustDB(), api.Cache, projectVCSServer)
88+
client, erra := repositoriesmanager.AuthorizedClient(ctx, db, api.Cache, projectVCSServer)
7989
if erra != nil {
8090
return sdk.WrapError(sdk.ErrNoReposManagerClientAuth, "getApplicationOverviewHandler> Cannot get repo client %s: %v", app.VCSServer, erra)
8191
}
@@ -93,7 +103,7 @@ func (api *API) getApplicationOverviewHandler() service.Handler {
93103
tagFilter := make(map[string]string, 1)
94104
tagFilter["git.branch"] = defaultBranch
95105
for _, w := range app.Usage.Workflows {
96-
runs, _, _, _, errR := workflow.LoadRuns(api.mustDB(), key, w.Name, 0, 5, tagFilter)
106+
runs, _, _, _, errR := workflow.LoadRuns(db, key, w.Name, 0, 5, tagFilter)
97107
if errR != nil {
98108
return sdk.WrapError(errR, "getApplicationOverviewHandler> Unable to load runs")
99109
}

engine/api/workflow/dao_coverage.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/ovh/cds/engine/api/cache"
1111
"github.com/ovh/cds/engine/api/database/gorpmapping"
12+
"github.com/ovh/cds/engine/api/metrics"
1213
"github.com/ovh/cds/engine/api/repositoriesmanager"
1314
"github.com/ovh/cds/sdk"
1415
)
@@ -194,6 +195,9 @@ func ComputeLatestDefaultBranchReport(ctx context.Context, db gorp.SqlExecutor,
194195
}
195196
defaultCoverage.Report.Files = nil
196197
covReport.Trend.DefaultBranch = defaultCoverage.Report
198+
} else {
199+
metrics.PushCoverage(proj.Key, wnr.ApplicationID, wnr.WorkflowID, wnr.Number, covReport.Report)
197200
}
201+
198202
return nil
199203
}

sdk/metric.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import "time"
55
const (
66
MetricKeyVulnerability = "Vulnerability"
77
MetricKeyUnitTest = "UnitTest"
8+
MetricKeyCoverage = "Coverage"
89
)
910

1011
// Metric represent a CDS metric

ui/src/app/views/application/show/home/application.home.component.ts

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import {Component, Input, OnInit} from '@angular/core';
2-
import {TranslateService} from '@ngx-translate/core';
3-
import {Application, Overview, Severity} from '../../../../model/application.model';
4-
import {ChartData, ChartSeries, GraphConfiguration, GraphType} from '../../../../model/graph.model';
5-
import {Metric} from '../../../../model/metric.model';
6-
import {Tests} from '../../../../model/pipeline.model';
7-
import {Project} from '../../../../model/project.model';
8-
import {ApplicationNoCacheService} from '../../../../service/application/application.nocache.service';
1+
import { Component, Input, OnInit } from '@angular/core';
2+
import { TranslateService } from '@ngx-translate/core';
3+
import { Application, Overview, Severity } from '../../../../model/application.model';
4+
import { ChartData, ChartSeries, GraphConfiguration, GraphType } from '../../../../model/graph.model';
5+
import { Metric } from '../../../../model/metric.model';
6+
import { Tests } from '../../../../model/pipeline.model';
7+
import { Project } from '../../../../model/project.model';
8+
import { ApplicationNoCacheService } from '../../../../service/application/application.nocache.service';
99

1010
@Component({
1111
selector: 'app-home',
@@ -31,13 +31,18 @@ export class ApplicationHomeComponent implements OnInit {
3131
this.overview = d;
3232
if (d && d.graphs.length > 0) {
3333
d.graphs.forEach(g => {
34-
switch (g.type) {
35-
case 'Vulnerability':
36-
this.createVulnDashboard(g.datas);
37-
break;
38-
case 'UnitTest':
39-
this.createUnitTestDashboard(g.datas);
40-
break;
34+
if (g.datas && g.datas.length) {
35+
switch (g.type) {
36+
case 'Vulnerability':
37+
this.createVulnDashboard(g.datas);
38+
break;
39+
case 'UnitTest':
40+
this.createUnitTestDashboard(g.datas);
41+
break;
42+
case 'Coverage':
43+
this.createCoverageDashboard(g.datas);
44+
break;
45+
}
4146
}
4247
});
4348
}
@@ -122,4 +127,35 @@ export class ApplicationHomeComponent implements OnInit {
122127
});
123128
this.dashboards.push(cc);
124129
}
130+
131+
createCoverageDashboard(metrics: Array<Metric>): void {
132+
let cc = new GraphConfiguration(GraphType.AREA_STACKED);
133+
cc.title = this._translate.instant('graph_coverage_title');
134+
cc.colorScheme = { domain: [] };
135+
cc.gradient = false;
136+
cc.showXAxis = true;
137+
cc.showYAxis = true;
138+
cc.showLegend = false;
139+
cc.showXAxisLabel = true;
140+
cc.showYAxisLabel = true;
141+
cc.xAxisLabel = this._translate.instant('graph_vulnerability_x');
142+
cc.yAxisLabel = this._translate.instant('graph_coverage_y');
143+
cc.datas = new Array<ChartData>();
144+
145+
let cd = new ChartData();
146+
cd.name = this._translate.instant('graph_coverage_y');
147+
cd.series = new Array<ChartSeries>();
148+
metrics.forEach(m => {
149+
let v = m.value['percent'];
150+
if (v) {
151+
let cs = new ChartSeries();
152+
cs.name = m.run.toString();
153+
cs.value = v;
154+
cd.series.push(cs);
155+
}
156+
});
157+
cc.datas.push(cd);
158+
cc.colorScheme['domain'].push('#4286f4');
159+
this.dashboards.push(cc);
160+
}
125161
}

ui/src/assets/i18n/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,8 @@
353353
"graph_unittest_title": "Unit Tests",
354354
"graph_unittest_x": "N° workflow",
355355
"graph_unittest_y": "Total",
356+
"graph_coverage_title": "Code coverage",
357+
"graph_coverage_y": "Percentage",
356358

357359
"group_added": "Group added",
358360
"group_deleted": "Group deleted",

ui/src/assets/i18n/fr.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,8 @@
353353
"graph_unittest_title": "Tests unitaires",
354354
"graph_unittest_x": "N° workflow",
355355
"graph_unittest_y": "Total",
356+
"graph_coverage_title": "Couverture",
357+
"graph_coverage_y": "Taux de couverture",
356358

357359
"group_added": "Groupe ajouté",
358360
"group_deleted": "Groupe supprimé",

0 commit comments

Comments
 (0)