mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
ci: improve angular.io deployment process for the master branch (#43963)
Previously, the master branch was only deployed to the `next-angular-io-site` Firebase site, which is connected to the `next.angular.io` domain. However, if the master major version was higher than the stable major version (or the RC major version in case there was an active RC), we also had to manually configure (via the Firebase console and/or DNS records) the `v<X>.angular.io` domain to redirect to `next.angular.io`. Then, once `<X>` became the new stable or RC version, we had to manually remove the redirect (to let `v<X>.angular.io` be redirected to `angular.io` or `rc.angular.io`). This commit is part of a new process that reduces the manual steps as follows (the steps below only apply when the master major version is higher than the current stable and RC (if applicable)): - A `v<X>-angular-io-site` Firebase site will be created as soon as the version in the `master` branch's `package.json` is updated to a new major. - The `v<X>.angular.io` domain will be connected to that new Firebase site. - When deploying from the master branch, we will deploy to both `next-angular-io-site` and `v<X>-angular-io-site`. In addition, the deployment to `v<X>-angular-io-site` will update the Firebase config file to redirect to `next.angular.io`. - When the master version becomes the new stable/RC, we will start deploying to `v<X>-angular-io-site` from the stable/RC branch, which will update the Firebase config to stop redirecting to `next.angular.io` and redirect to `(rc.)angular.io` instead (without requiring changes in the Firebase console or DNS). PR Close #43963
This commit is contained in:
committed by
Alex Rickabaugh
parent
6662fcfa12
commit
3084df8b64
@@ -28,14 +28,16 @@
|
||||
* | from? | | | redirectVersionDomainToRc(*) |
|
||||
* | |--------|---------------------------------|---------------------------------|
|
||||
* | | MASTER | next | next |
|
||||
* | | | | |
|
||||
* | | | redirectVersionDomainToNext(**) | redirectVersionDomainToNext(**) |
|
||||
* |-----------|--------|---------------------------------|---------------------------------|
|
||||
*
|
||||
* (*): Only if `v<RC>` > `v<STABLE>`.
|
||||
* (**): Only if (no active RC and `v<NEXT>` > `v<STABLE>`) or (active RC and `v<NEXT>` > `v<RC>`).
|
||||
*
|
||||
* NOTES:
|
||||
* - The `v<X>-angular-io-site` Firebase site should be created (and connected to the
|
||||
* `v<X>.angular.io` subdomain) before a new RC branch is created.
|
||||
* `v<X>.angular.io` subdomain) before the version in the `master` branch's `package.json` is
|
||||
* updated to a new major.
|
||||
* - When a new major version is released, the deploy CI jobs for the new stable branch (prev. RC
|
||||
* or next) and the old stable branch must be run AFTER the new stable version has been
|
||||
* published to NPM, because the NPM info is used to determine what the stable version is.
|
||||
@@ -57,6 +59,7 @@ sh.set('-e');
|
||||
|
||||
// Constants
|
||||
const DIRNAME = u.getDirname(import.meta.url);
|
||||
const ROOT_PKG_PATH = `${DIRNAME}/../../../package.json`;
|
||||
|
||||
// Exports
|
||||
export {
|
||||
@@ -129,7 +132,10 @@ function computeDeploymentsInfo(
|
||||
}
|
||||
|
||||
// The deployment mode is computed based on the branch we are building.
|
||||
const currentBranchMajorVersion = u.computeMajorVersion(currentBranch);
|
||||
const currentVersionPattern = /^\d+\.\d+\.x$/.test(currentBranch) ?
|
||||
currentBranch : // The current branch name is a version pattern.
|
||||
u.loadJson(ROOT_PKG_PATH).version; // We need to retrieve the version from `package.json`.
|
||||
const currentBranchMajorVersion = u.computeMajorVersion(currentVersionPattern);
|
||||
const stableBranchMajorVersion = u.computeMajorVersion(stableBranch);
|
||||
const deploymentInfoPerTarget = {
|
||||
// PRIMARY DEPLOY TARGETS
|
||||
@@ -189,6 +195,16 @@ function computeDeploymentsInfo(
|
||||
// Since there can be multiple secondary deployments (each tweaking the primary one in different
|
||||
// ways), it is a good idea to ensure that any pre-deploy actions are undone in the post-deploy
|
||||
// phase.
|
||||
redirectVersionDomainToNext: {
|
||||
name: 'redirectVersionDomainToNext',
|
||||
type: 'secondary',
|
||||
deployEnv: 'next',
|
||||
projectId: 'angular-io',
|
||||
siteId: `v${currentBranchMajorVersion}-angular-io-site`,
|
||||
deployedUrl: `https://v${currentBranchMajorVersion}.angular.io/`,
|
||||
preDeployActions: [pre.redirectAllToNext],
|
||||
postDeployActions: [pre.undo.redirectAllToNext, post.testRedirectToNext],
|
||||
},
|
||||
redirectVersionDomainToRc: {
|
||||
name: 'redirectVersionDomainToRc',
|
||||
type: 'secondary',
|
||||
@@ -228,15 +244,33 @@ function computeDeploymentsInfo(
|
||||
},
|
||||
};
|
||||
|
||||
// If the current branch is `master`, deploy as `next`.
|
||||
if (currentBranch === 'master') {
|
||||
return [deploymentInfoPerTarget.next];
|
||||
}
|
||||
|
||||
// Determine if there is an active RC version by checking whether the most recent minor branch is
|
||||
// the stable branch or not.
|
||||
const mostRecentMinorBranch = u.getMostRecentMinorBranch();
|
||||
const rcBranch = (mostRecentMinorBranch !== stableBranch) ? mostRecentMinorBranch : null;
|
||||
const isRcActive = rcBranch !== null;
|
||||
|
||||
// If the current branch is `master`, deploy as `next`.
|
||||
if (currentBranch === 'master') {
|
||||
// In order to determine whether to also deploy to `v<NEXT>-angular-io-site` we need to compare
|
||||
// `v<NEXT>` with either `v<RC>` (if there is an active RC) or `v<STABLE>`.
|
||||
const otherVersion = isRcActive ? u.computeMajorVersion(rcBranch) : stableBranchMajorVersion;
|
||||
|
||||
return (currentBranchMajorVersion > otherVersion) ?
|
||||
// The next major version is greater than the RC or stable major version.
|
||||
// Deploy to both `next-angular-io-site` and `v<NEXT>-angular-io-site`.
|
||||
[
|
||||
deploymentInfoPerTarget.next,
|
||||
deploymentInfoPerTarget.redirectVersionDomainToNext,
|
||||
] :
|
||||
// The next major version is not greater than the RC or stable major version.
|
||||
// Only deploy to `next-angular-io-site` (since `v<NEXT>-angular-io-site` is probably
|
||||
// `v<RC>-angular-io-site` or `v<STABLE>-angular-io-site` and we don't want to overwrite the
|
||||
// RC or stable deployment).
|
||||
[
|
||||
deploymentInfoPerTarget.next,
|
||||
];
|
||||
}
|
||||
|
||||
// If the current branch is the RC branch, deploy as `rc`.
|
||||
if (currentBranch === rcBranch) {
|
||||
@@ -257,7 +291,7 @@ function computeDeploymentsInfo(
|
||||
|
||||
// If the current branch is the stable branch, deploy as `stable`.
|
||||
if (currentBranch === stableBranch) {
|
||||
return (rcBranch !== null) ?
|
||||
return isRcActive ?
|
||||
// There is an active RC version. Only deploy to the `stable` projects/sites.
|
||||
[
|
||||
deploymentInfoPerTarget.stable,
|
||||
|
||||
@@ -79,7 +79,13 @@ describe('deploy-to-firebase:', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('master - deploy success', () => {
|
||||
it('master - deploy success - no active RC, major higher than stable', () => {
|
||||
const mostRecentMajorVersion = u.computeMajorVersion(mostRecentMinorBranch);
|
||||
const fakeMasterMajorVersion = mostRecentMajorVersion + 1;
|
||||
|
||||
// Fake the `package.json` version.
|
||||
spyOn(u, 'loadJson').and.returnValue({version: `${fakeMasterMajorVersion}.0.0-next.42`});
|
||||
|
||||
expect(getDeploymentsInfoFor({
|
||||
CI_REPO_OWNER: 'angular',
|
||||
CI_REPO_NAME: 'angular',
|
||||
@@ -87,6 +93,108 @@ describe('deploy-to-firebase:', () => {
|
||||
CI_BRANCH: 'master',
|
||||
CI_STABLE_BRANCH: mostRecentMinorBranch,
|
||||
CI_COMMIT: latestCommits.master,
|
||||
})).toEqual([
|
||||
{
|
||||
name: 'next',
|
||||
type: 'primary',
|
||||
deployEnv: 'next',
|
||||
projectId: 'angular-io',
|
||||
siteId: 'next-angular-io-site',
|
||||
deployedUrl: 'https://next.angular.io/',
|
||||
preDeployActions: ['function:build', 'function:checkPayloadSize'],
|
||||
postDeployActions: ['function:testPwaScore'],
|
||||
},
|
||||
{
|
||||
name: 'redirectVersionDomainToNext',
|
||||
type: 'secondary',
|
||||
deployEnv: 'next',
|
||||
projectId: 'angular-io',
|
||||
siteId: `v${fakeMasterMajorVersion}-angular-io-site`,
|
||||
deployedUrl: `https://v${fakeMasterMajorVersion}.angular.io/`,
|
||||
preDeployActions: ['function:redirectAllToNext'],
|
||||
postDeployActions: ['function:undoRedirectAllToNext', 'function:testRedirectToNext'],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('master - deploy success - no active RC, major same as stable', () => {
|
||||
const mostRecentMajorVersion = u.computeMajorVersion(mostRecentMinorBranch);
|
||||
|
||||
// Fake the `package.json` version.
|
||||
spyOn(u, 'loadJson').and.returnValue({version: `${mostRecentMajorVersion}.42.0`});
|
||||
|
||||
expect(getDeploymentsInfoFor({
|
||||
CI_REPO_OWNER: 'angular',
|
||||
CI_REPO_NAME: 'angular',
|
||||
CI_PULL_REQUEST: 'false',
|
||||
CI_BRANCH: 'master',
|
||||
CI_STABLE_BRANCH: mostRecentMinorBranch,
|
||||
CI_COMMIT: latestCommits.master,
|
||||
})).toEqual([
|
||||
{
|
||||
name: 'next',
|
||||
type: 'primary',
|
||||
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 - deploy success - active RC, major higher than RC and stable', () => {
|
||||
const mostRecentMajorVersion = u.computeMajorVersion(mostRecentMinorBranch);
|
||||
const fakeMasterMajorVersion = mostRecentMajorVersion + 1;
|
||||
|
||||
// Fake the `package.json` version.
|
||||
spyOn(u, 'loadJson').and.returnValue({version: `${fakeMasterMajorVersion}.0.0-next.42`});
|
||||
|
||||
expect(getDeploymentsInfoFor({
|
||||
CI_REPO_OWNER: 'angular',
|
||||
CI_REPO_NAME: 'angular',
|
||||
CI_PULL_REQUEST: 'false',
|
||||
CI_BRANCH: 'master',
|
||||
CI_STABLE_BRANCH: '4.4.x',
|
||||
CI_COMMIT: latestCommits.master,
|
||||
})).toEqual([
|
||||
{
|
||||
name: 'next',
|
||||
type: 'primary',
|
||||
deployEnv: 'next',
|
||||
projectId: 'angular-io',
|
||||
siteId: 'next-angular-io-site',
|
||||
deployedUrl: 'https://next.angular.io/',
|
||||
preDeployActions: ['function:build', 'function:checkPayloadSize'],
|
||||
postDeployActions: ['function:testPwaScore'],
|
||||
},
|
||||
{
|
||||
name: 'redirectVersionDomainToNext',
|
||||
type: 'secondary',
|
||||
deployEnv: 'next',
|
||||
projectId: 'angular-io',
|
||||
siteId: `v${fakeMasterMajorVersion}-angular-io-site`,
|
||||
deployedUrl: `https://v${fakeMasterMajorVersion}.angular.io/`,
|
||||
preDeployActions: ['function:redirectAllToNext'],
|
||||
postDeployActions: ['function:undoRedirectAllToNext', 'function:testRedirectToNext'],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('master - deploy success - active RC, major same as RC and higher than stable', () => {
|
||||
const mostRecentMajorVersion = u.computeMajorVersion(mostRecentMinorBranch);
|
||||
|
||||
// Fake the `package.json` version.
|
||||
spyOn(u, 'loadJson').and.returnValue({version: `${mostRecentMajorVersion}.0.0-next.42`});
|
||||
|
||||
expect(getDeploymentsInfoFor({
|
||||
CI_REPO_OWNER: 'angular',
|
||||
CI_REPO_NAME: 'angular',
|
||||
CI_PULL_REQUEST: 'false',
|
||||
CI_BRANCH: 'master',
|
||||
CI_STABLE_BRANCH: '4.4.x',
|
||||
CI_COMMIT: latestCommits.master,
|
||||
})).toEqual([
|
||||
{
|
||||
name: 'next',
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import fs from 'fs';
|
||||
import {dirname} from 'path';
|
||||
import sh from 'shelljs';
|
||||
import {fileURLToPath} from 'url';
|
||||
@@ -25,6 +26,7 @@ const exp = {
|
||||
getLatestCommit,
|
||||
getMostRecentMinorBranch,
|
||||
getRemoteRefs,
|
||||
loadJson,
|
||||
logSectionHeader,
|
||||
nameFunction,
|
||||
yarn,
|
||||
@@ -32,8 +34,8 @@ const exp = {
|
||||
export default exp;
|
||||
|
||||
// Helpers
|
||||
function computeMajorVersion(branchName) {
|
||||
return +branchName.split('.', 1)[0];
|
||||
function computeMajorVersion(versionPattern) {
|
||||
return +versionPattern.split('.', 1)[0];
|
||||
}
|
||||
|
||||
function getDirname(fileUrl) {
|
||||
@@ -82,6 +84,10 @@ function getLatestCommit(branchName, options = undefined) {
|
||||
return exp.getRemoteRefs(branchName, options)[0].slice(0, 40);
|
||||
}
|
||||
|
||||
function loadJson(filePath) {
|
||||
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
||||
}
|
||||
|
||||
function logSectionHeader(message) {
|
||||
console.log(`\n\n\n==== ${message} ====\n`);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import fs from 'fs';
|
||||
import sh from 'shelljs';
|
||||
import u from './utils.mjs';
|
||||
|
||||
@@ -226,6 +227,17 @@ describe('deploy-to-firebase/utils:', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('loadJson()', () => {
|
||||
let readFileSyncSpy;
|
||||
|
||||
beforeEach(() => readFileSyncSpy = spyOn(fs, 'readFileSync'));
|
||||
|
||||
it('should load and parse a JSON file', () => {
|
||||
readFileSyncSpy.withArgs('/foo/bar.json', 'utf8').and.returnValue('{"foo": "bar"}');
|
||||
expect(u.loadJson('/foo/bar.json')).toEqual({foo: 'bar'});
|
||||
});
|
||||
});
|
||||
|
||||
describe('logSectionHeader()', () => {
|
||||
let logSpy;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user