Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
tinayuangao committed Jan 25, 2017
1 parent e8e84e8 commit 4b75f00
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 58 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
"@angular/forms": "^2.2.0",
"@angular/http": "^2.2.0",
"@angular/platform-browser": "^2.2.0",
"@types/es6-promise": "0.0.32",
"core-js": "^2.4.1",
"firebase": "^3.6.7",
"google-cloud": "^0.45.1",
"image-diff": "^1.6.3",
"rxjs": "5.0.0-beta.12",
Expand Down
5 changes: 2 additions & 3 deletions tools/gulp/task_helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import * as fs from 'fs';
import * as gulp from 'gulp';
import * as gulpTs from 'gulp-typescript';
import * as path from 'path';

import {NPM_VENDOR_FILES, PROJECT_ROOT, DIST_ROOT, SASS_AUTOPREFIXER_OPTIONS} from './constants';


Expand Down Expand Up @@ -213,7 +212,7 @@ export function sequenceTask(...args: any[]) {
}

/** Opens a connection to the firebase realtime database. */
export function openFirebaseDatabase() {
export function openFirebaseDashboardDatabase() {
// 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({
Expand Down Expand Up @@ -251,7 +250,7 @@ export function openScreenshotsCloudStorage() {
}

/** Opens a connection to the firebase realtime database for screenshots. */
export function openScreenshotsFirebaseDatabase() {
export function openFirebaseScreenshotsDatabase() {
// Initialize the Firebase application with admin credentials.
// Credentials need to be for a Service Account, which can be created in the Firebase console.
let screenshotApp = firebaseAdmin.initializeApp({
Expand Down
4 changes: 2 additions & 2 deletions tools/gulp/tasks/payload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ 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 {openFirebaseDashboardDatabase, isTravisPushBuild} from '../task_helpers';
import {spawnSync} from 'child_process';

// Those imports lack types.
Expand Down Expand Up @@ -48,7 +48,7 @@ function getUglifiedSize(filePath: string) {
/** 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();
let database = openFirebaseDashboardDatabase();

// Write the results to the payloads object with the latest Git SHA as key.
return database.ref('payloads').child(latestSha).set(results)
Expand Down
126 changes: 74 additions & 52 deletions tools/gulp/tasks/screenshots.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {task} from 'gulp';
import {readdirSync, statSync, existsSync, mkdirSync} from 'fs';
import {openScreenshotsCloudStorage, openScreenshotsFirebaseDatabase} from '../task_helpers';
import {openScreenshotsCloudStorage, openFirebaseScreenshotsDatabase} from '../task_helpers';
import * as path from 'path';
import * as firebase from 'firebase';
const imageDiff = require('image-diff');

const SCREENSHOT_DIR = './screenshots';
Expand All @@ -11,38 +13,50 @@ const FIREBASE_REPORT = 'screenshot/reports';
task('screenshots', () => {
let prNumber = process.env['TRAVIS_PULL_REQUEST'];
if (prNumber) {
let database = openScreenshotsFirebaseDatabase();
return getFilenameList(database)
let database = openFirebaseScreenshotsDatabase();
return getScreenFilenames(database)
.then((filenames: string[]) => {
return downloadReferenceScreenshots(filenames, database)
.then((results: any) => {
return compareScreenshots(filenames, database, prNumber);
return downloadAllGolds(filenames, database)
.then(() => {
return diffAllScreenshots(filenames, database, prNumber);
});
})
.then((results: boolean) => {
return database.ref(FIREBASE_REPORT).child(`${prNumber}/result`).set(results);
})
.then(() => database.ref(FIREBASE_REPORT).child(`${prNumber}/commit`).set(process.env['TRAVIS_COMMIT']))
.then(() => setFilenameList(database, prNumber))
.then((results: boolean) => updateResult(database, prNumber, results))
.then(() => setScreenFilenames(database, prNumber))
.then(() => uploadScreenshots(prNumber, 'diff'))
.then(() => uploadScreenshots(prNumber, 'test'))
.then(() => updateCommit(database, prNumber))
.then(() => database.goOffline(), () => database.goOffline());
}
});

function updateFileResult(database: firebase.database.Database, prNumber: string,
filenameKey: string, result: boolean) {
return database.ref(FIREBASE_REPORT).child(`${prNumber}/results/${filenameKey}`).set(result);
}

function updateResult(database: firebase.database.Database, prNumber: string, result: boolean) {
return database.ref(FIREBASE_REPORT).child(`${prNumber}/result`).set(result);
}

function updateCommit(database: firebase.database.Database, prNumber: string) {
return database.ref(FIREBASE_REPORT).child(`${prNumber}/commit`).set(process.env['TRAVIS_COMMIT']);
}

/** Get a list of filenames from firebase database. */
function getFilenameList(database: any) : Promise<string[]> {
return database.ref(FIREBASE_FILELIST).once('value').then(function(snapshots: any) {
function getScreenFilenames(database: any) : firebase.Promise<string[]> {
return database.ref(FIREBASE_FILELIST).once('value')
.then((snapshots: firebase.database.DataSnapshot) => {
return snapshots.val();
});
}

/** Upload a list of filenames to firebase database as reference. */
function setFilenameList(database: any,
reportKey?: string): Promise<any> {
/** Upload a list of filenames to firebase database as gold. */
function setScreenFilenames(database: firebase.database.Database,
reportKey?: string): firebase.Promise<any> {
let filenames: string[] = [];
readdirSync(SCREENSHOT_DIR).map(function(file) {
let fullName = SCREENSHOT_DIR + '/' + file;
readdirSync(SCREENSHOT_DIR).map((file: string) => {
let fullName = path.join(SCREENSHOT_DIR, file);
let key = file.replace('.screenshot.png', '');
if (!statSync(fullName).isDirectory() && key) {
filenames.push(file);
Expand All @@ -54,23 +68,31 @@ function setFilenameList(database: any,
return filelistDatabase.set(filenames);
}

/** Upload screenshots to google cloud storage. */
/**
* Upload screenshots to google cloud storage.
* @param {string} reportKey - The key used in firebase. Here it is the PR number.
* If there's no reportKey, we will upload images to 'golds/' folder
* @param {string} mode - Can be 'test' or 'diff' or null.
* If the images are the test results, mode should be 'test'.
* If the images are the diff images generated, mode should be 'diff'.
* For golds mode should be null.
*/
function uploadScreenshots(reportKey?: string, mode?: 'test' | 'diff') {
let bucket = openScreenshotsCloudStorage();

let promises: Promise<any>[] = [];
let promises: firebase.Promise<any>[] = [];
let localDir = mode == 'diff' ? `${SCREENSHOT_DIR}/diff` : SCREENSHOT_DIR;
readdirSync(localDir).map(function(file) {
let fileName = localDir + '/' + file;
readdirSync(localDir).map((file: string) => {
let fileName = path.join(localDir, file);
let key = file.replace('.screenshot.png', '');
let destination = (mode == null || !reportKey) ?
`references/${file}` : `screenshots/${reportKey}/${mode}/${file}`;
`golds/${file}` : `screenshots/${reportKey}/${mode}/${file}`;

if (!statSync(fileName).isDirectory() && key) {
promises.push(bucket.upload(fileName, { destination: destination }));
}
});
return Promise.all(promises);
return firebase.Promise.all(promises);
}

/** Check whether the directory exists. If not then create one. */
Expand All @@ -80,57 +102,57 @@ function _makeDir(dirName: string) {
}
}

/** Download references screenshots. */
function downloadReferenceScreenshots(
filenames: string[], database: any): Promise<any> {
_makeDir(`${SCREENSHOT_DIR}/references`);
/** Download golds screenshots. */
function downloadAllGolds(
filenames: string[], database: firebase.database.Database): firebase.Promise<void[]> {
_makeDir(`${SCREENSHOT_DIR}/golds`);

return Promise.all(filenames.map((filename: string) => {
return _downloadReferenceScreenshot(filename);
return firebase.Promise.all(filenames.map((filename: string) => {
return downloadGold(filename);
}));
}

/** Download one reference screenshot */
function _downloadReferenceScreenshot(filename: string): Promise<any> {
/** Download one gold screenshot */
function downloadGold(filename: string): Promise<void> {
let bucket = openScreenshotsCloudStorage();
return bucket.file(`references/${filename}`).download({
destination: `${SCREENSHOT_DIR}/references/${filename}`
return bucket.file(`golds/${filename}`).download({
destination: `${SCREENSHOT_DIR}/golds/${filename}`
});
}

/** Compare the test result and the reference. */
function compareScreenshots(filenames: string[], database: any, reportKey: string): Promise<any> {
return Promise.all(filenames.map((filename) =>
_compareScreenshot(filename, database, reportKey)))
.then((results: any) => results.every((value: boolean) => value == true));
/** Compare the test result and the gold. */
function diffAllScreenshots(filenames: string[], database: firebase.database.Database,
reportKey: string): firebase.Promise<boolean> {
return firebase.Promise.all(filenames.map((filename) =>
diffScreenshot(filename, database, reportKey)))
.then((results: boolean[]) => results.every((value: boolean) => value == true));
}

function _compareScreenshot(filename: string, database: any,
reportKey: string): Promise<any> {
let expectedUrl = `${SCREENSHOT_DIR}/references/${filename}`;
let actualUrl = `${SCREENSHOT_DIR}/${filename}`;
function diffScreenshot(filename: string, database: firebase.database.Database,
reportKey: string): firebase.Promise<boolean> {
// TODO(tinayuangao): Run the downloads and diffs in parallel.
let goldUrl = `${SCREENSHOT_DIR}/golds/${filename}`;
let pullRequestUrl = `${SCREENSHOT_DIR}/${filename}`;
let diffUrl = `${SCREENSHOT_DIR}/diff/${filename}`;
let filenameKey = filename.replace('.screenshot.png', '');

if (existsSync(expectedUrl) && existsSync(actualUrl)) {
return new Promise(function(resolve, reject) {
if (existsSync(goldUrl) && existsSync(pullRequestUrl)) {
return new firebase.Promise((resolve: any, reject: any) => {
imageDiff({
actualImage: actualUrl,
expectedImage: expectedUrl,
actualImage: pullRequestUrl,
expectedImage: goldUrl,
diffImage: diffUrl,
}, function (err: any, imagesAreSame: boolean) {
}, (err: any, imagesAreSame: boolean) => {
if (err) {
console.log(err);
imagesAreSame = false;
reject(err);
}
resolve(imagesAreSame);
return database.ref(FIREBASE_REPORT).child(`${reportKey}/results/${filenameKey}`)
.set(imagesAreSame);
return updateFileResult(database, reportKey, filenameKey, imagesAreSame);
});
});
} else {
return database.ref(FIREBASE_REPORT).child(`${reportKey}/results/${filenameKey}`)
.set(false).then(() => false);
return updateFileResult(database, reportKey, filenameKey, false).then(() => false);
}
}

0 comments on commit 4b75f00

Please sign in to comment.