Skip to content

build: add dashboard firebase functions #4806

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 31, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions scripts/ci/publish-artifacts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ $(npm bin)/gulp docs

# Run publishing of artifacts in parallel.
# This is possible because the output has been built before.
./scripts/release/publish-build-artifacts.sh --no-build &
./scripts/release/publish-docs-content.sh --no-build &
./scripts/deploy/publish-build-artifacts.sh --no-build &
./scripts/deploy/publish-docs-content.sh --no-build &

# Deploy the screenshot functions for each push build.
./scripts/release/deploy-screenshot-functions.sh &
# Deploy the screenshot and dashboard functions for each push build.
./scripts/deploy/deploy-screenshot-functions.sh &
./scripts/deploy/deploy-dashboard-functions.sh &

wait
24 changes: 24 additions & 0 deletions scripts/deploy/deploy-dashboard-functions.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/bash

# Go to the project root directory
cd $(dirname ${0})/../..

# Paths to the dashboard and functions directories.
dashboardFolder=tools/dashboard

# Go to the dashboard folder because otherwise the Firebase CLI tries to deploy the wrong project.
cd ${dashboardFolder}

# Install node modules for dashboard functions. Firebase CLI needs to execute the functions
# before it can collect all functions and deploy them.
(cd functions; npm install)

if [ -z ${MATERIAL2_DASHBOARD_ACCESS_TOKEN} ]; then
echo "Error: No access token for firebase specified." \
"Please set the environment variable 'MATERIAL2_DASHBOARD_ACCESS_TOKEN'."
exit 1
fi

# Deploy the dashboard functions to Firebase. For now only the functions will be deployed.
$(npm bin)/firebase deploy \
--only functions --token ${MATERIAL2_DASHBOARD_ACCESS_TOKEN} --project material2-dashboard
11 changes: 11 additions & 0 deletions tools/dashboard/firebase.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"hosting": {
"public": "dist",
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}
1 change: 1 addition & 0 deletions tools/dashboard/functions/functions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {payloadGithubStatus} from './payload-github-status';
43 changes: 43 additions & 0 deletions tools/dashboard/functions/github/github-status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {config} from 'firebase-functions';

const request = require('request');
const {version, name} = require('../package.json');

/** API token for the Github repository. Required to set the github status on commits and PRs. */
const repoToken = config().repoToken;

/** Data that must be specified to set a Github PR status. */
export type GithubStatusData = {
result: boolean;
name: string;
description: string;
url: string;
};

/** Function that sets a Github commit status */
export function setGithubStatus(commitSHA: string, data: GithubStatusData) {
const state = data.result ? 'success' : 'failure';

const requestData = JSON.stringify({
state: state,
target_url: data.url,
context: data.name,
description: data.description
});

const headers = {
'Authorization': `token ${repoToken}`,
'User-Agent': `${name}/${version}`,
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(requestData)
};

return new Promise((resolve) => {
request({
url: `https://api.github.com/repos/angular/material2/statuses/${commitSHA}`,
method: 'POST',
form: requestData,
headers: headers
}, (error: any, response: any) => resolve(response.statusCode));
});
}
16 changes: 16 additions & 0 deletions tools/dashboard/functions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Entry point for the Firebase functions of the dashboard app. Firebase functions only support
* JavaScript files and therefore the TypeScript files needs to be transpiled.
*/

'use strict';

const path = require('path');

// Enable TypeScript compilation at runtime using ts-node.
require('ts-node').register({
project: path.join(__dirname, 'tsconfig.json')
});

// Export all functions from the TypeScript source.
Object.assign(exports, require('./functions'));
22 changes: 22 additions & 0 deletions tools/dashboard/functions/jwt/verify-token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {verify} from 'jsonwebtoken';
import {config} from 'firebase-functions';

/** The JWT secret. This is used to validate JWT. */
const jwtSecret = config().jwtSecret;

/** The repo slug. This is used to validate the JWT is sent from correct repo. */
const repoSlug = config().repoSlug;

export function verifyToken(token: string): boolean {
try {
const tokenPayload = verify(token, jwtSecret, {issuer: 'Travis CI, GmbH'});

if (tokenPayload.slug !== repoSlug) {
console.log(`JWT slugs are not matching. Expected ${repoSlug}`);
}

return true;
} catch (e) {
return false;
}
}
14 changes: 14 additions & 0 deletions tools/dashboard/functions/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "material2-dashboard-functions",
"version": "0.0.1",
"main": "index.js",
"dependencies": {
"@types/jsonwebtoken": "^7.2.0",
"firebase-admin": "~4.2.1",
"firebase-functions": "^0.5.7",
"jsonwebtoken": "^7.4.1",
"request": "^2.81.0",
"ts-node": "^3.0.4",
"typescript": "^2.3.3"
}
}
30 changes: 30 additions & 0 deletions tools/dashboard/functions/payload-github-status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {https} from 'firebase-functions';
import {verifyToken} from './jwt/verify-token';
import {setGithubStatus} from './github/github-status';

export const payloadGithubStatus = https.onRequest(async (request, response) => {
const authToken = request.header('auth-token');
const commitSha = request.header('commit-sha');
const payloadDiff = parseInt(request.header('commit-payload-diff'));

if (!verifyToken(authToken)) {
return response.status(403).json({message: 'Auth token is not valid'});
}

if (!commitSha) {
return response.status(404).json({message: 'No commit has been specified'});
}

if (!payloadDiff || isNaN(payloadDiff)) {
return response.status(400).json({message: 'No valid payload diff has been specified.'});
}

await setGithubStatus(commitSha, {
result: true,
name: 'Library Payload',
url: `https://travis-ci.org/angular/material2/jobs/${process.env['TRAVIS_JOB_ID']}`,
description: `${payloadDiff > 0 ? `+` : ''} ${payloadDiff.toFixed(2)}KB`
});

response.json({message: 'Payload Github status successfully set.'});
});
16 changes: 16 additions & 0 deletions tools/dashboard/functions/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"lib": ["es2015", "es2016", "dom"],
"module": "commonjs",
"moduleResolution": "node",
"noEmitOnError": true,
"noImplicitAny": true,
"sourceMap": true,
"target": "es5",
"baseUrl": "",
"outDir": "../../../dist/dashboard-functions/"
},
"files": [
"./functions.ts"
]
}