From ba72af9e88e9196ae33a1f8de2987da4cfdbc44a Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Thu, 19 Dec 2024 08:13:24 +0000 Subject: [PATCH 1/2] feat(ng-dev): support releasing when operating in a hybrid pnpm rules_js repo Updating the `package.json` for a release also requires updating some Aspect lock files that capture the hash of the `package.json` file. The release tool currently doesn't do this, and some tricky manual workaround steps are needed. This commit automatically runs the sync command. --- ng-dev/release/config/index.ts | 6 +++++ ng-dev/release/publish/BUILD.bazel | 1 + ng-dev/release/publish/actions.ts | 11 +++++++-- ng-dev/release/publish/external-commands.ts | 26 +++++++++++++++++++++ 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/ng-dev/release/config/index.ts b/ng-dev/release/config/index.ts index da99574c7..2ab80255b 100644 --- a/ng-dev/release/config/index.ts +++ b/ng-dev/release/config/index.ts @@ -61,6 +61,12 @@ export interface ReleaseConfig { newVersion: string, builtPackagesWithInfo: BuiltPackageWithInfo[], ) => Promise; + + /** + * Whether the repository is in rules_js interop mode, relying on + * integrity files to be automatically updated. + */ + rulesJsInteropMode?: boolean; } /** diff --git a/ng-dev/release/publish/BUILD.bazel b/ng-dev/release/publish/BUILD.bazel index 9a2117397..c177cfb17 100644 --- a/ng-dev/release/publish/BUILD.bazel +++ b/ng-dev/release/publish/BUILD.bazel @@ -23,6 +23,7 @@ ts_library( "@npm//@types/semver", "@npm//@types/yargs", "@npm//ejs", + "@npm//fast-glob", "@npm//folder-hash", "@npm//semver", "@npm//typed-graphqlify", diff --git a/ng-dev/release/publish/actions.ts b/ng-dev/release/publish/actions.ts index b88a7f622..7fec54a8e 100644 --- a/ng-dev/release/publish/actions.ts +++ b/ng-dev/release/publish/actions.ts @@ -6,8 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {promises as fs} from 'fs'; -import {join} from 'path'; +import {promises as fs, existsSync} from 'fs'; +import path, {join} from 'path'; import semver from 'semver'; import {workspaceRelativePackageJsonPath} from '../../utils/constants.js'; @@ -41,6 +41,7 @@ import {githubReleaseBodyLimit} from './constants.js'; import {ExternalCommands} from './external-commands.js'; import {promptToInitiatePullRequestMerge} from './prompt-merge.js'; import {Prompt} from '../../utils/prompt.js'; +import {glob} from 'fast-glob'; /** Interface describing a Github repository. */ export interface GithubRepo { @@ -129,6 +130,10 @@ export abstract class ReleaseAction { // to avoid unnecessary diff. IDEs usually add a trailing new line. await fs.writeFile(pkgJsonPath, `${JSON.stringify(pkgJson, null, 2)}\n`); Log.info(green(` ✓ Updated project version to ${pkgJson.version}`)); + + if (this.config.rulesJsInteropMode && existsSync(path.join(this.projectDir, '.aspect'))) { + await ExternalCommands.invokeBazelUpdateAspectLockFiles(this.projectDir); + } } /** Gets the most recent commit of a specified branch. */ @@ -221,6 +226,8 @@ export abstract class ReleaseAction { await this.createCommit(commitMessage, [ workspaceRelativePackageJsonPath, workspaceRelativeChangelogPath, + // Ensure modified Aspect lock files are included in the release commit. + ...(this.config.rulesJsInteropMode ? glob.sync('.aspect/**', {cwd: this.projectDir}) : []), ]); // The caretaker may have attempted to make additional changes. These changes would diff --git a/ng-dev/release/publish/external-commands.ts b/ng-dev/release/publish/external-commands.ts index d92a3576a..7a6c764ac 100644 --- a/ng-dev/release/publish/external-commands.ts +++ b/ng-dev/release/publish/external-commands.ts @@ -256,4 +256,30 @@ export abstract class ExternalCommands { throw new FatalReleaseActionError(); } } + + /** + * Invokes the `yarn bazel run @npm2//:sync` command in order + * to refresh Aspect lock files. + */ + static async invokeBazelUpdateAspectLockFiles(projectDir: string): Promise { + // Note: We cannot use `yarn` directly as command because we might operate in + // a different publish branch and the current `PATH` will point to the Yarn version + // that invoked the release tool. More details in the function description. + const yarnCommand = await resolveYarnScriptForProject(projectDir); + + try { + // Note: No progress indicator needed as that is the responsibility of the command. + // TODO: Consider using an Ora spinner instead to ensure minimal console output. + await ChildProcess.spawn( + yarnCommand.binary, + [...yarnCommand.args, 'bazelisk', 'run', '@npm2//:sync'], + {cwd: projectDir}, + ); + } catch (e) { + // Note: Gracefully handling these errors because `sync` command + // alway exits with a non-zero exit code. + } + + Log.info(green(' ✓ Updated Aspect `rules_js` lock files.')); + } } From ddbc36a9969f62ea6dd6c36df6df0da01c1ad5a7 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Thu, 19 Dec 2024 12:09:02 +0000 Subject: [PATCH 2/2] fixup! feat(ng-dev): support releasing when operating in a hybrid pnpm rules_js repo Feedback --- ng-dev/release/publish/actions.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/ng-dev/release/publish/actions.ts b/ng-dev/release/publish/actions.ts index 7fec54a8e..60409d3a7 100644 --- a/ng-dev/release/publish/actions.ts +++ b/ng-dev/release/publish/actions.ts @@ -222,13 +222,16 @@ export abstract class ReleaseAction { // Commit message for the release point. const commitMessage = getCommitMessageForRelease(newVersion); + const filesToCommit = [workspaceRelativePackageJsonPath, workspaceRelativeChangelogPath]; + + // Ensure modified Aspect lock files are included in the release commit. + // TODO: Remove after `rules_js` migration is complete. + if (this.config.rulesJsInteropMode) { + filesToCommit.push(...glob.sync(['.aspect/**', 'pnpm-lock.yaml'], {cwd: this.projectDir})); + } + // Create a release staging commit including changelog and version bump. - await this.createCommit(commitMessage, [ - workspaceRelativePackageJsonPath, - workspaceRelativeChangelogPath, - // Ensure modified Aspect lock files are included in the release commit. - ...(this.config.rulesJsInteropMode ? glob.sync('.aspect/**', {cwd: this.projectDir}) : []), - ]); + await this.createCommit(commitMessage, filesToCommit); // The caretaker may have attempted to make additional changes. These changes would // not be captured into the release commit. The working directory should remain clean,