Skip to content

build: ensure angular version placeholder is up-to-date when staging release #17465

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 51 additions & 1 deletion tools/release/stage-release.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as OctokitApi from '@octokit/rest';
import chalk from 'chalk';
import {readFileSync, writeFileSync} from 'fs';
import {existsSync, readFileSync, writeFileSync} from 'fs';
import {join} from 'path';
import {BaseReleaseTask} from './base-release-task';
import {promptAndGenerateChangelog} from './changelog';
Expand All @@ -12,6 +12,9 @@ import {parseVersionName, Version} from './version-name/parse-version';
/** Default filename for the changelog. */
export const CHANGELOG_FILE_NAME = 'CHANGELOG.md';

/** Path to the Bazel file that configures the release output. */
const BAZEL_RELEASE_CONFIG_PATH = './packages.bzl';

/**
* Class that can be instantiated in order to stage a new release. The tasks requires user
* interaction/input through command line prompts.
Expand Down Expand Up @@ -89,6 +92,7 @@ class StageReleaseTask extends BaseReleaseTask {
const publishBranch = this.switchToPublishBranch(newVersion);

this.verifyLocalCommitsMatchUpstream(publishBranch);
this._verifyAngularPeerDependencyVersion(newVersion);
await this._verifyPassingGithubStatus(publishBranch);

if (!this.git.checkoutNewBranch(stagingBranch)) {
Expand Down Expand Up @@ -147,6 +151,52 @@ class StageReleaseTask extends BaseReleaseTask {
writeFileSync(this.packageJsonPath, JSON.stringify(newPackageJson, null, 2) + '\n');
}

/**
* Ensures that the Angular version placeholder has been correctly updated to support
* given Angular versions. The following rules apply:
* `N.x.x` requires Angular `^N.0.0 || (N+1).0.0-0`
* `N.0.0-x` requires Angular `^N.0.0-0 || (N+1).0.0-0`
*/
private _verifyAngularPeerDependencyVersion(newVersion: Version) {
const currentVersionRange = this._getAngularVersionPlaceholderOrExit();
const isMajorWithPrerelease = newVersion.minor === 0 && newVersion.patch === 0 &&
newVersion.prereleaseLabel !== null;
const requiredRange = isMajorWithPrerelease ?
`^${newVersion.major}.0.0-0 || ^${newVersion.major + 1}.0.0-0` :
`^${newVersion.major}.0.0 || ^${newVersion.major + 1}.0.0-0`;

if (requiredRange !== currentVersionRange) {
console.error(chalk.red(` ✘ Cannot stage release. The required Angular version range ` +
`is invalid. The version range should be: ${requiredRange}`));
console.error(chalk.red(` Please manually update the version range ` +
`in: ${BAZEL_RELEASE_CONFIG_PATH}`));
return process.exit(1);
}
}

/**
* Gets the Angular version placeholder from the bazel release config. If
* the placeholder could not be found, the process will be terminated.
*/
private _getAngularVersionPlaceholderOrExit(): string {
const bzlConfigPath = join(this.projectDir, BAZEL_RELEASE_CONFIG_PATH);
if (!existsSync(bzlConfigPath)) {
console.error(chalk.red(` ✘ Cannot stage release. Could not find the file which sets ` +
`the Angular peerDependency placeholder value. Looked for: ${bzlConfigPath}`));
return process.exit(1);
}

const configFileContent = readFileSync(bzlConfigPath, 'utf8');
const matches = configFileContent.match(/ANGULAR_PACKAGE_VERSION = ["']([^"']+)/);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not know of a better way to get the version placeholder from the Bazel .bzl file.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could make a nodejs_binary that takes in the version placeholder as an argument and writes it to stdout or a genrule that outputs the placeholder to a file.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's what we are doing for the rollup globals check (the genrule). Though it would complicate things if a file needs to be built by Bazel whenever the staging script runs. i.e. would we just spawn a process to build it?

The nodejs binary one is more interesting, but unfortunately it would complicate things too. If you remember, we used Bazel initially for the release scripts, but the scripts ran in the Bazel bin directory..

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the genrule, yeah, that's what I had in mind (spawn a child process).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that would work. I don't mind much either. Happy to do the genrule if you slightly prefer it more than the other options. I'm somehow preferring the current one since we basically just need static analysis and actually building seems unnecessary. It's a more robust idea though.

if (!matches || !matches[1]) {
console.error(chalk.red(` ✘ Cannot stage release. Could not find the ` +
`"ANGULAR_PACKAGE_VERSION" variable. Please ensure this variable exists. ` +
`Looked in: ${bzlConfigPath}`));
return process.exit(1);
}
return matches[1];
}

/** Verifies that the latest commit of the current branch is passing all Github statuses. */
private async _verifyPassingGithubStatus(expectedPublishBranch: string) {
const commitRef = this.git.getLocalCommitSha('HEAD');
Expand Down