From f833baf5324a610022d1421ea8be852521c11c3f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Dec 2025 22:55:44 +0000 Subject: [PATCH 1/9] Initial plan From 41311b36f07bc6612056afd308b99d76973557d5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Dec 2025 23:11:21 +0000 Subject: [PATCH 2/9] Add IgnoredParametersPlugin to forward parameterNamesToIgnore to environment variable Co-authored-by: dmichon-msft <26827560+dmichon-msft@users.noreply.github.com> --- .../cli/scriptActions/PhasedScriptAction.ts | 4 + .../operations/IgnoredParametersPlugin.ts | 30 +++ .../test/IgnoredParametersPlugin.test.ts | 211 ++++++++++++++++++ 3 files changed, 245 insertions(+) create mode 100644 libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts create mode 100644 libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts diff --git a/libraries/rush-lib/src/cli/scriptActions/PhasedScriptAction.ts b/libraries/rush-lib/src/cli/scriptActions/PhasedScriptAction.ts index b7d7ef8a692..6bf22cd9c18 100644 --- a/libraries/rush-lib/src/cli/scriptActions/PhasedScriptAction.ts +++ b/libraries/rush-lib/src/cli/scriptActions/PhasedScriptAction.ts @@ -59,6 +59,7 @@ import { WeightedOperationPlugin } from '../../logic/operations/WeightedOperatio import { getVariantAsync, VARIANT_PARAMETER } from '../../api/Variants'; import { Selection } from '../../logic/Selection'; import { NodeDiagnosticDirPlugin } from '../../logic/operations/NodeDiagnosticDirPlugin'; +import { IgnoredParametersPlugin } from '../../logic/operations/IgnoredParametersPlugin'; import { DebugHashesPlugin } from '../../logic/operations/DebugHashesPlugin'; import { measureAsyncFn, measureFn } from '../../utilities/performance'; @@ -409,6 +410,9 @@ export class PhasedScriptAction extends BaseScriptAction i new WeightedOperationPlugin().apply(hooks); new ValidateOperationsPlugin(terminal).apply(hooks); + // Forward ignored parameters to child processes as an environment variable + new IgnoredParametersPlugin().apply(hooks); + const showTimeline: boolean = this._timelineParameter?.value ?? false; if (showTimeline) { const { ConsoleTimelinePlugin } = await import( diff --git a/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts b/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts new file mode 100644 index 00000000000..928f1332d28 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IPhasedCommandPlugin, PhasedCommandHooks } from '../../pluginFramework/PhasedCommandHooks'; +import type { IEnvironment } from '../../utilities/Utilities'; +import type { IOperationExecutionResult } from './IOperationExecutionResult'; + +const PLUGIN_NAME: 'IgnoredParametersPlugin' = 'IgnoredParametersPlugin'; + +/** + * Phased command plugin that forwards the value of the `parameterNamesToIgnore` operation setting + * to child processes as the RUSHSTACK_OPERATION_IGNORED_PARAMETERS environment variable. + */ +export class IgnoredParametersPlugin implements IPhasedCommandPlugin { + public apply(hooks: PhasedCommandHooks): void { + hooks.createEnvironmentForOperation.tap( + PLUGIN_NAME, + (env: IEnvironment, record: IOperationExecutionResult) => { + const { settings } = record.operation; + + // If there are parameter names to ignore, set the environment variable + if (settings?.parameterNamesToIgnore && settings.parameterNamesToIgnore.length > 0) { + env.RUSHSTACK_OPERATION_IGNORED_PARAMETERS = settings.parameterNamesToIgnore.join(' '); + } + + return env; + } + ); + } +} diff --git a/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts b/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts new file mode 100644 index 00000000000..3e60092e0c6 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts @@ -0,0 +1,211 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import path from 'node:path'; +import { JsonFile } from '@rushstack/node-core-library'; +import { ConsoleTerminalProvider, Terminal } from '@rushstack/terminal'; + +import { RushConfiguration } from '../../../api/RushConfiguration'; +import { CommandLineConfiguration, type IPhasedCommandConfig } from '../../../api/CommandLineConfiguration'; +import type { Operation } from '../Operation'; +import type { ICommandLineJson } from '../../../api/CommandLineJson'; +import { PhasedOperationPlugin } from '../PhasedOperationPlugin'; +import { ShellOperationRunnerPlugin } from '../ShellOperationRunnerPlugin'; +import { IgnoredParametersPlugin } from '../IgnoredParametersPlugin'; +import { + type ICreateOperationsContext, + PhasedCommandHooks +} from '../../../pluginFramework/PhasedCommandHooks'; +import { RushProjectConfiguration } from '../../../api/RushProjectConfiguration'; +import type { IEnvironment } from '../../../utilities/Utilities'; + +describe(IgnoredParametersPlugin.name, () => { + it('should set RUSHSTACK_OPERATION_IGNORED_PARAMETERS environment variable', async () => { + const rushJsonFile: string = path.resolve(__dirname, `../../test/parameterIgnoringRepo/rush.json`); + const commandLineJsonFile: string = path.resolve( + __dirname, + `../../test/parameterIgnoringRepo/common/config/rush/command-line.json` + ); + + const rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + const commandLineJson: ICommandLineJson = JsonFile.load(commandLineJsonFile); + + const commandLineConfiguration = new CommandLineConfiguration(commandLineJson); + const buildCommand: IPhasedCommandConfig = commandLineConfiguration.commands.get( + 'build' + )! as IPhasedCommandConfig; + + // Load project configurations + const terminalProvider: ConsoleTerminalProvider = new ConsoleTerminalProvider(); + const terminal: Terminal = new Terminal(terminalProvider); + + const projectConfigurations = await RushProjectConfiguration.tryLoadForProjectsAsync( + rushConfiguration.projects, + terminal + ); + + const fakeCreateOperationsContext: Pick< + ICreateOperationsContext, + | 'phaseOriginal' + | 'phaseSelection' + | 'projectSelection' + | 'projectsInUnknownState' + | 'projectConfigurations' + | 'rushConfiguration' + > = { + phaseOriginal: buildCommand.phases, + phaseSelection: buildCommand.phases, + projectSelection: new Set(rushConfiguration.projects), + projectsInUnknownState: new Set(rushConfiguration.projects), + projectConfigurations, + rushConfiguration + }; + + const hooks: PhasedCommandHooks = new PhasedCommandHooks(); + + // Apply plugins + new PhasedOperationPlugin().apply(hooks); + new ShellOperationRunnerPlugin().apply(hooks); + new IgnoredParametersPlugin().apply(hooks); + + const operations: Set = await hooks.createOperations.promise( + new Set(), + fakeCreateOperationsContext as ICreateOperationsContext + ); + + // Test project 'a' which has parameterNamesToIgnore: ["--production"] + const operationA = Array.from(operations).find((op) => op.name === 'a'); + expect(operationA).toBeDefined(); + + // Create a mock operation execution result with required fields + const mockRecordA = { + operation: operationA!, + collatedWriter: {} as any, + debugMode: false, + quietMode: true, + _operationMetadataManager: {} as any, + stopwatch: {} as any, + status: {} as any, + environment: undefined, + error: undefined, + silent: false, + stdioSummarizer: {} as any, + problemCollector: {} as any, + nonCachedDurationMs: undefined, + metadataFolderPath: undefined, + logFilePaths: undefined, + getStateHash: () => '', + getStateHashComponents: () => [], + runWithTerminalAsync: async () => {} + } as any; + + // Call the hook to get the environment + const envA: IEnvironment = hooks.createEnvironmentForOperation.call({ ...process.env }, mockRecordA); + + // Verify the environment variable is set correctly for project 'a' + expect(envA.RUSHSTACK_OPERATION_IGNORED_PARAMETERS).toBe('--production'); + + // Test project 'b' which has parameterNamesToIgnore: ["--verbose", "--config", "--mode", "--tags"] + const operationB = Array.from(operations).find((op) => op.name === 'b'); + expect(operationB).toBeDefined(); + + const mockRecordB = { + operation: operationB!, + collatedWriter: {} as any, + debugMode: false, + quietMode: true, + _operationMetadataManager: {} as any, + stopwatch: {} as any, + status: {} as any, + environment: undefined, + error: undefined, + silent: false, + stdioSummarizer: {} as any, + problemCollector: {} as any, + nonCachedDurationMs: undefined, + metadataFolderPath: undefined, + logFilePaths: undefined, + getStateHash: () => '', + getStateHashComponents: () => [], + runWithTerminalAsync: async () => {} + } as any; + + const envB: IEnvironment = hooks.createEnvironmentForOperation.call({ ...process.env }, mockRecordB); + + // Verify the environment variable is set correctly for project 'b' + expect(envB.RUSHSTACK_OPERATION_IGNORED_PARAMETERS).toBe('--verbose --config --mode --tags'); + }); + + it('should not set environment variable when parameterNamesToIgnore is not specified', async () => { + const rushJsonFile: string = path.resolve(__dirname, `../../test/customShellCommandinBulkRepo/rush.json`); + const commandLineJsonFile: string = path.resolve( + __dirname, + `../../test/customShellCommandinBulkRepo/common/config/rush/command-line.json` + ); + + const rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + const commandLineJson: ICommandLineJson = JsonFile.load(commandLineJsonFile); + + const commandLineConfiguration = new CommandLineConfiguration(commandLineJson); + const echoCommand: IPhasedCommandConfig = commandLineConfiguration.commands.get( + 'echo' + )! as IPhasedCommandConfig; + + const fakeCreateOperationsContext: Pick< + ICreateOperationsContext, + | 'phaseOriginal' + | 'phaseSelection' + | 'projectSelection' + | 'projectsInUnknownState' + | 'projectConfigurations' + > = { + phaseOriginal: echoCommand.phases, + phaseSelection: echoCommand.phases, + projectSelection: new Set(rushConfiguration.projects), + projectsInUnknownState: new Set(rushConfiguration.projects), + projectConfigurations: new Map() + }; + + const hooks: PhasedCommandHooks = new PhasedCommandHooks(); + + // Apply plugins + new PhasedOperationPlugin().apply(hooks); + new ShellOperationRunnerPlugin().apply(hooks); + new IgnoredParametersPlugin().apply(hooks); + + const operations: Set = await hooks.createOperations.promise( + new Set(), + fakeCreateOperationsContext as ICreateOperationsContext + ); + + // Get any operation + const operation = Array.from(operations)[0]; + expect(operation).toBeDefined(); + + const mockRecord = { + operation, + collatedWriter: {} as any, + debugMode: false, + quietMode: true, + _operationMetadataManager: {} as any, + stopwatch: {} as any, + status: {} as any, + environment: undefined, + error: undefined, + silent: false, + stdioSummarizer: {} as any, + problemCollector: {} as any, + nonCachedDurationMs: undefined, + metadataFolderPath: undefined, + logFilePaths: undefined, + getStateHash: () => '', + getStateHashComponents: () => [], + runWithTerminalAsync: async () => {} + } as any; + + const env: IEnvironment = hooks.createEnvironmentForOperation.call({ ...process.env }, mockRecord); + + // Verify the environment variable is not set + expect(env.RUSHSTACK_OPERATION_IGNORED_PARAMETERS).toBeUndefined(); + }); +}); From c6b1c1ddf8146b7d9633c1aec083db99242fec7f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Dec 2025 23:15:01 +0000 Subject: [PATCH 3/9] Refactor tests to use helper function for mock objects Co-authored-by: dmichon-msft <26827560+dmichon-msft@users.noreply.github.com> --- .../test/IgnoredParametersPlugin.test.ts | 93 +++++++------------ 1 file changed, 32 insertions(+), 61 deletions(-) diff --git a/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts b/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts index 3e60092e0c6..dc397534a43 100644 --- a/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts +++ b/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts @@ -19,6 +19,32 @@ import { import { RushProjectConfiguration } from '../../../api/RushProjectConfiguration'; import type { IEnvironment } from '../../../utilities/Utilities'; +/** + * Helper function to create a minimal mock record for testing the createEnvironmentForOperation hook + */ +function createMockRecord(operation: Operation): any { + return { + operation, + collatedWriter: {} as any, + debugMode: false, + quietMode: true, + _operationMetadataManager: {} as any, + stopwatch: {} as any, + status: {} as any, + environment: undefined, + error: undefined, + silent: false, + stdioSummarizer: {} as any, + problemCollector: {} as any, + nonCachedDurationMs: undefined, + metadataFolderPath: undefined, + logFilePaths: undefined, + getStateHash: () => '', + getStateHashComponents: () => [], + runWithTerminalAsync: async () => {} + }; +} + describe(IgnoredParametersPlugin.name, () => { it('should set RUSHSTACK_OPERATION_IGNORED_PARAMETERS environment variable', async () => { const rushJsonFile: string = path.resolve(__dirname, `../../test/parameterIgnoringRepo/rush.json`); @@ -78,26 +104,7 @@ describe(IgnoredParametersPlugin.name, () => { expect(operationA).toBeDefined(); // Create a mock operation execution result with required fields - const mockRecordA = { - operation: operationA!, - collatedWriter: {} as any, - debugMode: false, - quietMode: true, - _operationMetadataManager: {} as any, - stopwatch: {} as any, - status: {} as any, - environment: undefined, - error: undefined, - silent: false, - stdioSummarizer: {} as any, - problemCollector: {} as any, - nonCachedDurationMs: undefined, - metadataFolderPath: undefined, - logFilePaths: undefined, - getStateHash: () => '', - getStateHashComponents: () => [], - runWithTerminalAsync: async () => {} - } as any; + const mockRecordA = createMockRecord(operationA!); // Call the hook to get the environment const envA: IEnvironment = hooks.createEnvironmentForOperation.call({ ...process.env }, mockRecordA); @@ -109,26 +116,7 @@ describe(IgnoredParametersPlugin.name, () => { const operationB = Array.from(operations).find((op) => op.name === 'b'); expect(operationB).toBeDefined(); - const mockRecordB = { - operation: operationB!, - collatedWriter: {} as any, - debugMode: false, - quietMode: true, - _operationMetadataManager: {} as any, - stopwatch: {} as any, - status: {} as any, - environment: undefined, - error: undefined, - silent: false, - stdioSummarizer: {} as any, - problemCollector: {} as any, - nonCachedDurationMs: undefined, - metadataFolderPath: undefined, - logFilePaths: undefined, - getStateHash: () => '', - getStateHashComponents: () => [], - runWithTerminalAsync: async () => {} - } as any; + const mockRecordB = createMockRecord(operationB!); const envB: IEnvironment = hooks.createEnvironmentForOperation.call({ ...process.env }, mockRecordB); @@ -158,12 +146,14 @@ describe(IgnoredParametersPlugin.name, () => { | 'projectSelection' | 'projectsInUnknownState' | 'projectConfigurations' + | 'rushConfiguration' > = { phaseOriginal: echoCommand.phases, phaseSelection: echoCommand.phases, projectSelection: new Set(rushConfiguration.projects), projectsInUnknownState: new Set(rushConfiguration.projects), - projectConfigurations: new Map() + projectConfigurations: new Map(), + rushConfiguration }; const hooks: PhasedCommandHooks = new PhasedCommandHooks(); @@ -182,26 +172,7 @@ describe(IgnoredParametersPlugin.name, () => { const operation = Array.from(operations)[0]; expect(operation).toBeDefined(); - const mockRecord = { - operation, - collatedWriter: {} as any, - debugMode: false, - quietMode: true, - _operationMetadataManager: {} as any, - stopwatch: {} as any, - status: {} as any, - environment: undefined, - error: undefined, - silent: false, - stdioSummarizer: {} as any, - problemCollector: {} as any, - nonCachedDurationMs: undefined, - metadataFolderPath: undefined, - logFilePaths: undefined, - getStateHash: () => '', - getStateHashComponents: () => [], - runWithTerminalAsync: async () => {} - } as any; + const mockRecord = createMockRecord(operation); const env: IEnvironment = hooks.createEnvironmentForOperation.call({ ...process.env }, mockRecord); From 490659bf5e894c097e98b516643ca45c67498ac6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Dec 2025 23:17:57 +0000 Subject: [PATCH 4/9] Address code review feedback - simplify PLUGIN_NAME constant Co-authored-by: dmichon-msft <26827560+dmichon-msft@users.noreply.github.com> --- .../rush-lib/src/logic/operations/IgnoredParametersPlugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts b/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts index 928f1332d28..5d853b3dce1 100644 --- a/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts +++ b/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts @@ -5,7 +5,7 @@ import type { IPhasedCommandPlugin, PhasedCommandHooks } from '../../pluginFrame import type { IEnvironment } from '../../utilities/Utilities'; import type { IOperationExecutionResult } from './IOperationExecutionResult'; -const PLUGIN_NAME: 'IgnoredParametersPlugin' = 'IgnoredParametersPlugin'; +const PLUGIN_NAME: string = 'IgnoredParametersPlugin'; /** * Phased command plugin that forwards the value of the `parameterNamesToIgnore` operation setting From ddc3cca6d13ea2eb03f52e33400237a338dbb57a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Dec 2025 23:59:14 +0000 Subject: [PATCH 5/9] Address feedback: export env var constant and simplify test mocks Co-authored-by: dmichon-msft <26827560+dmichon-msft@users.noreply.github.com> --- .../operations/IgnoredParametersPlugin.ts | 9 ++++- .../test/IgnoredParametersPlugin.test.ts | 35 +++++++------------ 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts b/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts index 5d853b3dce1..c58b7f6cc7e 100644 --- a/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts +++ b/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts @@ -7,6 +7,13 @@ import type { IOperationExecutionResult } from './IOperationExecutionResult'; const PLUGIN_NAME: string = 'IgnoredParametersPlugin'; +/** + * Environment variable name for forwarding ignored parameters to child processes + * @public + */ +export const RUSHSTACK_OPERATION_IGNORED_PARAMETERS_ENV_VAR: string = + 'RUSHSTACK_OPERATION_IGNORED_PARAMETERS'; + /** * Phased command plugin that forwards the value of the `parameterNamesToIgnore` operation setting * to child processes as the RUSHSTACK_OPERATION_IGNORED_PARAMETERS environment variable. @@ -20,7 +27,7 @@ export class IgnoredParametersPlugin implements IPhasedCommandPlugin { // If there are parameter names to ignore, set the environment variable if (settings?.parameterNamesToIgnore && settings.parameterNamesToIgnore.length > 0) { - env.RUSHSTACK_OPERATION_IGNORED_PARAMETERS = settings.parameterNamesToIgnore.join(' '); + env[RUSHSTACK_OPERATION_IGNORED_PARAMETERS_ENV_VAR] = settings.parameterNamesToIgnore.join(' '); } return env; diff --git a/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts b/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts index dc397534a43..4730e8a167e 100644 --- a/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts +++ b/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts @@ -11,38 +11,27 @@ import type { Operation } from '../Operation'; import type { ICommandLineJson } from '../../../api/CommandLineJson'; import { PhasedOperationPlugin } from '../PhasedOperationPlugin'; import { ShellOperationRunnerPlugin } from '../ShellOperationRunnerPlugin'; -import { IgnoredParametersPlugin } from '../IgnoredParametersPlugin'; +import { + IgnoredParametersPlugin, + RUSHSTACK_OPERATION_IGNORED_PARAMETERS_ENV_VAR +} from '../IgnoredParametersPlugin'; import { type ICreateOperationsContext, PhasedCommandHooks } from '../../../pluginFramework/PhasedCommandHooks'; import { RushProjectConfiguration } from '../../../api/RushProjectConfiguration'; import type { IEnvironment } from '../../../utilities/Utilities'; +import type { IOperationRunnerContext } from '../IOperationRunner'; +import type { IOperationExecutionResult } from '../IOperationExecutionResult'; /** * Helper function to create a minimal mock record for testing the createEnvironmentForOperation hook */ -function createMockRecord(operation: Operation): any { +function createMockRecord(operation: Operation): IOperationRunnerContext & IOperationExecutionResult { return { operation, - collatedWriter: {} as any, - debugMode: false, - quietMode: true, - _operationMetadataManager: {} as any, - stopwatch: {} as any, - status: {} as any, - environment: undefined, - error: undefined, - silent: false, - stdioSummarizer: {} as any, - problemCollector: {} as any, - nonCachedDurationMs: undefined, - metadataFolderPath: undefined, - logFilePaths: undefined, - getStateHash: () => '', - getStateHashComponents: () => [], - runWithTerminalAsync: async () => {} - }; + environment: undefined + } as IOperationRunnerContext & IOperationExecutionResult; } describe(IgnoredParametersPlugin.name, () => { @@ -110,7 +99,7 @@ describe(IgnoredParametersPlugin.name, () => { const envA: IEnvironment = hooks.createEnvironmentForOperation.call({ ...process.env }, mockRecordA); // Verify the environment variable is set correctly for project 'a' - expect(envA.RUSHSTACK_OPERATION_IGNORED_PARAMETERS).toBe('--production'); + expect(envA[RUSHSTACK_OPERATION_IGNORED_PARAMETERS_ENV_VAR]).toBe('--production'); // Test project 'b' which has parameterNamesToIgnore: ["--verbose", "--config", "--mode", "--tags"] const operationB = Array.from(operations).find((op) => op.name === 'b'); @@ -121,7 +110,7 @@ describe(IgnoredParametersPlugin.name, () => { const envB: IEnvironment = hooks.createEnvironmentForOperation.call({ ...process.env }, mockRecordB); // Verify the environment variable is set correctly for project 'b' - expect(envB.RUSHSTACK_OPERATION_IGNORED_PARAMETERS).toBe('--verbose --config --mode --tags'); + expect(envB[RUSHSTACK_OPERATION_IGNORED_PARAMETERS_ENV_VAR]).toBe('--verbose --config --mode --tags'); }); it('should not set environment variable when parameterNamesToIgnore is not specified', async () => { @@ -177,6 +166,6 @@ describe(IgnoredParametersPlugin.name, () => { const env: IEnvironment = hooks.createEnvironmentForOperation.call({ ...process.env }, mockRecord); // Verify the environment variable is not set - expect(env.RUSHSTACK_OPERATION_IGNORED_PARAMETERS).toBeUndefined(); + expect(env[RUSHSTACK_OPERATION_IGNORED_PARAMETERS_ENV_VAR]).toBeUndefined(); }); }); From cbcf32485f98d493521897f338b34e2e0e45b68d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 02:13:07 +0000 Subject: [PATCH 6/9] Use comma separator for environment variable to clarify enumeration Co-authored-by: dmichon-msft <26827560+dmichon-msft@users.noreply.github.com> --- .../rush-lib/src/logic/operations/IgnoredParametersPlugin.ts | 2 +- .../src/logic/operations/test/IgnoredParametersPlugin.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts b/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts index c58b7f6cc7e..d6f14ceb2de 100644 --- a/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts +++ b/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts @@ -27,7 +27,7 @@ export class IgnoredParametersPlugin implements IPhasedCommandPlugin { // If there are parameter names to ignore, set the environment variable if (settings?.parameterNamesToIgnore && settings.parameterNamesToIgnore.length > 0) { - env[RUSHSTACK_OPERATION_IGNORED_PARAMETERS_ENV_VAR] = settings.parameterNamesToIgnore.join(' '); + env[RUSHSTACK_OPERATION_IGNORED_PARAMETERS_ENV_VAR] = settings.parameterNamesToIgnore.join(','); } return env; diff --git a/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts b/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts index 4730e8a167e..c724fb7bc03 100644 --- a/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts +++ b/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts @@ -110,7 +110,7 @@ describe(IgnoredParametersPlugin.name, () => { const envB: IEnvironment = hooks.createEnvironmentForOperation.call({ ...process.env }, mockRecordB); // Verify the environment variable is set correctly for project 'b' - expect(envB[RUSHSTACK_OPERATION_IGNORED_PARAMETERS_ENV_VAR]).toBe('--verbose --config --mode --tags'); + expect(envB[RUSHSTACK_OPERATION_IGNORED_PARAMETERS_ENV_VAR]).toBe('--verbose,--config,--mode,--tags'); }); it('should not set environment variable when parameterNamesToIgnore is not specified', async () => { From fd280ef9c1e3b9a8ed415c1f2dbd2ef61dbfe5e6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 19:31:12 +0000 Subject: [PATCH 7/9] Rename environment variable to RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES Co-authored-by: dmichon-msft <26827560+dmichon-msft@users.noreply.github.com> --- .../src/logic/operations/IgnoredParametersPlugin.ts | 7 +++---- .../logic/operations/test/IgnoredParametersPlugin.test.ts | 8 ++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts b/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts index d6f14ceb2de..c34f56c48e3 100644 --- a/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts +++ b/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts @@ -11,12 +11,11 @@ const PLUGIN_NAME: string = 'IgnoredParametersPlugin'; * Environment variable name for forwarding ignored parameters to child processes * @public */ -export const RUSHSTACK_OPERATION_IGNORED_PARAMETERS_ENV_VAR: string = - 'RUSHSTACK_OPERATION_IGNORED_PARAMETERS'; +export const RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR: string = 'RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES'; /** * Phased command plugin that forwards the value of the `parameterNamesToIgnore` operation setting - * to child processes as the RUSHSTACK_OPERATION_IGNORED_PARAMETERS environment variable. + * to child processes as the RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES environment variable. */ export class IgnoredParametersPlugin implements IPhasedCommandPlugin { public apply(hooks: PhasedCommandHooks): void { @@ -27,7 +26,7 @@ export class IgnoredParametersPlugin implements IPhasedCommandPlugin { // If there are parameter names to ignore, set the environment variable if (settings?.parameterNamesToIgnore && settings.parameterNamesToIgnore.length > 0) { - env[RUSHSTACK_OPERATION_IGNORED_PARAMETERS_ENV_VAR] = settings.parameterNamesToIgnore.join(','); + env[RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR] = settings.parameterNamesToIgnore.join(','); } return env; diff --git a/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts b/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts index c724fb7bc03..1577ff51a83 100644 --- a/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts +++ b/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts @@ -13,7 +13,7 @@ import { PhasedOperationPlugin } from '../PhasedOperationPlugin'; import { ShellOperationRunnerPlugin } from '../ShellOperationRunnerPlugin'; import { IgnoredParametersPlugin, - RUSHSTACK_OPERATION_IGNORED_PARAMETERS_ENV_VAR + RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR } from '../IgnoredParametersPlugin'; import { type ICreateOperationsContext, @@ -99,7 +99,7 @@ describe(IgnoredParametersPlugin.name, () => { const envA: IEnvironment = hooks.createEnvironmentForOperation.call({ ...process.env }, mockRecordA); // Verify the environment variable is set correctly for project 'a' - expect(envA[RUSHSTACK_OPERATION_IGNORED_PARAMETERS_ENV_VAR]).toBe('--production'); + expect(envA[RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR]).toBe('--production'); // Test project 'b' which has parameterNamesToIgnore: ["--verbose", "--config", "--mode", "--tags"] const operationB = Array.from(operations).find((op) => op.name === 'b'); @@ -110,7 +110,7 @@ describe(IgnoredParametersPlugin.name, () => { const envB: IEnvironment = hooks.createEnvironmentForOperation.call({ ...process.env }, mockRecordB); // Verify the environment variable is set correctly for project 'b' - expect(envB[RUSHSTACK_OPERATION_IGNORED_PARAMETERS_ENV_VAR]).toBe('--verbose,--config,--mode,--tags'); + expect(envB[RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR]).toBe('--verbose,--config,--mode,--tags'); }); it('should not set environment variable when parameterNamesToIgnore is not specified', async () => { @@ -166,6 +166,6 @@ describe(IgnoredParametersPlugin.name, () => { const env: IEnvironment = hooks.createEnvironmentForOperation.call({ ...process.env }, mockRecord); // Verify the environment variable is not set - expect(env[RUSHSTACK_OPERATION_IGNORED_PARAMETERS_ENV_VAR]).toBeUndefined(); + expect(env[RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR]).toBeUndefined(); }); }); From 361478027783ff838b521fa0d095356a54d53d04 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 21:30:47 +0000 Subject: [PATCH 8/9] Add change file for parameterNamesToIgnore environment variable feature Co-authored-by: dmichon-msft <26827560+dmichon-msft@users.noreply.github.com> --- ...rward-parameter-names-ignore_2025-12-10-21-30.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 common/changes/@microsoft/rush/copilot-forward-parameter-names-ignore_2025-12-10-21-30.json diff --git a/common/changes/@microsoft/rush/copilot-forward-parameter-names-ignore_2025-12-10-21-30.json b/common/changes/@microsoft/rush/copilot-forward-parameter-names-ignore_2025-12-10-21-30.json new file mode 100644 index 00000000000..06a244e9141 --- /dev/null +++ b/common/changes/@microsoft/rush/copilot-forward-parameter-names-ignore_2025-12-10-21-30.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Forward parameterNamesToIgnore to child processes via RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES environment variable", + "type": "none", + "packageName": "@microsoft/rush" + } + ], + "packageName": "@microsoft/rush", + "email": "198982749+Copilot@users.noreply.github.com" +} From 6524f79983d0b6999e115a8aac852b10df9da7ea Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 01:06:10 +0000 Subject: [PATCH 9/9] Address feedback: use JSON.stringify for env var and update type annotations Co-authored-by: iclanton <5010588+iclanton@users.noreply.github.com> --- ...-forward-parameter-names-ignore_2025-12-10-21-30.json | 2 +- .../src/logic/operations/IgnoredParametersPlugin.ts | 9 ++++++--- .../operations/test/IgnoredParametersPlugin.test.ts | 6 ++++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/common/changes/@microsoft/rush/copilot-forward-parameter-names-ignore_2025-12-10-21-30.json b/common/changes/@microsoft/rush/copilot-forward-parameter-names-ignore_2025-12-10-21-30.json index 06a244e9141..5879bd3e5f7 100644 --- a/common/changes/@microsoft/rush/copilot-forward-parameter-names-ignore_2025-12-10-21-30.json +++ b/common/changes/@microsoft/rush/copilot-forward-parameter-names-ignore_2025-12-10-21-30.json @@ -1,7 +1,7 @@ { "changes": [ { - "comment": "Forward parameterNamesToIgnore to child processes via RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES environment variable", + "comment": "Forward the `parameterNamesToIgnore` `/config/rush-project.json` property to child processes via a `RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES` environment variable", "type": "none", "packageName": "@microsoft/rush" } diff --git a/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts b/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts index c34f56c48e3..0de6aa422f6 100644 --- a/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts +++ b/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts @@ -5,13 +5,14 @@ import type { IPhasedCommandPlugin, PhasedCommandHooks } from '../../pluginFrame import type { IEnvironment } from '../../utilities/Utilities'; import type { IOperationExecutionResult } from './IOperationExecutionResult'; -const PLUGIN_NAME: string = 'IgnoredParametersPlugin'; +const PLUGIN_NAME: 'IgnoredParametersPlugin' = 'IgnoredParametersPlugin'; /** * Environment variable name for forwarding ignored parameters to child processes * @public */ -export const RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR: string = 'RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES'; +export const RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR: 'RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES' = + 'RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES'; /** * Phased command plugin that forwards the value of the `parameterNamesToIgnore` operation setting @@ -26,7 +27,9 @@ export class IgnoredParametersPlugin implements IPhasedCommandPlugin { // If there are parameter names to ignore, set the environment variable if (settings?.parameterNamesToIgnore && settings.parameterNamesToIgnore.length > 0) { - env[RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR] = settings.parameterNamesToIgnore.join(','); + env[RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR] = JSON.stringify( + settings.parameterNamesToIgnore + ); } return env; diff --git a/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts b/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts index 1577ff51a83..ee6b3fe6d3b 100644 --- a/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts +++ b/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts @@ -99,7 +99,7 @@ describe(IgnoredParametersPlugin.name, () => { const envA: IEnvironment = hooks.createEnvironmentForOperation.call({ ...process.env }, mockRecordA); // Verify the environment variable is set correctly for project 'a' - expect(envA[RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR]).toBe('--production'); + expect(envA[RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR]).toBe('["--production"]'); // Test project 'b' which has parameterNamesToIgnore: ["--verbose", "--config", "--mode", "--tags"] const operationB = Array.from(operations).find((op) => op.name === 'b'); @@ -110,7 +110,9 @@ describe(IgnoredParametersPlugin.name, () => { const envB: IEnvironment = hooks.createEnvironmentForOperation.call({ ...process.env }, mockRecordB); // Verify the environment variable is set correctly for project 'b' - expect(envB[RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR]).toBe('--verbose,--config,--mode,--tags'); + expect(envB[RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR]).toBe( + '["--verbose","--config","--mode","--tags"]' + ); }); it('should not set environment variable when parameterNamesToIgnore is not specified', async () => {