Skip to content

Commit 54f4954

Browse files
committed
Add google cloud storage
1 parent 592f33f commit 54f4954

File tree

4 files changed

+173
-0
lines changed

4 files changed

+173
-0
lines changed

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@
3131
"@angular/forms": "^2.2.0",
3232
"@angular/http": "^2.2.0",
3333
"@angular/platform-browser": "^2.2.0",
34+
"@types/es6-promise": "0.0.32",
3435
"core-js": "^2.4.1",
36+
"google-cloud": "^0.45.1",
37+
"image-diff": "^1.6.3",
3538
"rxjs": "5.0.0-beta.12",
3639
"systemjs": "0.19.38",
3740
"zone.js": "^0.6.23"

tools/gulp/gulpfile.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ import './tasks/unit-test';
1212
import './tasks/docs';
1313
import './tasks/aot';
1414
import './tasks/payload';
15+
import './tasks/screenshots';

tools/gulp/task_helpers.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const gulpAutoprefixer = require('gulp-autoprefixer');
1717
const gulpConnect = require('gulp-connect');
1818
const resolveBin = require('resolve-bin');
1919
const firebaseAdmin = require('firebase-admin');
20+
const gcloud = require('google-cloud');
2021

2122

2223
/** If the string passed in is a glob, returns it, otherwise append '**\/*' to it. */
@@ -233,3 +234,36 @@ export function openFirebaseDatabase() {
233234
export function isTravisPushBuild() {
234235
return process.env['TRAVIS_PULL_REQUEST'] === 'false';
235236
}
237+
238+
/** Open Google Cloud Storage for screenshots */
239+
export function openScreenshotsCloudStorage() {
240+
// Enable Storage
241+
let gcs = gcloud.storage({
242+
projectId: 'material2-screenshots',
243+
credentials: {
244+
client_email: 'firebase-adminsdk-t4209@material2-screenshots.iam.gserviceaccount.com',
245+
private_key: (process.env['MATERIAL2_SCREENSHOT_FIREBASE_KEY'] || '').replace(/\\n/g, '\n')
246+
},
247+
});
248+
249+
// Reference an existing bucket.
250+
return gcs.bucket('material2-screenshots.appspot.com');
251+
}
252+
253+
/** Opens a connection to the firebase realtime database for screenshots. */
254+
export function openScreenshotsFirebaseDatabase() {
255+
// Initialize the Firebase application with admin credentials.
256+
// Credentials need to be for a Service Account, which can be created in the Firebase console.
257+
let screenshotApp = firebaseAdmin.initializeApp({
258+
credential: firebaseAdmin.credential.cert({
259+
project_id: 'material2-screenshots',
260+
client_email: 'firebase-adminsdk-t4209@material2-screenshots.iam.gserviceaccount.com',
261+
// In Travis CI the private key will be incorrect because the line-breaks are escaped.
262+
// The line-breaks need to persist in the service account private key.
263+
private_key: (process.env['MATERIAL2_SCREENSHOT_FIREBASE_KEY'] || '').replace(/\\n/g, '\n')
264+
}),
265+
databaseURL: 'https://material2-screenshots.firebaseio.com'
266+
}, 'material2-screenshots');
267+
268+
return screenshotApp.database();
269+
}

tools/gulp/tasks/screenshots.ts

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import {task} from 'gulp';
2+
import {readdirSync, statSync, existsSync, mkdirSync} from 'fs';
3+
import {openScreenshotsCloudStorage, openScreenshotsFirebaseDatabase} from '../task_helpers';
4+
const imageDiff = require('image-diff');
5+
6+
const SCREENSHOT_DIR = './screenshots';
7+
const FIREBASE_FILELIST = 'screenshot/filenames';
8+
const FIREBASE_REPORT = 'screenshot/reports';
9+
10+
/** Task which upload screenshots generated from e2e test. */
11+
task('screenshots', () => {
12+
let prNumber = process.env['TRAVIS_PULL_REQUEST'];
13+
if (prNumber) {
14+
let database = openScreenshotsFirebaseDatabase();
15+
return getFilenameList(database)
16+
.then((filenames: string[]) => {
17+
return downloadReferenceScreenshots(filenames, database)
18+
.then((results: any) => {
19+
return compareScreenshots(filenames, database, prNumber);
20+
});
21+
})
22+
.then((results: boolean) => {
23+
return database.ref(FIREBASE_REPORT).child(`${prNumber}/result`).set(results);
24+
})
25+
.then(() => setFilenameList(database, prNumber))
26+
.then(() => uploadScreenshots(prNumber, 'diff'))
27+
.then(() => uploadScreenshots(prNumber, 'test'))
28+
.then(() => database.goOffline(), () => database.goOffline());
29+
}
30+
});
31+
32+
/** Get a list of filenames from firebase database. */
33+
function getFilenameList(database: any) : Promise<string[]> {
34+
return database.ref(FIREBASE_FILELIST).once('value').then(function(snapshots: any) {
35+
return snapshots.val();
36+
});
37+
}
38+
39+
/** Upload a list of filenames to firebase database as reference. */
40+
function setFilenameList(database: any,
41+
reportKey?: string): Promise<any> {
42+
let filenames: string[] = [];
43+
readdirSync(SCREENSHOT_DIR).map(function(file) {
44+
let fullName = SCREENSHOT_DIR + '/' + file;
45+
let key = file.replace('.screenshot.png', '');
46+
if (!statSync(fullName).isDirectory() && key) {
47+
filenames.push(file);
48+
}
49+
});
50+
let filelistDatabase = reportKey ?
51+
database.ref(FIREBASE_REPORT).child(reportKey).child('filenames') :
52+
database.ref(FIREBASE_FILELIST);
53+
return filelistDatabase.set(filenames);
54+
}
55+
56+
/** Upload screenshots to google cloud storage. */
57+
function uploadScreenshots(reportKey?: string, mode?: 'test' | 'diff') {
58+
let bucket = openScreenshotsCloudStorage();
59+
60+
let promises: Promise<any>[] = [];
61+
let localDir = mode == 'diff' ? `${SCREENSHOT_DIR}/diff` : SCREENSHOT_DIR;
62+
readdirSync(localDir).map(function(file) {
63+
let fileName = localDir + '/' + file;
64+
let key = file.replace('.screenshot.png', '');
65+
let destination = (mode == null || !reportKey) ?
66+
`references/${file}` : `screenshots/${reportKey}/${mode}/${file}`;
67+
68+
if (!statSync(fileName).isDirectory() && key) {
69+
promises.push(bucket.upload(fileName, { destination: destination }));
70+
}
71+
});
72+
return Promise.all(promises);
73+
}
74+
75+
/** Check whether the directory exists. If not then create one. */
76+
function _makeDir(dirName: string) {
77+
if (!existsSync(dirName)) {
78+
mkdirSync(dirName, '744');
79+
}
80+
}
81+
82+
/** Download references screenshots. */
83+
function downloadReferenceScreenshots(
84+
filenames: string[], database: any): Promise<any> {
85+
_makeDir(`${SCREENSHOT_DIR}/references`);
86+
87+
return Promise.all(filenames.map((filename: string) => {
88+
return _downloadReferenceScreenshot(filename);
89+
}));
90+
}
91+
92+
/** Download one reference screenshot */
93+
function _downloadReferenceScreenshot(filename: string): Promise<any> {
94+
let bucket = openScreenshotsCloudStorage();
95+
return bucket.file(`references/${filename}`).download({
96+
destination: `${SCREENSHOT_DIR}/references/${filename}`
97+
});
98+
}
99+
100+
/** Compare the test result and the reference. */
101+
function compareScreenshots(filenames: string[], database: any, reportKey: string): Promise<any> {
102+
return Promise.all(filenames.map((filename) =>
103+
_compareScreenshot(filename, database, reportKey)))
104+
.then((results: any) => results.every((value: boolean) => value == true));
105+
}
106+
107+
function _compareScreenshot(filename: string, database: any,
108+
reportKey: string): Promise<any> {
109+
let expectedUrl = `${SCREENSHOT_DIR}/references/${filename}`;
110+
let actualUrl = `${SCREENSHOT_DIR}/${filename}`;
111+
let diffUrl = `${SCREENSHOT_DIR}/diff/${filename}`;
112+
let filenameKey = filename.replace('.screenshot.png', '');
113+
114+
if (existsSync(expectedUrl) && existsSync(actualUrl)) {
115+
return new Promise(function(resolve, reject) {
116+
imageDiff({
117+
actualImage: actualUrl,
118+
expectedImage: expectedUrl,
119+
diffImage: diffUrl,
120+
}, function (err: any, imagesAreSame: boolean) {
121+
if (err) {
122+
console.log(err);
123+
imagesAreSame = false;
124+
reject(err);
125+
}
126+
resolve(imagesAreSame);
127+
return database.ref(FIREBASE_REPORT).child(`${reportKey}/results/${filenameKey}`)
128+
.set(imagesAreSame);
129+
});
130+
});
131+
} else {
132+
return database.ref(FIREBASE_REPORT).child(`${reportKey}/results/${filenameKey}`)
133+
.set(false).then(() => false);
134+
}
135+
}

0 commit comments

Comments
 (0)