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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user