fix(docs-infra): fix redirecting `rc.angular.io` to `angular.io` when no active RC (#39853)
Currently there is an issue with redirecting `rc.angular.io` to `angular.io` when there is no active RC. If a user has visited `rc.angular.io` before and has a ServiceWorker registered for that subdomain, they will never "see" the redirect to `angular.io`. This commit fixes the problem by doing an additional deployment from the stable branch to the `rc-angular-io-site` Firebase site when there is no active RC. This additional deployment will ensure that: 1. Users will be temporarily redirected from `rc.angular.io` to `angular.io`. 2. Users with a registered ServiceWorker (who don't see the redirect) will have their ServiceWorker unregistered on the next visit. 3. The content on both sites is identical. See #39760 for more details on the problem and the solution. NOTE: As mentioned in #39760, for this fix to take affect, we need to remove the redirect from `rc.angular.io` to `angular.io` in the Firebase console for site `rc-angular-io-site`. Fixes #39760 PR Close #39853
This commit is contained in:
parent
1e39e493fb
commit
cf1f5a1e37
|
@ -4,7 +4,7 @@
|
|||
//
|
||||
'use strict';
|
||||
|
||||
const {cd, cp, exec, set} = require('shelljs');
|
||||
const {cd, cp, exec, mv, sed, set} = require('shelljs');
|
||||
|
||||
set('-e');
|
||||
|
||||
|
@ -17,6 +17,7 @@ const NG_REMOTE_URL = `https://github.com/${REPO_SLUG}.git`;
|
|||
module.exports = {
|
||||
computeDeploymentsInfo,
|
||||
computeInputVars,
|
||||
computeMajorVersion,
|
||||
getLatestCommit,
|
||||
getMostRecentMinorBranch,
|
||||
};
|
||||
|
@ -122,6 +123,17 @@ function computeDeploymentsInfo(
|
|||
preDeployActions: [build, checkPayloadSize],
|
||||
postDeployActions: [testPwaScore],
|
||||
},
|
||||
// Config for deploying the stable build to the RC Firebase site when there is no active RC.
|
||||
// See https://github.com/angular/angular/issues/39760 for more info on the purpose of this
|
||||
// special deployment.
|
||||
noActiveRc: {
|
||||
deployEnv: 'stable',
|
||||
projectId: 'angular-io',
|
||||
siteId: 'rc-angular-io-site',
|
||||
deployedUrl: 'https://rc.angular.io/',
|
||||
preDeployActions: [removeServiceWorker, redirectToAngularIo],
|
||||
postDeployActions: [testNoActiveRcDeployment],
|
||||
},
|
||||
archive: {
|
||||
deployEnv: 'archive',
|
||||
projectId: 'angular-io',
|
||||
|
@ -149,7 +161,17 @@ function computeDeploymentsInfo(
|
|||
|
||||
// If the current branch is the stable branch, deploy as `stable`.
|
||||
if (currentBranch === stableBranch) {
|
||||
return [deploymentInfoPerTarget.stable];
|
||||
return (rcBranch !== null) ?
|
||||
// There is an active RC version. Only deploy to the `stable` project/site.
|
||||
[deploymentInfoPerTarget.stable] :
|
||||
// There is no active RC version. In addition to deploying to the `stable` project/site,
|
||||
// deploy to `rc` to ensure it redirects to `stable`.
|
||||
// See https://github.com/angular/angular/issues/39760 for more info on the purpose of this
|
||||
// special deployment.
|
||||
[
|
||||
deploymentInfoPerTarget.stable,
|
||||
deploymentInfoPerTarget.noActiveRc,
|
||||
];
|
||||
}
|
||||
|
||||
// If we get here, it means that the current branch is neither `master`, nor the RC or stable
|
||||
|
@ -263,6 +285,21 @@ function getLatestCommit(branchName, remote = undefined) {
|
|||
return getRemoteRefs(branchName, remote)[0].slice(0, 40);
|
||||
}
|
||||
|
||||
function redirectToAngularIo() {
|
||||
// Update the Firebase hosting configuration redirect all non-file requests (i.e. requests that do
|
||||
// not contain a dot in their last path segment) to `angular.io`.
|
||||
// See https://firebase.google.com/docs/hosting/full-config#redirects.
|
||||
const redirectRule =
|
||||
'{"type": 302, "regex": "^(.*/[^./]*)$", "destination": "https://angular.io:1"}';
|
||||
sed('-i', /(\s*)"redirects": \[/, `$&\n$1 ${redirectRule},\n`, 'firebase.json');
|
||||
}
|
||||
|
||||
function removeServiceWorker() {
|
||||
// Rename the SW manifest (`ngsw.json`). This will cause the ServiceWorker to unregister itself.
|
||||
// See https://angular.io/guide/service-worker-devops#fail-safe.
|
||||
mv('dist/ngsw.json', 'dist/ngsw.json.bak');
|
||||
}
|
||||
|
||||
function serializeActions(actions) {
|
||||
return actions.map(fn => fn.name).join(', ');
|
||||
}
|
||||
|
@ -271,6 +308,41 @@ function skipDeployment(reason) {
|
|||
return {reason, skipped: true};
|
||||
}
|
||||
|
||||
function testNoActiveRcDeployment({deployedUrl}) {
|
||||
const deployedOrigin = deployedUrl.replace(/\/$/, '');
|
||||
|
||||
// Ensure a request for `ngsw.json` returns 404.
|
||||
const ngswJsonUrl = `${deployedOrigin}/ngsw.json`;
|
||||
const ngswJsonScript = `https.get('${ngswJsonUrl}', res => console.log(res.statusCode))`;
|
||||
const ngswJsonActualStatusCode = exec(`node --eval "${ngswJsonScript}"`, {silent: true}).trim();
|
||||
const ngswJsonExpectedStatusCode = '404';
|
||||
|
||||
if (ngswJsonActualStatusCode !== ngswJsonExpectedStatusCode) {
|
||||
throw new Error(
|
||||
`Expected '${ngswJsonUrl}' to return a status code of '${ngswJsonExpectedStatusCode}', ` +
|
||||
`but it returned '${ngswJsonActualStatusCode}'.`);
|
||||
}
|
||||
|
||||
// Ensure a request for `foo/bar` is redirected to `https://angular.io/foo/bar`.
|
||||
const fooBarUrl = `${deployedOrigin}/foo/bar?baz=qux`;
|
||||
const fooBarScript =
|
||||
`https.get('${fooBarUrl}', res => console.log(res.statusCode, res.headers.location))`;
|
||||
const [fooBarActualStatusCode, fooBarActualRedirectUrl] =
|
||||
exec(`node --eval "${fooBarScript}"`, {silent: true}).trim().split(' ');
|
||||
const fooBarExpectedStatusCode = '302';
|
||||
const fooBarExpectedRedirectUrl = 'https://angular.io/foo/bar?baz=qux';
|
||||
|
||||
if (fooBarActualStatusCode !== fooBarExpectedStatusCode) {
|
||||
throw new Error(
|
||||
`Expected '${fooBarUrl}' to return a status code of '${fooBarExpectedStatusCode}', but ` +
|
||||
`it returned '${fooBarActualStatusCode}'.`);
|
||||
} else if (fooBarActualRedirectUrl !== fooBarExpectedRedirectUrl) {
|
||||
throw new Error(
|
||||
`Expected '${fooBarUrl}' to be redirected to '${fooBarExpectedRedirectUrl}', but it was ` +
|
||||
`but it was redirected to '${fooBarActualRedirectUrl}'.`);
|
||||
}
|
||||
}
|
||||
|
||||
function testPwaScore({deployedUrl, minPwaScore}) {
|
||||
console.log('\n\n\n==== Run PWA-score tests. ====\n');
|
||||
yarn(`test-pwa-score "${deployedUrl}" "${minPwaScore}"`);
|
||||
|
|
|
@ -5,6 +5,7 @@ const {execSync} = require('child_process');
|
|||
const {
|
||||
computeDeploymentsInfo,
|
||||
computeInputVars,
|
||||
computeMajorVersion,
|
||||
getLatestCommit,
|
||||
getMostRecentMinorBranch,
|
||||
} = require('./deploy-to-firebase');
|
||||
|
@ -104,7 +105,7 @@ describe('deploy-to-firebase:', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
it('stable - deploy success', () => {
|
||||
it('stable - deploy success - active RC', () => {
|
||||
expect(getDeploymentsInfoFor({
|
||||
CI_REPO_OWNER: 'angular',
|
||||
CI_REPO_NAME: 'angular',
|
||||
|
@ -124,6 +125,34 @@ describe('deploy-to-firebase:', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
it('stable - deploy success - no active RC', () => {
|
||||
expect(getDeploymentsInfoFor({
|
||||
CI_REPO_OWNER: 'angular',
|
||||
CI_REPO_NAME: 'angular',
|
||||
CI_PULL_REQUEST: 'false',
|
||||
CI_BRANCH: mostRecentMinorBranch,
|
||||
CI_STABLE_BRANCH: mostRecentMinorBranch,
|
||||
CI_COMMIT: latestCommits[mostRecentMinorBranch],
|
||||
})).toEqual([
|
||||
{
|
||||
deployEnv: 'stable',
|
||||
projectId: 'angular-io',
|
||||
siteId: `v${computeMajorVersion(mostRecentMinorBranch)}-angular-io-site`,
|
||||
deployedUrl: 'https://angular.io/',
|
||||
preDeployActions: ['function:build', 'function:checkPayloadSize'],
|
||||
postDeployActions: ['function:testPwaScore'],
|
||||
},
|
||||
{
|
||||
deployEnv: 'stable',
|
||||
projectId: 'angular-io',
|
||||
siteId: 'rc-angular-io-site',
|
||||
deployedUrl: 'https://rc.angular.io/',
|
||||
preDeployActions: ['function:removeServiceWorker', 'function:redirectToAngularIo'],
|
||||
postDeployActions: ['function:testNoActiveRcDeployment'],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('stable - skip deploy - commit not HEAD', () => {
|
||||
expect(getDeploymentsInfoFor({
|
||||
CI_REPO_OWNER: 'angular',
|
||||
|
|
Loading…
Reference in New Issue