From e2989b3b983cbf0738c92cff62b6aa612ad5e588 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Tue, 3 Jan 2017 22:31:49 +0100 Subject: [PATCH] chore: track library payload in database (#2463) Closes #111 --- .travis.yml | 1 + package.json | 2 ++ scripts/ci/build-and-test.sh | 2 ++ scripts/ci/sources/mode.sh | 4 +++ tools/gulp/gulpfile.ts | 1 + tools/gulp/task_helpers.ts | 22 ++++++++++++++ tools/gulp/tasks/ci.ts | 3 ++ tools/gulp/tasks/payload.ts | 56 ++++++++++++++++++++++++++++++++++++ 8 files changed, 91 insertions(+) create mode 100644 tools/gulp/tasks/payload.ts diff --git a/.travis.yml b/.travis.yml index f952f434584..586fc23aa63 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,6 +31,7 @@ env: # Order: a slower build first, so that we don't occupy an idle travis worker waiting for others to complete. - MODE=lint - MODE=aot + - MODE=payload - MODE=e2e - MODE=saucelabs_required - MODE=browserstack_required diff --git a/package.json b/package.json index ba06e6a1629..e873dc345a8 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "dgeni": "^0.4.2", "dgeni-packages": "^0.16.2", "express": "^4.14.0", + "firebase-admin": "^4.0.4", "firebase-tools": "^2.2.1", "fs-extra": "^0.26.5", "glob": "^6.0.4", @@ -103,6 +104,7 @@ "tslint": "^3.13.0", "typedoc": "^0.5.1", "typescript": "~2.0.10", + "uglify-js": "^2.7.5", "which": "^1.2.4" } } diff --git a/scripts/ci/build-and-test.sh b/scripts/ci/build-and-test.sh index 4d324b6ce3d..86f60c7d302 100755 --- a/scripts/ci/build-and-test.sh +++ b/scripts/ci/build-and-test.sh @@ -19,6 +19,8 @@ elif is_e2e; then $(npm bin)/gulp ci:e2e elif is_aot; then $(npm bin)/gulp ci:aot +elif is_payload; then + $(npm bin)/gulp ci:payload else $(npm bin)/gulp ci:test fi diff --git a/scripts/ci/sources/mode.sh b/scripts/ci/sources/mode.sh index 94205ff6163..ca22c8d90b0 100644 --- a/scripts/ci/sources/mode.sh +++ b/scripts/ci/sources/mode.sh @@ -11,4 +11,8 @@ is_lint() { is_aot() { [[ "$MODE" = aot ]] +} + +is_payload() { + [[ "$MODE" = payload ]] } \ No newline at end of file diff --git a/tools/gulp/gulpfile.ts b/tools/gulp/gulpfile.ts index ca13982aec5..02b2e1d0fbc 100644 --- a/tools/gulp/gulpfile.ts +++ b/tools/gulp/gulpfile.ts @@ -11,3 +11,4 @@ import './tasks/serve'; import './tasks/unit-test'; import './tasks/docs'; import './tasks/aot'; +import './tasks/payload'; diff --git a/tools/gulp/task_helpers.ts b/tools/gulp/task_helpers.ts index d460c850d75..ac158ceeeef 100644 --- a/tools/gulp/task_helpers.ts +++ b/tools/gulp/task_helpers.ts @@ -16,6 +16,7 @@ const gulpSourcemaps = require('gulp-sourcemaps'); const gulpAutoprefixer = require('gulp-autoprefixer'); const gulpConnect = require('gulp-connect'); const resolveBin = require('resolve-bin'); +const firebaseAdmin = require('firebase-admin'); /** If the string passed in is a glob, returns it, otherwise append '**\/*' to it. */ @@ -211,3 +212,24 @@ export function sequenceTask(...args: any[]) { ); }; } + +/** Opens a connection to the firebase realtime database. */ +export function openFirebaseDatabase() { + // Initialize the Firebase application with admin credentials. + // Credentials need to be for a Service Account, which can be created in the Firebase console. + firebaseAdmin.initializeApp({ + credential: firebaseAdmin.credential.cert({ + project_id: 'material2-dashboard', + client_email: 'firebase-adminsdk-ch1ob@material2-dashboard.iam.gserviceaccount.com', + private_key: process.env['MATERIAL2_FIREBASE_PRIVATE_KEY'] + }), + databaseURL: 'https://material2-dashboard.firebaseio.com' + }); + + return firebaseAdmin.database(); +} + +/** Whether gulp currently runs inside of Travis as a push. */ +export function isTravisPushBuild() { + return process.env['TRAVIS_PULL_REQUEST'] === 'false'; +} diff --git a/tools/gulp/tasks/ci.ts b/tools/gulp/tasks/ci.ts index 6af2b698f98..f1d3f5d26ee 100644 --- a/tools/gulp/tasks/ci.ts +++ b/tools/gulp/tasks/ci.ts @@ -14,3 +14,6 @@ task('ci:e2e', ['e2e']); /** Task to verify that all components work with AOT compilation. */ task('ci:aot', ['aot:build']); + +/** Task which reports the size of the library and stores it in a database. */ +task('ci:payload', ['payload']); diff --git a/tools/gulp/tasks/payload.ts b/tools/gulp/tasks/payload.ts new file mode 100644 index 00000000000..ec83a652f25 --- /dev/null +++ b/tools/gulp/tasks/payload.ts @@ -0,0 +1,56 @@ +import {task} from 'gulp'; +import {join} from 'path'; +import {statSync, readFileSync} from 'fs'; +import {DIST_COMPONENTS_ROOT} from '../constants'; +import {openFirebaseDatabase, isTravisPushBuild} from '../task_helpers'; +import {spawnSync} from 'child_process'; + +// Those imports lack types. +const uglifyJs = require('uglify-js'); + +const BUNDLE_PATH = join(DIST_COMPONENTS_ROOT, 'bundles', 'material.umd.js'); + +/** Task which runs test against the size of whole library. */ +task('payload', ['build:release'], () => { + + let results = { + umd_kb: getFilesize(BUNDLE_PATH), + umd_minified_uglify_kb: getUglifiedSize(BUNDLE_PATH), + timestamp: Date.now() + }; + + // Print the results to the console, so we can read it from the CI. + console.log('Payload Results:', JSON.stringify(results, null, 2)); + + // Publish the results to firebase when it runs on Travis and not as a PR. + if (isTravisPushBuild()) { + return publishResults(results); + } + +}); + +/** Returns the size of a file in kilobytes. */ +function getFilesize(filePath: string) { + return statSync(filePath).size / 1000; +} + +/** Returns the size of a uglify minified file in kilobytes */ +function getUglifiedSize(filePath: string) { + let fileContent = readFileSync(filePath, 'utf-8'); + + let compressedFile = uglifyJs.minify(fileContent, { + fromString: true + }); + + return Buffer.byteLength(compressedFile.code, 'utf8') / 1000; +} + +/** Publishes the given results to the firebase database. */ +function publishResults(results: any) { + let latestSha = spawnSync('git', ['rev-parse', 'HEAD']).stdout.toString().trim(); + let database = openFirebaseDatabase(); + + // Write the results to the payloads object with the latest Git SHA as key. + return database.ref('payloads').child(latestSha).set(results) + .then(() => database.goOffline(), () => database.goOffline()); +}