1
1
import { task } from 'gulp' ;
2
2
import { join } from 'path' ;
3
3
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' ;
7
5
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' ) ;
8
10
9
11
/** Path to the directory where all bundles are living. */
10
12
const bundlesDir = join ( buildConfig . outputDir , 'bundles' ) ;
11
13
12
14
/** Task which runs test against the size of material. */
13
- task ( 'payload' , [ 'material:clean-build' ] , ( ) => {
15
+ task ( 'payload' , [ 'material:clean-build' ] , async ( ) => {
14
16
15
- let results = {
17
+ const results = {
16
18
timestamp : Date . now ( ) ,
17
19
// Material bundles
18
20
material_umd : getBundleSize ( 'material.umd.js' ) ,
@@ -29,9 +31,23 @@ task('payload', ['material:clean-build'], () => {
29
31
// Print the results to the console, so we can read it from the CI.
30
32
console . log ( 'Payload Results:' , JSON . stringify ( results , null , 2 ) ) ;
31
33
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 ( ) ;
35
51
}
36
52
37
53
} ) ;
@@ -46,14 +62,81 @@ function getFilesize(filePath: string) {
46
62
return statSync ( filePath ) . size / 1000 ;
47
63
}
48
64
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 ( ) ;
54
140
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 ;
59
142
}
0 commit comments