mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
build: add dashboard firebase functions (#4806)
* build: add dashboard firebase functions * Adds a new folder for the dashboard project that for now only contains firebase functions. * The firebase functions will be used to securely make API calls to the Github API (e.g payload status) * Functions will be automatically deployed as same as screenshot functions. * Address feedback
This commit is contained in:
committed by
mmalerba
parent
f169152638
commit
964033ce8d
@@ -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
|
||||
|
||||
Executable
+24
@@ -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
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"hosting": {
|
||||
"public": "dist",
|
||||
"rewrites": [
|
||||
{
|
||||
"source": "**",
|
||||
"destination": "/index.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export {payloadGithubStatus} from './payload-github-status';
|
||||
@@ -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));
|
||||
});
|
||||
}
|
||||
@@ -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'));
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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.'});
|
||||
});
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user