Skip to content

Commit 828a275

Browse files
authored
chore(*): deploy (docs|code) .angularjs.org to Firebase via Travis
- code.angularjs.org and docs.angularjs.org are two separate Firebase projects - both are automatically deployed via Travis config - Travis is split up into 2 build stages: first, all tests are run, and if they pass, the deploy stage runs a single job with both deployments (actual deployment depends on the state of the commit) - docs. is deployed directly to Firebase hosting - code. is uploaded to Firebase Google Cloud Storage and uses Firebase hosting rewrites to acces the files - jenkins builds still push the code builds to the code.angularjs.org Github repository Closes angular#9674 Closes angular#16093
1 parent 7e97db9 commit 828a275

19 files changed

+308
-65
lines changed

.firebaserc

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"projects": {
3+
"default": "docs-angularjs-org-9p2"
4+
}
5+
}

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ performance/temp*.html
99
*~
1010
*.swp
1111
angular.js.tmproj
12-
/node_modules/
12+
node_modules/
1313
bower_components/
1414
angular.xcodeproj
1515
.idea

.travis.yml

+54-12
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ cache:
1010

1111
branches:
1212
except:
13-
- /^g3_.*$/
13+
- "/^g3_.*$/"
1414

1515
env:
1616
matrix:
@@ -20,14 +20,15 @@ env:
2020
- JOB=e2e TEST_TARGET=jqlite BROWSER_PROVIDER=saucelabs
2121
- JOB=e2e TEST_TARGET=jquery BROWSER_PROVIDER=saucelabs
2222
global:
23-
- CXX=g++-4.8 # node 4 likes the G++ v4.8 compiler
23+
# node 4 likes the G++ v4.8 compiler
24+
# see https://docs.travis-ci.com/user/languages/javascript-with-nodejs#Node.js-v4-(or-io.js-v3)-compiler-requirements
25+
- CXX=g++-4.8
2426
- SAUCE_USERNAME=angular-ci
2527
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
2628
- LOGS_DIR=/tmp/angular-build/logs
2729
- BROWSER_PROVIDER_READY_FILE=/tmp/browsersprovider-tunnel-ready
30+
- secure: oTBjhnOKhs0qDSKTf7fE4f6DYiNDPycvB7qfSF5QRIbJK/LK/J4UtFwetXuXj79HhUZG9qnoT+5e7lPaiaMlpsIKn9ann7ffqFWN1E8TMtpJF+AGigx3djYElwfgf5nEnFUFhwjFzvbfpZNnxVGgX5YbIZpe/WUbHkP4ffU0Wks=
2831

29-
# node 4 likes the G++ v4.8 compiler
30-
# see https://docs.travis-ci.com/user/languages/javascript-with-nodejs#Node.js-v4-(or-io.js-v3)-compiler-requirements
3132
addons:
3233
apt:
3334
sources:
@@ -37,20 +38,61 @@ addons:
3738

3839
before_script:
3940
- du -sh ./node_modules ./bower_components/ || true
40-
- ./scripts/travis/before_build.sh
41-
41+
- "./scripts/travis/before_build.sh"
4242
script:
43-
- ./scripts/travis/build.sh
43+
- "./scripts/travis/build.sh"
4444

4545
after_script:
46-
- ./scripts/travis/tear_down_browser_provider.sh
47-
- ./scripts/travis/print_logs.sh
46+
- "./scripts/travis/tear_down_browser_provider.sh"
47+
- "./scripts/travis/print_logs.sh"
4848

4949
notifications:
5050
webhooks:
5151
urls:
5252
- https://webhooks.gitter.im/e/d2120f3f2bb39a4531b2
5353
- http://104.197.9.155:8484/hubot/travis/activity #hubot-server
54-
on_success: always # options: [always|never|change] default: always
55-
on_failure: always # options: [always|never|change] default: always
56-
on_start: always # default: false
54+
on_success: always # options: [always|never|change] default: always
55+
on_failure: always # options: [always|never|change] default: always
56+
on_start: always # default: false
57+
58+
jobs:
59+
include:
60+
- stage: deploy
61+
env:
62+
- JOB=deploy
63+
before_script: skip
64+
script:
65+
- "./scripts/travis/build.sh"
66+
# Work around the 10min Travis timeout so the code.angularjs firebase+gcs code deploy can complete
67+
before_deploy: |
68+
function keep_alive() {
69+
while true; do
70+
echo -en "\a"
71+
sleep 5
72+
done
73+
}
74+
keep_alive &
75+
deploy:
76+
- provider: firebase
77+
skip_cleanup: true
78+
token:
79+
secure: $FIREBASE_TOKEN
80+
on:
81+
repo: angular/angular.js
82+
all_branches: true
83+
# deploy a new docs version when the commit is tagged on the "latest" npm version
84+
condition: $TRAVIS_TAG != '' && $( jq ".distTag" "package.json" | tr -d "\"[:space:]" ) = latest
85+
- provider: gcs
86+
skip_cleanup: true
87+
access_key_id: GOOGLDB7W2J3LFHICF3R
88+
secret_access_key:
89+
secure: tHIFdSq55qkyZf9zT/3+VkhUrTvOTMuswxXU3KyWaBrSieZqG0UnUDyNm+n3lSfX95zEl/+rJAWbfvhVSxZi13ndOtvRF+MdI1cvow2JynP0aDSiPffEvVrZOmihD6mt2SlMfhskr5FTduQ69kZG6DfLcve1PPDaIwnbOv3phb8=
90+
bucket: code-angularjs-org-338b8.appspot.com
91+
local-dir: upload
92+
detect_encoding: true # detects gzip compression
93+
on:
94+
repo: angular/angular.js
95+
all_branches: true
96+
# upload the build when the commit is tagged or the branch is "master"
97+
condition: $TRAVIS_TAG != '' || ($TRAVIS_PULL_REQUEST = false && $TRAVIS_BRANCH = master)
98+

Gruntfile.js

+12-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ if (!process.env.TRAVIS && !process.env.JENKINS_HOME) {
4949
}
5050
}
5151

52-
5352
module.exports = function(grunt) {
5453

5554
// this loads all the node_modules that start with `grunt-` as plugins
@@ -64,6 +63,8 @@ module.exports = function(grunt) {
6463
NG_VERSION.cdn = versionInfo.cdnVersion;
6564
var dist = 'angular-' + NG_VERSION.full;
6665

66+
var deployVersion = NG_VERSION.isSnapshot ? 'snapshot' : NG_VERSION.full;
67+
6768
if (versionInfo.cdnVersion == null) {
6869
throw new Error('Unable to read CDN version, are you offline or has the CDN not been properly pushed?\n' +
6970
'Perhaps you want to set the NG1_BUILD_NO_REMOTE_VERSION_REQUESTS environment variable?');
@@ -324,6 +325,15 @@ module.exports = function(grunt) {
324325
expand: true,
325326
dot: true,
326327
dest: dist + '/'
328+
},
329+
firebaseCodeDeploy: {
330+
options: {
331+
mode: 'gzip'
332+
},
333+
src: ['**'],
334+
cwd: 'build',
335+
expand: true,
336+
dest: 'upload/' + deployVersion + '/'
327337
}
328338
},
329339

@@ -418,7 +428,7 @@ module.exports = function(grunt) {
418428
'write',
419429
'docs',
420430
'copy',
421-
'compress'
431+
'compress:build'
422432
]);
423433
grunt.registerTask('ci-checks', [
424434
'ddescribe-iit',

firebase.json

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"hosting": {
3+
"public": "build/docs",
4+
"ignore": [
5+
"/index.html",
6+
"/index-debug.html",
7+
"/index-jquery.html"
8+
],
9+
"rewrites": [
10+
{
11+
"source": "/",
12+
"destination": "/index-production.html"
13+
},
14+
{
15+
"source": "/index.html",
16+
"destination": "/index-production.html"
17+
},
18+
{
19+
"source": "**/*!(.jpg|.jpeg|.gif|.png|.html|.js|.json|.css|.svg|.ttf|.woff|.woff2|.eot)",
20+
"destination": "/index-production.html"
21+
}
22+
]
23+
}
24+
}

readme.firebase.docs.md

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Firebase for docs.angularjs.org
2+
===============================
3+
4+
The docs are deployed to Google Firebase hosting via Travis deployment config, which expects
5+
firebase.json and .firebaserc in the repository root.
6+
7+
See travis.yml for the complete deployment config.
8+
9+
See /scripts/code.angularjs.org-firebase/readme.firebase.code.md for the firebase deployment to
10+
code.angularjs.org
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"env": {
3+
"es6": true
4+
}
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"projects": {
3+
"default": "code-angularjs-org-338b8"
4+
}
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"hosting": {
3+
"public": "public",
4+
"redirects": [
5+
{
6+
"source": "/:version/docs",
7+
"destination": "/:version/docs/index.html",
8+
"type": 301
9+
}
10+
],
11+
"rewrites": [
12+
{
13+
"source": "/**",
14+
"function": "sendStoredFile"
15+
}
16+
]
17+
},
18+
"storage": {
19+
"rules": "storage.rules"
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
'use strict';
2+
3+
const functions = require('firebase-functions');
4+
const gcs = require('@google-cloud/storage')();
5+
const path = require('path');
6+
7+
const gcsBucketId = `${process.env.GCLOUD_PROJECT}.appspot.com`;
8+
const LOCAL_TMP_FOLDER = '/tmp/';
9+
10+
const BROWSER_CACHE_DURATION = 300;
11+
const CDN_CACHE_DURATION = 600;
12+
13+
function sendStoredFile(request, response) {
14+
let filePathSegments = request.path.split('/').filter((segment) => {
15+
// Remove empty leading or trailing path parts
16+
return segment !== '';
17+
});
18+
19+
const version = filePathSegments[0];
20+
const isDocsPath = filePathSegments[1] === 'docs';
21+
const lastSegment = filePathSegments[filePathSegments.length - 1];
22+
const bucket = gcs.bucket(gcsBucketId);
23+
24+
let downloadSource;
25+
let downloadDestination;
26+
let fileName;
27+
28+
if (isDocsPath && filePathSegments.length === 2) {
29+
fileName = 'index.html';
30+
filePathSegments = [version, 'docs', fileName];
31+
} else {
32+
fileName = lastSegment;
33+
}
34+
35+
downloadSource = path.join.apply(null, filePathSegments);
36+
downloadDestination = `${LOCAL_TMP_FOLDER}${fileName}`;
37+
38+
downloadAndSend(downloadSource, downloadDestination).catch(error => {
39+
if (isDocsPath && error.code === 404) {
40+
fileName = 'index.html';
41+
filePathSegments = [version, 'docs', fileName];
42+
downloadSource = path.join.apply(null, filePathSegments);
43+
downloadDestination = `${LOCAL_TMP_FOLDER}${fileName}`;
44+
45+
return downloadAndSend(downloadSource, downloadDestination);
46+
}
47+
48+
return Promise.reject(error);
49+
}).catch(error => {
50+
let message = 'General error';
51+
if (error.code === 404) {
52+
if (fileName.split('.').length === 1) {
53+
message = 'Directory listing is not supported';
54+
} else {
55+
message = 'File not found';
56+
}
57+
}
58+
59+
return response.status(error.code).send(message);
60+
});
61+
62+
function downloadAndSend(downloadSource, downloadDestination) {
63+
return bucket.file(downloadSource).download({
64+
destination: downloadDestination
65+
}).then(() => {
66+
return response.status(200)
67+
.set({
68+
'Cache-Control': `public, max-age=${BROWSER_CACHE_DURATION}, s-maxage=${CDN_CACHE_DURATION}`
69+
})
70+
.sendFile(downloadDestination);
71+
});
72+
}
73+
}
74+
75+
exports.sendStoredFile = functions.https.onRequest(sendStoredFile);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "functions-firebase-code.angularjs.org",
3+
"description": "Cloud Functions to serve files from gcs to code.angularjs.org",
4+
"dependencies": {
5+
"@google-cloud/storage": "^1.1.1",
6+
"firebase-admin": "^4.2.1",
7+
"firebase-functions": "^0.5.9"
8+
},
9+
"private": true
10+
}
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
google-site-verification: googleb96cceae5888d79f.html
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1">
6+
<title>AngularJS</title>
7+
</head>
8+
<body>
9+
</body>
10+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
User-agent: *
2+
3+
Disallow: /*docs/
4+
Disallow: /*i18n/
5+
Disallow: /*.zip$
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Firebase for code.angularjs.org
2+
===============================
3+
4+
This folder contains the Google Firebase scripts for the code.angularjs.org setup.
5+
6+
firebase.json contains the rewrite rules that route every subdirectory request to the cloud function
7+
in functions/index.js that serves the docs from the Firebase Google Cloud Storage bucket.
8+
9+
The deployment to the Google Cloud Storage bucket happens automatically via Travis. See the travis.yml
10+
file in the repository root.
11+
12+
See /readme.firebase.docs.md for the firebase deployment to docs.angularjs.org
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
service firebase.storage {
2+
match /b/{bucket}/o {
3+
match /{allPaths=**} {
4+
allow read, write: if request.auth!=null;
5+
}
6+
}
7+
}

scripts/code.angularjs.org/publish.sh

+3-14
Original file line numberDiff line numberDiff line change
@@ -59,23 +59,12 @@ function _update_code() {
5959

6060
echo "-- Pushing code.angularjs.org"
6161
git push origin master
62-
63-
for backend in "$@" ; do
64-
echo "-- Refreshing code.angularjs.org: backend=$backend"
65-
66-
# FIXME: We gave up publishing to code.angularjs.org because the GCE automatically removes firewall
67-
# rules that allow access to port 8003.
68-
69-
# curl http://$backend:8003/gitFetchSite.php
70-
done
7162
}
7263

7364
function publish {
74-
# The TXT record for backends.angularjs.org is a CSV of the IP addresses for
75-
# the currently serving Compute Engine backends.
76-
# code.angularjs.org is served out of port 8003 on these backends.
77-
backends=("$(dig backends.angularjs.org +short TXT | python -c 'print raw_input()[1:-1].replace(",", "\n")')")
78-
_update_code ${backends[@]}
65+
# publish updates the code.angularjs.org Github repository
66+
# the deployment to Firebase happens via Travis
67+
_update_code
7968
}
8069

8170
source $(dirname $0)/../utils.inc

0 commit comments

Comments
 (0)