@toptal/davinci-monorepo 8.1.3 → 8.1.4-alpha-CRT-5891-create-coverage-command-2488e674.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/davinci-monorepo.js +2 -0
- package/package.json +10 -9
- package/src/commands/__snapshots__/group-coverage-by-codeowners.test.js.snap +61 -0
- package/src/commands/codeowners/core/codeowners/codeowners.js +24 -14
- package/src/commands/coverage.js +11 -0
- package/src/commands/generate-team-coverage.js +138 -0
- package/src/commands/group-coverage-by-codeowners.js +99 -0
- package/src/commands/group-coverage-by-codeowners.test.js +23 -0
- package/src/index.js +2 -0
package/bin/davinci-monorepo.js
CHANGED
|
@@ -7,6 +7,7 @@ import { createGraphGenerateCommand } from '../src/commands/graph-generate.js'
|
|
|
7
7
|
import metricsCommand from '../src/commands/metrics.js'
|
|
8
8
|
// eslint-disable-next-line no-restricted-syntax
|
|
9
9
|
import codeownersCommand from '../src/commands/codeowners/index.js'
|
|
10
|
+
import { coverageCommand } from '../src/commands/coverage.js'
|
|
10
11
|
|
|
11
12
|
cliEngine.loadCommands(
|
|
12
13
|
[
|
|
@@ -14,6 +15,7 @@ cliEngine.loadCommands(
|
|
|
14
15
|
createGraphGenerateCommand,
|
|
15
16
|
metricsCommand,
|
|
16
17
|
codeownersCommand,
|
|
18
|
+
coverageCommand,
|
|
17
19
|
],
|
|
18
20
|
'davinci-monorepo'
|
|
19
21
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toptal/davinci-monorepo",
|
|
3
|
-
"version": "8.1.
|
|
3
|
+
"version": "8.1.4-alpha-CRT-5891-create-coverage-command-2488e674.2+2488e674",
|
|
4
4
|
"description": "Monorepo utility tools",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -33,24 +33,25 @@
|
|
|
33
33
|
"url": "https://github.com/toptal/davinci/issues"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
+
"@nodelib/fs.walk": "^1.2.6",
|
|
36
37
|
"@oclif/core": "^1.16.1",
|
|
37
|
-
"@toptal/davinci-cli-shared": "2.3.
|
|
38
|
+
"@toptal/davinci-cli-shared": "2.3.1-alpha-CRT-5891-create-coverage-command-2488e674.34+2488e674",
|
|
38
39
|
"chalk": "^4.1.2",
|
|
40
|
+
"codeowners": "5.1.1",
|
|
39
41
|
"dependency-cruiser": "^12.5.0",
|
|
40
|
-
"execa": "^5.1.1",
|
|
41
|
-
"glob": "^8.0.3",
|
|
42
|
-
"ramda": "^0.28.0",
|
|
43
|
-
"@nodelib/fs.walk": "^1.2.6",
|
|
44
42
|
"ervy": "^1.0.7",
|
|
43
|
+
"execa": "^5.1.1",
|
|
45
44
|
"find-up": "5.0.0",
|
|
45
|
+
"glob": "^8.0.3",
|
|
46
46
|
"ignore": "^5.2.0",
|
|
47
47
|
"is-directory": "^0.3.1",
|
|
48
48
|
"lodash": "4.17.21",
|
|
49
49
|
"ora": "^5.4.1",
|
|
50
|
-
"
|
|
51
|
-
"
|
|
50
|
+
"ramda": "^0.28.0",
|
|
51
|
+
"true-case-path": "^1.0.3"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@jest/globals": "^29.4.2"
|
|
55
|
-
}
|
|
55
|
+
},
|
|
56
|
+
"gitHead": "2488e6747994019dbeab8517629432f68e9af814"
|
|
56
57
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`groupCoverageByCodeownersCommand has the correct command structure 1`] = `
|
|
4
|
+
"{
|
|
5
|
+
"_events": {},
|
|
6
|
+
"_eventsCount": 1,
|
|
7
|
+
"commands": [],
|
|
8
|
+
"options": [
|
|
9
|
+
{
|
|
10
|
+
"flags": "-r, --repository <repository_name>",
|
|
11
|
+
"description": "specify repository name",
|
|
12
|
+
"required": true,
|
|
13
|
+
"optional": false,
|
|
14
|
+
"variadic": false,
|
|
15
|
+
"mandatory": true,
|
|
16
|
+
"short": "-r",
|
|
17
|
+
"long": "--repository",
|
|
18
|
+
"negate": false,
|
|
19
|
+
"hidden": false,
|
|
20
|
+
"conflictsWith": []
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"parent": null,
|
|
24
|
+
"_allowUnknownOption": false,
|
|
25
|
+
"_allowExcessArguments": true,
|
|
26
|
+
"_args": [],
|
|
27
|
+
"args": [],
|
|
28
|
+
"rawArgs": [],
|
|
29
|
+
"processedArgs": [],
|
|
30
|
+
"_scriptPath": null,
|
|
31
|
+
"_name": "group-coverage-by-codeowners",
|
|
32
|
+
"_optionValues": {},
|
|
33
|
+
"_optionValueSources": {},
|
|
34
|
+
"_storeOptionsAsProperties": false,
|
|
35
|
+
"_executableHandler": false,
|
|
36
|
+
"_executableFile": null,
|
|
37
|
+
"_executableDir": null,
|
|
38
|
+
"_defaultCommandName": null,
|
|
39
|
+
"_exitCallback": null,
|
|
40
|
+
"_aliases": [],
|
|
41
|
+
"_combineFlagAndOptionalValue": true,
|
|
42
|
+
"_description": "TODO: group-coverage-by-codeowners",
|
|
43
|
+
"_summary": "",
|
|
44
|
+
"_enablePositionalOptions": false,
|
|
45
|
+
"_passThroughOptions": false,
|
|
46
|
+
"_lifeCycleHooks": {},
|
|
47
|
+
"_showHelpAfterError": false,
|
|
48
|
+
"_showSuggestionAfterError": true,
|
|
49
|
+
"_outputConfiguration": {},
|
|
50
|
+
"_hidden": false,
|
|
51
|
+
"_hasHelpOption": true,
|
|
52
|
+
"_helpFlags": "-h, --help",
|
|
53
|
+
"_helpDescription": "display help for command",
|
|
54
|
+
"_helpShortFlag": "-h",
|
|
55
|
+
"_helpLongFlag": "--help",
|
|
56
|
+
"_helpCommandName": "help",
|
|
57
|
+
"_helpCommandnameAndArgs": "help [command]",
|
|
58
|
+
"_helpCommandDescription": "display help for command",
|
|
59
|
+
"_helpConfiguration": {}
|
|
60
|
+
}"
|
|
61
|
+
`;
|
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
/* eslint-disable import/no-extraneous-dependencies */
|
|
2
1
|
// @ts-check
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
import ignore from 'ignore'
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
import getCodeownersFilePath from '../utils/get-codeowners-file-path.js'
|
|
7
6
|
|
|
7
|
+
/**
|
|
8
|
+
* @param {string} pathString
|
|
9
|
+
*/
|
|
8
10
|
const ownerMatcher = pathString => {
|
|
9
|
-
// @ts-ignore
|
|
10
11
|
const matcher = ignore({ ignorecase: false }).add(pathString)
|
|
11
12
|
|
|
12
13
|
return matcher.ignores.bind(matcher)
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
/**
|
|
17
|
+
* @param {string} currentPath
|
|
18
|
+
* @param {string} fileName
|
|
19
|
+
*/
|
|
15
20
|
// eslint-disable-next-line func-style
|
|
16
21
|
function Codeowners(currentPath, fileName = 'CODEOWNERS') {
|
|
17
22
|
const { codeownersDirectory, codeownersFilePath } = getCodeownersFilePath(
|
|
@@ -52,16 +57,21 @@ function Codeowners(currentPath, fileName = 'CODEOWNERS') {
|
|
|
52
57
|
this.ignore = ignore
|
|
53
58
|
}
|
|
54
59
|
|
|
55
|
-
|
|
60
|
+
Codeowners.prototype.getOwner =
|
|
61
|
+
/**
|
|
62
|
+
* @param {string} filePath
|
|
63
|
+
*/
|
|
64
|
+
function getOwner(filePath) {
|
|
65
|
+
console.log({ filePath })
|
|
66
|
+
console.log({ entries: this.ownerEntries })
|
|
56
67
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
68
|
+
for (const entry of this.ownerEntries) {
|
|
69
|
+
if (entry.match(filePath)) {
|
|
70
|
+
return entry.usernames
|
|
71
|
+
}
|
|
61
72
|
}
|
|
62
|
-
}
|
|
63
73
|
|
|
64
|
-
|
|
65
|
-
}
|
|
74
|
+
return []
|
|
75
|
+
}
|
|
66
76
|
|
|
67
|
-
|
|
77
|
+
export default Codeowners
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { generateTeamCoverageCommand } from './generate-team-coverage.js'
|
|
2
|
+
import { groupCoverageByCodeownersCommand } from './group-coverage-by-codeowners.js'
|
|
3
|
+
|
|
4
|
+
export const coverageCommand = program => {
|
|
5
|
+
const coverage = program.createCommand('coverage').description('TODO ..')
|
|
6
|
+
|
|
7
|
+
generateTeamCoverageCommand(coverageCommand)
|
|
8
|
+
groupCoverageByCodeownersCommand(coverageCommand)
|
|
9
|
+
|
|
10
|
+
return coverage
|
|
11
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import * as url from 'url'
|
|
3
|
+
import execa from 'execa'
|
|
4
|
+
import fs from 'fs'
|
|
5
|
+
|
|
6
|
+
import Codeowners from './codeowners/core/codeowners/codeowners.js'
|
|
7
|
+
|
|
8
|
+
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
|
|
9
|
+
const rootProjectPath = path.join(__dirname, '../../')
|
|
10
|
+
|
|
11
|
+
const sanitizeTeamName = team => team.replace('/', '-').replace('@', '')
|
|
12
|
+
|
|
13
|
+
const sanitizeNycPercentage = percentage =>
|
|
14
|
+
percentage === 'Unknown' ? 0 : percentage
|
|
15
|
+
|
|
16
|
+
// eslint-disable-next-line max-statements
|
|
17
|
+
const generateTeamCoverage = async () => {
|
|
18
|
+
const codeowners = new Codeowners(rootProjectPath)
|
|
19
|
+
|
|
20
|
+
const ownerEntries = codeowners.ownerEntries
|
|
21
|
+
const uniqueTeams = ownerEntries
|
|
22
|
+
.flatMap(entry => entry.usernames)
|
|
23
|
+
// eslint-disable-next-line id-length
|
|
24
|
+
.filter((v, i, a) => a.indexOf(v) === i)
|
|
25
|
+
|
|
26
|
+
// eslint-disable-next-line no-console
|
|
27
|
+
console.log('Teams:', uniqueTeams)
|
|
28
|
+
|
|
29
|
+
const teams = uniqueTeams
|
|
30
|
+
|
|
31
|
+
await execa.command(`rm -rf coverage/teams`)
|
|
32
|
+
await execa.command(`mkdir coverage/teams`)
|
|
33
|
+
|
|
34
|
+
for await (const team of teams) {
|
|
35
|
+
const sanitizedTeam = sanitizeTeamName(team)
|
|
36
|
+
|
|
37
|
+
await execa.command(`mkdir coverage/teams/${sanitizedTeam}`)
|
|
38
|
+
await execa.command(`mkdir coverage/teams/${sanitizedTeam}/jest`)
|
|
39
|
+
await execa.command(`mkdir coverage/teams/${sanitizedTeam}/cypress`)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for await (const team of teams) {
|
|
43
|
+
// eslint-disable-next-line no-console
|
|
44
|
+
console.log('Team coverage:', team)
|
|
45
|
+
|
|
46
|
+
const sanitizedTeam = sanitizeTeamName(team)
|
|
47
|
+
|
|
48
|
+
await execa.command(
|
|
49
|
+
`cp coverage/jest/coverage-final-${sanitizedTeam}.json coverage/teams/${sanitizedTeam}/jest/coverage-final.json`
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
// TODO add nyc as deps?
|
|
53
|
+
await execa.command(
|
|
54
|
+
`yarn nyc report --temp-dir coverage/teams/${sanitizedTeam}/jest --reporter json-summary --reporter html --report-dir coverage/teams/${sanitizedTeam}/jest`
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
await execa.command(
|
|
58
|
+
`cp coverage/cypress/coverage-final-${sanitizedTeam}.json coverage/teams/${sanitizedTeam}/cypress/coverage-final.json`
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
await execa.command(
|
|
62
|
+
`yarn nyc report --temp-dir coverage/teams/${sanitizedTeam}/cypress --reporter json-summary --reporter html --report-dir coverage/teams/${sanitizedTeam}/cypress`
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const results = []
|
|
67
|
+
const created_at = new Date().toISOString()
|
|
68
|
+
|
|
69
|
+
// TODO pass it as param
|
|
70
|
+
const repo = 'client-portal'
|
|
71
|
+
|
|
72
|
+
for await (const team of teams) {
|
|
73
|
+
const sanitizedTeam = sanitizeTeamName(team)
|
|
74
|
+
const result = {
|
|
75
|
+
created_at,
|
|
76
|
+
team,
|
|
77
|
+
repo,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const jestCoverageSummary = JSON.parse(
|
|
81
|
+
fs.readFileSync(
|
|
82
|
+
`coverage/teams/${sanitizedTeam}/jest/coverage-summary.json`,
|
|
83
|
+
'utf8'
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
result.jest_lines_coverage = sanitizeNycPercentage(
|
|
88
|
+
jestCoverageSummary.total.lines.pct
|
|
89
|
+
)
|
|
90
|
+
result.jest_statements_coverage = sanitizeNycPercentage(
|
|
91
|
+
jestCoverageSummary.total.statements.pct
|
|
92
|
+
)
|
|
93
|
+
result.jest_functions_coverage = sanitizeNycPercentage(
|
|
94
|
+
jestCoverageSummary.total.functions.pct
|
|
95
|
+
)
|
|
96
|
+
result.jest_branches_coverage = sanitizeNycPercentage(
|
|
97
|
+
jestCoverageSummary.total.branches.pct
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
const cypressCoverageSummary = JSON.parse(
|
|
101
|
+
fs.readFileSync(
|
|
102
|
+
`coverage/teams/${sanitizedTeam}/cypress/coverage-summary.json`,
|
|
103
|
+
'utf8'
|
|
104
|
+
)
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
result.cypress_lines_coverage = sanitizeNycPercentage(
|
|
108
|
+
cypressCoverageSummary.total.lines.pct
|
|
109
|
+
)
|
|
110
|
+
result.cypress_statements_coverage = sanitizeNycPercentage(
|
|
111
|
+
cypressCoverageSummary.total.statements.pct
|
|
112
|
+
)
|
|
113
|
+
result.cypress_functions_coverage = sanitizeNycPercentage(
|
|
114
|
+
cypressCoverageSummary.total.functions.pct
|
|
115
|
+
)
|
|
116
|
+
result.cypress_branches_coverage = sanitizeNycPercentage(
|
|
117
|
+
cypressCoverageSummary.total.branches.pct
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
results.push(result)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
fs.writeFileSync(
|
|
124
|
+
'team-tests-coverage-results.json',
|
|
125
|
+
JSON.stringify(results, null, 2)
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export const generateTeamCoverageCommand = program => {
|
|
130
|
+
return program
|
|
131
|
+
.createCommand('generate-team-coverage')
|
|
132
|
+
.description('TODO: generate-team-coverage')
|
|
133
|
+
.requiredOption(
|
|
134
|
+
'-r, --repository <repository_name>',
|
|
135
|
+
'specify repository name'
|
|
136
|
+
)
|
|
137
|
+
.action((_, options) => generateTeamCoverage(options))
|
|
138
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
import * as url from 'url'
|
|
4
|
+
|
|
5
|
+
import Codeowners from './codeowners/core/codeowners/codeowners.js'
|
|
6
|
+
|
|
7
|
+
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
|
|
8
|
+
const rootProjectPath = path.join(__dirname, '../../')
|
|
9
|
+
|
|
10
|
+
const readJestCoverageReport = () => {
|
|
11
|
+
const jestCoverageReportPath = path.join(
|
|
12
|
+
rootProjectPath,
|
|
13
|
+
'coverage/jest/coverage-final-jest.json'
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
const data = fs.readFileSync(jestCoverageReportPath, 'utf8')
|
|
17
|
+
|
|
18
|
+
return JSON.parse(data)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const readCypressCoverageReport = () => {
|
|
22
|
+
const cypressCoverageReportPath = path.join(
|
|
23
|
+
rootProjectPath,
|
|
24
|
+
'coverage/cypress/coverage-final-cypress.json'
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
const data = fs.readFileSync(cypressCoverageReportPath, 'utf8')
|
|
28
|
+
|
|
29
|
+
return JSON.parse(data)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const sanitizeTeamName = team => team.replace('/', '-').replace('@', '')
|
|
33
|
+
|
|
34
|
+
const splitReportIntoTeams = (reportObj, teams, codeowners, coveragePath) => {
|
|
35
|
+
const teamsReport = {}
|
|
36
|
+
|
|
37
|
+
Object.entries(reportObj).forEach(([reportPathKey, report]) => {
|
|
38
|
+
const file = report.path
|
|
39
|
+
const relativePath = path.relative(rootProjectPath, file)
|
|
40
|
+
|
|
41
|
+
const owners = codeowners.getOwner(relativePath)
|
|
42
|
+
|
|
43
|
+
owners.forEach(owner => {
|
|
44
|
+
teamsReport[owner] = {
|
|
45
|
+
...teamsReport[owner],
|
|
46
|
+
[reportPathKey]: report,
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
teams.map(team => {
|
|
52
|
+
const teamReport = teamsReport[team] || {}
|
|
53
|
+
const sanitizedTeamPath = sanitizeTeamName(team)
|
|
54
|
+
|
|
55
|
+
const reportPath = path.join(
|
|
56
|
+
rootProjectPath,
|
|
57
|
+
`${coveragePath}/coverage-final-${sanitizedTeamPath}.json`
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
fs.writeFileSync(reportPath, JSON.stringify(teamReport, null, 2))
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const getAllTeams = codeowners => {
|
|
65
|
+
const ownerEntries = codeowners.ownerEntries
|
|
66
|
+
const uniqueTeams = ownerEntries
|
|
67
|
+
.flatMap(entry => entry.usernames)
|
|
68
|
+
// eslint-disable-next-line id-length
|
|
69
|
+
.filter((v, i, a) => a.indexOf(v) === i)
|
|
70
|
+
|
|
71
|
+
// eslint-disable-next-line no-console
|
|
72
|
+
console.log('Teams:', uniqueTeams)
|
|
73
|
+
|
|
74
|
+
return uniqueTeams
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const groupCoverageByCodeowners = async options => {
|
|
78
|
+
console.log(options)
|
|
79
|
+
|
|
80
|
+
const jestReport = readJestCoverageReport()
|
|
81
|
+
const cypressReport = readCypressCoverageReport()
|
|
82
|
+
|
|
83
|
+
const codeowners = new Codeowners(rootProjectPath)
|
|
84
|
+
const teams = getAllTeams(codeowners)
|
|
85
|
+
|
|
86
|
+
splitReportIntoTeams(jestReport, teams, codeowners, 'coverage/jest')
|
|
87
|
+
splitReportIntoTeams(cypressReport, teams, codeowners, 'coverage/cypress')
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const groupCoverageByCodeownersCommand = program => {
|
|
91
|
+
return program
|
|
92
|
+
.createCommand('group-coverage-by-codeowners')
|
|
93
|
+
.description('TODO: group-coverage-by-codeowners')
|
|
94
|
+
.requiredOption(
|
|
95
|
+
'-r, --repository <repository_name>',
|
|
96
|
+
'specify repository name'
|
|
97
|
+
)
|
|
98
|
+
.action((_, options) => groupCoverageByCodeowners(options))
|
|
99
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jest } from '@jest/globals'
|
|
2
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
|
|
5
|
+
import { groupCoverageByCodeownersCommand } from './group-coverage-by-codeowners.js'
|
|
6
|
+
|
|
7
|
+
describe('groupCoverageByCodeownersCommand', () => {
|
|
8
|
+
let program
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
program = new Command()
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
jest.clearAllMocks()
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('has the correct command structure', () => {
|
|
19
|
+
const command = groupCoverageByCodeownersCommand(program)
|
|
20
|
+
|
|
21
|
+
expect(JSON.stringify(command, null, 2)).toMatchSnapshot()
|
|
22
|
+
})
|
|
23
|
+
})
|
package/src/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import detectCircularityCommandCreator from './commands/detect-circularity.js'
|
|
|
2
2
|
import metricsCommandCreator from './commands/metrics.js'
|
|
3
3
|
import { createGraphGenerateCommand } from './commands/graph-generate.js'
|
|
4
4
|
import codeownersCommand from './commands/codeowners/index.js'
|
|
5
|
+
import { coverageCommand } from './commands/coverage.js'
|
|
5
6
|
import checkIfMonorepo from './utils/check-if-monorepo.js'
|
|
6
7
|
import getPackages from './utils/get-packages.js'
|
|
7
8
|
|
|
@@ -15,6 +16,7 @@ export const commands = [
|
|
|
15
16
|
metricsCommandCreator,
|
|
16
17
|
createGraphGenerateCommand,
|
|
17
18
|
codeownersCommand,
|
|
19
|
+
coverageCommand,
|
|
18
20
|
]
|
|
19
21
|
|
|
20
22
|
export default {
|