From 65e50e26c9553c07ba37eef38d3a7bbbaf2b4ce6 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Fri, 19 Dec 2025 12:33:55 +0000 Subject: [PATCH 1/3] feat(ng-dev): add `sync-module-bazel` command to update `pnpm` and `typescript` versions and integrity in `MODULE.bazel` This is helpful to ensure that these versions are always synced. --- MODULE.bazel | 3 +- MODULE.bazel.lock | 8 +- ng-dev/misc/cli.ts | 2 + ng-dev/misc/sync-module-bazel/cli.ts | 120 +++++++++++++++++++++++++++ renovate-presets/default.json5 | 17 +++- renovate.json | 1 + 6 files changed, 145 insertions(+), 6 deletions(-) create mode 100644 ng-dev/misc/sync-module-bazel/cli.ts diff --git a/MODULE.bazel b/MODULE.bazel index d72ecbc75..a905dd1b7 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -68,7 +68,8 @@ use_repo(rules_angular, rules_angular_configurable_deps = "dev_infra_rules_angul pnpm = use_extension("@aspect_rules_js//npm:extensions.bzl", "pnpm") pnpm.pnpm( name = "pnpm", - pnpm_version = "10.16.1", + pnpm_version = "10.26.0", + pnpm_version_integrity = "sha512-Oz9scl6+cSUGwKsa1BM8+GsfS2h+/85iqbOLTXLjlUJC5kMZD8UfoWQpScc19APevUT1yw7dZXq+Y6i2p+HkAg==", ) use_repo(pnpm, "pnpm") diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 60e3ce851..a1ebbf235 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -410,7 +410,7 @@ "@@aspect_rules_js+//npm:extensions.bzl%pnpm": { "general": { "bzlTransitiveDigest": "zVV86HvMwDBJ8IsFt27k/Sjq0vCMPr8b8X9OAuprQ6w=", - "usagesDigest": "ZhbEw77ZyU/0//oi7ZG1g+T//EAz9+tI3MinUH//LSo=", + "usagesDigest": "yvNsPkPdz1NdbmMmM3BXRO+s1FJ8T1pFsHK6OLF1Zcs=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, @@ -419,11 +419,11 @@ "repoRuleId": "@@aspect_rules_js+//npm/private:npm_import.bzl%npm_import_rule", "attributes": { "package": "pnpm", - "version": "10.16.1", + "version": "10.26.0", "root_package": "", "link_workspace": "", "link_packages": {}, - "integrity": "sha512-DhVaomKduGcrSehHXaYiaqS96oX9zf3BU1CHSUbU88kfqvZMvcSl0auAAvRz1cP87c0ZeYnPA5D5ut08BGeHBg==", + "integrity": "sha512-Oz9scl6+cSUGwKsa1BM8+GsfS2h+/85iqbOLTXLjlUJC5kMZD8UfoWQpScc19APevUT1yw7dZXq+Y6i2p+HkAg==", "url": "", "commit": "", "patch_args": [ @@ -446,7 +446,7 @@ "repoRuleId": "@@aspect_rules_js+//npm/private:npm_import.bzl%npm_import_links", "attributes": { "package": "pnpm", - "version": "10.16.1", + "version": "10.26.0", "dev": false, "root_package": "", "link_packages": {}, diff --git a/ng-dev/misc/cli.ts b/ng-dev/misc/cli.ts index 79242f2ae..8c4f22e6e 100644 --- a/ng-dev/misc/cli.ts +++ b/ng-dev/misc/cli.ts @@ -7,6 +7,7 @@ */ import {Argv} from 'yargs'; +import {SyncModuleBazelModule} from './sync-module-bazel/cli.js'; import {BuildAndLinkCommandModule} from './build-and-link/cli.js'; import {GeneratedFilesModule} from './generated-files/cli.js'; import {GeneratedNodeJsToolchainModule} from './generate-nodejs-toolchain/cli.js'; @@ -16,6 +17,7 @@ export function buildMiscParser(localYargs: Argv) { return localYargs .help() .strict() + .command(SyncModuleBazelModule) .command(BuildAndLinkCommandModule) .command(GeneratedFilesModule) .command(GeneratedNodeJsToolchainModule); diff --git a/ng-dev/misc/sync-module-bazel/cli.ts b/ng-dev/misc/sync-module-bazel/cli.ts new file mode 100644 index 000000000..2b25ea0b5 --- /dev/null +++ b/ng-dev/misc/sync-module-bazel/cli.ts @@ -0,0 +1,120 @@ +/** + * @license + * Copyright Google LLC + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Argv, CommandModule} from 'yargs'; +import {readFileSync, writeFileSync} from 'node:fs'; +import {execSync} from 'node:child_process'; +import {join} from 'node:path'; +import {Log} from '../../utils/logging'; + +async function builder(argv: Argv) { + return argv; +} + +async function handler() { + const rootDir = process.cwd(); + const packageJsonPath = join(rootDir, 'package.json'); + const moduleBazelPath = join(rootDir, 'MODULE.bazel'); + + interface PackageJson { + engines?: { + pnpm?: string; + }; + dependencies?: { + typescript?: string; + }; + devDependencies?: { + typescript?: string; + }; + } + + // Read package.json + const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as PackageJson; + const pnpmVersion = packageJson.engines?.pnpm; + const tsVersion = packageJson.dependencies?.typescript || packageJson.devDependencies?.typescript; + + if (!pnpmVersion) { + throw new Error('Could not find engines.pnpm in package.json'); + } + + if (!tsVersion) { + throw new Error('Could not find typescript in dependencies or devDependencies in package.json'); + } + + // Helper to get integrity + async function getIntegrity(pkg: string, version: string): Promise { + const response = await fetch(`https://registry.npmjs.org/${pkg}/${version}`); + if (!response.ok) { + throw new Error(`Failed to request ${pkg}@${version}: ${response.statusText}`); + } + + const {dist} = (await response.json()) as {dist: {integrity: string}}; + + return dist.integrity; + } + + // Read MODULE.bazel + let originalBazelContent = readFileSync(moduleBazelPath, 'utf8'); + let moduleBazelContent = originalBazelContent; + + if (moduleBazelContent.includes('pnpm_version')) { + console.log(`Resolving integrity for pnpm@${pnpmVersion}...`); + const pnpmIntegrity = await getIntegrity('pnpm', pnpmVersion); + + // Update pnpm version and integrity + moduleBazelContent = moduleBazelContent.replace( + /pnpm_version = ".*?"/, + `pnpm_version = "${pnpmVersion}"`, + ); + + if (moduleBazelContent.includes('pnpm_version_integrity =')) { + moduleBazelContent = moduleBazelContent.replace( + /pnpm_version_integrity = ".*?"/, + `pnpm_version_integrity = "${pnpmIntegrity}"`, + ); + } else { + moduleBazelContent = moduleBazelContent.replace( + /pnpm_version = ".*?"/, + `$&,\n pnpm_version_integrity = "${pnpmIntegrity}"`, + ); + } + } + + // Update typescript version and integrity + if (moduleBazelContent.includes('ts_version')) { + console.log(`Resolving integrity for typescript@${tsVersion}...`); + const tsIntegrity = await getIntegrity('typescript', tsVersion); + + moduleBazelContent = moduleBazelContent.replace( + /ts_version = ".*?"/, + `ts_version = "${tsVersion}"`, + ); + moduleBazelContent = moduleBazelContent.replace( + /ts_integrity = ".*?"/, + `ts_integrity = "${tsIntegrity}"`, + ); + + if (originalBazelContent !== moduleBazelContent) { + writeFileSync(moduleBazelPath, moduleBazelContent); + + try { + execSync('pnpm bazel mod deps --lockfile_mode=update', {stdio: 'inherit'}); + } catch (e) { + Log.debug(e); + } + } + } +} + +/** CLI command module. */ +export const SyncModuleBazelModule: CommandModule = { + builder, + handler, + command: 'sync-module-bazel', + describe: 'Sync pnpm and typescript versions in MODULE.bazel with package.json.', +}; diff --git a/renovate-presets/default.json5 b/renovate-presets/default.json5 index c39024137..931a2be1e 100644 --- a/renovate-presets/default.json5 +++ b/renovate-presets/default.json5 @@ -47,6 +47,7 @@ // Workaround for https://github.com/renovatebot/renovate/issues/25557 { postUpgradeTasks: { + matchManagers: ['bazel', 'bazel-module', 'bazelisk'], commands: [ 'bash -c "git restore .npmrc || true"', // If `.npmrc` doesn't exist, avoid a hard error. 'bazel mod deps --lockfile_mode=update', @@ -55,7 +56,21 @@ // run when in the same branch there are mixtures of update types by different managers. executionMode: 'update', }, - matchManagers: ['bazel', 'bazel-module', 'bazelisk'], + }, + + // Enable 'postUpdateTasks' for changes that effect the typescript and pnpm versions. + // This is to ensure that the `MODULE.bazel` is updated with the correct versions. + { + matchManagers: ['npm'], + matchDepNames: ['pnpm', 'typescript'], + postUpgradeTasks: { + commands: [ + 'git restore .npmrc || true', // In case `.npmrc` avoid a hard error. + 'pnpm install --frozen-lockfile', + 'pnpm ng-dev misc sync-module-bazel || true', // TODO(alanagius): Remove || true once all repos update to the latest ng-dev. + ], + executionMode: 'branch', + }, }, // Rule to require manual approval for NPM updates on branches other than 'main'. diff --git a/renovate.json b/renovate.json index ec81023c1..9a4c85934 100644 --- a/renovate.json +++ b/renovate.json @@ -13,6 +13,7 @@ "commands": [ "pnpm install --frozen-lockfile", "pnpm bazel mod deps --lockfile_mode=update", + "pnpm ng-dev misc sync-module-bazel", "pnpm update-generated-files" ], "executionMode": "branch" From e2c8384e880f77ed6f57f80e5f949f0359d72932 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Fri, 9 Jan 2026 13:15:18 +0000 Subject: [PATCH 2/3] fixup! feat(ng-dev): add `sync-module-bazel` command to update `pnpm` and `typescript` versions and integrity in `MODULE.bazel` --- MODULE.bazel | 17 +- MODULE.bazel.lock | 338 ++++++++++++++++-- ng-dev/misc/sync-module-bazel/cli.ts | 100 ++---- .../sync-module-bazel/sync-module-bazel.ts | 239 +++++++++++++ renovate-presets/default.json5 | 8 +- 5 files changed, 592 insertions(+), 110 deletions(-) create mode 100644 ng-dev/misc/sync-module-bazel/sync-module-bazel.ts diff --git a/MODULE.bazel b/MODULE.bazel index a905dd1b7..1af17392a 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -54,7 +54,18 @@ rules_ts_ext.deps( use_repo(rules_ts_ext, "npm_typescript") node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node") -node.toolchain(node_version_from_nvmrc = "//:.nvmrc") +node.toolchain( + node_repositories = { + "24.11.0-darwin_arm64": ("node-v24.11.0-darwin-arm64.tar.gz", "node-v24.11.0-darwin-arm64", "0be2ab2816a4fa02d1acff014a434f29f56d8d956f5af6a98b70ced6c5f4d201"), + "24.11.0-darwin_amd64": ("node-v24.11.0-darwin-x64.tar.gz", "node-v24.11.0-darwin-x64", "3884671e87f46f773832d98a0a6cabcc5ec4f637084f0f3515b69e66ea27f2f1"), + "24.11.0-linux_arm64": ("node-v24.11.0-linux-arm64.tar.xz", "node-v24.11.0-linux-arm64", "33a6673b2c7bffeae9deec7f9f8b31aad9119b08f13d49b2ca3ee3bebfe8260f"), + "24.11.0-linux_ppc64le": ("node-v24.11.0-linux-ppc64le.tar.xz", "node-v24.11.0-linux-ppc64le", "5e9fd1936c08ad6bf0cc69266af3f9815b598ff63419640da8379f7bd9afe9f5"), + "24.11.0-linux_s390x": ("node-v24.11.0-linux-s390x.tar.xz", "node-v24.11.0-linux-s390x", "8c7eca962686b98c0c5eaf46d96f24cd6d0e2f950954051027899c6b57bc7680"), + "24.11.0-linux_amd64": ("node-v24.11.0-linux-x64.tar.xz", "node-v24.11.0-linux-x64", "46da9a098973ab7ba4fca76945581ecb2eaf468de347173897044382f10e0a0a"), + "24.11.0-windows_amd64": ("node-v24.11.0-win-x64.zip", "node-v24.11.0-win-x64", "1054540bce22b54ec7e50ebc078ec5d090700a77657607a58f6a64df21f49fdd"), + }, + node_version = "24.11.0", +) use_repo(node, "nodejs_toolchains") rules_angular = use_extension("@rules_angular//setup:extensions.bzl", "rules_angular") @@ -68,8 +79,8 @@ use_repo(rules_angular, rules_angular_configurable_deps = "dev_infra_rules_angul pnpm = use_extension("@aspect_rules_js//npm:extensions.bzl", "pnpm") pnpm.pnpm( name = "pnpm", - pnpm_version = "10.26.0", - pnpm_version_integrity = "sha512-Oz9scl6+cSUGwKsa1BM8+GsfS2h+/85iqbOLTXLjlUJC5kMZD8UfoWQpScc19APevUT1yw7dZXq+Y6i2p+HkAg==", + pnpm_version = "10.27.0", + pnpm_version_integrity = "sha512-ctaZ2haxF5wUup5k3HHJpAmIy9xlwmTLDkidt96RfyDc9NZNhyNiXylpulLUt+KhFwaC2awqXcrqq3MrfhbwSg==", ) use_repo(pnpm, "pnpm") diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index a1ebbf235..be08ecaec 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -410,7 +410,7 @@ "@@aspect_rules_js+//npm:extensions.bzl%pnpm": { "general": { "bzlTransitiveDigest": "zVV86HvMwDBJ8IsFt27k/Sjq0vCMPr8b8X9OAuprQ6w=", - "usagesDigest": "yvNsPkPdz1NdbmMmM3BXRO+s1FJ8T1pFsHK6OLF1Zcs=", + "usagesDigest": "UaYooNgoy5qa2BLt6yXhg7QmU2JXzOnGUZ3iDRDvGMI=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, @@ -419,11 +419,11 @@ "repoRuleId": "@@aspect_rules_js+//npm/private:npm_import.bzl%npm_import_rule", "attributes": { "package": "pnpm", - "version": "10.26.0", + "version": "10.27.0", "root_package": "", "link_workspace": "", "link_packages": {}, - "integrity": "sha512-Oz9scl6+cSUGwKsa1BM8+GsfS2h+/85iqbOLTXLjlUJC5kMZD8UfoWQpScc19APevUT1yw7dZXq+Y6i2p+HkAg==", + "integrity": "sha512-ctaZ2haxF5wUup5k3HHJpAmIy9xlwmTLDkidt96RfyDc9NZNhyNiXylpulLUt+KhFwaC2awqXcrqq3MrfhbwSg==", "url": "", "commit": "", "patch_args": [ @@ -446,7 +446,7 @@ "repoRuleId": "@@aspect_rules_js+//npm/private:npm_import.bzl%npm_import_links", "attributes": { "package": "pnpm", - "version": "10.26.0", + "version": "10.27.0", "dev": false, "root_package": "", "link_packages": {}, @@ -1074,7 +1074,7 @@ "@@rules_nodejs+//nodejs:extensions.bzl%node": { "general": { "bzlTransitiveDigest": "NwcLXHrbh2hoorA/Ybmcpjxsn/6avQmewDglodkDrgo=", - "usagesDigest": "Ab2bmKbs5/aClAgtuYRf1QCmN2QQh4joAZnKh+M6qb4=", + "usagesDigest": "imdVFPS2OEPCd8po4qeEyzUkZPNhZlmMto2WffUSLa0=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, @@ -1083,12 +1083,47 @@ "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories", "attributes": { "node_download_auth": {}, - "node_repositories": {}, + "node_repositories": { + "24.11.0-darwin_arm64": [ + "node-v24.11.0-darwin-arm64.tar.gz", + "node-v24.11.0-darwin-arm64", + "0be2ab2816a4fa02d1acff014a434f29f56d8d956f5af6a98b70ced6c5f4d201" + ], + "24.11.0-darwin_amd64": [ + "node-v24.11.0-darwin-x64.tar.gz", + "node-v24.11.0-darwin-x64", + "3884671e87f46f773832d98a0a6cabcc5ec4f637084f0f3515b69e66ea27f2f1" + ], + "24.11.0-linux_arm64": [ + "node-v24.11.0-linux-arm64.tar.xz", + "node-v24.11.0-linux-arm64", + "33a6673b2c7bffeae9deec7f9f8b31aad9119b08f13d49b2ca3ee3bebfe8260f" + ], + "24.11.0-linux_ppc64le": [ + "node-v24.11.0-linux-ppc64le.tar.xz", + "node-v24.11.0-linux-ppc64le", + "5e9fd1936c08ad6bf0cc69266af3f9815b598ff63419640da8379f7bd9afe9f5" + ], + "24.11.0-linux_s390x": [ + "node-v24.11.0-linux-s390x.tar.xz", + "node-v24.11.0-linux-s390x", + "8c7eca962686b98c0c5eaf46d96f24cd6d0e2f950954051027899c6b57bc7680" + ], + "24.11.0-linux_amd64": [ + "node-v24.11.0-linux-x64.tar.xz", + "node-v24.11.0-linux-x64", + "46da9a098973ab7ba4fca76945581ecb2eaf468de347173897044382f10e0a0a" + ], + "24.11.0-windows_amd64": [ + "node-v24.11.0-win-x64.zip", + "node-v24.11.0-win-x64", + "1054540bce22b54ec7e50ebc078ec5d090700a77657607a58f6a64df21f49fdd" + ] + }, "node_urls": [ "https://nodejs.org/dist/v{version}/{filename}" ], - "node_version": "20.19.5", - "node_version_from_nvmrc": "@@//:.nvmrc", + "node_version": "24.11.0", "include_headers": false, "platform": "linux_amd64" } @@ -1097,12 +1132,47 @@ "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories", "attributes": { "node_download_auth": {}, - "node_repositories": {}, + "node_repositories": { + "24.11.0-darwin_arm64": [ + "node-v24.11.0-darwin-arm64.tar.gz", + "node-v24.11.0-darwin-arm64", + "0be2ab2816a4fa02d1acff014a434f29f56d8d956f5af6a98b70ced6c5f4d201" + ], + "24.11.0-darwin_amd64": [ + "node-v24.11.0-darwin-x64.tar.gz", + "node-v24.11.0-darwin-x64", + "3884671e87f46f773832d98a0a6cabcc5ec4f637084f0f3515b69e66ea27f2f1" + ], + "24.11.0-linux_arm64": [ + "node-v24.11.0-linux-arm64.tar.xz", + "node-v24.11.0-linux-arm64", + "33a6673b2c7bffeae9deec7f9f8b31aad9119b08f13d49b2ca3ee3bebfe8260f" + ], + "24.11.0-linux_ppc64le": [ + "node-v24.11.0-linux-ppc64le.tar.xz", + "node-v24.11.0-linux-ppc64le", + "5e9fd1936c08ad6bf0cc69266af3f9815b598ff63419640da8379f7bd9afe9f5" + ], + "24.11.0-linux_s390x": [ + "node-v24.11.0-linux-s390x.tar.xz", + "node-v24.11.0-linux-s390x", + "8c7eca962686b98c0c5eaf46d96f24cd6d0e2f950954051027899c6b57bc7680" + ], + "24.11.0-linux_amd64": [ + "node-v24.11.0-linux-x64.tar.xz", + "node-v24.11.0-linux-x64", + "46da9a098973ab7ba4fca76945581ecb2eaf468de347173897044382f10e0a0a" + ], + "24.11.0-windows_amd64": [ + "node-v24.11.0-win-x64.zip", + "node-v24.11.0-win-x64", + "1054540bce22b54ec7e50ebc078ec5d090700a77657607a58f6a64df21f49fdd" + ] + }, "node_urls": [ "https://nodejs.org/dist/v{version}/{filename}" ], - "node_version": "20.19.5", - "node_version_from_nvmrc": "@@//:.nvmrc", + "node_version": "24.11.0", "include_headers": false, "platform": "linux_arm64" } @@ -1111,12 +1181,47 @@ "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories", "attributes": { "node_download_auth": {}, - "node_repositories": {}, + "node_repositories": { + "24.11.0-darwin_arm64": [ + "node-v24.11.0-darwin-arm64.tar.gz", + "node-v24.11.0-darwin-arm64", + "0be2ab2816a4fa02d1acff014a434f29f56d8d956f5af6a98b70ced6c5f4d201" + ], + "24.11.0-darwin_amd64": [ + "node-v24.11.0-darwin-x64.tar.gz", + "node-v24.11.0-darwin-x64", + "3884671e87f46f773832d98a0a6cabcc5ec4f637084f0f3515b69e66ea27f2f1" + ], + "24.11.0-linux_arm64": [ + "node-v24.11.0-linux-arm64.tar.xz", + "node-v24.11.0-linux-arm64", + "33a6673b2c7bffeae9deec7f9f8b31aad9119b08f13d49b2ca3ee3bebfe8260f" + ], + "24.11.0-linux_ppc64le": [ + "node-v24.11.0-linux-ppc64le.tar.xz", + "node-v24.11.0-linux-ppc64le", + "5e9fd1936c08ad6bf0cc69266af3f9815b598ff63419640da8379f7bd9afe9f5" + ], + "24.11.0-linux_s390x": [ + "node-v24.11.0-linux-s390x.tar.xz", + "node-v24.11.0-linux-s390x", + "8c7eca962686b98c0c5eaf46d96f24cd6d0e2f950954051027899c6b57bc7680" + ], + "24.11.0-linux_amd64": [ + "node-v24.11.0-linux-x64.tar.xz", + "node-v24.11.0-linux-x64", + "46da9a098973ab7ba4fca76945581ecb2eaf468de347173897044382f10e0a0a" + ], + "24.11.0-windows_amd64": [ + "node-v24.11.0-win-x64.zip", + "node-v24.11.0-win-x64", + "1054540bce22b54ec7e50ebc078ec5d090700a77657607a58f6a64df21f49fdd" + ] + }, "node_urls": [ "https://nodejs.org/dist/v{version}/{filename}" ], - "node_version": "20.19.5", - "node_version_from_nvmrc": "@@//:.nvmrc", + "node_version": "24.11.0", "include_headers": false, "platform": "linux_s390x" } @@ -1125,12 +1230,47 @@ "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories", "attributes": { "node_download_auth": {}, - "node_repositories": {}, + "node_repositories": { + "24.11.0-darwin_arm64": [ + "node-v24.11.0-darwin-arm64.tar.gz", + "node-v24.11.0-darwin-arm64", + "0be2ab2816a4fa02d1acff014a434f29f56d8d956f5af6a98b70ced6c5f4d201" + ], + "24.11.0-darwin_amd64": [ + "node-v24.11.0-darwin-x64.tar.gz", + "node-v24.11.0-darwin-x64", + "3884671e87f46f773832d98a0a6cabcc5ec4f637084f0f3515b69e66ea27f2f1" + ], + "24.11.0-linux_arm64": [ + "node-v24.11.0-linux-arm64.tar.xz", + "node-v24.11.0-linux-arm64", + "33a6673b2c7bffeae9deec7f9f8b31aad9119b08f13d49b2ca3ee3bebfe8260f" + ], + "24.11.0-linux_ppc64le": [ + "node-v24.11.0-linux-ppc64le.tar.xz", + "node-v24.11.0-linux-ppc64le", + "5e9fd1936c08ad6bf0cc69266af3f9815b598ff63419640da8379f7bd9afe9f5" + ], + "24.11.0-linux_s390x": [ + "node-v24.11.0-linux-s390x.tar.xz", + "node-v24.11.0-linux-s390x", + "8c7eca962686b98c0c5eaf46d96f24cd6d0e2f950954051027899c6b57bc7680" + ], + "24.11.0-linux_amd64": [ + "node-v24.11.0-linux-x64.tar.xz", + "node-v24.11.0-linux-x64", + "46da9a098973ab7ba4fca76945581ecb2eaf468de347173897044382f10e0a0a" + ], + "24.11.0-windows_amd64": [ + "node-v24.11.0-win-x64.zip", + "node-v24.11.0-win-x64", + "1054540bce22b54ec7e50ebc078ec5d090700a77657607a58f6a64df21f49fdd" + ] + }, "node_urls": [ "https://nodejs.org/dist/v{version}/{filename}" ], - "node_version": "20.19.5", - "node_version_from_nvmrc": "@@//:.nvmrc", + "node_version": "24.11.0", "include_headers": false, "platform": "linux_ppc64le" } @@ -1139,12 +1279,47 @@ "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories", "attributes": { "node_download_auth": {}, - "node_repositories": {}, + "node_repositories": { + "24.11.0-darwin_arm64": [ + "node-v24.11.0-darwin-arm64.tar.gz", + "node-v24.11.0-darwin-arm64", + "0be2ab2816a4fa02d1acff014a434f29f56d8d956f5af6a98b70ced6c5f4d201" + ], + "24.11.0-darwin_amd64": [ + "node-v24.11.0-darwin-x64.tar.gz", + "node-v24.11.0-darwin-x64", + "3884671e87f46f773832d98a0a6cabcc5ec4f637084f0f3515b69e66ea27f2f1" + ], + "24.11.0-linux_arm64": [ + "node-v24.11.0-linux-arm64.tar.xz", + "node-v24.11.0-linux-arm64", + "33a6673b2c7bffeae9deec7f9f8b31aad9119b08f13d49b2ca3ee3bebfe8260f" + ], + "24.11.0-linux_ppc64le": [ + "node-v24.11.0-linux-ppc64le.tar.xz", + "node-v24.11.0-linux-ppc64le", + "5e9fd1936c08ad6bf0cc69266af3f9815b598ff63419640da8379f7bd9afe9f5" + ], + "24.11.0-linux_s390x": [ + "node-v24.11.0-linux-s390x.tar.xz", + "node-v24.11.0-linux-s390x", + "8c7eca962686b98c0c5eaf46d96f24cd6d0e2f950954051027899c6b57bc7680" + ], + "24.11.0-linux_amd64": [ + "node-v24.11.0-linux-x64.tar.xz", + "node-v24.11.0-linux-x64", + "46da9a098973ab7ba4fca76945581ecb2eaf468de347173897044382f10e0a0a" + ], + "24.11.0-windows_amd64": [ + "node-v24.11.0-win-x64.zip", + "node-v24.11.0-win-x64", + "1054540bce22b54ec7e50ebc078ec5d090700a77657607a58f6a64df21f49fdd" + ] + }, "node_urls": [ "https://nodejs.org/dist/v{version}/{filename}" ], - "node_version": "20.19.5", - "node_version_from_nvmrc": "@@//:.nvmrc", + "node_version": "24.11.0", "include_headers": false, "platform": "darwin_amd64" } @@ -1153,12 +1328,47 @@ "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories", "attributes": { "node_download_auth": {}, - "node_repositories": {}, + "node_repositories": { + "24.11.0-darwin_arm64": [ + "node-v24.11.0-darwin-arm64.tar.gz", + "node-v24.11.0-darwin-arm64", + "0be2ab2816a4fa02d1acff014a434f29f56d8d956f5af6a98b70ced6c5f4d201" + ], + "24.11.0-darwin_amd64": [ + "node-v24.11.0-darwin-x64.tar.gz", + "node-v24.11.0-darwin-x64", + "3884671e87f46f773832d98a0a6cabcc5ec4f637084f0f3515b69e66ea27f2f1" + ], + "24.11.0-linux_arm64": [ + "node-v24.11.0-linux-arm64.tar.xz", + "node-v24.11.0-linux-arm64", + "33a6673b2c7bffeae9deec7f9f8b31aad9119b08f13d49b2ca3ee3bebfe8260f" + ], + "24.11.0-linux_ppc64le": [ + "node-v24.11.0-linux-ppc64le.tar.xz", + "node-v24.11.0-linux-ppc64le", + "5e9fd1936c08ad6bf0cc69266af3f9815b598ff63419640da8379f7bd9afe9f5" + ], + "24.11.0-linux_s390x": [ + "node-v24.11.0-linux-s390x.tar.xz", + "node-v24.11.0-linux-s390x", + "8c7eca962686b98c0c5eaf46d96f24cd6d0e2f950954051027899c6b57bc7680" + ], + "24.11.0-linux_amd64": [ + "node-v24.11.0-linux-x64.tar.xz", + "node-v24.11.0-linux-x64", + "46da9a098973ab7ba4fca76945581ecb2eaf468de347173897044382f10e0a0a" + ], + "24.11.0-windows_amd64": [ + "node-v24.11.0-win-x64.zip", + "node-v24.11.0-win-x64", + "1054540bce22b54ec7e50ebc078ec5d090700a77657607a58f6a64df21f49fdd" + ] + }, "node_urls": [ "https://nodejs.org/dist/v{version}/{filename}" ], - "node_version": "20.19.5", - "node_version_from_nvmrc": "@@//:.nvmrc", + "node_version": "24.11.0", "include_headers": false, "platform": "darwin_arm64" } @@ -1167,12 +1377,47 @@ "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories", "attributes": { "node_download_auth": {}, - "node_repositories": {}, + "node_repositories": { + "24.11.0-darwin_arm64": [ + "node-v24.11.0-darwin-arm64.tar.gz", + "node-v24.11.0-darwin-arm64", + "0be2ab2816a4fa02d1acff014a434f29f56d8d956f5af6a98b70ced6c5f4d201" + ], + "24.11.0-darwin_amd64": [ + "node-v24.11.0-darwin-x64.tar.gz", + "node-v24.11.0-darwin-x64", + "3884671e87f46f773832d98a0a6cabcc5ec4f637084f0f3515b69e66ea27f2f1" + ], + "24.11.0-linux_arm64": [ + "node-v24.11.0-linux-arm64.tar.xz", + "node-v24.11.0-linux-arm64", + "33a6673b2c7bffeae9deec7f9f8b31aad9119b08f13d49b2ca3ee3bebfe8260f" + ], + "24.11.0-linux_ppc64le": [ + "node-v24.11.0-linux-ppc64le.tar.xz", + "node-v24.11.0-linux-ppc64le", + "5e9fd1936c08ad6bf0cc69266af3f9815b598ff63419640da8379f7bd9afe9f5" + ], + "24.11.0-linux_s390x": [ + "node-v24.11.0-linux-s390x.tar.xz", + "node-v24.11.0-linux-s390x", + "8c7eca962686b98c0c5eaf46d96f24cd6d0e2f950954051027899c6b57bc7680" + ], + "24.11.0-linux_amd64": [ + "node-v24.11.0-linux-x64.tar.xz", + "node-v24.11.0-linux-x64", + "46da9a098973ab7ba4fca76945581ecb2eaf468de347173897044382f10e0a0a" + ], + "24.11.0-windows_amd64": [ + "node-v24.11.0-win-x64.zip", + "node-v24.11.0-win-x64", + "1054540bce22b54ec7e50ebc078ec5d090700a77657607a58f6a64df21f49fdd" + ] + }, "node_urls": [ "https://nodejs.org/dist/v{version}/{filename}" ], - "node_version": "20.19.5", - "node_version_from_nvmrc": "@@//:.nvmrc", + "node_version": "24.11.0", "include_headers": false, "platform": "windows_amd64" } @@ -1181,12 +1426,47 @@ "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories", "attributes": { "node_download_auth": {}, - "node_repositories": {}, + "node_repositories": { + "24.11.0-darwin_arm64": [ + "node-v24.11.0-darwin-arm64.tar.gz", + "node-v24.11.0-darwin-arm64", + "0be2ab2816a4fa02d1acff014a434f29f56d8d956f5af6a98b70ced6c5f4d201" + ], + "24.11.0-darwin_amd64": [ + "node-v24.11.0-darwin-x64.tar.gz", + "node-v24.11.0-darwin-x64", + "3884671e87f46f773832d98a0a6cabcc5ec4f637084f0f3515b69e66ea27f2f1" + ], + "24.11.0-linux_arm64": [ + "node-v24.11.0-linux-arm64.tar.xz", + "node-v24.11.0-linux-arm64", + "33a6673b2c7bffeae9deec7f9f8b31aad9119b08f13d49b2ca3ee3bebfe8260f" + ], + "24.11.0-linux_ppc64le": [ + "node-v24.11.0-linux-ppc64le.tar.xz", + "node-v24.11.0-linux-ppc64le", + "5e9fd1936c08ad6bf0cc69266af3f9815b598ff63419640da8379f7bd9afe9f5" + ], + "24.11.0-linux_s390x": [ + "node-v24.11.0-linux-s390x.tar.xz", + "node-v24.11.0-linux-s390x", + "8c7eca962686b98c0c5eaf46d96f24cd6d0e2f950954051027899c6b57bc7680" + ], + "24.11.0-linux_amd64": [ + "node-v24.11.0-linux-x64.tar.xz", + "node-v24.11.0-linux-x64", + "46da9a098973ab7ba4fca76945581ecb2eaf468de347173897044382f10e0a0a" + ], + "24.11.0-windows_amd64": [ + "node-v24.11.0-win-x64.zip", + "node-v24.11.0-win-x64", + "1054540bce22b54ec7e50ebc078ec5d090700a77657607a58f6a64df21f49fdd" + ] + }, "node_urls": [ "https://nodejs.org/dist/v{version}/{filename}" ], - "node_version": "20.19.5", - "node_version_from_nvmrc": "@@//:.nvmrc", + "node_version": "24.11.0", "include_headers": false, "platform": "windows_arm64" } diff --git a/ng-dev/misc/sync-module-bazel/cli.ts b/ng-dev/misc/sync-module-bazel/cli.ts index 2b25ea0b5..d0230a94e 100644 --- a/ng-dev/misc/sync-module-bazel/cli.ts +++ b/ng-dev/misc/sync-module-bazel/cli.ts @@ -8,106 +8,57 @@ import {Argv, CommandModule} from 'yargs'; import {readFileSync, writeFileSync} from 'node:fs'; -import {execSync} from 'node:child_process'; import {join} from 'node:path'; -import {Log} from '../../utils/logging'; +import {determineRepoBaseDirFromCwd} from '../../utils/repo-directory'; +import {PackageJson, syncNodeJs, syncPnpm, syncTypeScript} from './sync-module-bazel'; +import {ChildProcess} from '../../utils/child-process'; async function builder(argv: Argv) { return argv; } async function handler() { - const rootDir = process.cwd(); + const rootDir = determineRepoBaseDirFromCwd(); const packageJsonPath = join(rootDir, 'package.json'); const moduleBazelPath = join(rootDir, 'MODULE.bazel'); - - interface PackageJson { - engines?: { - pnpm?: string; - }; - dependencies?: { - typescript?: string; - }; - devDependencies?: { - typescript?: string; - }; - } + const nvmrcPath = join(rootDir, '.nvmrc'); // Read package.json const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as PackageJson; const pnpmVersion = packageJson.engines?.pnpm; const tsVersion = packageJson.dependencies?.typescript || packageJson.devDependencies?.typescript; + // Read .nvmrc + let nvmrcVersion: string | undefined; + try { + nvmrcVersion = readFileSync(nvmrcPath, 'utf8').trim().replace(/^v/, ''); + } catch { + // .nvmrc is optional. + } + if (!pnpmVersion) { - throw new Error('Could not find engines.pnpm in package.json'); + throw new Error('Could find engines.pnpm in package.json'); } if (!tsVersion) { throw new Error('Could not find typescript in dependencies or devDependencies in package.json'); } - // Helper to get integrity - async function getIntegrity(pkg: string, version: string): Promise { - const response = await fetch(`https://registry.npmjs.org/${pkg}/${version}`); - if (!response.ok) { - throw new Error(`Failed to request ${pkg}@${version}: ${response.statusText}`); - } - - const {dist} = (await response.json()) as {dist: {integrity: string}}; - - return dist.integrity; - } - // Read MODULE.bazel - let originalBazelContent = readFileSync(moduleBazelPath, 'utf8'); + const originalBazelContent = readFileSync(moduleBazelPath, 'utf8'); let moduleBazelContent = originalBazelContent; - if (moduleBazelContent.includes('pnpm_version')) { - console.log(`Resolving integrity for pnpm@${pnpmVersion}...`); - const pnpmIntegrity = await getIntegrity('pnpm', pnpmVersion); - - // Update pnpm version and integrity - moduleBazelContent = moduleBazelContent.replace( - /pnpm_version = ".*?"/, - `pnpm_version = "${pnpmVersion}"`, - ); - - if (moduleBazelContent.includes('pnpm_version_integrity =')) { - moduleBazelContent = moduleBazelContent.replace( - /pnpm_version_integrity = ".*?"/, - `pnpm_version_integrity = "${pnpmIntegrity}"`, - ); - } else { - moduleBazelContent = moduleBazelContent.replace( - /pnpm_version = ".*?"/, - `$&,\n pnpm_version_integrity = "${pnpmIntegrity}"`, - ); - } - } - - // Update typescript version and integrity - if (moduleBazelContent.includes('ts_version')) { - console.log(`Resolving integrity for typescript@${tsVersion}...`); - const tsIntegrity = await getIntegrity('typescript', tsVersion); - - moduleBazelContent = moduleBazelContent.replace( - /ts_version = ".*?"/, - `ts_version = "${tsVersion}"`, - ); - moduleBazelContent = moduleBazelContent.replace( - /ts_integrity = ".*?"/, - `ts_integrity = "${tsIntegrity}"`, - ); + moduleBazelContent = await syncPnpm(moduleBazelContent, pnpmVersion); + moduleBazelContent = await syncTypeScript(moduleBazelContent, tsVersion); + moduleBazelContent = await syncNodeJs(moduleBazelContent, nvmrcVersion); - if (originalBazelContent !== moduleBazelContent) { - writeFileSync(moduleBazelPath, moduleBazelContent); + if (originalBazelContent !== moduleBazelContent) { + writeFileSync(moduleBazelPath, moduleBazelContent); - try { - execSync('pnpm bazel mod deps --lockfile_mode=update', {stdio: 'inherit'}); - } catch (e) { - Log.debug(e); - } - } + ChildProcess.spawnSync('pnpm', ['buildifier', 'MODULE.bazel']); + ChildProcess.spawnSync('pnpm', ['bazel', 'mod', 'deps', '--lockfile_mode=update'], { + suppressErrorOnFailingExitCode: true, + }); } } @@ -116,5 +67,6 @@ export const SyncModuleBazelModule: CommandModule = { builder, handler, command: 'sync-module-bazel', - describe: 'Sync pnpm and typescript versions in MODULE.bazel with package.json.', + describe: + 'Sync node.js, pnpm and typescript versions in MODULE.bazel with package.json and .nvmrc.', }; diff --git a/ng-dev/misc/sync-module-bazel/sync-module-bazel.ts b/ng-dev/misc/sync-module-bazel/sync-module-bazel.ts new file mode 100644 index 000000000..42111a508 --- /dev/null +++ b/ng-dev/misc/sync-module-bazel/sync-module-bazel.ts @@ -0,0 +1,239 @@ +/** + * @license + * Copyright Google LLC + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Log} from '../../utils/logging'; + +export interface PackageJson { + engines?: { + pnpm?: string; + node?: string; + }; + dependencies?: { + typescript?: string; + }; + devDependencies?: { + typescript?: string; + }; +} + +interface RepositoryInfo { + filename: string; + sha: string; + type: string; +} + +const REPOSITORY_TYPES: Record = { + 'darwin-arm64.tar.gz': 'darwin_arm64', + 'darwin-x64.tar.gz': 'darwin_amd64', + 'linux-x64.tar.xz': 'linux_amd64', + 'linux-arm64.tar.xz': 'linux_arm64', + 'linux-s390x.tar.xz': 'linux_s390x', + 'win-x64.zip': 'windows_amd64', + 'linux-ppc64le.tar.xz': 'linux_ppc64le', +}; + +/** RegExp that matches the pnpm version assignment in MODULE.bazel. */ +const PNPM_VERSION_REGEXP = /pnpm_version(?:_from)? = ".*?"/; +/** RegExp that matches the pnpm integrity assignment in MODULE.bazel. */ +const PNPM_INTEGRITY_REGEXP = /pnpm_version_integrity = ".*?"/; +/** RegExp that matches the TypeScript version assignment in MODULE.bazel. */ +const TS_VERSION_REGEXP = /ts_version(?:_from)? = ".*?"/; +/** RegExp that matches the TypeScript integrity assignment in MODULE.bazel. */ +const TS_INTEGRITY_REGEXP = /ts_integrity = ".*?"/; +/** RegExp that matches the Node.js version assignment in MODULE.bazel. */ +const NODE_VERSION_REGEXP = /node_version = "(.*?)"/; +/** RegExp that matches the Node.js repositories assignment in MODULE.bazel. */ +const NODE_REPOSITORIES_REGEXP = /node_repositories = \{[\s\S]*?\}/; + +/** Fetches the integrity for a given package version from the npm registry. */ +async function getNpmPackageIntegrity(pkg: string, version: string): Promise { + const response = await fetch(`https://registry.npmjs.org/${pkg}/${version}`); + if (!response.ok) { + throw new Error(`Failed to request ${pkg}@${version}: ${response.statusText}`); + } + + const {dist} = (await response.json()) as {dist: {integrity: string}}; + + return dist.integrity; +} + +/** Fetches the repository information for a given Node.js version. */ +async function getNodeJsRepositories(version: string): Promise { + const response = await fetch(`https://nodejs.org/dist/v${version}/SHASUMS256.txt`); + if (!response.ok) { + throw new Error(`Failed to get SHASUMS for Node.js v${version}: ${response.statusText}`); + } + const text = await response.text(); + + return text + .split('\n') + .filter(Boolean) + .map((line: string): RepositoryInfo | undefined => { + const [sha, filename] = line.trim().split(/\s+/); + if (!filename) return undefined; + + const fileTypeSuffix = filename.replace(/^node-v[\d.]+-/, ''); + const type = REPOSITORY_TYPES[fileTypeSuffix]; + + return type ? {filename, sha, type} : undefined; + }) + .filter((repo): repo is RepositoryInfo => repo !== undefined); +} + +/** Updates the version and integrity in the MODULE.bazel content for PNPM/TS. */ +function updateVersionAndIntegrity( + content: string, + version: string, + integrity: string, + versionRegExp: RegExp, + integrityRegExp: RegExp, + versionKey: string, + integrityKey: string, +): string { + const newVal = `${versionKey} = "${version}"`; + const result = content.replace(versionRegExp, newVal); + + return integrityRegExp.test(result) + ? result.replace(integrityRegExp, `${integrityKey} = "${integrity}"`) + : result.replace(newVal, `${newVal},\n ${integrityKey} = "${integrity}"`); +} + +/** + * Processes a `node.toolchain` block args string and updates it with + * the correct versions and repositories. + */ +async function processNodeToolchainArgs( + args: string, + nvmrcVersion: string | undefined, +): Promise { + const useVersionFromNvm = args.includes('node_version_from_nvmrc'); + const versionMatch = args.match(NODE_VERSION_REGEXP); + let effectiveVersion = versionMatch?.[1]; + + if (useVersionFromNvm) { + if (!nvmrcVersion) { + throw new Error('node_version_from_nvmrc used but .nvmrc not found'); + } + + effectiveVersion = nvmrcVersion; + } else if (effectiveVersion && effectiveVersion !== nvmrcVersion) { + args = args.replace(NODE_VERSION_REGEXP, `node_version = "${nvmrcVersion}"`); + effectiveVersion = nvmrcVersion; + } + if (!effectiveVersion) { + return args; + } + + Log.info(`Resolving Node.js repositories for v${effectiveVersion}...`); + const repositories = await getNodeJsRepositories(effectiveVersion); + const lines = repositories.map(({filename, sha, type}) => { + const strippedFilename = filename.replace(/(\.tar)?\.[^.]+$/, ''); + + return ` "${effectiveVersion}-${type}": ("${filename}", "${strippedFilename}", "${sha}"),`; + }); + + const reposDict = `{\n${lines.join('\n')}\n }`; + + if (NODE_REPOSITORIES_REGEXP.test(args)) { + return args.replace(NODE_REPOSITORIES_REGEXP, `node_repositories = ${reposDict}`); + } + + const separator = args.trim().endsWith(',') ? '' : ','; + return `${args.trim()}${separator}\n node_repositories = ${reposDict}\n`; +} + +/** Synchronizes the PNPM version and integrity in MODULE.bazel. */ +export async function syncPnpm(content: string, version: string): Promise { + if (!PNPM_VERSION_REGEXP.test(content)) { + return content; + } + + Log.info(`Resolving integrity for pnpm@${version}...`); + const pnpmIntegrity = await getNpmPackageIntegrity('pnpm', version); + + return updateVersionAndIntegrity( + content, + version, + pnpmIntegrity, + PNPM_VERSION_REGEXP, + PNPM_INTEGRITY_REGEXP, + 'pnpm_version', + 'pnpm_version_integrity', + ); +} + +/** Synchronizes the TypeScript version and integrity in MODULE.bazel. */ +export async function syncTypeScript(content: string, version: string): Promise { + if (!TS_VERSION_REGEXP.test(content)) { + return content; + } + + Log.info(`Resolving integrity for typescript@${version}...`); + const tsIntegrity = await getNpmPackageIntegrity('typescript', version); + + return updateVersionAndIntegrity( + content, + version, + tsIntegrity, + TS_VERSION_REGEXP, + TS_INTEGRITY_REGEXP, + 'ts_version', + 'ts_integrity', + ); +} + +/** Finds the index of the closing parenthesis for a balanced block. */ +function findClosedParenIndex(content: string, startIndex: number): number { + let balance = 1; + + for (let i = startIndex + 1; i < content.length; i++) { + if (content[i] === '(') { + balance++; + } else if (content[i] === ')') { + balance--; + } + + if (balance === 0) { + return i; + } + } + + return -1; +} + +/** Synchronizes the Node.js toolchain versions and repositories in MODULE.bazel. */ +export async function syncNodeJs( + content: string, + nvmrcVersion: string | undefined, +): Promise { + const parts: string[] = []; + let lastIndex = 0; + let startIndex = 0; + + while ((startIndex = content.indexOf('node.toolchain(', startIndex)) !== -1) { + const openParenIndex = startIndex + 'node.toolchain('.length - 1; + const endIndex = findClosedParenIndex(content, openParenIndex); + + if (endIndex === -1) { + break; + } + + parts.push(content.slice(lastIndex, startIndex)); + + const args = content.slice(openParenIndex + 1, endIndex); + const updatedArgs = await processNodeToolchainArgs(args, nvmrcVersion); + parts.push(`node.toolchain(${updatedArgs})`); + + lastIndex = endIndex + 1; + startIndex = lastIndex; + } + + parts.push(content.slice(lastIndex)); + + return parts.join(''); +} diff --git a/renovate-presets/default.json5 b/renovate-presets/default.json5 index 931a2be1e..c1fa9c038 100644 --- a/renovate-presets/default.json5 +++ b/renovate-presets/default.json5 @@ -61,13 +61,13 @@ // Enable 'postUpdateTasks' for changes that effect the typescript and pnpm versions. // This is to ensure that the `MODULE.bazel` is updated with the correct versions. { - matchManagers: ['npm'], - matchDepNames: ['pnpm', 'typescript'], + matchManagers: ['npm', 'nvm'], + matchDepNames: ['pnpm', 'typescript', 'node'], postUpgradeTasks: { commands: [ - 'git restore .npmrc || true', // In case `.npmrc` avoid a hard error. + 'bash -c "git restore .npmrc || true"', // If `.npmrc` doesn't exist, avoid a hard error. 'pnpm install --frozen-lockfile', - 'pnpm ng-dev misc sync-module-bazel || true', // TODO(alanagius): Remove || true once all repos update to the latest ng-dev. + 'bash -c "pnpm ng-dev misc sync-module-bazel || true"', // If `ng-dev` doesn't exist, avoid a hard error. ], executionMode: 'branch', }, From 3964af92de742e15c748b9dba8d2b8e66a63d7e0 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Fri, 9 Jan 2026 17:10:14 +0000 Subject: [PATCH 3/3] fixup! feat(ng-dev): add `sync-module-bazel` command to update `pnpm` and `typescript` versions and integrity in `MODULE.bazel` --- ng-dev/misc/BUILD.bazel | 1 + ng-dev/misc/sync-module-bazel/cli.ts | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ng-dev/misc/BUILD.bazel b/ng-dev/misc/BUILD.bazel index a5207f360..72581d588 100644 --- a/ng-dev/misc/BUILD.bazel +++ b/ng-dev/misc/BUILD.bazel @@ -7,6 +7,7 @@ ts_project( deps = [ "//ng-dev:node_modules/@types/node", "//ng-dev:node_modules/@types/yargs", + "//ng-dev/format", "//ng-dev/release/build", "//ng-dev/release/config", "//ng-dev/utils", diff --git a/ng-dev/misc/sync-module-bazel/cli.ts b/ng-dev/misc/sync-module-bazel/cli.ts index d0230a94e..47b9e6e5e 100644 --- a/ng-dev/misc/sync-module-bazel/cli.ts +++ b/ng-dev/misc/sync-module-bazel/cli.ts @@ -12,6 +12,7 @@ import {join} from 'node:path'; import {determineRepoBaseDirFromCwd} from '../../utils/repo-directory'; import {PackageJson, syncNodeJs, syncPnpm, syncTypeScript} from './sync-module-bazel'; import {ChildProcess} from '../../utils/child-process'; +import {formatFiles} from '../../format/format'; async function builder(argv: Argv) { return argv; @@ -55,7 +56,8 @@ async function handler() { if (originalBazelContent !== moduleBazelContent) { writeFileSync(moduleBazelPath, moduleBazelContent); - ChildProcess.spawnSync('pnpm', ['buildifier', 'MODULE.bazel']); + await formatFiles(['MODULE.bazel']); + ChildProcess.spawnSync('pnpm', ['bazel', 'mod', 'deps', '--lockfile_mode=update'], { suppressErrorOnFailingExitCode: true, });