@jsenv/lighthouse-impact 1.2.1 → 2.1.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/README.md +24 -30
- package/main.js +2 -3
- package/package.json +24 -28
- package/src/{getLighthouseReportUsingHeadlessChrome.js → generateLighthouseReport.js} +87 -72
- package/src/internal/createLighthouseImpactComment.js +34 -15
- package/src/{logLighthouseReport.js → internal/formatLighthouseReportForLog.js} +2 -2
- package/src/internal/patchOrPostGists.js +42 -16
- package/src/reportLighthouseImpact.js +11 -30
package/README.md
CHANGED
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
# Lighthouse impact
|
|
2
|
-
|
|
3
|
-
Report pull request impacts on lighthouse score.
|
|
4
|
-
|
|
5
|
-
[](https://www.npmjs.com/package/@jsenv/lighthouse-impact)
|
|
6
|
-
[](https://github.com/jsenv/lighthouse-impact/actions?workflow=main)
|
|
7
|
-
[](https://codecov.io/gh/jsenv/lighthouse-impact)
|
|
8
|
-
|
|
9
|
-
# Presentation
|
|
1
|
+
# Lighthouse impact [](https://www.npmjs.com/package/@jsenv/lighthouse-impact) [](https://github.com/jsenv/lighthouse-impact/actions?workflow=main) [](https://codecov.io/gh/jsenv/lighthouse-impact)
|
|
10
2
|
|
|
11
3
|
`@jsenv/lighthouse-impact` analyses a pull request impact on lighthouse score. This analysis is posted in a comment of the pull request on GitHub.
|
|
12
4
|
|
|
@@ -32,7 +24,7 @@ The first thing you need is a script capable to generate a lighthouse report.
|
|
|
32
24
|
npm install --save-dev @jsenv/lighthouse-impact
|
|
33
25
|
```
|
|
34
26
|
|
|
35
|
-
|
|
27
|
+
_lighthouse.mjs_
|
|
36
28
|
|
|
37
29
|
```js
|
|
38
30
|
/*
|
|
@@ -42,24 +34,23 @@ _generate_lighthouse_report.mjs_
|
|
|
42
34
|
*/
|
|
43
35
|
import { createServer } from "node:http"
|
|
44
36
|
import { readFileSync } from "node:fs"
|
|
45
|
-
import {
|
|
37
|
+
import { generateLighthouseReport } from "@jsenv/lighthouse-impact"
|
|
46
38
|
|
|
47
39
|
const htmlFileUrl = new URL("./index.html", import.meta.url)
|
|
48
40
|
const html = String(readFileSync(htmlFileUrl))
|
|
49
41
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"content-type": "text/html",
|
|
54
|
-
})
|
|
55
|
-
response.end(html)
|
|
42
|
+
const server = createServer((request, response) => {
|
|
43
|
+
response.writeHead(200, {
|
|
44
|
+
"content-type": "text/html",
|
|
56
45
|
})
|
|
57
|
-
|
|
58
|
-
|
|
46
|
+
response.end(html)
|
|
47
|
+
})
|
|
48
|
+
server.listen(8080)
|
|
49
|
+
server.unref()
|
|
59
50
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
51
|
+
export const lighthouseReport = await generateLighthouseReport(
|
|
52
|
+
"http://127.0.0.1:8080",
|
|
53
|
+
)
|
|
63
54
|
```
|
|
64
55
|
|
|
65
56
|
_index.html_
|
|
@@ -78,7 +69,7 @@ _index.html_
|
|
|
78
69
|
</html>
|
|
79
70
|
```
|
|
80
71
|
|
|
81
|
-
At this stage, you could generate a lighthouse report on your machine. For an example, see [package.json#
|
|
72
|
+
At this stage, you could generate a lighthouse report on your machine. For an example, see [package.json#L37](./package.json#L37) and [script/lighthouse/lighthouse.mjs#L19](./script/lighthouse/lighthouse.mjs#L19).
|
|
82
73
|
|
|
83
74
|
Now it's time to configure a workflow to compare lighthouse reports before and after merging a pull request.
|
|
84
75
|
|
|
@@ -108,10 +99,10 @@ jobs:
|
|
|
108
99
|
- name: Setup git
|
|
109
100
|
uses: actions/checkout@v2
|
|
110
101
|
- name: Setup node
|
|
111
|
-
uses: actions/setup-node@
|
|
102
|
+
uses: actions/setup-node@v2
|
|
112
103
|
with:
|
|
113
|
-
node-version: "16.
|
|
114
|
-
- name:
|
|
104
|
+
node-version: "16.13.0"
|
|
105
|
+
- name: Install node modules
|
|
115
106
|
run: npm install
|
|
116
107
|
- name: Report lighthouse impact
|
|
117
108
|
run: node ./report_lighthouse_impact.mjs
|
|
@@ -127,11 +118,14 @@ _report_lighthouse_impact.mjs_
|
|
|
127
118
|
* See https://github.com/jsenv/lighthouse-impact#how-it-works
|
|
128
119
|
*/
|
|
129
120
|
|
|
130
|
-
import {
|
|
121
|
+
import {
|
|
122
|
+
reportLighthouseImpact,
|
|
123
|
+
readGitHubWorkflowEnv,
|
|
124
|
+
} from "@jsenv/lighthouse-impact"
|
|
131
125
|
|
|
132
|
-
reportLighthouseImpact({
|
|
126
|
+
await reportLighthouseImpact({
|
|
133
127
|
...readGitHubWorkflowEnv(),
|
|
134
|
-
|
|
128
|
+
lighthouseReportPath: "./lighthouse.mjs#lighthouseReport",
|
|
135
129
|
})
|
|
136
130
|
```
|
|
137
131
|
|
|
@@ -173,7 +167,7 @@ reportLighthouseImpact({
|
|
|
173
167
|
+ repositoryName: process.env.TRAVIS_REPO_SLUG.split("/")[1],
|
|
174
168
|
+ pullRequestNumber: process.env.TRAVIS_PULL_REQUEST,
|
|
175
169
|
+ githubToken: process.env.GITHUB_TOKEN, // see next step
|
|
176
|
-
|
|
170
|
+
lighthouseReportPath: "./lighthouse.mjs#lighthouseReport",
|
|
177
171
|
})
|
|
178
172
|
```
|
|
179
173
|
|
package/main.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { generateLighthouseReport } from "./src/generateLighthouseReport.js"
|
|
2
2
|
|
|
3
|
-
export {
|
|
4
|
-
export { logLighthouseReport } from "./src/logLighthouseReport.js"
|
|
3
|
+
export { readGitHubWorkflowEnv } from "@jsenv/github-pull-request-impact"
|
|
5
4
|
export { reportLighthouseImpact } from "./src/reportLighthouseImpact.js"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/lighthouse-impact",
|
|
3
|
-
"version": "1.2
|
|
3
|
+
"version": "2.1.2",
|
|
4
4
|
"description": "Package description",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"url": "https://github.com/jsenv/lighthouse-impact"
|
|
14
14
|
},
|
|
15
15
|
"engines": {
|
|
16
|
-
"node": ">=
|
|
16
|
+
"node": ">=16.13.0"
|
|
17
17
|
},
|
|
18
18
|
"publishConfig": {
|
|
19
19
|
"access": "public",
|
|
@@ -26,47 +26,43 @@
|
|
|
26
26
|
},
|
|
27
27
|
"./*": "./*"
|
|
28
28
|
},
|
|
29
|
+
"main": "./main.js",
|
|
29
30
|
"files": [
|
|
30
31
|
"/src/",
|
|
31
32
|
"/main.js"
|
|
32
33
|
],
|
|
33
34
|
"scripts": {
|
|
34
|
-
"eslint
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
35
|
+
"eslint": "node ./node_modules/eslint/bin/eslint.js . --ext=.js,.mjs",
|
|
36
|
+
"importmap": "node ./script/importmap/importmap.mjs",
|
|
37
|
+
"performance": "node --expose-gc ./script/performance/performance.mjs --log",
|
|
38
|
+
"lighthouse": "node ./script/lighthouse/lighthouse.mjs --local",
|
|
38
39
|
"generate-comment-snapshot-file": "node ./test/comment/generate_comment_snapshot_file.mjs",
|
|
39
40
|
"test": "node ./script/test/test.mjs",
|
|
40
41
|
"test-with-coverage": "npm run test -- --coverage",
|
|
41
|
-
"prettier
|
|
42
|
-
"prettier-format-stage": "npm run prettier-format -- --staged",
|
|
43
|
-
"prettier-check": "npm run prettier-format -- --dry-run",
|
|
44
|
-
"prepublishOnly": "node ./script/publish/remove_postinstall.mjs",
|
|
45
|
-
"postpublish": "node ./script/publish/restore_postinstall.mjs"
|
|
42
|
+
"prettier": "prettier --write ."
|
|
46
43
|
},
|
|
47
44
|
"dependencies": {
|
|
48
|
-
"@jsenv/
|
|
45
|
+
"@jsenv/abort": "4.1.2",
|
|
46
|
+
"@jsenv/dynamic-import-worker": "1.0.0",
|
|
47
|
+
"@jsenv/filesystem": "2.5.1",
|
|
49
48
|
"@jsenv/github-pull-request-impact": "1.6.4",
|
|
50
49
|
"@jsenv/logger": "4.0.1",
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"lighthouse": "8.2.0"
|
|
50
|
+
"chrome-launcher": "0.15.0",
|
|
51
|
+
"lighthouse": "9.1.0"
|
|
54
52
|
},
|
|
55
53
|
"devDependencies": {
|
|
56
|
-
"@jsenv/assert": "2.
|
|
57
|
-
"@jsenv/
|
|
58
|
-
"@jsenv/
|
|
59
|
-
"@jsenv/eslint-config": "15.0.2",
|
|
54
|
+
"@jsenv/assert": "2.4.0",
|
|
55
|
+
"@jsenv/core": "24.5.8",
|
|
56
|
+
"@jsenv/eslint-config": "16.0.9",
|
|
60
57
|
"@jsenv/github-release-package": "1.2.3",
|
|
61
|
-
"@jsenv/importmap-eslint-resolver": "5.1
|
|
62
|
-
"@jsenv/importmap-node-module": "
|
|
58
|
+
"@jsenv/importmap-eslint-resolver": "5.2.1",
|
|
59
|
+
"@jsenv/importmap-node-module": "2.8.0",
|
|
63
60
|
"@jsenv/package-publish": "1.6.2",
|
|
64
|
-
"@jsenv/performance-impact": "
|
|
65
|
-
"@jsenv/
|
|
66
|
-
"
|
|
67
|
-
"eslint": "
|
|
68
|
-
"eslint-plugin-
|
|
69
|
-
"
|
|
70
|
-
"prettier": "2.3.2"
|
|
61
|
+
"@jsenv/performance-impact": "2.2.1",
|
|
62
|
+
"@jsenv/server": "12.2.0",
|
|
63
|
+
"eslint": "8.4.1",
|
|
64
|
+
"eslint-plugin-html": "6.2.0",
|
|
65
|
+
"eslint-plugin-import": "2.25.3",
|
|
66
|
+
"prettier": "2.5.1"
|
|
71
67
|
}
|
|
72
68
|
}
|
|
@@ -3,30 +3,24 @@
|
|
|
3
3
|
import { createRequire } from "node:module"
|
|
4
4
|
|
|
5
5
|
import { createLogger } from "@jsenv/logger"
|
|
6
|
+
import { Abort, raceProcessTeardownEvents } from "@jsenv/abort"
|
|
7
|
+
|
|
6
8
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
executeAsyncFunction,
|
|
12
|
-
} from "@jsenv/cancellation"
|
|
13
|
-
import { writeFile, resolveUrl } from "@jsenv/util"
|
|
9
|
+
writeFile,
|
|
10
|
+
resolveUrl,
|
|
11
|
+
assertAndNormalizeDirectoryUrl,
|
|
12
|
+
} from "@jsenv/filesystem"
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
import { formatLighthouseReportForLog } from "./internal/formatLighthouseReportForLog.js"
|
|
16
15
|
|
|
17
|
-
const
|
|
18
|
-
// eslint-disable-next-line import/no-unresolved
|
|
19
|
-
const ReportGenerator = require("lighthouse/report/report-generator")
|
|
20
|
-
const { computeMedianRun } = require("lighthouse/lighthouse-core/lib/median-run.js")
|
|
21
|
-
const chromeLauncher = require("chrome-launcher")
|
|
16
|
+
const require = createRequire(import.meta.url)
|
|
22
17
|
|
|
23
|
-
export const
|
|
18
|
+
export const generateLighthouseReport = async (
|
|
24
19
|
url,
|
|
25
20
|
{
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
signal = new AbortController().signal,
|
|
22
|
+
handleSIGINT = true,
|
|
28
23
|
logLevel,
|
|
29
|
-
projectDirectoryUrl,
|
|
30
24
|
|
|
31
25
|
headless = true,
|
|
32
26
|
gpu = false,
|
|
@@ -38,29 +32,33 @@ export const getLighthouseReportUsingHeadlessChrome = async (
|
|
|
38
32
|
runCount = 1,
|
|
39
33
|
delayBetweenEachRunInSeconds = 1,
|
|
40
34
|
|
|
41
|
-
jsonFile
|
|
35
|
+
projectDirectoryUrl, // required only when jsonFile or htmlFile is passed
|
|
36
|
+
log = false,
|
|
37
|
+
jsonFile = false,
|
|
42
38
|
jsonFileRelativeUrl = "./lighthouse/lighthouse_report.json",
|
|
43
39
|
jsonFileLog = true,
|
|
44
|
-
htmlFile =
|
|
40
|
+
htmlFile = false,
|
|
45
41
|
htmlFileRelativeUrl = "./lighthouse/lighthouse_report.html",
|
|
46
42
|
htmlFileLog = true,
|
|
47
43
|
} = {},
|
|
48
44
|
) => {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
45
|
+
const ReportGenerator = require("lighthouse/report/generator/report-generator.js")
|
|
46
|
+
const {
|
|
47
|
+
computeMedianRun,
|
|
48
|
+
} = require("lighthouse/lighthouse-core/lib/median-run.js")
|
|
49
|
+
const chromeLauncher = require("chrome-launcher")
|
|
50
|
+
|
|
51
|
+
const generateReportOperation = Abort.startOperation()
|
|
52
|
+
generateReportOperation.addAbortSignal(signal)
|
|
53
|
+
if (handleSIGINT) {
|
|
54
|
+
generateReportOperation.addAbortSource((abort) => {
|
|
55
|
+
return raceProcessTeardownEvents(
|
|
56
|
+
{
|
|
57
|
+
SIGINT: true,
|
|
58
|
+
},
|
|
59
|
+
abort,
|
|
60
|
+
)
|
|
61
|
+
})
|
|
64
62
|
}
|
|
65
63
|
|
|
66
64
|
const jsenvGenerateLighthouseReport = async () => {
|
|
@@ -75,39 +73,63 @@ export const getLighthouseReportUsingHeadlessChrome = async (
|
|
|
75
73
|
"--disk-cache-size=1",
|
|
76
74
|
// "--disk-cache-dir=/dev/null",
|
|
77
75
|
]
|
|
78
|
-
const chrome = await
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
76
|
+
const chrome = await chromeLauncher.launch({ chromeFlags })
|
|
77
|
+
if (generateReportOperation.signal.aborted) {
|
|
78
|
+
return { aborted: true }
|
|
79
|
+
}
|
|
80
|
+
|
|
82
81
|
const lighthouseOptions = {
|
|
83
82
|
chromeFlags,
|
|
84
83
|
port: chrome.port,
|
|
85
84
|
}
|
|
86
85
|
|
|
87
86
|
const reports = []
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
await
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
87
|
+
try {
|
|
88
|
+
await Array(runCount)
|
|
89
|
+
.fill()
|
|
90
|
+
.reduce(async (previous, _, index) => {
|
|
91
|
+
generateReportOperation.throwIfAborted()
|
|
92
|
+
await previous
|
|
93
|
+
|
|
94
|
+
if (index > 0 && delayBetweenEachRunInSeconds) {
|
|
95
|
+
await new Promise((resolve) =>
|
|
96
|
+
setTimeout(resolve, delayBetweenEachRunInSeconds * 1000),
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
generateReportOperation.throwIfAborted()
|
|
100
|
+
const report = await generateOneLighthouseReport(url, {
|
|
101
|
+
lighthouseOptions,
|
|
102
|
+
config,
|
|
103
|
+
})
|
|
104
|
+
reports.push(report)
|
|
105
|
+
}, Promise.resolve())
|
|
106
|
+
} catch (e) {
|
|
107
|
+
if (Abort.isAbortError(e)) {
|
|
108
|
+
return { aborted: true }
|
|
109
|
+
}
|
|
110
|
+
throw e
|
|
111
|
+
}
|
|
102
112
|
|
|
103
113
|
const lighthouseReport = computeMedianRun(reports)
|
|
114
|
+
|
|
115
|
+
if (log) {
|
|
116
|
+
logger.info(formatLighthouseReportForLog(lighthouseReport))
|
|
117
|
+
}
|
|
118
|
+
|
|
104
119
|
await chrome.kill()
|
|
105
120
|
|
|
121
|
+
if (jsonFile || htmlFile) {
|
|
122
|
+
projectDirectoryUrl = assertAndNormalizeDirectoryUrl(projectDirectoryUrl)
|
|
123
|
+
}
|
|
124
|
+
|
|
106
125
|
const promises = []
|
|
107
126
|
if (jsonFile) {
|
|
108
127
|
promises.push(
|
|
109
128
|
(async () => {
|
|
110
|
-
const jsonFileUrl = resolveUrl(
|
|
129
|
+
const jsonFileUrl = resolveUrl(
|
|
130
|
+
jsonFileRelativeUrl,
|
|
131
|
+
projectDirectoryUrl,
|
|
132
|
+
)
|
|
111
133
|
const json = JSON.stringify(lighthouseReport, null, " ")
|
|
112
134
|
await writeFile(jsonFileUrl, json)
|
|
113
135
|
if (jsonFileLog) {
|
|
@@ -119,7 +141,10 @@ export const getLighthouseReportUsingHeadlessChrome = async (
|
|
|
119
141
|
if (htmlFile) {
|
|
120
142
|
promises.push(
|
|
121
143
|
(async () => {
|
|
122
|
-
const htmlFileUrl = resolveUrl(
|
|
144
|
+
const htmlFileUrl = resolveUrl(
|
|
145
|
+
htmlFileRelativeUrl,
|
|
146
|
+
projectDirectoryUrl,
|
|
147
|
+
)
|
|
123
148
|
const html = ReportGenerator.generateReportHtml(lighthouseReport)
|
|
124
149
|
await writeFile(htmlFileUrl, html)
|
|
125
150
|
if (htmlFileLog) {
|
|
@@ -133,29 +158,19 @@ export const getLighthouseReportUsingHeadlessChrome = async (
|
|
|
133
158
|
return lighthouseReport
|
|
134
159
|
}
|
|
135
160
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
cleanup()
|
|
142
|
-
}
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
catchCancellation: true,
|
|
146
|
-
considerUnhandledRejectionsAsExceptions: true,
|
|
147
|
-
},
|
|
148
|
-
)
|
|
161
|
+
try {
|
|
162
|
+
return await jsenvGenerateLighthouseReport()
|
|
163
|
+
} finally {
|
|
164
|
+
await generateReportOperation.end()
|
|
165
|
+
}
|
|
149
166
|
}
|
|
150
167
|
|
|
151
168
|
const generateOneLighthouseReport = async (
|
|
152
169
|
url,
|
|
153
|
-
{
|
|
170
|
+
{ lighthouseOptions, config },
|
|
154
171
|
) => {
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
start: () => lighthouse(url, lighthouseOptions, config),
|
|
158
|
-
})
|
|
172
|
+
const lighthouse = require("lighthouse")
|
|
173
|
+
const results = await lighthouse(url, lighthouseOptions, config)
|
|
159
174
|
|
|
160
175
|
// use results.lhr for the JS-consumeable output
|
|
161
176
|
// https://github.com/GoogleChrome/lighthouse/blob/master/types/lhr.d.ts
|
|
@@ -38,8 +38,12 @@ export const createLighthouseImpactComment = ({
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
const bodyLines = [
|
|
41
|
-
...(beforeMergeGist
|
|
42
|
-
|
|
41
|
+
...(beforeMergeGist
|
|
42
|
+
? [`<!-- before_merge_gist_id=${beforeMergeGist.id} -->`]
|
|
43
|
+
: []),
|
|
44
|
+
...(afterMergeGist
|
|
45
|
+
? [`<!-- after_merge_gist_id=${afterMergeGist.id} -->`]
|
|
46
|
+
: []),
|
|
43
47
|
`<h4>Lighthouse impact</h4>`,
|
|
44
48
|
...(impactAnalysisEnabled
|
|
45
49
|
? [
|
|
@@ -76,19 +80,24 @@ const renderBody = ({
|
|
|
76
80
|
pullRequestBase,
|
|
77
81
|
pullRequestHead,
|
|
78
82
|
}) => {
|
|
79
|
-
return Object.keys(afterMergeLighthouseReport.categories).map(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
return Object.keys(afterMergeLighthouseReport.categories).map(
|
|
84
|
+
(categoryName) => {
|
|
85
|
+
return renderCategory(categoryName, {
|
|
86
|
+
beforeMergeLighthouseReport,
|
|
87
|
+
afterMergeLighthouseReport,
|
|
88
|
+
pullRequestBase,
|
|
89
|
+
pullRequestHead,
|
|
90
|
+
})
|
|
91
|
+
},
|
|
92
|
+
).join(`
|
|
87
93
|
|
|
88
94
|
`)
|
|
89
95
|
}
|
|
90
96
|
|
|
91
|
-
const renderCategory = (
|
|
97
|
+
const renderCategory = (
|
|
98
|
+
category,
|
|
99
|
+
{ beforeMergeLighthouseReport, afterMergeLighthouseReport },
|
|
100
|
+
) => {
|
|
92
101
|
const beforeMergeDisplayedScore = scoreToDisplayedScore(
|
|
93
102
|
beforeMergeLighthouseReport.categories[category].score,
|
|
94
103
|
)
|
|
@@ -114,7 +123,8 @@ const renderCategory = (category, { beforeMergeLighthouseReport, afterMergeLight
|
|
|
114
123
|
</details>`
|
|
115
124
|
}
|
|
116
125
|
|
|
117
|
-
const scoreToDisplayedScore = (floatingNumber) =>
|
|
126
|
+
const scoreToDisplayedScore = (floatingNumber) =>
|
|
127
|
+
Math.round(floatingNumber * 100)
|
|
118
128
|
|
|
119
129
|
const renderCategoryAudits = (
|
|
120
130
|
category,
|
|
@@ -156,7 +166,10 @@ const renderCategoryAudits = (
|
|
|
156
166
|
return
|
|
157
167
|
}
|
|
158
168
|
|
|
159
|
-
if (
|
|
169
|
+
if (
|
|
170
|
+
typeof beforeMergeAuditOutput === "number" &&
|
|
171
|
+
typeof afterMergeAuditOutput === "number"
|
|
172
|
+
) {
|
|
160
173
|
const diff = afterMergeAuditOutput - beforeMergeAuditOutput
|
|
161
174
|
|
|
162
175
|
audits.push([
|
|
@@ -170,7 +183,9 @@ const renderCategoryAudits = (
|
|
|
170
183
|
|
|
171
184
|
audits.push([
|
|
172
185
|
`<td nowrap>${auditId}</td>`,
|
|
173
|
-
`<td nowrap>${
|
|
186
|
+
`<td nowrap>${
|
|
187
|
+
beforeMergeAuditOutput === afterMergeAuditOutput ? "none" : "---"
|
|
188
|
+
}</td>`,
|
|
174
189
|
`<td nowrap>${beforeMergeAuditOutput}</td>`,
|
|
175
190
|
`<td nowrap>${afterMergeAuditOutput}</td>`,
|
|
176
191
|
])
|
|
@@ -237,7 +252,11 @@ const renderAudit = (audit) => {
|
|
|
237
252
|
return null
|
|
238
253
|
}
|
|
239
254
|
|
|
240
|
-
const renderGistLinks = ({
|
|
255
|
+
const renderGistLinks = ({
|
|
256
|
+
beforeMergeGist,
|
|
257
|
+
afterMergeGist,
|
|
258
|
+
pullRequestBase,
|
|
259
|
+
}) => {
|
|
241
260
|
return `<sub>
|
|
242
261
|
Impact analyzed comparing <a href="${gistIdToReportUrl(
|
|
243
262
|
beforeMergeGist.id,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const formatLighthouseReportForLog = (lighthouseReport) => {
|
|
2
2
|
const scores = {}
|
|
3
3
|
Object.keys(lighthouseReport.categories).forEach((name) => {
|
|
4
4
|
scores[name] = lighthouseReport.categories[name].score
|
|
5
5
|
})
|
|
6
|
-
|
|
6
|
+
return JSON.stringify(scores, null, " ")
|
|
7
7
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
/* eslint-disable new-cap */
|
|
2
2
|
import { createDetailedMessage } from "@jsenv/logger"
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
GET,
|
|
5
|
+
POST,
|
|
6
|
+
PATCH,
|
|
7
|
+
} from "@jsenv/github-pull-request-impact/src/internal/git_hub_api.js"
|
|
4
8
|
|
|
5
9
|
// https://developer.github.com/v3/gists/#create-a-gist
|
|
6
10
|
|
|
@@ -27,8 +31,10 @@ export const patchOrPostGists = async ({
|
|
|
27
31
|
afterMergeGistId = gistIds.afterMergeGistId
|
|
28
32
|
logger.debug(
|
|
29
33
|
createDetailedMessage(`gists found in comment body`, {
|
|
30
|
-
"before merging gist with lighthouse report":
|
|
31
|
-
|
|
34
|
+
"before merging gist with lighthouse report":
|
|
35
|
+
gistIdToUrl(beforeMergeGistId),
|
|
36
|
+
"after merging gist with lighthouse report":
|
|
37
|
+
gistIdToUrl(afterMergeGistId),
|
|
32
38
|
}),
|
|
33
39
|
)
|
|
34
40
|
} else {
|
|
@@ -39,10 +45,16 @@ export const patchOrPostGists = async ({
|
|
|
39
45
|
logger.debug(`update or create both gists.`)
|
|
40
46
|
let [beforeMergeGist, afterMergeGist] = await Promise.all([
|
|
41
47
|
beforeMergeGistId
|
|
42
|
-
? GET(`https://api.github.com/gists/${beforeMergeGistId}`, {
|
|
48
|
+
? GET(`https://api.github.com/gists/${beforeMergeGistId}`, {
|
|
49
|
+
cancellationToken,
|
|
50
|
+
githubToken,
|
|
51
|
+
})
|
|
43
52
|
: null,
|
|
44
53
|
afterMergeGistId
|
|
45
|
-
? GET(`https://api.github.com/gists/${afterMergeGistId}`, {
|
|
54
|
+
? GET(`https://api.github.com/gists/${afterMergeGistId}`, {
|
|
55
|
+
cancellationToken,
|
|
56
|
+
githubToken,
|
|
57
|
+
})
|
|
46
58
|
: null,
|
|
47
59
|
])
|
|
48
60
|
|
|
@@ -65,10 +77,14 @@ export const patchOrPostGists = async ({
|
|
|
65
77
|
logger.info(`base gist updated`)
|
|
66
78
|
} else {
|
|
67
79
|
logger.info(`creating base gist`)
|
|
68
|
-
beforeMergeGist = await POST(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
80
|
+
beforeMergeGist = await POST(
|
|
81
|
+
`https://api.github.com/gists`,
|
|
82
|
+
beforeMergeGistBody,
|
|
83
|
+
{
|
|
84
|
+
cancellationToken,
|
|
85
|
+
githubToken,
|
|
86
|
+
},
|
|
87
|
+
)
|
|
72
88
|
logger.info(`base gist created at ${gistIdToUrl(beforeMergeGist.id)}`)
|
|
73
89
|
}
|
|
74
90
|
|
|
@@ -79,7 +95,9 @@ export const patchOrPostGists = async ({
|
|
|
79
95
|
beforeMerge: false,
|
|
80
96
|
})
|
|
81
97
|
if (afterMergeGist) {
|
|
82
|
-
logger.info(
|
|
98
|
+
logger.info(
|
|
99
|
+
`updating after merge gist at ${gistIdToUrl(afterMergeGist.id)}`,
|
|
100
|
+
)
|
|
83
101
|
afterMergeGist = await PATCH(
|
|
84
102
|
`https://api.github.com/gists/${afterMergeGist.id}`,
|
|
85
103
|
afterMergeGistBody,
|
|
@@ -91,10 +109,14 @@ export const patchOrPostGists = async ({
|
|
|
91
109
|
logger.info(`after merge gist updated`)
|
|
92
110
|
} else {
|
|
93
111
|
logger.info(`creating after merge gist`)
|
|
94
|
-
afterMergeGist = await POST(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
112
|
+
afterMergeGist = await POST(
|
|
113
|
+
`https://api.github.com/gists`,
|
|
114
|
+
afterMergeGistBody,
|
|
115
|
+
{
|
|
116
|
+
cancellationToken,
|
|
117
|
+
githubToken,
|
|
118
|
+
},
|
|
119
|
+
)
|
|
98
120
|
logger.info(`after merge gist created at ${gistIdToUrl(afterMergeGist.id)}`)
|
|
99
121
|
}
|
|
100
122
|
|
|
@@ -120,8 +142,12 @@ const createGistBody = (
|
|
|
120
142
|
}
|
|
121
143
|
}
|
|
122
144
|
|
|
123
|
-
const beforeMergeGistIdRegex = new RegExp(
|
|
124
|
-
|
|
145
|
+
const beforeMergeGistIdRegex = new RegExp(
|
|
146
|
+
"<!-- before_merge_gist_id=([a-zA-Z0-9_]+) -->",
|
|
147
|
+
)
|
|
148
|
+
const afterMergeGistIdRegex = new RegExp(
|
|
149
|
+
"<!-- after_merge_gist_id=([a-zA-Z0-9_]+) -->",
|
|
150
|
+
)
|
|
125
151
|
|
|
126
152
|
const gistIdsFromComment = (comment) => {
|
|
127
153
|
const beforeMergeGistIdMatch = comment.body.match(beforeMergeGistIdRegex)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { commentGitHubPullRequestImpact } from "@jsenv/github-pull-request-impact"
|
|
2
|
-
import { assertAndNormalizeDirectoryUrl, resolveUrl
|
|
2
|
+
import { assertAndNormalizeDirectoryUrl, resolveUrl } from "@jsenv/filesystem"
|
|
3
|
+
import { importOneExportFromFile } from "@jsenv/dynamic-import-worker"
|
|
3
4
|
|
|
4
5
|
import { patchOrPostGists } from "./internal/patchOrPostGists.js"
|
|
5
6
|
import { createLighthouseImpactComment } from "./internal/createLighthouseImpactComment.js"
|
|
@@ -7,6 +8,8 @@ import { createLighthouseImpactComment } from "./internal/createLighthouseImpact
|
|
|
7
8
|
export const reportLighthouseImpact = async ({
|
|
8
9
|
logLevel,
|
|
9
10
|
commandLogs = false,
|
|
11
|
+
// TODO: update { cancellationToken, cancelOnSIGINT } in "@jsenv/github-pull-request-impact"
|
|
12
|
+
// to use { signal, handleSIGINT } instead
|
|
10
13
|
cancellationToken,
|
|
11
14
|
cancelOnSIGINT,
|
|
12
15
|
projectDirectoryUrl,
|
|
@@ -16,7 +19,7 @@ export const reportLighthouseImpact = async ({
|
|
|
16
19
|
repositoryName,
|
|
17
20
|
pullRequestNumber,
|
|
18
21
|
installCommand = "npm install",
|
|
19
|
-
|
|
22
|
+
lighthouseReportPath,
|
|
20
23
|
|
|
21
24
|
runLink,
|
|
22
25
|
commitInGeneratedByInfo,
|
|
@@ -24,14 +27,14 @@ export const reportLighthouseImpact = async ({
|
|
|
24
27
|
skipGistWarning = false,
|
|
25
28
|
}) => {
|
|
26
29
|
projectDirectoryUrl = assertAndNormalizeDirectoryUrl(projectDirectoryUrl)
|
|
27
|
-
if (typeof
|
|
30
|
+
if (typeof lighthouseReportPath !== "string") {
|
|
28
31
|
throw new TypeError(
|
|
29
|
-
`
|
|
32
|
+
`lighthouseReportPath must be a string but received ${lighthouseReportPath}`,
|
|
30
33
|
)
|
|
31
34
|
}
|
|
32
35
|
projectDirectoryUrl = assertAndNormalizeDirectoryUrl(projectDirectoryUrl)
|
|
33
|
-
const
|
|
34
|
-
|
|
36
|
+
const lighthouseReportUrl = resolveUrl(
|
|
37
|
+
lighthouseReportPath,
|
|
35
38
|
projectDirectoryUrl,
|
|
36
39
|
)
|
|
37
40
|
|
|
@@ -51,19 +54,9 @@ export const reportLighthouseImpact = async ({
|
|
|
51
54
|
|
|
52
55
|
collectInfo: async ({ execCommandInProjectDirectory }) => {
|
|
53
56
|
await execCommandInProjectDirectory(installCommand)
|
|
54
|
-
await
|
|
55
|
-
|
|
56
|
-
const { generateLighthouseReport } = await import(
|
|
57
|
-
`${moduleGeneratingLighthouseReportUrl}?cache_busting=${Date.now()}`
|
|
57
|
+
const lighthouseReport = await importOneExportFromFile(
|
|
58
|
+
lighthouseReportUrl,
|
|
58
59
|
)
|
|
59
|
-
if (typeof generateLighthouseReport !== "function") {
|
|
60
|
-
throw new TypeError(
|
|
61
|
-
`generateLighthouseReport export must be a function, got ${generateLighthouseReport}`,
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const lighthouseReport = await generateLighthouseReport()
|
|
66
|
-
|
|
67
60
|
return { version: 1, data: lighthouseReport }
|
|
68
61
|
},
|
|
69
62
|
commentIdentifier: `<!-- Generated by @jsenv/lighthouse-impact -->`,
|
|
@@ -132,15 +125,3 @@ export const reportLighthouseImpact = async ({
|
|
|
132
125
|
catchError,
|
|
133
126
|
})
|
|
134
127
|
}
|
|
135
|
-
|
|
136
|
-
const assertGenerateLighthouseReportFileExists = async (fileUrl) => {
|
|
137
|
-
const fileStat = await readFileSystemNodeStat(fileUrl, {
|
|
138
|
-
nullIfNotFound: true,
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
if (!fileStat) {
|
|
142
|
-
throw new Error(
|
|
143
|
-
`Cannot find the file responsible to export generateLighthouseReport at ${fileUrl}`,
|
|
144
|
-
)
|
|
145
|
-
}
|
|
146
|
-
}
|