From 95425319adb2b09acc815f9a5cfc69cb67902b9f Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Mon, 14 Sep 2026 22:14:10 -0400 Subject: [PATCH 1/2] Use Executable.waitForExitAsync. --- .../actions/BumpDecoupledLocalDependencies.ts | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/repo-scripts/repo-toolbox/src/cli/actions/BumpDecoupledLocalDependencies.ts b/repo-scripts/repo-toolbox/src/cli/actions/BumpDecoupledLocalDependencies.ts index c109fdc282..b7ba4ccfec 100644 --- a/repo-scripts/repo-toolbox/src/cli/actions/BumpDecoupledLocalDependencies.ts +++ b/repo-scripts/repo-toolbox/src/cli/actions/BumpDecoupledLocalDependencies.ts @@ -10,24 +10,16 @@ import type { IRushConfigurationJson } from '@microsoft/rush-lib/lib/api/RushCon import { CommandLineAction } from '@rushstack/ts-command-line'; async function _getLatestPublishedVersionAsync(terminal: ITerminal, packageName: string): Promise { - return await new Promise((resolve: (result: string) => void, reject: (error: Error) => void) => { - const childProcess: ChildProcess = Executable.spawn('npm', ['view', packageName, 'version'], { - stdio: ['ignore', 'pipe', 'pipe'] - }); - const stdoutBuffer: string[] = []; - childProcess.stdout!.on('data', (chunk) => stdoutBuffer.push(chunk)); - childProcess.on('close', (exitCode: number | null, signal: NodeJS.Signals | null) => { - if (exitCode) { - reject(new Error(`Exited with ${exitCode}`)); - } else if (signal) { - reject(new Error(`Terminated by ${signal}`)); - } else { - const version: string = stdoutBuffer.join('').trim(); - terminal.writeLine(`Found version "${version}" for "${packageName}"`); - resolve(version); - } - }); + const childProcess: ChildProcess = Executable.spawn('npm', ['view', packageName, 'version'], { + stdio: ['ignore', 'pipe', 'pipe'] + }); + const { stdout: version } = await Executable.waitForExitAsync(childProcess, { + encoding: 'utf-8', + throwOnNonZeroExitCode: true, + throwOnSignal: true }); + terminal.writeLine(`Found version "${version}" for "${packageName}"`); + return version; } interface IProjectLike { From 2bc07fc3b89c7cc45dd3b7e1071b0929a3308c8b Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Tue, 15 Sep 2026 13:56:17 -0400 Subject: [PATCH 2/2] Allow selecting the feed for decoupled dependency bumps --- .../azure-pipelines/npm-post-publish.yaml | 5 ++- .../actions/BumpDecoupledLocalDependencies.ts | 35 ++++++++++++++++--- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index 06bde01cc1..0dbe3b3b7e 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -115,9 +115,12 @@ extends: --verbose DisplayName: 'Rush Build (repo-toolbox)' + # Query the public feed directly to bypass propagation latency in the private feed. - template: /common/config/azure-pipelines/templates/run-repo-toolbox.yaml@self parameters: - Arguments: 'bump-decoupled-local-dependencies' + Arguments: > + bump-decoupled-local-dependencies + --feed-url https://registry.npmjs.org/ DisplayName: 'Bump decoupled local dependencies' # If Rush itself was updated by bump-decoupled-local-dependencies, we need to bootstrap diff --git a/repo-scripts/repo-toolbox/src/cli/actions/BumpDecoupledLocalDependencies.ts b/repo-scripts/repo-toolbox/src/cli/actions/BumpDecoupledLocalDependencies.ts index b7ba4ccfec..77b26b03b6 100644 --- a/repo-scripts/repo-toolbox/src/cli/actions/BumpDecoupledLocalDependencies.ts +++ b/repo-scripts/repo-toolbox/src/cli/actions/BumpDecoupledLocalDependencies.ts @@ -7,10 +7,19 @@ import { Async, Executable, FileSystem, type FolderItem, JsonFile } from '@rushs import type { ITerminal } from '@rushstack/terminal'; import { DependencyType, PackageJsonEditor, RushConfiguration, type Subspace } from '@microsoft/rush-lib'; import type { IRushConfigurationJson } from '@microsoft/rush-lib/lib/api/RushConfiguration'; -import { CommandLineAction } from '@rushstack/ts-command-line'; +import { CommandLineAction, type CommandLineStringParameter } from '@rushstack/ts-command-line'; + +async function _getLatestPublishedVersionAsync( + terminal: ITerminal, + packageName: string, + feedUrl: string | undefined +): Promise { + const npmArgs: string[] = ['view', packageName, 'version']; + if (feedUrl) { + npmArgs.push('--registry', feedUrl); + } -async function _getLatestPublishedVersionAsync(terminal: ITerminal, packageName: string): Promise { - const childProcess: ChildProcess = Executable.spawn('npm', ['view', packageName, 'version'], { + const childProcess: ChildProcess = Executable.spawn('npm', npmArgs, { stdio: ['ignore', 'pipe', 'pipe'] }); const { stdout: version } = await Executable.waitForExitAsync(childProcess, { @@ -30,6 +39,7 @@ interface IProjectLike { } export class BumpDecoupledLocalDependencies extends CommandLineAction { + readonly #feedUrlParameter: CommandLineStringParameter; readonly #terminal: ITerminal; public constructor(terminal: ITerminal) { @@ -40,10 +50,17 @@ export class BumpDecoupledLocalDependencies extends CommandLineAction { }); this.#terminal = terminal; + + this.#feedUrlParameter = this.defineStringParameter({ + parameterLongName: '--feed-url', + description: 'The package feed URL to query for the latest published versions.', + argumentName: 'FEED_URL' + }); } protected override async onExecuteAsync(): Promise { const terminal: ITerminal = this.#terminal; + const feedUrl: string | undefined = this.#feedUrlParameter.value; const rushConfiguration: RushConfiguration = RushConfiguration.loadFromDefaultLocation({ startingFolder: process.cwd() }); @@ -117,7 +134,11 @@ export class BumpDecoupledLocalDependencies extends CommandLineAction { await Async.forEachAsync( allDecoupledLocalDependencyNames, async (decoupledLocalDependencyName) => { - const version: string = await _getLatestPublishedVersionAsync(terminal, decoupledLocalDependencyName); + const version: string = await _getLatestPublishedVersionAsync( + terminal, + decoupledLocalDependencyName, + feedUrl + ); decoupledLocalDependencyVersionsByName.set(decoupledLocalDependencyName, version); }, { @@ -170,7 +191,11 @@ export class BumpDecoupledLocalDependencies extends CommandLineAction { terminal.writeLine(); // Update the Rush version in rush.json - const latestRushVersion: string = await _getLatestPublishedVersionAsync(terminal, '@microsoft/rush'); + const latestRushVersion: string = await _getLatestPublishedVersionAsync( + terminal, + '@microsoft/rush', + feedUrl + ); const rushJson: IRushConfigurationJson = await JsonFile.loadAsync(rushJsonFile); const existingRushVersion: string = rushJson.rushVersion; const rushWasUpdated: boolean = existingRushVersion !== latestRushVersion;