@@ -2,16 +2,18 @@ import {task} from 'gulp';
2
2
import { join } from 'path' ;
3
3
import { statSync } from 'fs' ;
4
4
import { DIST_ROOT } from '../build-config' ;
5
- import { spawnSync } from 'child_process' ;
6
- import { isTravisMasterBuild } from '../util/travis-ci' ;
5
+ import { isTravisBuild , isTravisMasterBuild } from '../util/travis-ci' ;
7
6
import { openFirebaseDashboardApp } from '../util/firebase' ;
8
7
8
+ // These imports lack of type definitions.
9
+ const request = require ( 'request' ) ;
10
+
9
11
const bundlesDir = join ( DIST_ROOT , 'bundles' ) ;
10
12
11
13
/** Task which runs test against the size of material. */
12
- task ( 'payload' , [ 'material:clean-build' ] , ( ) => {
14
+ task ( 'payload' , [ 'material:clean-build' ] , async ( ) => {
13
15
14
- let results = {
16
+ const results = {
15
17
timestamp : Date . now ( ) ,
16
18
// Material bundles
17
19
material_umd : getBundleSize ( 'material.umd.js' ) ,
@@ -28,9 +30,21 @@ task('payload', ['material:clean-build'], () => {
28
30
// Print the results to the console, so we can read it from the CI.
29
31
console . log ( 'Payload Results:' , JSON . stringify ( results , null , 2 ) ) ;
30
32
31
- // Publish the results to firebase when it runs on Travis and not as a PR.
32
- if ( isTravisMasterBuild ( ) ) {
33
- return publishResults ( results ) ;
33
+ if ( isTravisBuild ( ) ) {
34
+ // Open a connection to Firebase. For PRs the connection will be established as a guest.
35
+ const firebaseApp = openFirebaseDashboardApp ( ! isTravisMasterBuild ( ) ) ;
36
+ const database = firebaseApp . database ( ) ;
37
+ const currentSha = process . env [ 'TRAVIS_PULL_REQUEST_SHA' ] || process . env [ 'TRAVIS_COMMIT' ] ;
38
+
39
+ // Upload the payload results and calculate the payload diff in parallel. Otherwise the
40
+ // payload task will take much more time inside of Travis builds.
41
+ await Promise . all ( [
42
+ uploadPayloadResults ( database , currentSha , results ) ,
43
+ calculatePayloadDiff ( database , currentSha , results )
44
+ ] ) ;
45
+
46
+ // Disconnect database connection because Firebase otherwise prevents Gulp from exiting.
47
+ firebaseApp . delete ( ) ;
34
48
}
35
49
36
50
} ) ;
@@ -45,14 +59,73 @@ function getFilesize(filePath: string) {
45
59
return statSync ( filePath ) . size / 1000 ;
46
60
}
47
61
48
- /** Publishes the given results to the firebase database. */
49
- function publishResults ( results : any ) {
50
- const latestSha = spawnSync ( 'git' , [ 'rev-parse' , 'HEAD' ] ) . stdout . toString ( ) . trim ( ) ;
51
- const dashboardApp = openFirebaseDashboardApp ( ) ;
52
- const database = dashboardApp . database ( ) ;
62
+ /**
63
+ * Calculates the difference between the last and current library payload.
64
+ * The results will be published as a commit status on Github.
65
+ */
66
+ async function calculatePayloadDiff ( database : any , currentSha : string , currentPayload : any ) {
67
+ const authToken = process . env [ 'FIREBASE_ACCESS_TOKEN' ] ;
68
+
69
+ if ( ! authToken ) {
70
+ console . error ( 'Cannot calculate Payload diff because there is no "FIREBASE_ACCESS_TOKEN" ' +
71
+ 'environment variable set.' ) ;
72
+ return ;
73
+ }
74
+
75
+ const previousPayload = await getLastPayloadResults ( database ) ;
76
+
77
+ // Calculate library sizes by combining the CDK and Material FESM 2015 bundles.
78
+ const previousSize = previousPayload . cdk_fesm_2015 + previousPayload . material_fesm_2015 ;
79
+ const currentSize = currentPayload . cdk_fesm_2015 + currentPayload . material_fesm_2015 ;
80
+ const deltaSize = currentSize - previousSize ;
81
+
82
+ // Update the Github status of the current commit by sending a request to the dashboard
83
+ // firebase http trigger function.
84
+ await updateGithubStatus ( currentSha , deltaSize , authToken ) ;
85
+ }
86
+
87
+ /**
88
+ * Updates the Github status of a given commit by sending a request to a Firebase function of
89
+ * the dashboard. The function has access to the Github repository and can set status for PRs too.
90
+ */
91
+ async function updateGithubStatus ( commitSha : string , payloadDiff : number , authToken : string ) {
92
+ const options = {
93
+ url : 'https://us-central1-material2-dashboard.cloudfunctions.net/payloadGithubStatus' ,
94
+ headers : {
95
+ 'User-Agent' : 'Material2/PayloadTask' ,
96
+ 'auth-token' : authToken ,
97
+ 'commit-sha' : commitSha ,
98
+ 'commit-payload-diff' : payloadDiff
99
+ }
100
+ } ;
101
+
102
+ return new Promise ( ( resolve , reject ) => {
103
+ request ( options , ( err : any , response : any , body : string ) => {
104
+ if ( err ) {
105
+ reject ( `Dashboard Error ${ err . toString ( ) } ` ) ;
106
+ } else {
107
+ console . info ( 'Dashboard Response: ' , JSON . parse ( body ) . message ) ;
108
+ resolve ( response . statusCode ) ;
109
+ }
110
+ } ) ;
111
+ } ) ;
112
+ }
113
+
114
+ /** Uploads the current payload results to the Dashboard database. */
115
+ async function uploadPayloadResults ( database : any , currentSha : string , currentPayload : any ) {
116
+ if ( isTravisMasterBuild ( ) ) {
117
+ await database . ref ( 'payloads' ) . child ( currentSha ) . set ( currentPayload ) ;
118
+ }
119
+ }
120
+
121
+ /** Gets the last payload uploaded from previous Travis builds. */
122
+ async function getLastPayloadResults ( database : admin . database . Database ) {
123
+ const snapshot = await database . ref ( 'payloads' )
124
+ . orderByChild ( 'timestamp' )
125
+ . limitToLast ( 1 )
126
+ . once ( 'value' ) ;
53
127
54
- // Write the results to the payloads object with the latest Git SHA as key.
55
- return database . ref ( 'payloads' ) . child ( latestSha ) . set ( results )
56
- . catch ( ( err : any ) => console . error ( err ) )
57
- . then ( ( ) => dashboardApp . delete ( ) ) ;
128
+ // The value of the DataSnapshot is an object with the SHA as a key. Only return the
129
+ // value of the object because the SHA is not necessary.
130
+ return snapshot . val ( ) [ Object . keys ( snapshot . val ( ) ) [ 0 ] ] ;
58
131
}
0 commit comments