angular/aio/scripts/deploy-to-firebase/utils.mjs
George Kalpakas ea676514e9 feat(docs-infra): add more granular support for configuring Firebase redirects at deployment (#43963)
Previously, there was a `deploy-to-firebase` pre-deploy action for
configuring Firebase to redirect non-file requests to `angular.io`. This
is used for ensuring that `rc.angular.io` is correctly redirected to
`angular.io`, even when people have previously visited (and have a
ServiceWorker activated on) `rc.angular.io`.

This commit adds pre-deploy actions for configuring Firebase to redirect
a deployment to any of `angular.io`, `rc.angular.io` or
`next.angular.io` and also configure whether all requests or only
non-file requests will be redirected.
In a future commit, this will allow managing redirects for the `stable`,
`rc` and `next` deployments via the Firebase config file (without
requiring changes in the Firebase console or DNS).

PR Close #43963
2021-10-29 15:05:03 -07:00

103 lines
3.3 KiB
JavaScript

import {dirname} from 'path';
import sh from 'shelljs';
import {fileURLToPath} from 'url';
// Constants
const REPO_SLUG = 'angular/angular';
const NG_REMOTE_URL = `https://github.com/${REPO_SLUG}.git`;
const ORIGINS = {
Next: 'https://next.angular.io',
Rc: 'https://rc.angular.io',
Stable: 'https://angular.io',
};
const _GIT_REMOTE_REFS_CACHE = new Map();
// Exports
const exp = {
_GIT_REMOTE_REFS_CACHE,
NG_REMOTE_URL,
ORIGINS,
REPO_SLUG,
computeMajorVersion,
getDirname,
getLatestCommit,
getMostRecentMinorBranch,
getRemoteRefs,
logSectionHeader,
nameFunction,
yarn,
};
export default exp;
// Helpers
function computeMajorVersion(branchName) {
return +branchName.split('.', 1)[0];
}
function getDirname(fileUrl) {
return dirname(fileURLToPath(fileUrl));
}
function getRemoteRefs(
refOrPattern, {remote = exp.NG_REMOTE_URL, retrieveFromCache = true} = {}) {
// If remote refs for the same `refOrPattern` and `remote` have been requested before, return the
// cached results. This improves the performance and ensures a more stable behavior.
//
// NOTE:
// This shouldn't make any difference during normal execution (since there are no duplicate
// requests atm), but makes the tests more stable (for example, avoiding errors caused by pushing
// a new commit on a branch while the tests execute, which would cause `getLatestCommit()` to
// return a different value).
const cmd = `git ls-remote ${remote} ${refOrPattern}`;
const result = (retrieveFromCache && exp._GIT_REMOTE_REFS_CACHE.has(cmd)) ?
exp._GIT_REMOTE_REFS_CACHE.get(cmd) :
sh.exec(cmd, {silent: true}).trim().split('\n');
// Cache the result for future use (regardless of the value of `retrieveFromCache`).
exp._GIT_REMOTE_REFS_CACHE.set(cmd, result);
return result;
}
function getMostRecentMinorBranch(major = '*', options = undefined) {
// List the branches that start with the given major version (or any major if none given).
return exp.getRemoteRefs(`refs/heads/${major}.*.x`, options)
// Extract the branch name.
.map(line => line.split('/')[2])
// Filter out branches that are not of the format `<number>.<number>.x`.
.filter(name => /^\d+\.\d+\.x$/.test(name))
// Sort by version.
.sort((a, b) => {
const [majorA, minorA] = a.split('.');
const [majorB, minorB] = b.split('.');
return (majorA - majorB) || (minorA - minorB);
})
// Get the branch corresponding to the highest version.
.pop();
}
function getLatestCommit(branchName, options = undefined) {
return exp.getRemoteRefs(branchName, options)[0].slice(0, 40);
}
function logSectionHeader(message) {
console.log(`\n\n\n==== ${message} ====\n`);
}
function nameFunction(name, fn) {
// Overwrite the function's `name` property to make debugging easier (and allow tests that relied
// on `Function#name` to continue to work for dynamically generated functions).
return Object.defineProperty(fn, 'name', {value: name});
}
function yarn(cmd) {
// Using `--silent` to ensure no secret env variables are printed.
//
// NOTE:
// This is not strictly necessary, since CircleCI will mask secret environment variables in the
// output (see https://circleci.com/docs/2.0/env-vars/#secrets-masking), but is an extra
// precaution.
return sh.exec(`yarn --silent ${cmd}`);
}