@jsenv/lighthouse-impact 1.1.1 → 2.1.0
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 +35 -35
- package/main.js +2 -2
- package/package.json +25 -24
- package/src/{getLighthouseReportUsingHeadlessChrome.js → generateLighthouseReport.js} +44 -15
- package/src/internal/createLighthouseImpactComment.js +34 -15
- package/src/internal/formatLighthouseReportForLog.js +7 -0
- package/src/internal/patchOrPostGists.js +42 -16
- package/src/reportLighthouseImpact.js +9 -30
package/README.md
CHANGED
|
@@ -1,18 +1,10 @@
|
|
|
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
|
|
|
13
5
|
- Helps you to catch lighthouse score impacts before merging a pull request
|
|
14
|
-
- Can be added to any workflow like a GitHub workflow
|
|
15
6
|
- Gives you the ability to get lighthouse report on your machine during dev
|
|
7
|
+
- Can be added to any automated process (GitHub workflow, Jenkins, ...)
|
|
16
8
|
|
|
17
9
|
# Pull request comment
|
|
18
10
|
|
|
@@ -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,9 +69,9 @@ _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
|
|
72
|
+
At this stage, you could generate a lighthouse report on your machine. For an example, see [package.json#L36](./package.json#L36) and [script/lighthouse/generate_lighthouse_report.mjs#L37](./script/lighthouse/generate_lighthouse_report.mjs#L37).
|
|
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
|
|
|
85
76
|
## GitHub workflow
|
|
86
77
|
|
|
@@ -127,25 +118,28 @@ _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
126
|
reportLighthouseImpact({
|
|
133
127
|
...readGitHubWorkflowEnv(),
|
|
134
|
-
|
|
128
|
+
lighthouseReportPath: "./generate_lighthouse_report.mjs#lighthouseReport",
|
|
135
129
|
})
|
|
136
130
|
```
|
|
137
131
|
|
|
138
|
-
## Other
|
|
132
|
+
## Other tools
|
|
139
133
|
|
|
140
|
-
|
|
134
|
+
If you want to use an other tool than GitHub worflow to run the pull request comparison, like Jenkins, there is a few things to do:
|
|
141
135
|
|
|
142
136
|
1. Replicate _lighthouse_impact.yml_
|
|
143
137
|
2. Adjust _report_lighthouse_impact.mjs_
|
|
144
|
-
3. Create a GitHub token
|
|
138
|
+
3. Create a GitHub token (required to post comment on GitHub)
|
|
145
139
|
|
|
146
140
|
### 1. Replicate _lighthouse_impact.yml_
|
|
147
141
|
|
|
148
|
-
Your
|
|
142
|
+
Your script must reproduce the state where your git repository has been cloned and you are currently on the pull request branch. Something like the commands below.
|
|
149
143
|
|
|
150
144
|
```console
|
|
151
145
|
git init
|
|
@@ -158,7 +152,9 @@ node ./report_lighthouse_impact.mjs
|
|
|
158
152
|
|
|
159
153
|
### 2. Adjust _report_lighthouse_impact.mjs_
|
|
160
154
|
|
|
161
|
-
When outside a GitHub workflow, you cannot use _readGitHubWorkflowEnv()_.
|
|
155
|
+
When outside a GitHub workflow, you cannot use _readGitHubWorkflowEnv()_.
|
|
156
|
+
It means you must pass several parameters to _reportLighthouseImpact_.
|
|
157
|
+
The example below assume code is executed by Travis.
|
|
162
158
|
|
|
163
159
|
```diff
|
|
164
160
|
- import { reportLighthouseImpact, readGitHubWorkflowEnv } from "@jsenv/lighthouse-impact"
|
|
@@ -171,14 +167,15 @@ reportLighthouseImpact({
|
|
|
171
167
|
+ repositoryName: process.env.TRAVIS_REPO_SLUG.split("/")[1],
|
|
172
168
|
+ pullRequestNumber: process.env.TRAVIS_PULL_REQUEST,
|
|
173
169
|
+ githubToken: process.env.GITHUB_TOKEN, // see next step
|
|
174
|
-
|
|
175
|
-
generateLighthouseReportFileRelativeUrl: "./generate_lighthouse_report.mjs",
|
|
170
|
+
lighthouseReportPath: "./generate_lighthouse_report.mjs#lighthouseReport",
|
|
176
171
|
})
|
|
177
172
|
```
|
|
178
173
|
|
|
179
174
|
### 3. Create a GitHub token
|
|
180
175
|
|
|
181
|
-
The GitHub token is required to be able to post a commment in the pull request.
|
|
176
|
+
The GitHub token is required to be able to post a commment in the pull request.
|
|
177
|
+
You need to create a GitHub token with `repo` scope at https://github.com/settings/tokens/new.
|
|
178
|
+
Finally you need to setup this environment variable. The exact way to do this is specific to the tools your are using.
|
|
182
179
|
|
|
183
180
|
# Lighthouse report viewer
|
|
184
181
|
|
|
@@ -186,7 +183,10 @@ The pull request comment can contain links to see lighthouse reports in [Lightho
|
|
|
186
183
|
|
|
187
184
|

|
|
188
185
|
|
|
189
|
-
To unlock this you need a GitHub token with the right to create gists.
|
|
186
|
+
To unlock this you need a GitHub token with the right to create gists.
|
|
187
|
+
Every github workflow has access to a magic token `secrets.GITHUB_TOKEN`.
|
|
188
|
+
But this token is not allowed to create gists.
|
|
189
|
+
We need to update the worflow file like [lighthouse-score-impact.yml#L21](./.github/workflows/lighthouse_impact.yml#L21) to use an other token that will have the rights to create gists.
|
|
190
190
|
|
|
191
191
|
```diff
|
|
192
192
|
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
package/main.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { generateLighthouseReport } from "./src/generateLighthouseReport.js"
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { readGitHubWorkflowEnv } from "@jsenv/github-pull-request-impact"
|
|
4
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": "
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Package description",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -16,8 +16,7 @@
|
|
|
16
16
|
"node": ">=14.17.0"
|
|
17
17
|
},
|
|
18
18
|
"publishConfig": {
|
|
19
|
-
"access": "public"
|
|
20
|
-
"registry": "https://registry.npmjs.org"
|
|
19
|
+
"access": "public"
|
|
21
20
|
},
|
|
22
21
|
"type": "module",
|
|
23
22
|
"exports": {
|
|
@@ -31,43 +30,45 @@
|
|
|
31
30
|
"/main.js"
|
|
32
31
|
],
|
|
33
32
|
"scripts": {
|
|
34
|
-
"eslint-check": "node ./node_modules/eslint/bin/eslint.js .",
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"generate-
|
|
33
|
+
"eslint-check": "node ./node_modules/eslint/bin/eslint.js . --ext=.js,.mjs",
|
|
34
|
+
"generate-importmap": "node ./script/importmap/generate_importmap.mjs",
|
|
35
|
+
"measure-performances": "node --expose-gc ./script/performance/generate_performance_report.mjs --log",
|
|
36
|
+
"generate-lighthouse-report": "node ./script/lighthouse/generate_lighthouse_report.mjs --local",
|
|
37
|
+
"generate-comment-snapshot-file": "node ./test/comment/generate_comment_snapshot_file.mjs",
|
|
38
|
+
"test": "node ./script/test/test.mjs",
|
|
38
39
|
"test-with-coverage": "npm run test -- --coverage",
|
|
39
|
-
"prettier-format": "node ./script/prettier/prettier_format.
|
|
40
|
+
"prettier-format": "node ./script/prettier/prettier_format.mjs",
|
|
40
41
|
"prettier-format-stage": "npm run prettier-format -- --staged",
|
|
41
42
|
"prettier-check": "npm run prettier-format -- --dry-run",
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"upload-coverage": "node ./script/upload-coverage/upload-coverage.js",
|
|
45
|
-
"prepublishOnly": "node ./script/transform-package/remove-postinstall.js",
|
|
46
|
-
"postpublish": "node ./script/transform-package/restore-postinstall.js"
|
|
43
|
+
"prepublishOnly": "node ./script/publish/remove_postinstall.mjs",
|
|
44
|
+
"postpublish": "node ./script/publish/restore_postinstall.mjs"
|
|
47
45
|
},
|
|
48
46
|
"dependencies": {
|
|
49
47
|
"@jsenv/cancellation": "3.0.0",
|
|
48
|
+
"@jsenv/dynamic-import-worker": "1.0.0",
|
|
49
|
+
"@jsenv/filesystem": "2.3.1",
|
|
50
50
|
"@jsenv/github-pull-request-impact": "1.6.4",
|
|
51
51
|
"@jsenv/logger": "4.0.1",
|
|
52
|
-
"@jsenv/util": "4.1.1",
|
|
53
52
|
"chrome-launcher": "0.14.0",
|
|
54
53
|
"lighthouse": "8.2.0"
|
|
55
54
|
},
|
|
56
55
|
"devDependencies": {
|
|
57
|
-
"@
|
|
56
|
+
"@babel/core": "7.15.8",
|
|
57
|
+
"@babel/eslint-parser": "7.15.8",
|
|
58
|
+
"@jsenv/assert": "2.3.2",
|
|
58
59
|
"@jsenv/codecov-upload": "3.5.0",
|
|
59
|
-
"@jsenv/core": "
|
|
60
|
-
"@jsenv/eslint-config": "
|
|
60
|
+
"@jsenv/core": "23.0.5",
|
|
61
|
+
"@jsenv/eslint-config": "16.0.8",
|
|
61
62
|
"@jsenv/github-release-package": "1.2.3",
|
|
62
|
-
"@jsenv/importmap-eslint-resolver": "5.1.
|
|
63
|
-
"@jsenv/importmap-node-module": "
|
|
63
|
+
"@jsenv/importmap-eslint-resolver": "5.1.2",
|
|
64
|
+
"@jsenv/importmap-node-module": "2.4.1",
|
|
64
65
|
"@jsenv/package-publish": "1.6.2",
|
|
65
|
-
"@jsenv/performance-impact": "
|
|
66
|
+
"@jsenv/performance-impact": "2.0.2",
|
|
66
67
|
"@jsenv/prettier-check-project": "5.6.1",
|
|
67
|
-
"@jsenv/server": "
|
|
68
|
+
"@jsenv/server": "7.2.0",
|
|
68
69
|
"eslint": "7.32.0",
|
|
69
|
-
"eslint-plugin-html": "6.
|
|
70
|
-
"eslint-plugin-import": "2.
|
|
71
|
-
"prettier": "2.
|
|
70
|
+
"eslint-plugin-html": "6.2.0",
|
|
71
|
+
"eslint-plugin-import": "2.25.2",
|
|
72
|
+
"prettier": "2.4.1"
|
|
72
73
|
}
|
|
73
74
|
}
|
|
@@ -10,23 +10,22 @@ import {
|
|
|
10
10
|
createOperation,
|
|
11
11
|
executeAsyncFunction,
|
|
12
12
|
} from "@jsenv/cancellation"
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
writeFile,
|
|
15
|
+
resolveUrl,
|
|
16
|
+
assertAndNormalizeDirectoryUrl,
|
|
17
|
+
} from "@jsenv/filesystem"
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
import { formatLighthouseReportForLog } from "./internal/formatLighthouseReportForLog.js"
|
|
16
20
|
|
|
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")
|
|
21
|
+
const require = createRequire(import.meta.url)
|
|
22
22
|
|
|
23
|
-
export const
|
|
23
|
+
export const generateLighthouseReport = async (
|
|
24
24
|
url,
|
|
25
25
|
{
|
|
26
26
|
cancellationToken = createCancellationToken(),
|
|
27
27
|
cancelOnSIGINT = true,
|
|
28
28
|
logLevel,
|
|
29
|
-
projectDirectoryUrl,
|
|
30
29
|
|
|
31
30
|
headless = true,
|
|
32
31
|
gpu = false,
|
|
@@ -38,20 +37,32 @@ export const getLighthouseReportUsingHeadlessChrome = async (
|
|
|
38
37
|
runCount = 1,
|
|
39
38
|
delayBetweenEachRunInSeconds = 1,
|
|
40
39
|
|
|
41
|
-
jsonFile
|
|
40
|
+
projectDirectoryUrl, // required only when jsonFile or htmlFile is passed
|
|
41
|
+
log = false,
|
|
42
|
+
jsonFile = false,
|
|
42
43
|
jsonFileRelativeUrl = "./lighthouse/lighthouse_report.json",
|
|
43
44
|
jsonFileLog = true,
|
|
44
|
-
htmlFile =
|
|
45
|
+
htmlFile = false,
|
|
45
46
|
htmlFileRelativeUrl = "./lighthouse/lighthouse_report.html",
|
|
46
47
|
htmlFileLog = true,
|
|
47
48
|
} = {},
|
|
48
49
|
) => {
|
|
50
|
+
// eslint-disable-next-line import/no-unresolved
|
|
51
|
+
const ReportGenerator = require("lighthouse/report/report-generator")
|
|
52
|
+
const {
|
|
53
|
+
computeMedianRun,
|
|
54
|
+
} = require("lighthouse/lighthouse-core/lib/median-run.js")
|
|
55
|
+
const chromeLauncher = require("chrome-launcher")
|
|
56
|
+
|
|
49
57
|
let cleanup = () => {}
|
|
50
58
|
|
|
51
59
|
if (cancelOnSIGINT) {
|
|
52
60
|
const processCancellationSource = createCancellationSource()
|
|
53
61
|
const processCancellationToken = processCancellationSource.token
|
|
54
|
-
cancellationToken = composeCancellationToken(
|
|
62
|
+
cancellationToken = composeCancellationToken(
|
|
63
|
+
cancellationToken,
|
|
64
|
+
processCancellationToken,
|
|
65
|
+
)
|
|
55
66
|
const SIGINTCallback = () => {
|
|
56
67
|
processCancellationSource.cancel("process SIGINT")
|
|
57
68
|
}
|
|
@@ -90,7 +101,9 @@ export const getLighthouseReportUsingHeadlessChrome = async (
|
|
|
90
101
|
.reduce(async (previous, _, index) => {
|
|
91
102
|
await previous
|
|
92
103
|
if (index > 0 && delayBetweenEachRunInSeconds) {
|
|
93
|
-
await new Promise((resolve) =>
|
|
104
|
+
await new Promise((resolve) =>
|
|
105
|
+
setTimeout(resolve, delayBetweenEachRunInSeconds * 1000),
|
|
106
|
+
)
|
|
94
107
|
}
|
|
95
108
|
const report = await generateOneLighthouseReport(url, {
|
|
96
109
|
cancellationToken,
|
|
@@ -101,13 +114,25 @@ export const getLighthouseReportUsingHeadlessChrome = async (
|
|
|
101
114
|
}, Promise.resolve())
|
|
102
115
|
|
|
103
116
|
const lighthouseReport = computeMedianRun(reports)
|
|
117
|
+
|
|
118
|
+
if (log) {
|
|
119
|
+
logger.info(formatLighthouseReportForLog(lighthouseReport))
|
|
120
|
+
}
|
|
121
|
+
|
|
104
122
|
await chrome.kill()
|
|
105
123
|
|
|
124
|
+
if (jsonFile || htmlFile) {
|
|
125
|
+
projectDirectoryUrl = assertAndNormalizeDirectoryUrl(projectDirectoryUrl)
|
|
126
|
+
}
|
|
127
|
+
|
|
106
128
|
const promises = []
|
|
107
129
|
if (jsonFile) {
|
|
108
130
|
promises.push(
|
|
109
131
|
(async () => {
|
|
110
|
-
const jsonFileUrl = resolveUrl(
|
|
132
|
+
const jsonFileUrl = resolveUrl(
|
|
133
|
+
jsonFileRelativeUrl,
|
|
134
|
+
projectDirectoryUrl,
|
|
135
|
+
)
|
|
111
136
|
const json = JSON.stringify(lighthouseReport, null, " ")
|
|
112
137
|
await writeFile(jsonFileUrl, json)
|
|
113
138
|
if (jsonFileLog) {
|
|
@@ -119,7 +144,10 @@ export const getLighthouseReportUsingHeadlessChrome = async (
|
|
|
119
144
|
if (htmlFile) {
|
|
120
145
|
promises.push(
|
|
121
146
|
(async () => {
|
|
122
|
-
const htmlFileUrl = resolveUrl(
|
|
147
|
+
const htmlFileUrl = resolveUrl(
|
|
148
|
+
htmlFileRelativeUrl,
|
|
149
|
+
projectDirectoryUrl,
|
|
150
|
+
)
|
|
123
151
|
const html = ReportGenerator.generateReportHtml(lighthouseReport)
|
|
124
152
|
await writeFile(htmlFileUrl, html)
|
|
125
153
|
if (htmlFileLog) {
|
|
@@ -152,6 +180,7 @@ const generateOneLighthouseReport = async (
|
|
|
152
180
|
url,
|
|
153
181
|
{ cancellationToken, lighthouseOptions, config },
|
|
154
182
|
) => {
|
|
183
|
+
const lighthouse = require("lighthouse")
|
|
155
184
|
const results = await createOperation({
|
|
156
185
|
cancellationToken,
|
|
157
186
|
start: () => lighthouse(url, lighthouseOptions, config),
|
|
@@ -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,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"
|
|
@@ -16,7 +17,7 @@ export const reportLighthouseImpact = async ({
|
|
|
16
17
|
repositoryName,
|
|
17
18
|
pullRequestNumber,
|
|
18
19
|
installCommand = "npm install",
|
|
19
|
-
|
|
20
|
+
lighthouseReportPath,
|
|
20
21
|
|
|
21
22
|
runLink,
|
|
22
23
|
commitInGeneratedByInfo,
|
|
@@ -24,14 +25,14 @@ export const reportLighthouseImpact = async ({
|
|
|
24
25
|
skipGistWarning = false,
|
|
25
26
|
}) => {
|
|
26
27
|
projectDirectoryUrl = assertAndNormalizeDirectoryUrl(projectDirectoryUrl)
|
|
27
|
-
if (typeof
|
|
28
|
+
if (typeof lighthouseReportPath !== "string") {
|
|
28
29
|
throw new TypeError(
|
|
29
|
-
`
|
|
30
|
+
`lighthouseReportPath must be a string but received ${lighthouseReportPath}`,
|
|
30
31
|
)
|
|
31
32
|
}
|
|
32
33
|
projectDirectoryUrl = assertAndNormalizeDirectoryUrl(projectDirectoryUrl)
|
|
33
|
-
const
|
|
34
|
-
|
|
34
|
+
const lighthouseReportUrl = resolveUrl(
|
|
35
|
+
lighthouseReportPath,
|
|
35
36
|
projectDirectoryUrl,
|
|
36
37
|
)
|
|
37
38
|
|
|
@@ -51,19 +52,9 @@ export const reportLighthouseImpact = async ({
|
|
|
51
52
|
|
|
52
53
|
collectInfo: async ({ execCommandInProjectDirectory }) => {
|
|
53
54
|
await execCommandInProjectDirectory(installCommand)
|
|
54
|
-
await
|
|
55
|
-
|
|
56
|
-
const { generateLighthouseReport } = await import(
|
|
57
|
-
`${moduleGeneratingLighthouseReportUrl}?cache_busting=${Date.now()}`
|
|
55
|
+
const lighthouseReport = await importOneExportFromFile(
|
|
56
|
+
lighthouseReportUrl,
|
|
58
57
|
)
|
|
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
58
|
return { version: 1, data: lighthouseReport }
|
|
68
59
|
},
|
|
69
60
|
commentIdentifier: `<!-- Generated by @jsenv/lighthouse-impact -->`,
|
|
@@ -132,15 +123,3 @@ export const reportLighthouseImpact = async ({
|
|
|
132
123
|
catchError,
|
|
133
124
|
})
|
|
134
125
|
}
|
|
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
|
-
}
|