Skip to content

Commit 25fe80a

Browse files
committed
build: payload github status
* Show payload deta on PRs using the Github Statuses API.
1 parent 9c45865 commit 25fe80a

File tree

3 files changed

+115
-20
lines changed

3 files changed

+115
-20
lines changed

tools/gulp/tasks/payload.ts

Lines changed: 100 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
import {task} from 'gulp';
22
import {join} from 'path';
33
import {statSync} from 'fs';
4-
import {spawnSync} from 'child_process';
5-
import {isTravisMasterBuild} from '../util/travis-ci';
6-
import {openFirebaseDashboardApp} from '../util/firebase';
4+
import {isTravisBuild, isTravisMasterBuild} from '../util/travis-ci';
75
import {buildConfig} from '../packaging/build-config';
6+
import {openFirebaseDashboardApp, openFirebaseDashboardAppAsGuest} from '../util/firebase';
7+
8+
// These imports lack of type definitions.
9+
const request = require('request');
810

911
/** Path to the directory where all bundles are living. */
1012
const bundlesDir = join(buildConfig.outputDir, 'bundles');
1113

1214
/** Task which runs test against the size of material. */
13-
task('payload', ['material:clean-build'], () => {
15+
task('payload', ['material:clean-build'], async () => {
1416

15-
let results = {
17+
const results = {
1618
timestamp: Date.now(),
1719
// Material bundles
1820
material_umd: getBundleSize('material.umd.js'),
@@ -29,9 +31,23 @@ task('payload', ['material:clean-build'], () => {
2931
// Print the results to the console, so we can read it from the CI.
3032
console.log('Payload Results:', JSON.stringify(results, null, 2));
3133

32-
// Publish the results to firebase when it runs on Travis and not as a PR.
33-
if (isTravisMasterBuild()) {
34-
return publishResults(results);
34+
if (isTravisBuild()) {
35+
// Open a connection to Firebase. For PRs the connection will be established as a guest.
36+
const firebaseApp = isTravisMasterBuild() ?
37+
openFirebaseDashboardApp() :
38+
openFirebaseDashboardAppAsGuest();
39+
const database = firebaseApp.database();
40+
const currentSha = process.env['TRAVIS_PULL_REQUEST_SHA'] || process.env['TRAVIS_COMMIT'];
41+
42+
// Upload the payload results and calculate the payload diff in parallel. Otherwise the
43+
// payload task will take much more time inside of Travis builds.
44+
await Promise.all([
45+
uploadPayloadResults(database, currentSha, results),
46+
calculatePayloadDiff(database, currentSha, results)
47+
]);
48+
49+
// Disconnect database connection because Firebase otherwise prevents Gulp from exiting.
50+
firebaseApp.delete();
3551
}
3652

3753
});
@@ -46,14 +62,81 @@ function getFilesize(filePath: string) {
4662
return statSync(filePath).size / 1000;
4763
}
4864

49-
/** Publishes the given results to the firebase database. */
50-
function publishResults(results: any) {
51-
const latestSha = spawnSync('git', ['rev-parse', 'HEAD']).stdout.toString().trim();
52-
const dashboardApp = openFirebaseDashboardApp();
53-
const database = dashboardApp.database();
65+
/**
66+
* Calculates the difference between the last and current library payload.
67+
* The results will be published as a commit status on Github.
68+
*/
69+
async function calculatePayloadDiff(database: any, currentSha: string, currentPayload: any) {
70+
const authToken = process.env['FIREBASE_ACCESS_TOKEN'];
71+
72+
if (!authToken) {
73+
console.error('Cannot calculate Payload diff because there is no "FIREBASE_ACCESS_TOKEN" ' +
74+
'environment variable set.');
75+
return;
76+
}
77+
78+
const previousPayload = await getLastPayloadResults(database);
79+
80+
if (!previousPayload) {
81+
console.warn('There are no previous payload results uploaded. Cannot calculate payload ' +
82+
'difference for this job');
83+
return;
84+
}
85+
86+
// Calculate library sizes by combining the CDK and Material FESM 2015 bundles.
87+
const previousSize = previousPayload.cdk_fesm_2015 + previousPayload.material_fesm_2015;
88+
const currentSize = currentPayload.cdk_fesm_2015 + currentPayload.material_fesm_2015;
89+
const deltaSize = currentSize - previousSize;
90+
91+
// Update the Github status of the current commit by sending a request to the dashboard
92+
// firebase http trigger function.
93+
await updateGithubStatus(currentSha, deltaSize, authToken);
94+
}
95+
96+
/**
97+
* Updates the Github status of a given commit by sending a request to a Firebase function of
98+
* the dashboard. The function has access to the Github repository and can set status for PRs too.
99+
*/
100+
async function updateGithubStatus(commitSha: string, payloadDiff: number, authToken: string) {
101+
const options = {
102+
url: 'https://us-central1-material2-board.cloudfunctions.net/payloadGithubStatus',
103+
headers: {
104+
'User-Agent': 'Material2/PayloadTask',
105+
'auth-token': authToken,
106+
'commit-sha': commitSha,
107+
'commit-payload-diff': payloadDiff
108+
}
109+
};
110+
111+
return new Promise((resolve, reject) => {
112+
request(options, (err: any, response: any, body: string) => {
113+
if (err) {
114+
reject(`Dashboard Error ${err.toString()}`);
115+
} else {
116+
console.info('Dashboard Response:', JSON.parse(body).message);
117+
resolve(response.statusCode);
118+
}
119+
});
120+
});
121+
}
122+
123+
/** Uploads the current payload results to the Dashboard database. */
124+
async function uploadPayloadResults(database: any, currentSha: string, currentPayload: any) {
125+
if (isTravisMasterBuild()) {
126+
await database.ref('payloads').child(currentSha).set(currentPayload);
127+
}
128+
}
129+
130+
/** Gets the last payload uploaded from previous Travis builds. */
131+
async function getLastPayloadResults(database: admin.database.Database) {
132+
const snapshot = await database.ref('payloads')
133+
.orderByChild('timestamp')
134+
.limitToLast(1)
135+
.once('value');
136+
137+
// The value of the DataSnapshot is an object with the SHA as a key. Later only the
138+
// first value of the object will be returned because the SHA is unnecessary.
139+
const results = snapshot.val();
54140

55-
// Write the results to the payloads object with the latest Git SHA as key.
56-
return database.ref('payloads').child(latestSha).set(results)
57-
.catch((err: any) => console.error(err))
58-
.then(() => dashboardApp.delete());
141+
return snapshot.hasChildren() ? results[Object.keys(results)[0]] : null;
59142
}

tools/gulp/util/firebase.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,30 @@ const cloudStorage = require('@google-cloud/storage');
55
// Firebase configuration for the Screenshot project. Use the config from the screenshot functions.
66
const screenshotFirebaseConfig = require('../../screenshot-test/functions/config.json');
77

8-
/** Opens a connection to the Firebase dashboard app. */
9-
export function openFirebaseDashboardApp() {
8+
/** Database URL of the dashboard firebase project.*/
9+
const dashboardDatabaseUrl = 'https://material2-board.firebaseio.com';
10+
11+
/** Opens a connection to the Firebase dashboard app using a service account. */
12+
export function openFirebaseDashboardApp(asGuest = false) {
1013
// Initialize the Firebase application with firebaseAdmin credentials.
1114
// Credentials need to be for a Service Account, which can be created in the Firebase console.
1215
return firebaseAdmin.initializeApp({
16+
databaseURL: dashboardDatabaseUrl,
1317
credential: firebaseAdmin.credential.cert({
1418
project_id: 'material2-board',
1519
client_email: '[email protected]',
1620
// In Travis CI the private key will be incorrect because the line-breaks are escaped.
1721
// The line-breaks need to persist in the service account private key.
1822
private_key: decode(process.env['MATERIAL2_BOARD_FIREBASE_SERVICE_KEY'])
1923
}),
20-
databaseURL: 'https://material2-board.firebaseio.com'
2124
});
2225
}
2326

27+
/** Opens a connection to the Firebase dashboard app with no authentication. */
28+
export function openFirebaseDashboardAppAsGuest() {
29+
return firebase.initializeApp({ databaseURL: dashboardDatabaseUrl });
30+
}
31+
2432
/**
2533
* Open Google Cloud Storage for screenshots.
2634
* The files uploaded to google cloud are also available to firebase storage.

tools/gulp/util/travis-ci.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,7 @@
22
export function isTravisMasterBuild() {
33
return process.env['TRAVIS_PULL_REQUEST'] === 'false';
44
}
5+
6+
export function isTravisBuild() {
7+
return process.env['TRAVIS'] === 'true';
8+
}

0 commit comments

Comments
 (0)