Skip to content

Commit b01065f

Browse files
committed
initial action setup
1 parent e6cfdcc commit b01065f

File tree

1,458 files changed

+396997
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,458 files changed

+396997
-0
lines changed

.github/workflows/test.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
on: [push, pull_request]
2+
3+
jobs:
4+
5+
test_job:
6+
runs-on: ubuntu-latest
7+
name: WPT Test
8+
steps:
9+
- name: Checkout
10+
uses: actions/checkout@v2
11+
- name: WebPageTest Action
12+
id: webpagetest-action
13+
uses: ./
14+
with:
15+
apiKey: ${{ secrets.WPT_API_KEY }}
16+
urls: |
17+
https://www.cnn.com/
18+
https://www.timkadlec.com/
19+
budget: './wpt-budget.json'
20+
label: 'GH Action test'
21+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.secrets
2+
.github/workflows/local.yml

action.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: 'WebPageTest GitHub Action'
2+
description: 'Automatically run WebPageTest against URLs'
3+
inputs:
4+
apiKey:
5+
description: 'WebPageTest API Token'
6+
required: true
7+
urls:
8+
description: 'List of URL(s) to test'
9+
budget:
10+
description: 'WebPageTest Test Specs JSON file'
11+
label:
12+
description: 'Label for test (shows up in WebPageTest)'
13+
GITHUB_TOKEN:
14+
description: 'Secret GitHub Token (automatically provided by GitHub)'
15+
runs:
16+
using: 'node12'
17+
main: 'index.js'

index.js

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
const WebPageTest = require("webpagetest");
2+
const core = require("@actions/core");
3+
const github = require('@actions/github');
4+
5+
const ejs = require('ejs');
6+
7+
const WPT_BUDGET = core.getInput('budget');
8+
const WPT_API_KEY = core.getInput('apiKey');
9+
const WPT_URLS = core.getInput('urls').split("\n");
10+
const WPT_LABEL = core.getInput('label');
11+
const GITHUB_TOKEN = core.getInput('GITHUB_TOKEN');
12+
const GH_EVENT_NAME = process.env.GITHUB_EVENT_NAME;
13+
14+
const runTest = (wpt, url, options) => {
15+
// clone options object to avoid WPT wrapper issue
16+
let tempOptions = JSON.parse(JSON.stringify(options));
17+
18+
return new Promise((resolve, reject) => {
19+
wpt.runTest(url, tempOptions, async(err, result) => {
20+
try {
21+
if (result) {
22+
return resolve({'result':result,'err':err});
23+
} else {
24+
return reject(err);
25+
}
26+
} catch (e) {
27+
core.info(e);
28+
}
29+
})
30+
});
31+
}
32+
33+
const retrieveResults = (wpt, testId) => {
34+
return new Promise((resolve, reject) => {
35+
wpt.getTestResults(testId, (err, data) => {
36+
if (data) {
37+
return resolve(data);
38+
} else {
39+
return reject(err);
40+
}
41+
});
42+
});
43+
}
44+
async function renderComment(data) {
45+
try {
46+
const octokit = github.getOctokit(GITHUB_TOKEN, {log: console});
47+
const context = github.context;
48+
console.info(data);
49+
let markdown = await ejs.renderFile('./templates/comment.md', data);
50+
markdown
51+
.replace(/\%/g, '%25')
52+
.replace(/\n/g, '%0A')
53+
.replace(/\r/g, '%0D')
54+
55+
core.info(markdown);
56+
//submit a comment
57+
await octokit.issues.createComment({
58+
owner: context.repo.owner,
59+
repo: context.repo.repo,
60+
issue_number: context.payload.pull_request.number,
61+
body: markdown
62+
});
63+
} catch (e) {
64+
core.info(e);
65+
}
66+
}
67+
async function run() {
68+
69+
const wpt = new WebPageTest('www.webpagetest.org',WPT_API_KEY);
70+
71+
//TODO: make this configurable
72+
let options = {
73+
"firstViewOnly": true,
74+
"runs": 1,
75+
"location": 'Dulles:Chrome',
76+
"connectivity": '4G',
77+
"pollResults": 5,
78+
"timeout": 240
79+
}
80+
if (WPT_BUDGET) {
81+
options.specs = require(WPT_BUDGET);
82+
}
83+
if (WPT_LABEL) {
84+
options.label = WPT_LABEL;
85+
}
86+
core.startGroup(`Testing urls in WebPageTest..`);
87+
//for our commit
88+
let runData = {};
89+
runData["tests"] = [];
90+
91+
Promise.all(WPT_URLS.map(async url=> {
92+
try {
93+
await runTest(wpt, url, options)
94+
.then(async result => {
95+
try {
96+
if (result.result.testId) {
97+
//test submitted with specs
98+
core.info('Tests successfully completed for '
99+
+ url +'. Full results at https://'
100+
+ wpt.config.hostname + '/result/' + result.result.testId);
101+
102+
if (GH_EVENT_NAME == 'pull_request') {
103+
let testResults = await retrieveResults(wpt, result.result.testId);
104+
let testData = {
105+
"url": testResults.data.url,
106+
"testLink": testResults.data.summary,
107+
"waterfall": testResults.data.median.firstView.images.waterfall
108+
}
109+
runData["tests"].push(testData);
110+
}
111+
// testspecs also returns the number of assertion fails as err
112+
// > 0 means we need to fail
113+
if (result.err && result.err > 0) {
114+
if (result.err == 1) {
115+
core.setFailed('One performance budget not met.')
116+
} else {
117+
core.setFailed(result.err + ' performance budgets not met.')
118+
}
119+
}
120+
return;
121+
} else if (result.result.data) {
122+
//test was submitted without testspecs
123+
core.info('Tests successfully completed for ' + url
124+
+'. Full results at ' + result.result.data.summary);
125+
126+
if (GH_EVENT_NAME == 'pull_request') {
127+
let testResults = await retrieveResults(wpt, result.result.data.id);
128+
let testData = {
129+
"url": testResults.data.url,
130+
"testLink": testResults.data.summary,
131+
"waterfall": testResults.data.median.firstView.thumbnails.waterfall
132+
}
133+
runData["tests"].push(testData);
134+
}
135+
return;
136+
} else {
137+
return;
138+
}
139+
} catch (e) {
140+
core.info(e);
141+
}
142+
143+
});
144+
} catch (e) {
145+
console.info(e);
146+
}
147+
})).then(() => {
148+
if (GH_EVENT_NAME == 'pull_request') {
149+
renderComment(runData);
150+
}
151+
});
152+
153+
return;
154+
}
155+
156+
run();

node_modules/.bin/_mocha

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

node_modules/.bin/ejs

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

node_modules/.bin/flat

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

node_modules/.bin/he

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

node_modules/.bin/jake

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

node_modules/.bin/js-yaml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)