This repository has been archived by the owner on Feb 8, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Check site performance using Lighthouse (#884)
* Add lighthouse runner * Run lighthouse as a Github action * Install node modules for lighthouse runner in CI * Fix invalid Circle CI config * Try to fix invalid Circle CI config again * Remove excess backslashes from Circle CI config * Ignore lighthouse runner in CI * Workaround github actions changing docker workdir * Use workspaces in CI to store node_modules This should hopefully be faster than checking out from cache all the time * Fix error in lighthouse runner * Update lighthouse action to leave a PR comment * Make lighthouse error fail the github action * Make it easier to run lighthouse action locally * Add console log in getPullRequestIdsForRef * Change lighthouse action to accept commit refs Previously it expected branch refs and errorred on commit refs, but github provides commit refs * Remove console log in lighthouse action
- Loading branch information
Sam Rowe
authored
Feb 17, 2020
1 parent
88ff626
commit e71c952
Showing
10 changed files
with
1,778 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,5 @@ coverage | |
dist | ||
flow-typed/npm | ||
website-next | ||
**/node_modules/** | ||
lighthouse/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
workflow "Check website performance" { | ||
on = "deployment" | ||
resolves = ["Run Lighthouse"] | ||
} | ||
|
||
action "Run Lighthouse" { | ||
uses = "./lighthouse" | ||
|
||
secrets = ["GITHUB_TOKEN"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules/ | ||
.node-version |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"settings": { | ||
"import/resolver": "node" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
v12.0.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
FROM node:12.2.0-stretch-slim | ||
|
||
|
||
LABEL "com.github.actions.name"="Lighthouse" | ||
LABEL "com.github.actions.description"="Reports on the performance of the website" | ||
LABEL "com.github.actions.icon"="activity" | ||
LABEL "com.github.actions.color"="red" | ||
|
||
|
||
# Install Google Chrome & dumb-init (https://github.com/Yelp/dumb-init) | ||
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \ | ||
&& sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \ | ||
&& apt-get update \ | ||
&& apt-get -y upgrade \ | ||
&& apt-get install -y google-chrome-stable dumb-init --no-install-recommends \ | ||
&& rm -rf /var/lib/apt/lists/* \ | ||
&& rm -rf /src/*.deb | ||
|
||
|
||
# Install dependencies | ||
ENV NODE_ENV=production | ||
COPY package.json yarn.lock / | ||
RUN yarn install --frozen-lockfile --production | ||
|
||
|
||
# Add a chrome user and setup home dir | ||
# RUN groupadd --system chrome && \ | ||
# useradd --system --create-home --gid chrome --groups audio,video chrome && \ | ||
# mkdir --parents /home/chrome/reports && \ | ||
# chown --recursive chrome:chrome /home/chrome | ||
|
||
# USER chrome | ||
|
||
|
||
COPY runner.js / | ||
|
||
#VOLUME /home/chrome/reports | ||
#WORKDIR /home/chrome/reports | ||
|
||
# Disable Lighthouse error reporting to prevent prompt. | ||
# ENV CI=true | ||
|
||
|
||
EXPOSE 8080 | ||
|
||
|
||
ENTRYPOINT ["dumb-init", "--", "node", "/runner.js"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"name": "lighthouse-runner", | ||
"version": "1.0.0", | ||
"main": "index.js", | ||
"license": "UNLICENSED", | ||
"private": true, | ||
"dependencies": { | ||
"chrome-launcher": "^0.10.7", | ||
"lighthouse": "^5.0.0", | ||
"node-fetch": "^2.6.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
const lighthouse = require('lighthouse'); | ||
const chromeLauncher = require('chrome-launcher'); | ||
const fs = require('fs'); | ||
const fetch = require('node-fetch'); | ||
|
||
const repoFullName = process.env.GITHUB_REPOSITORY; | ||
const githubEventPath = process.env.GITHUB_EVENT_PATH; | ||
const githubAuthToken = process.env.GITHUB_TOKEN; | ||
|
||
/* eslint-disable no-use-before-define */ | ||
|
||
function runLighthouse({ targetUrl }) { | ||
const chromeFlags = [ | ||
'--headless', | ||
'--no-sandbox', // chrome sandboxing requires docker container to have the | ||
// `SYS_ADMIN` capability added which is not supported by GitHub actions | ||
]; | ||
|
||
return chromeLauncher.launch({ chromeFlags }).then(chrome => { | ||
const opts = { | ||
port: chrome.port, | ||
output: 'html', | ||
}; | ||
|
||
const config = null; | ||
|
||
return lighthouse(targetUrl, opts, config).then(results => { | ||
// use results.lhr for the JS-consumable output | ||
// https://github.com/GoogleChrome/lighthouse/blob/master/types/lhr.d.ts | ||
// use results.report for the HTML/JSON/CSV output as a string | ||
// use results.artifacts for the trace/screenshots/other specific case you need (rarer) | ||
return chrome.kill().then(() => results); | ||
}); | ||
}); | ||
} | ||
|
||
function readArgumentsFromEnvironment() { | ||
if (!githubEventPath) { | ||
// eslint-disable-next-line no-console | ||
console.warn(`GITHUB_EVENT_PATH environment variable is not set, running locally.`); | ||
return { | ||
targetUrl: 'https://www-staging.red-badger.com/658e7ac/', | ||
ref: '7865779', | ||
repo: { | ||
owner: 'redbadger', | ||
name: 'website-honestly', | ||
}, | ||
}; | ||
} | ||
|
||
const { deployment } = JSON.parse(fs.readFileSync(githubEventPath)); | ||
|
||
const [owner, name] = repoFullName.split('/'); | ||
|
||
return { | ||
targetUrl: deployment.url, | ||
ref: deployment.ref, | ||
repo: { | ||
owner, | ||
name, | ||
}, | ||
}; | ||
} | ||
|
||
function run() { | ||
const { targetUrl, repo, ref } = readArgumentsFromEnvironment(); | ||
|
||
runLighthouse({ targetUrl }).then(results => reportResults({ results, repo, ref })); | ||
} | ||
|
||
async function reportResults({ results, repo, ref }) { | ||
const scores = Object.entries(results.lhr.categories) | ||
.map(([categoryName, { score }]) => `| ${categoryName} | ${score * 100} |`) | ||
.join('\n'); | ||
|
||
const body = ` | ||
⚡️ Lighthouse scores for latest changes: | ||
| Category | Score | | ||
| -------- | ----- | | ||
${scores} | ||
`; | ||
|
||
const pullRequestIds = await getPullRequestIdsForRef({ repo, ref }); | ||
|
||
await Promise.all(pullRequestIds.map(issueId => createComment({ body, issueId }))); | ||
} | ||
|
||
async function createComment({ body, issueId }) { | ||
const query = ` | ||
mutation AddLighthouseComment($IssueId: ID!, $Body: String!) { | ||
addComment(input: {subjectId: $IssueId, body: $Body}) { | ||
clientMutationId | ||
} | ||
} | ||
`; | ||
|
||
const variables = { | ||
IssueId: issueId, | ||
Body: body, | ||
}; | ||
|
||
await gitHubGraphqlRequest({ query, variables }); | ||
} | ||
|
||
async function getPullRequestIdsForRef({ repo: { owner, name }, ref }) { | ||
const query = ` | ||
query PullRequestIdsForRef($RepoOwner: String!, $RepoName: String!, $Ref: String!) { | ||
repository(owner: $RepoOwner, name: $RepoName) { | ||
object(expression: $Ref) { | ||
...on Commit { | ||
associatedPullRequests(first: 10) { | ||
nodes { | ||
id | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
`; | ||
|
||
const variables = { | ||
RepoOwner: owner, | ||
RepoName: name, | ||
Ref: ref, | ||
}; | ||
|
||
const { | ||
repository: { | ||
object: { associatedPullRequests }, | ||
}, | ||
} = await gitHubGraphqlRequest({ query, variables }); | ||
|
||
if (!associatedPullRequests) return []; | ||
|
||
return associatedPullRequests.nodes.map(({ id }) => id); | ||
} | ||
|
||
async function gitHubGraphqlRequest({ query, variables }) { | ||
const response = await fetch(`https://api.github.com/graphql`, { | ||
method: 'POST', | ||
headers: { | ||
Authorization: `bearer ${githubAuthToken}`, | ||
}, | ||
body: JSON.stringify({ query, variables }), | ||
}); | ||
|
||
if (!response.ok) { | ||
throw new Error(`Bad response from GitHub api: ${response.statusText}`); | ||
} | ||
|
||
const { data } = await response.json(); | ||
|
||
return data; | ||
} | ||
|
||
run(); | ||
|
||
process.on('unhandledRejection', error => { | ||
// eslint-disable-next-line no-console | ||
console.error(error); | ||
process.exit(1); | ||
}); |
Oops, something went wrong.