diff --git a/docs/process/release.md b/docs/process/release.md index bad0b94a4b..5405ad039f 100644 --- a/docs/process/release.md +++ b/docs/process/release.md @@ -101,7 +101,7 @@ merge commits into LTS branches must open a pull request against the specific ba In general, cherry picks for LTS should only be done if it meets one of the criteria below: 1. It addresses a critical security vulnerability. -2. It fixes a breaking change in the external environment. +2. It fixes a breaking change in the external environment. For example, this could happen if one of the dependencies is deleted from NPM. 3. It fixes a legitimate failure on CI for a particular LTS branch. @@ -122,9 +122,20 @@ As commits are cherry-picked when PRs are merged, creating the release should be ```bash git commit -a -m 'release: vXX' git tag 'vXX' +``` -# Make sure to run these commands together, as missing tags can cause CI -# failures. +The package versions we are about to publish are derived from the git tag that +we just created. Double check that the versions are correct by running the +following command. + +```bash +yarn admin packages --version +``` + +Now push the commit and the tag to the upstream repository. +**Make sure to run these commands together, as missing tags can cause CI failures.** + +```bash git push upstream && git push upstream --tags ``` @@ -151,7 +162,10 @@ After closing the tab, you have successfully logged in, it is time to publish. **It is a good idea to wait for CI to be green on the patch branch and tag before doing the release.** -Check out the patch branch (e.g. `9.1.x`), then run: +For the first release of a major version, follow the instructions in +[Publishing a Major Version](#publishing-a-major-version) section. + +For non-major release, check out the patch branch (e.g. `9.1.x`), then run: ```bash yarn # Reload dependencies yarn admin publish @@ -208,3 +222,23 @@ If you don't have the firebase CLI installed, you can install it using `npm install --global firebase-tools` (or use your package manager of choice). This is detailed in [`etc/cli.angular.io/README.md`](https://github.com/angular/angular-cli/blob/master/etc/cli.angular.io/README.md). + +## Publishing a Major Version + +For the first release of a major version, say `v10.0.0`, checkout the major branch +(i.e. `10.0.x`), then run: + +```bash +yarn # Reload dependencies +yarn admin publish --tag next # a major release is always tagged as next initially +``` + +Confirm with downstream repositories (Components, etc) that everything is ok. +Once the release is stable, wait for Framework to retag their packages, then +retag the CLI packages as `latest`. +The command below will automatically retag stable packages as well as experimental +packages. + +```bash +yarn admin dist-tag --version 10.0.0 --tag latest +``` diff --git a/lib/packages.ts b/lib/packages.ts index 09ab1e719d..c664dec76b 100644 --- a/lib/packages.ts +++ b/lib/packages.ts @@ -171,13 +171,21 @@ function _getVersionFromGit(experimental: boolean): string { stableVersion += stableVersion.includes('+') ? '.with-local-changes' : '+with-local-changes'; } - experimentalVersion = `0.${stableVersion.replace(/^(\d+)\.(\d+)/, (_, major, minor) => { - return '' + (parseInt(major, 10) * 100 + parseInt(minor, 10)); - })}`; + experimentalVersion = stableToExperimentalVersion(stableVersion); return experimental ? experimentalVersion : stableVersion; } +/** + * Convert a stable version to its experimental equivalent. For example, + * stable = 10.2.3, experimental = 0.1002.3 + * @param stable Must begin with d+.d+ where d is a 0-9 digit. + */ +export function stableToExperimentalVersion(stable: string): string { + return `0.${stable.replace(/^(\d+)\.(\d+)/, (_, major, minor) => { + return '' + (parseInt(major, 10) * 100 + parseInt(minor, 10)); + })}`; +} // All the supported packages. Go through the packages directory and create a map of // name => PackageInfo. This map is partial as it lacks some information that requires the diff --git a/scripts/dist-tag.ts b/scripts/dist-tag.ts index 4b2a7c617f..667c265ac3 100644 --- a/scripts/dist-tag.ts +++ b/scripts/dist-tag.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -// tslint:disable: no-implicit-dependencies +// tslint:disable: no-implicit-dependencies we import @angular-devkit/core but +// it is not in package.json, which is fine, this is just a script. import { logging } from '@angular-devkit/core'; import { execSync } from 'child_process'; @@ -14,27 +15,47 @@ import { packages, stableToExperimentalVersion } from '../lib/packages'; interface DistTagOptions { /** - * Version must be specified in format d+.d+.d+ where d is a 0-9 digit. - * This must be a stable version with major version > 0. - * The script will automatically convert stable version to experimental. + * The version of CLI packages published to NPM. + * Version must begin with d+.d+.d+ where d is a 0-9 digit. + * For example, `1.2.3`, `10.0.0-next.0`, or `10.0.0-rc.0`. + * Since we publish both stable and experimental packages to NPM, the version + * provided here must be a stable version with major version > 0. + * The script will automatically convert stable version to experimental for + * experimental packages. */ version: string; /** * Tag is usually "latest" or "next", but could also be "v10-lts" for example. */ tag: string; + /** + * If true, prints the help message. + */ + help: boolean; } /** * This function adds a tag to all public packages in the CLI repo. */ export default function(args: DistTagOptions, logger: logging.Logger) { + if (args.help) { + logger.info(`dist-tag adds a tag to all public packages in the CLI repo. + +If the packages already have a tag associated with them, then dist-tag will +retag the packages. + +Usage: + --version the version of CLI packages published to NPM. + --tag the tag to add to CLI packages`); + + return; + } const {version, tag} = args; if (!version || version.startsWith('v')) { throw new Error('Version must be specified in format d+.d+.d+'); } if (version.startsWith('0')) { - throw new Error('Version must be "stable", with major version > 0'); + throw new Error(`Major version must be > 0, did you mean ${stableToExperimentalVersion(version)}?`); } if (!tag) { throw new Error('Tag must be non-empty, for example: latest, next, v10-lts, etc'); @@ -43,7 +64,7 @@ export default function(args: DistTagOptions, logger: logging.Logger) { for (const {name, experimental} of publicPackages) { const actualVersion = experimental ? stableToExperimentalVersion(version) : version; // See https://docs.npmjs.com/cli/dist-tag for documentation - const cmd = `npm dist-tag add ${name}@${actualVersion} ${tag}`; + const cmd = `npm dist-tag add '${name}@${actualVersion}' '${tag}'`; logger.debug(cmd); // print debug output by specifying --verbose const output = execSync(cmd, { encoding: 'utf8' }); logger.info(output.trim());