diff --git a/aio/scripts/deploy-to-firebase.js b/aio/scripts/deploy-to-firebase.js index b2975f9a33..f700b061d5 100644 --- a/aio/scripts/deploy-to-firebase.js +++ b/aio/scripts/deploy-to-firebase.js @@ -30,13 +30,15 @@ if (require.main === module) { console.log(deploymentInfo.reason); } else { console.log( - `Git branch : ${inputVars.currentBranch}\n` + - `Git commit : ${inputVars.currentCommit}\n` + - `Build/deploy mode : ${deploymentInfo.deployEnv}\n` + - `Firebase project : ${deploymentInfo.projectId}\n` + - `Firebase site : ${deploymentInfo.siteId}\n` + - `Deployment URLs : ${deploymentInfo.deployedUrl}\n` + - ` https://${deploymentInfo.siteId}.web.app/`); + `Git branch : ${inputVars.currentBranch}\n` + + `Git commit : ${inputVars.currentCommit}\n` + + `Build/deploy mode : ${deploymentInfo.deployEnv}\n` + + `Firebase project : ${deploymentInfo.projectId}\n` + + `Firebase site : ${deploymentInfo.siteId}\n` + + `Pre-deploy actions : ${serializeActions(deploymentInfo.preDeployActions)}\n` + + `Post-deploy actions : ${serializeActions(deploymentInfo.postDeployActions)}\n` + + `Deployment URLs : ${deploymentInfo.deployedUrl}\n` + + ` https://${deploymentInfo.siteId}.web.app/`); if (!isDryRun) { deploy({...inputVars, ...deploymentInfo}); @@ -45,6 +47,22 @@ if (require.main === module) { } // Helpers +function build({deployedUrl, deployEnv}) { + console.log('\n\n\n==== Build the AIO app. ====\n'); + yarn(`build --configuration=${deployEnv} --progress=false`); + + console.log('\n\n\n==== Add any mode-specific files into the AIO distribution. ====\n'); + cp('-rf', `src/extra-files/${deployEnv}/.`, 'dist/'); + + console.log('\n\n\n==== Update opensearch descriptor for AIO with `deployedUrl`. ====\n'); + yarn(`set-opensearch-url ${deployedUrl.replace(/[^/]$/, '$&/')}`); // The URL must end with `/`. +} + +function checkPayloadSize() { + console.log('\n\n\n==== Check payload size and upload the numbers to Firebase DB. ====\n'); + yarn('payload-size'); +} + function computeDeploymentInfo( {currentBranch, currentCommit, isPullRequest, repoName, repoOwner, stableBranch}) { // Do not deploy if we are running in a fork. @@ -72,24 +90,32 @@ function computeDeploymentInfo( projectId: 'angular-io', siteId: 'next-angular-io-site', deployedUrl: 'https://next.angular.io/', + preDeployActions: [build, checkPayloadSize], + postDeployActions: [testPwaScore], }, rc: { deployEnv: 'rc', projectId: 'angular-io', siteId: 'rc-angular-io-site', deployedUrl: 'https://rc.angular.io/', + preDeployActions: [build, checkPayloadSize], + postDeployActions: [testPwaScore], }, stable: { deployEnv: 'stable', projectId: 'angular-io', siteId: `v${currentBranchMajorVersion}-angular-io-site`, deployedUrl: 'https://angular.io/', + preDeployActions: [build, checkPayloadSize], + postDeployActions: [testPwaScore], }, archive: { deployEnv: 'archive', projectId: 'angular-io', siteId: `v${currentBranchMajorVersion}-angular-io-site`, deployedUrl: `https://v${currentBranchMajorVersion}.angular.io/`, + preDeployActions: [build, checkPayloadSize], + postDeployActions: [testPwaScore], }, }; @@ -160,21 +186,20 @@ function computeMajorVersion(branchName) { return +branchName.split('.', 1)[0]; } -function deploy( - {currentCommit, deployedUrl, deployEnv, firebaseToken, minPwaScore, projectId, siteId}) { +function deploy(data) { + const { + currentCommit, + firebaseToken, + postDeployActions, + preDeployActions, + projectId, + siteId, + } = data; + cd(`${__dirname}/..`); - console.log('\n\n\n==== Build the AIO app. ====\n'); - yarn(`build --configuration=${deployEnv} --progress=false`); - - console.log('\n\n\n==== Add any mode-specific files into the AIO distribution. ====\n'); - cp('-rf', `src/extra-files/${deployEnv}/.`, 'dist/'); - - console.log('\n\n\n==== Update opensearch descriptor for AIO with `deployedUrl`. ====\n'); - yarn(`set-opensearch-url ${deployedUrl.replace(/[^/]$/, '$&/')}`); // The URL must end with `/`. - - console.log('\n\n\n==== Check payload size and upload the numbers to Firebase DB. ====\n'); - yarn('payload-size'); + console.log('\n\n\n==== Run pre-deploy actions. ====\n'); + preDeployActions.forEach(fn => fn(data)); console.log('\n\n\n==== Deploy AIO to Firebase hosting. ====\n'); yarn(`firebase use "${projectId}" --token "${firebaseToken}"`); @@ -183,8 +208,8 @@ function deploy( `firebase deploy --only hosting:aio --message "Commit: ${currentCommit}" --non-interactive ` + `--token "${firebaseToken}"`); - console.log('\n\n\n==== Run PWA-score tests. ====\n'); - yarn(`test-pwa-score "${deployedUrl}" "${minPwaScore}"`); + console.log('\n\n\n==== Run post-deploy actions. ====\n'); + postDeployActions.forEach(fn => fn(data)); } function getRemoteRefs(refOrPattern, remote = NG_REMOTE_URL) { @@ -195,10 +220,19 @@ function getLatestCommit(branchName, remote = undefined) { return getRemoteRefs(branchName, remote)[0].slice(0, 40); } +function serializeActions(actions) { + return actions.map(fn => fn.name).join(', '); +} + function skipDeployment(reason) { return {reason, skipped: true}; } +function testPwaScore({deployedUrl, minPwaScore}) { + console.log('\n\n\n==== Run PWA-score tests. ====\n'); + yarn(`test-pwa-score "${deployedUrl}" "${minPwaScore}"`); +} + function yarn(cmd) { // Using `--silent` to ensure no secret env variables are printed. // diff --git a/aio/scripts/deploy-to-firebase.spec.js b/aio/scripts/deploy-to-firebase.spec.js index 696e7c6652..b7523fcc68 100644 --- a/aio/scripts/deploy-to-firebase.spec.js +++ b/aio/scripts/deploy-to-firebase.spec.js @@ -6,60 +6,70 @@ const {computeDeploymentInfo, computeInputVars, getLatestCommit} = require('./de describe('deploy-to-firebase:', () => { + // Helpers + const jsonFunctionReplacer = (_key, val) => + (typeof val === 'function') ? `function:${val.name}` : val; + const getDeploymentInfoFor = env => { + const deploymentInfo = computeDeploymentInfo(computeInputVars(env)); + return JSON.parse(JSON.stringify(deploymentInfo, jsonFunctionReplacer)); + }; + it('master - skip deploy - not angular', () => { - expect(computeDeploymentInfo(computeInputVars({ + expect(getDeploymentInfoFor({ CI_REPO_OWNER: 'angular', CI_REPO_NAME: 'notangular', - }))).toEqual({ + })).toEqual({ skipped: true, reason: 'Skipping deploy because this is not angular/angular.', }); }); it('master - skip deploy - angular fork', () => { - expect(computeDeploymentInfo(computeInputVars({ + expect(getDeploymentInfoFor({ CI_REPO_OWNER: 'notangular', CI_REPO_NAME: 'angular', - }))).toEqual({ + })).toEqual({ skipped: true, reason: 'Skipping deploy because this is not angular/angular.', }); }); it('master - skip deploy - pull request', () => { - expect(computeDeploymentInfo(computeInputVars({ + expect(getDeploymentInfoFor({ CI_REPO_OWNER: 'angular', CI_REPO_NAME: 'angular', CI_PULL_REQUEST: 'true', - }))).toEqual({ + })).toEqual({ skipped: true, reason: 'Skipping deploy because this is a PR build.', }); }); it('master - deploy success', () => { - expect(computeDeploymentInfo(computeInputVars({ + expect(getDeploymentInfoFor({ CI_REPO_OWNER: 'angular', CI_REPO_NAME: 'angular', CI_PULL_REQUEST: 'false', CI_BRANCH: 'master', CI_COMMIT: getLatestCommit('master'), - }))).toEqual({ + })).toEqual({ deployEnv: 'next', projectId: 'angular-io', siteId: 'next-angular-io-site', deployedUrl: 'https://next.angular.io/', + preDeployActions: ['function:build', 'function:checkPayloadSize'], + postDeployActions: ['function:testPwaScore'], }); }); it('master - skip deploy - commit not HEAD', () => { - expect(computeDeploymentInfo(computeInputVars({ + expect(getDeploymentInfoFor({ CI_REPO_OWNER: 'angular', CI_REPO_NAME: 'angular', CI_PULL_REQUEST: 'false', CI_BRANCH: 'master', CI_COMMIT: 'DUMMY_TEST_COMMIT', - }))).toEqual({ + })).toEqual({ skipped: true, reason: 'Skipping deploy because DUMMY_TEST_COMMIT is not the latest commit ' + @@ -68,30 +78,32 @@ describe('deploy-to-firebase:', () => { }); it('stable - deploy success', () => { - expect(computeDeploymentInfo(computeInputVars({ + expect(getDeploymentInfoFor({ CI_REPO_OWNER: 'angular', CI_REPO_NAME: 'angular', CI_PULL_REQUEST: 'false', CI_BRANCH: '4.3.x', CI_STABLE_BRANCH: '4.3.x', CI_COMMIT: getLatestCommit('4.3.x'), - }))).toEqual({ + })).toEqual({ deployEnv: 'stable', projectId: 'angular-io', siteId: 'v4-angular-io-site', deployedUrl: 'https://angular.io/', + preDeployActions: ['function:build', 'function:checkPayloadSize'], + postDeployActions: ['function:testPwaScore'], }); }); it('stable - skip deploy - commit not HEAD', () => { - expect(computeDeploymentInfo(computeInputVars({ + expect(getDeploymentInfoFor({ CI_REPO_OWNER: 'angular', CI_REPO_NAME: 'angular', CI_PULL_REQUEST: 'false', CI_BRANCH: '4.3.x', CI_STABLE_BRANCH: '4.3.x', CI_COMMIT: 'DUMMY_TEST_COMMIT', - }))).toEqual({ + })).toEqual({ skipped: true, reason: 'Skipping deploy because DUMMY_TEST_COMMIT is not the latest commit ' + @@ -100,48 +112,52 @@ describe('deploy-to-firebase:', () => { }); it('archive - deploy success', () => { - expect(computeDeploymentInfo(computeInputVars({ + expect(getDeploymentInfoFor({ CI_REPO_OWNER: 'angular', CI_REPO_NAME: 'angular', CI_PULL_REQUEST: 'false', CI_BRANCH: '2.4.x', CI_STABLE_BRANCH: '4.3.x', CI_COMMIT: getLatestCommit('2.4.x'), - }))).toEqual({ + })).toEqual({ deployEnv: 'archive', projectId: 'angular-io', siteId: 'v2-angular-io-site', deployedUrl: 'https://v2.angular.io/', + preDeployActions: ['function:build', 'function:checkPayloadSize'], + postDeployActions: ['function:testPwaScore'], }); }); // v9 used to be special-cased, because it was piloting the Firebase hosting "multisites" setup. // See https://angular-team.atlassian.net/browse/DEV-125 for more info. it('archive - deploy success (no special case for v9)', () => { - expect(computeDeploymentInfo(computeInputVars({ + expect(getDeploymentInfoFor({ CI_REPO_OWNER: 'angular', CI_REPO_NAME: 'angular', CI_PULL_REQUEST: 'false', CI_BRANCH: '9.1.x', CI_STABLE_BRANCH: '10.0.x', CI_COMMIT: getLatestCommit('9.1.x'), - }))).toEqual({ + })).toEqual({ deployEnv: 'archive', projectId: 'angular-io', siteId: 'v9-angular-io-site', deployedUrl: 'https://v9.angular.io/', + preDeployActions: ['function:build', 'function:checkPayloadSize'], + postDeployActions: ['function:testPwaScore'], }); }); it('archive - skip deploy - commit not HEAD', () => { - expect(computeDeploymentInfo(computeInputVars({ + expect(getDeploymentInfoFor({ CI_REPO_OWNER: 'angular', CI_REPO_NAME: 'angular', CI_PULL_REQUEST: 'false', CI_BRANCH: '2.4.x', CI_STABLE_BRANCH: '4.3.x', CI_COMMIT: 'DUMMY_TEST_COMMIT', - }))).toEqual({ + })).toEqual({ skipped: true, reason: 'Skipping deploy because DUMMY_TEST_COMMIT is not the latest commit ' + @@ -150,14 +166,14 @@ describe('deploy-to-firebase:', () => { }); it('archive - skip deploy - major same as stable, minor less than stable', () => { - expect(computeDeploymentInfo(computeInputVars({ + expect(getDeploymentInfoFor({ CI_REPO_OWNER: 'angular', CI_REPO_NAME: 'angular', CI_PULL_REQUEST: 'false', CI_BRANCH: '2.1.x', CI_STABLE_BRANCH: '2.2.x', CI_COMMIT: getLatestCommit('2.1.x'), - }))).toEqual({ + })).toEqual({ skipped: true, reason: 'Skipping deploy of branch "2.1.x" to Firebase.\n' + @@ -166,14 +182,14 @@ describe('deploy-to-firebase:', () => { }); it('archive - skip deploy - major lower than stable, minor not latest', () => { - expect(computeDeploymentInfo(computeInputVars({ + expect(getDeploymentInfoFor({ CI_REPO_OWNER: 'angular', CI_REPO_NAME: 'angular', CI_PULL_REQUEST: 'false', CI_BRANCH: '2.1.x', CI_STABLE_BRANCH: '4.3.x', CI_COMMIT: getLatestCommit('2.1.x'), - }))).toEqual({ + })).toEqual({ skipped: true, reason: 'Skipping deploy of branch "2.1.x" to Firebase.\n' + @@ -182,46 +198,50 @@ describe('deploy-to-firebase:', () => { }); it('rc - deploy success - major higher than stable', () => { - expect(computeDeploymentInfo(computeInputVars({ + expect(getDeploymentInfoFor({ CI_REPO_OWNER: 'angular', CI_REPO_NAME: 'angular', CI_PULL_REQUEST: 'false', CI_BRANCH: '4.4.x', CI_STABLE_BRANCH: '2.2.x', CI_COMMIT: getLatestCommit('4.4.x'), - }))).toEqual({ + })).toEqual({ deployEnv: 'rc', projectId: 'angular-io', siteId: 'rc-angular-io-site', deployedUrl: 'https://rc.angular.io/', + preDeployActions: ['function:build', 'function:checkPayloadSize'], + postDeployActions: ['function:testPwaScore'], }); }); it('rc - deploy success - major same as stable, minor higher', () => { - expect(computeDeploymentInfo(computeInputVars({ + expect(getDeploymentInfoFor({ CI_REPO_OWNER: 'angular', CI_REPO_NAME: 'angular', CI_PULL_REQUEST: 'false', CI_BRANCH: '2.4.x', CI_STABLE_BRANCH: '2.2.x', CI_COMMIT: getLatestCommit('2.4.x'), - }))).toEqual({ + })).toEqual({ deployEnv: 'rc', projectId: 'angular-io', siteId: 'rc-angular-io-site', deployedUrl: 'https://rc.angular.io/', + preDeployActions: ['function:build', 'function:checkPayloadSize'], + postDeployActions: ['function:testPwaScore'], }); }); it('rc - skip deploy - commit not HEAD', () => { - expect(computeDeploymentInfo(computeInputVars({ + expect(getDeploymentInfoFor({ CI_REPO_OWNER: 'angular', CI_REPO_NAME: 'angular', CI_PULL_REQUEST: 'false', CI_BRANCH: '2.4.x', CI_STABLE_BRANCH: '2.2.x', CI_COMMIT: 'DUMMY_TEST_COMMIT', - }))).toEqual({ + })).toEqual({ skipped: true, reason: 'Skipping deploy because DUMMY_TEST_COMMIT is not the latest commit ' + @@ -230,14 +250,14 @@ describe('deploy-to-firebase:', () => { }); it('rc - skip deploy - major same as stable, minor not latest', () => { - expect(computeDeploymentInfo(computeInputVars({ + expect(getDeploymentInfoFor({ CI_REPO_OWNER: 'angular', CI_REPO_NAME: 'angular', CI_PULL_REQUEST: 'false', CI_BRANCH: '2.1.x', CI_STABLE_BRANCH: '2.0.x', CI_COMMIT: getLatestCommit('2.1.x'), - }))).toEqual({ + })).toEqual({ skipped: true, reason: 'Skipping deploy of branch "2.1.x" to Firebase.\n' + @@ -246,14 +266,14 @@ describe('deploy-to-firebase:', () => { }); it('rc - skip deploy - major higher than stable, minor not latest', () => { - expect(computeDeploymentInfo(computeInputVars({ + expect(getDeploymentInfoFor({ CI_REPO_OWNER: 'angular', CI_REPO_NAME: 'angular', CI_PULL_REQUEST: 'false', CI_BRANCH: '4.3.x', CI_STABLE_BRANCH: '2.4.x', CI_COMMIT: getLatestCommit('4.3.x'), - }))).toEqual({ + })).toEqual({ skipped: true, reason: 'Skipping deploy of branch "4.3.x" to Firebase.\n' + @@ -273,12 +293,14 @@ describe('deploy-to-firebase:', () => { }; const result = execSync(cmd, {encoding: 'utf8', env}).trim(); expect(result).toBe( - 'Git branch : master\n' + - `Git commit : ${commit}\n` + - 'Build/deploy mode : next\n' + - 'Firebase project : angular-io\n' + - 'Firebase site : next-angular-io-site\n' + - 'Deployment URLs : https://next.angular.io/\n' + - ' https://next-angular-io-site.web.app/'); + 'Git branch : master\n' + + `Git commit : ${commit}\n` + + 'Build/deploy mode : next\n' + + 'Firebase project : angular-io\n' + + 'Firebase site : next-angular-io-site\n' + + 'Pre-deploy actions : build, checkPayloadSize\n' + + 'Post-deploy actions : testPwaScore\n' + + 'Deployment URLs : https://next.angular.io/\n' + + ' https://next-angular-io-site.web.app/'); }); });