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..60409d3a7 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. */ @@ -217,11 +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, - ]); + 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, 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.')); + } }