Chore: Script to generate betterer issue summary (#61857)

* wip

* finish script

* limit by message

* fix filter message

* Add template

* improve template

* codeowners devdep
This commit is contained in:
Josh Hunt 2023-01-26 10:48:33 +00:00 committed by GitHub
parent 64352e8d08
commit 43828e829b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 240 additions and 4 deletions

View File

@ -36,3 +36,5 @@ kinds/report.json
# Generated schema docs
docs/sources/developers/kinds/
scripts/cli/bettererIssueTemplate.md

View File

@ -54,7 +54,8 @@
"i18n:compile": "echo 'no i18n compile yet, all good'",
"betterer": "betterer",
"betterer:merge": "betterer merge",
"betterer:stats": "ts-node --transpile-only --project ./scripts/cli/tsconfig.json ./scripts/cli/reportBettererStats.ts"
"betterer:stats": "ts-node --transpile-only --project ./scripts/cli/tsconfig.json ./scripts/cli/reportBettererStats.ts",
"betterer:issues": "ts-node --transpile-only --project ./scripts/cli/tsconfig.json ./scripts/cli/generateBettererIssues.ts"
},
"grafana": {
"whatsNewUrl": "https://grafana.com/docs/grafana/next/whatsnew/whats-new-in-v9-2/",
@ -164,6 +165,7 @@
"@types/testing-library__jest-dom": "5.14.5",
"@types/tinycolor2": "1.4.3",
"@types/uuid": "8.3.4",
"@types/yargs": "17.0.12",
"@typescript-eslint/eslint-plugin": "5.42.0",
"@typescript-eslint/parser": "5.42.0",
"autoprefixer": "10.4.13",
@ -173,6 +175,7 @@
"babel-plugin-macros": "3.1.0",
"blob-polyfill": "7.0.20220408",
"browserslist": "^4.21.4",
"codeowners": "^5.1.1",
"copy-webpack-plugin": "9.0.1",
"css-loader": "6.7.1",
"css-minimizer-webpack-plugin": "4.2.2",
@ -244,7 +247,8 @@
"webpack-cli": "4.10.0",
"webpack-dev-server": "4.11.1",
"webpack-manifest-plugin": "5.0.0",
"webpack-merge": "5.8.0"
"webpack-merge": "5.8.0",
"yargs": "^17.5.1"
},
"dependencies": {
"@daybrush/utils": "1.10.0",

View File

@ -0,0 +1,7 @@
Hi <%= owner %>!
The following files have been marked as having issues regarding `<%= issueFilter %>: <%= issueMessageFilter %>`.
There are <%= totalIssueCount %> <%= plural('issue', totalIssueCount) %> over <%= fileCount %> <%= plural('file', fileCount) %>:
<% files.forEach((file) => { %>
- [ ] <%= file.issueCount %> <%= plural('issue', file.issueCount) %> in `<%= file.fileName %>` <% }) %>

View File

@ -0,0 +1,148 @@
import { betterer, BettererFileIssues } from '@betterer/betterer';
import Codeowners from 'codeowners';
import { readFile, writeFile } from 'fs/promises';
import { template } from 'lodash';
import path from 'path';
import { hideBin } from 'yargs/helpers';
import yargs from 'yargs/yargs';
const argv = yargs(hideBin(process.argv))
.option('template', {
demandOption: true,
alias: 't',
describe: 'Path to a template to use for each issue. See source bettererIssueTemplate.md for an example',
type: 'string',
default: './scripts/cli/bettererIssueTemplate.md',
})
.option('output', {
demandOption: true,
alias: 'o',
describe: 'Path to directory to save issues to',
type: 'string',
})
.option('test', {
demandOption: true,
alias: 'b',
describe: 'Name of the betterer test to produce the report for',
type: 'string',
})
.option('test-message', {
alias: 'm',
describe: 'Filter issues containing this message',
type: 'string',
})
.option('single-owner', {
type: 'boolean',
alias: 's',
describe: 'Only use first owner for files with multiple owners',
default: false,
})
.usage('Usage: yarn betterer:issues -t [path] -o [path] -b [string]')
.version(false)
.help('help').argv;
interface FileDetails {
fileName: string;
issueCount: number;
issues: BettererFileIssues;
}
// really dumb and simple pluralize function. not meant to be exhaustive
function plural(word: string, count: number) {
if (count === 0 || count > 1) {
return word + 's';
}
return word;
}
async function main() {
const args = await argv;
const templatePath = path.resolve(args.template);
const outputPath = path.resolve(args.output);
const templateString = (await readFile(templatePath)).toString();
const owners = new Codeowners();
const results = await betterer.results();
const filesByOwner: Record<string, FileDetails[]> = {};
for (const testResults of results.resultSummaries) {
if (testResults.name !== args.test) {
continue;
}
if (typeof testResults.details === 'string') {
continue;
}
for (const _fileName in testResults.details) {
const fileName = _fileName.replace(process.cwd() + '/', '');
const _details = testResults.details[_fileName];
let ownersForFile = owners.getOwner(fileName);
if (args.singleOwner) {
ownersForFile = [ownersForFile[0]];
}
const filterByMessage = args.testMessage?.length ? args.testMessage.toLowerCase() : undefined;
const filteredDetails = filterByMessage
? _details.filter((v) => v.message.toLowerCase().includes(filterByMessage))
: _details;
const numberOfIssues = filteredDetails.length;
if (numberOfIssues === 0) {
continue;
}
for (const owner of ownersForFile) {
if (!filesByOwner[owner]) {
filesByOwner[owner] = [];
}
filesByOwner[owner].push({
fileName,
issueCount: numberOfIssues,
issues: filteredDetails,
});
}
}
}
const contexts = Object.entries(filesByOwner).map(([owner, files]) => {
const fileCount = files.length;
const totalIssueCount = files.reduce((acc, v) => acc + v.issueCount, 0);
return {
owner,
files,
fileCount,
totalIssueCount,
issueFilter: args.test,
issueMessageFilter: args.testMessage,
};
});
const compiledTemplate = template(templateString, { imports: { plural } });
for (const context of contexts) {
const fileSafeOwner = context.owner.replace(/[^a-z0-9-]/gi, '_');
const fileSafeTestName = args.test.replace(/[^a-z0-9-]/gi, '_');
const outputFilePath = path.join(outputPath, `${fileSafeTestName}_${fileSafeOwner}.txt`);
const printed = compiledTemplate(context);
await writeFile(outputFilePath, printed);
const indented = printed
.split('\n')
.map((v) => `\t${v}`)
.join('\n');
console.log(`Printed issue for owner`, context.owner, 'to', outputFilePath);
console.log(indented);
}
}
main().catch(console.error);

View File

@ -7082,7 +7082,7 @@ __metadata:
languageName: node
linkType: hard
"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8":
"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.6, @nodelib/fs.walk@npm:^1.2.8":
version: 1.2.8
resolution: "@nodelib/fs.walk@npm:1.2.8"
dependencies:
@ -12111,6 +12111,15 @@ __metadata:
languageName: node
linkType: hard
"@types/yargs@npm:17.0.12":
version: 17.0.12
resolution: "@types/yargs@npm:17.0.12"
dependencies:
"@types/yargs-parser": "*"
checksum: 5b41d21d8624199f89db82209b2adab2e47867b3677e852fde65698be2ca48364b14c2e70cb0adc9bca4a2102c93dad2409cae0ad666ea36ae031ae1cb08a7b5
languageName: node
linkType: hard
"@types/yargs@npm:^15.0.0":
version: 15.0.14
resolution: "@types/yargs@npm:15.0.14"
@ -15861,6 +15870,25 @@ __metadata:
languageName: node
linkType: hard
"codeowners@npm:^5.1.1":
version: 5.1.1
resolution: "codeowners@npm:5.1.1"
dependencies:
"@nodelib/fs.walk": ^1.2.6
commander: ^6.2.1
find-up: ^2.1.0
ignore: ^3.3.10
is-directory: ^0.3.1
lodash.intersection: ^4.4.0
lodash.maxby: ^4.6.0
lodash.padend: ^4.6.1
true-case-path: ^1.0.3
bin:
codeowners: index.js
checksum: 9ffd67403e9d0defc5b9906dd986734c2c2a02cad758ab95b722558a1817f47925dd2bac58327b860edd66806bf5cd72a24b1f377fe6215cf0576fee3bfbac48
languageName: node
linkType: hard
"collapse-white-space@npm:^1.0.2":
version: 1.0.6
resolution: "collapse-white-space@npm:1.0.6"
@ -21731,6 +21759,7 @@ __metadata:
"@types/tinycolor2": 1.4.3
"@types/uuid": 8.3.4
"@types/webpack-env": 1.18.0
"@types/yargs": 17.0.12
"@typescript-eslint/eslint-plugin": 5.42.0
"@typescript-eslint/parser": 5.42.0
"@visx/event": 2.17.0
@ -21758,6 +21787,7 @@ __metadata:
calculate-size: 1.1.1
centrifuge: 3.1.0
classnames: 2.3.2
codeowners: ^5.1.1
comlink: 4.3.1
common-tags: 1.8.2
copy-webpack-plugin: 9.0.1
@ -21929,6 +21959,7 @@ __metadata:
webpack-merge: 5.8.0
whatwg-fetch: 3.6.2
xlsx: "https://cdn.sheetjs.com/xlsx-0.19.1/xlsx-0.19.1.tgz"
yargs: ^17.5.1
languageName: unknown
linkType: soft
@ -22887,6 +22918,13 @@ __metadata:
languageName: node
linkType: hard
"ignore@npm:^3.3.10":
version: 3.3.10
resolution: "ignore@npm:3.3.10"
checksum: 23e8cc776e367b56615ab21b78decf973a35dfca5522b39d9b47643d8168473b0d1f18dd1321a1bab466a12ea11a2411903f3b21644f4d5461ee0711ec8678bd
languageName: node
linkType: hard
"ignore@npm:^4.0.3":
version: 4.0.6
resolution: "ignore@npm:4.0.6"
@ -23514,6 +23552,13 @@ __metadata:
languageName: node
linkType: hard
"is-directory@npm:^0.3.1":
version: 0.3.1
resolution: "is-directory@npm:0.3.1"
checksum: dce9a9d3981e38f2ded2a80848734824c50ee8680cd09aa477bef617949715cfc987197a2ca0176c58a9fb192a1a0d69b535c397140d241996a609d5906ae524
languageName: node
linkType: hard
"is-docker@npm:^2.0.0, is-docker@npm:^2.1.1":
version: 2.2.1
resolution: "is-docker@npm:2.2.1"
@ -26395,6 +26440,13 @@ __metadata:
languageName: node
linkType: hard
"lodash.intersection@npm:^4.4.0":
version: 4.4.0
resolution: "lodash.intersection@npm:4.4.0"
checksum: 98935dcba1bbb981c3927e3822f6f6f344736c881df4b622e4e40ca4a125490425449e23179f46294a1b4c351de4e9a7bb60207cc6ddd65ecfd45ef727d35123
languageName: node
linkType: hard
"lodash.isequal@npm:^4.0.0":
version: 4.5.0
resolution: "lodash.isequal@npm:4.5.0"
@ -26416,6 +26468,13 @@ __metadata:
languageName: node
linkType: hard
"lodash.maxby@npm:^4.6.0":
version: 4.6.0
resolution: "lodash.maxby@npm:4.6.0"
checksum: 2f508383545bd9450e6509f1e5f3a3f737aac25a54225fe981b1a3c80faacc6d48d047695d799f5a7db80e8fc3c600e4736573cb2e6d0365c8f929bba5e5a1dd
languageName: node
linkType: hard
"lodash.memoize@npm:4.x, lodash.memoize@npm:^4.1.2":
version: 4.1.2
resolution: "lodash.memoize@npm:4.1.2"
@ -26437,6 +26496,13 @@ __metadata:
languageName: node
linkType: hard
"lodash.padend@npm:^4.6.1":
version: 4.6.1
resolution: "lodash.padend@npm:4.6.1"
checksum: c2e6e789debf83b98f5c085305cdcfff1067e7a31bda2a110fd765d3c11a99edfbeef570d9ef737ab3212006bdb8114e77622e518c18c1fce52b8fdfd9dab685
languageName: node
linkType: hard
"lodash.truncate@npm:^4.4.2":
version: 4.4.2
resolution: "lodash.truncate@npm:4.4.2"
@ -36890,6 +36956,15 @@ __metadata:
languageName: node
linkType: hard
"true-case-path@npm:^1.0.3":
version: 1.0.3
resolution: "true-case-path@npm:1.0.3"
dependencies:
glob: ^7.1.2
checksum: 2e2e3bf37b4b05db2e2a1d60329960a4aa697ad7a89bd97c66f5f4da83977897c29c704276e62bca62d055d8078065bc08a1c7a01f409de11c6592af8b442cbe
languageName: node
linkType: hard
"ts-dedent@npm:^2.0.0":
version: 2.2.0
resolution: "ts-dedent@npm:2.2.0"
@ -39351,7 +39426,7 @@ __metadata:
languageName: node
linkType: hard
"yargs@npm:^17.3.1, yargs@npm:^17.4.0":
"yargs@npm:^17.3.1, yargs@npm:^17.4.0, yargs@npm:^17.5.1":
version: 17.5.1
resolution: "yargs@npm:17.5.1"
dependencies: