[rush] (BREAKING CHANGE) Overhaul watch-mode to facilitate orchestration#5378
Open
dmichon-msft wants to merge 23 commits into
Open
[rush] (BREAKING CHANGE) Overhaul watch-mode to facilitate orchestration#5378dmichon-msft wants to merge 23 commits into
dmichon-msft wants to merge 23 commits into
Conversation
49f3abe to
2da4c4a
Compare
019bc07 to
7c87ca0
Compare
7c87ca0 to
6726d88
Compare
bmiddha
reviewed
Mar 12, 2026
dmichon-msft
commented
Mar 12, 2026
dmichon-msft
commented
Mar 12, 2026
284dc4c to
2224f15
Compare
iclanton
reviewed
Mar 17, 2026
iclanton
reviewed
Mar 17, 2026
2224f15 to
939b967
Compare
4ba3025 to
289ac41
Compare
bmiddha
approved these changes
Mar 21, 2026
289ac41 to
664d5a8
Compare
664d5a8 to
a3d9683
Compare
There was a problem hiding this comment.
Pull request overview
This PR introduces a new stateful OperationGraph execution model for Rush watch-mode/phased commands, moving per-iteration lifecycle hooks off PhasedCommandHooks and into a dedicated OperationGraphHooks exposed via operationGraph.hooks, to enable better orchestration by plugins across a watch session.
Changes:
- Replace “recreate operations per pass” with a session-long
IOperationGraphand per-iteration hooks (OperationGraphHooks). - Update in-repo plugins (serve, bridge-cache, buildxl graph) to the new
createOperationsAsync+onGraphCreatedAsynclifecycle and new runner contracts. - Add/adjust tests and public API surface for new
OperationGraph/parallelism/state-hash structures and options (e.g. include-all-projects watch graph).
Show a summary per file
| File | Description |
|---|---|
| rush-plugins/rush-serve-plugin/src/phasedCommandHandler.ts | Migrates serve plugin to new phased command lifecycle; adds dependency expansion and graph idle hook. |
| rush-plugins/rush-serve-plugin/src/api.types.ts | Updates WS API contracts for new graph/execution-state model. |
| rush-plugins/rush-serve-plugin/README.md | Updates client example code to new WS message shapes and state handling. |
| rush-plugins/rush-serve-plugin/package.json | Promotes @rushstack/terminal to dependencies. |
| rush-plugins/rush-buildxl-graph-plugin/src/test/GraphProcessor.test.ts | Updates tests to new runner shape/config-hash access. |
| rush-plugins/rush-buildxl-graph-plugin/src/GraphProcessor.ts | Switches graph “command” derivation to runner config hash. |
| rush-plugins/rush-buildxl-graph-plugin/src/DropBuildGraphPlugin.ts | Updates hook usage to createOperationsAsync. |
| rush-plugins/rush-buildxl-graph-plugin/src/debugGraphFiltering.ts | Adjusts debug filtering/return types for updated debug graph shape. |
| rush-plugins/rush-bridge-cache-plugin/src/BridgeCachePlugin.ts | Reworks cache plugin to run via IOperationGraph iteration hooks. |
| libraries/rush-sdk/src/test/snapshots/script.test.ts.snap | Updates SDK export snapshot for new symbols. |
| libraries/rush-lib/src/utilities/test/Stopwatch.test.ts | Adds tests for new startTimeOverride behavior. |
| libraries/rush-lib/src/utilities/Stopwatch.ts | Adds optional startTimeOverride support to start() and static start(). |
| libraries/rush-lib/src/schemas/command-line.schema.json | Adds schema for includeAllProjectsInWatchGraph. |
| libraries/rush-lib/src/pluginFramework/PhasedCommandHooks.ts | Removes old hooks, adds createOperationsAsync and onGraphCreatedAsync + new contexts. |
| libraries/rush-lib/src/pluginFramework/OperationGraphHooks.ts | New hook container for per-iteration and per-operation execution lifecycle. |
| libraries/rush-lib/src/logic/operations/WeightedOperationPlugin.ts | Removes old weight plugin (weight handling moved into execution record). |
| libraries/rush-lib/src/logic/operations/ValidateOperationsPlugin.ts | Moves validation to onGraphCreatedAsync operating on graph operations. |
| libraries/rush-lib/src/logic/operations/test/WeightedOperationPlugin.test.ts | Removes tests for deleted weight plugin. |
| libraries/rush-lib/src/logic/operations/test/ShellOperationRunnerPlugin.test.ts | Updates tests to new hooks/context shape. |
| libraries/rush-lib/src/logic/operations/test/PhasedOperationPlugin.test.ts | Updates tests for new graph lifecycle; adds full-graph enable/disable scenario. |
| libraries/rush-lib/src/logic/operations/test/ParseParallelism.test.ts | Adds new unit tests for parse/coerce parallelism helpers. |
| libraries/rush-lib/src/logic/operations/test/OperationExecutionRecord.test.ts | Adds tests for weight coercion and record behavior. |
| libraries/rush-lib/src/logic/operations/test/Operation.test.ts | Adds tests for new operation weight parsing and validation. |
| libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts | Updates tests to access env hook from graph.hooks. |
| libraries/rush-lib/src/logic/operations/test/BuildPlanPlugin.test.ts | Updates tests to execute via OperationGraph. |
| libraries/rush-lib/src/logic/operations/test/AsyncOperationQueue.test.ts | Updates test setup for new execution record context requirements. |
| libraries/rush-lib/src/logic/operations/test/snapshots/PhasedOperationPlugin.test.ts.snap | Updates snapshots for new selection/config semantics. |
| libraries/rush-lib/src/logic/operations/test/snapshots/ParseParallelism.test.ts.snap | Adds snapshots for new parseParallelism errors. |
| libraries/rush-lib/src/logic/operations/test/snapshots/OperationGraph.test.ts.snap | Renames snapshots to OperationGraph naming. |
| libraries/rush-lib/src/logic/operations/ShellOperationRunnerPlugin.ts | Updates runner initialization for initial/incremental commands. |
| libraries/rush-lib/src/logic/operations/ShellOperationRunner.ts | Updates runner signature + chooses initial vs incremental command per last state. |
| libraries/rush-lib/src/logic/operations/ShardedPhaseOperationPlugin.ts | Updates shell runner initialization signature for shards. |
| libraries/rush-lib/src/logic/operations/PnpmSyncCopyOperationPlugin.ts | Moves hook tap to graph.hooks.afterExecuteOperationAsync. |
| libraries/rush-lib/src/logic/operations/PhasedOperationPlugin.ts | Splits graph construction vs per-iteration enablement logic into graph hook. |
| libraries/rush-lib/src/logic/operations/ParseParallelism.ts | New parallelism parsing/coercion utilities and core-count caching. |
| libraries/rush-lib/src/logic/operations/OperationStatus.ts | Adds SUCCESS_STATUSES helper set. |
| libraries/rush-lib/src/logic/operations/OperationResultSummarizerPlugin.ts | Moves summarizer to afterExecuteIterationAsync. |
| libraries/rush-lib/src/logic/operations/OperationExecutionRecord.ts | Adds per-iteration enabled, weight coercion, invalidation callback, state-hash structuring, and centralized error wrapping. |
| libraries/rush-lib/src/logic/operations/OperationExecutionManager.ts | Deletes old stateless execution manager in favor of OperationGraph. |
| libraries/rush-lib/src/logic/operations/Operation.ts | Adds OperationEnabledState and scalar weight parsing; updates docs. |
| libraries/rush-lib/src/logic/operations/NodeDiagnosticDirPlugin.ts | Moves env mutation hook to graph.hooks.createEnvironmentForOperation. |
| libraries/rush-lib/src/logic/operations/LegacySkipPlugin.ts | Migrates skip logic to graph iteration/operation hooks. |
| libraries/rush-lib/src/logic/operations/IPCOperationRunnerPlugin.ts | Reworks IPC runner selection/commands for new incremental contract and invalidation callback. |
| libraries/rush-lib/src/logic/operations/IPCOperationRunner.ts | Implements lastState-driven initial/incremental command selection; uses invalidate callback; renames shutdown to close. |
| libraries/rush-lib/src/logic/operations/IOperationRunner.ts | Extends runner contract with lastState, invalidation callback, optional active/close. |
| libraries/rush-lib/src/logic/operations/IOperationGraph.ts | New public graph API contract (iteration scheduling, invalidation, enabled states, etc.). |
| libraries/rush-lib/src/logic/operations/IOperationExecutionResult.ts | Introduces structured state hash components and configurable operation/result interfaces. |
| libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts | Moves env mutation to graph hook. |
| libraries/rush-lib/src/logic/operations/DebugHashesPlugin.ts | Moves hash printing to graph iteration config hook and structured hash output. |
| libraries/rush-lib/src/logic/operations/ConsoleTimelinePlugin.ts | Moves timeline printing to afterExecuteIterationAsync. |
| libraries/rush-lib/src/logic/operations/BuildPlanPlugin.ts | Moves build plan generation to graph iteration config hook. |
| libraries/rush-lib/src/logic/buildCache/OperationBuildCache.ts | Generalizes build cache API to accept IBaseOperationExecutionResult. |
| libraries/rush-lib/src/index.ts | Exposes new graph/parallelism/state-hash types and hooks in public index. |
| libraries/rush-lib/src/cli/RushCommandLineParser.ts | Threads new watch option includeAllProjectsInWatchGraph into action setup. |
| libraries/rush-lib/src/cli/parsing/test/ParseParallelism.test.ts | Removes old CLI parsing parallelism tests (moved to operations layer). |
| libraries/rush-lib/src/cli/parsing/SelectionParameterSet.ts | Allows empty selection for watch “full graph” behavior. |
| libraries/rush-lib/src/cli/parsing/ParseParallelism.ts | Removes old parallelism parsing implementation (relocated). |
| libraries/rush-lib/src/api/EventHooks.ts | Minor doc wording update. |
| libraries/rush-lib/src/api/CommandLineJson.ts | Adds includeAllProjectsInWatchGraph to command-line JSON typing. |
| libraries/rush-lib/src/api/CommandLineConfiguration.ts | Plumbs includeAllProjectsInWatchGraph through normalized config. |
| common/reviews/api/rush-lib.api.md | Updates API report to include new graph/hooks/types and breaking changes. |
| common/config/subspaces/default/pnpm-lock.yaml | Updates lockfile for added rush-serve-plugin/terminal linkage. |
| common/config/rush/nonbrowser-approved-packages.json | Approves @rushstack/rush-serve-plugin for nonbrowser usage. |
| common/config/rush/experiments.json | Enables useIPCScriptsInWatchMode. |
| common/config/rush/command-line.json | Adjusts phase dependency declarations; adds --port for start. |
| common/config/rush-plugins/rush-serve-plugin.json | Adds config file for enabling rush-serve-plugin for start. |
| common/changes/@microsoft/rush/watch-rework_2025-09-26-23-50.json | Adds change file documenting breaking change. |
| apps/rush/src/start-dev.ts | Includes rush-serve-plugin in dev start harness. |
| apps/rush/package.json | Adds rush-serve-plugin dependency. |
Review details
Files not reviewed (1)
- common/config/subspaces/default/pnpm-lock.yaml: Generated file
- Files reviewed: 78/80 changed files
- Comments generated: 6
- Review effort level: Low
Comment on lines
52
to
+59
| /** | ||
| * If false, this operation is disabled and will/did not execute during the current run. | ||
| * The status will be reported as `Skipped`. | ||
| * The enabled state of the operation. | ||
| * - `never`: The operation is disabled and will not be executed. | ||
| * - `ignore-dependency-changes`: The operation will be executed if there are local changes in the project, | ||
| * otherwise it will be skipped. | ||
| * - `always`: The operation will be executed if it or any dependencies changed. | ||
| */ | ||
| enabled: boolean; | ||
| enabled: ReadableOperationEnabledState; |
Comment on lines
240
to
+244
| export type IWebSocketEventMessage = | ||
| | IWebSocketBeforeExecuteEventMessage | ||
| | IWebSocketAfterExecuteEventMessage | ||
| | IWebSocketBatchStatusChangeEventMessage | ||
| | IWebSocketSyncEventMessage; | ||
| | IWebSocketBeforeExecuteEventMessage | ||
| | IWebSocketSyncEventMessage |
Comment on lines
+207
to
+213
| /** | ||
| * Message sent to a WebSocket client containing a full refresh of only the dynamic execution states. | ||
| */ | ||
| export interface IWebSocketSyncOperationsEventMessage { | ||
| event: 'sync-operations'; | ||
| operations: IOperationInfo[]; | ||
| } |
Comment on lines
+79
to
83
| const commandToRun: string = (lastState && this._incrementalCommand) || this._initialCommand; | ||
|
|
||
| // Run the operation | ||
| terminal.writeLine(`Invoking: ${this.commandToRun}`); | ||
| terminal.writeLine(`Invoking (${lastState ? 'incremental' : 'initial'}): ${commandToRun}`); | ||
|
|
Comment on lines
+156
to
+159
| this.weight = _getFinalWeight( | ||
| settings?.weight ?? 1, | ||
| runner?.name ?? `${project.packageName} (${phase.name}` | ||
| ); |
Comment on lines
158
to
+160
|
|
||
| terminal.writeLine( | ||
| `Cache operation "${cacheAction}" completed successfully for ${successCount} out of ${filteredOperations.size} operations.` | ||
| // Bail out with a status indicating success; treat cache read as FromCache. | ||
| return cacheAction === CACHE_ACTION_READ ? OperationStatus.FromCache : OperationStatus.Success; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
[rush] (BREAKING CHANGE) Overhaul watch-mode to facilitate orchestration
Summary
Completely retools the watch engine in Rush to facilitate better interaction with plugins that wish to orchestrate the build process. Makes the Rush execution engine stateful across an entire Rush watch session.
BREAKING CHANGES
PhasedCommandHooksnow has only two hooks:createOperationsAsyncandonGraphCreatedAsync. All other hooks have been moved toOperationGraphHooks, accessible viaoperationGraph.hooksinside theonGraphCreatedAsynccallback.createOperationsis nowcreateOperationsAsync, and the properties on theICreateOperationsContextparameter have changed:isInitial,projectsInUnknownState,phaseOriginal, andinvalidateOperationhave been removed;generateFullGraphandincludePhaseDepshave been added.OperationGraphHooksclass. TapoperationGraph.hooksfor:configureIteration— synchronous hook to select which operations run in the next iterationbeforeExecuteIterationAsync— replacesbeforeExecuteOperationsAsyncafterExecuteIterationAsync— replacesafterExecuteOperationsAsyncbeforeExecuteOperationAsync— moved fromPhasedCommandHooksafterExecuteOperationAsync— moved fromPhasedCommandHookscreateEnvironmentForOperation— moved fromPhasedCommandHooksbeforeLog— moved fromPhasedCommandHooks; now invoked by the graph before writing telemetryonIdle— replaceswaitingForChanges(moved fromPhasedCommandHooks)onExecutionStatesUpdated,onEnableStatesChanged,onIterationScheduled,onGraphStateChanged,onInvalidateOperations— new hooksIOperationRunnerContextnow includesgetInvalidateCallback(), which returns a lightweight(reason: string) => voidcallback that marks the current operation for re-execution. This replaces the previousinvalidateOperationonICreateOperationsContextand removes the need for runners to capture anIOperationGraphreference.IOperationRunner.executeAsyncnow takes an optional second parameterlastState?: IOperationLastState, providing the previous execution result to inform incremental behavior (e.g. choosing an initial vs. incremental command).IBaseOperationExecutionResult.getStateHashComponents()now returns a structuredIOperationStateHashComponentsinterface ({ dependencies, local, config }) instead of a flatReadonlyArray<string>.IBaseOperationExecutionResult.metadataFolderPathis nowstring(wasstring | undefined).Details
The new lifecycle of a Rush phased command is that the command first invokes
createOperationsAsyncto create the session-long operation graph. This set of operations is then passed intoonGraphCreatedAsync, which constructs anIOperationGraphthat owns the lifecycle of the execution session.There is a new watch option
includeAllProjectsInWatchGraph(incommand-line.json) that, if set to true, will cause Rush to build the graph with all projects inrush.json, regardless of CLI selection parameters. Selected projects will only affect which projects are enabled for execution during the initial run. This also allows for a bare command, e.g.rush start, to select no projects. This feature is intended for use with plugins that offer the ability to alter the enabled/disabled states of operations in the graph while the session is ongoing. For an example, see@rushstack/rush-serve-plugin, which facilitates altering these states via Web Socket messages.Runner self-invalidation
Long-lived runners (e.g. IPC processes, file watchers) can now request re-execution directly via
context.getInvalidateCallback(). This returns a minimal closure that delegates toIOperationGraph.invalidateOperations(), without the runner needing access to the graph orOperationobject. TheIPCOperationRunneruses this internally to handlerequestRunIPC messages from child processes.Error handling
Operation runner errors are now uniformly caught and wrapped in
OperationErrorbyOperationExecutionRecord.executeAsync, rather than requiring each runner implementation to handle its own error wrapping.All in-repo plugins that interact with the Rush execution graph have also been updated.
How it was tested
Added unit tests for all functionality of the new
IOperationGraphAPI contract (633 tests passing).Manual validation via the rushstack repo's
rush startcommand for the CLI interaction (enable/disable debug or verbose, alter parallelism, pause/resume, kick a single build, invalidate, close runners).Impacted documentation
All watch-mode documentation. Plugin documentation for phased commands.
New docs added in this PR:
docs/rush/phased-commands.md— architecture reference for the phased command execution model,OperationGraphHooks,IOperationGraphAPI, andIOperationRunnercontractdocs/rush/plugin-migration-guide.md— hook-by-hook migration guide for plugin authors upgrading from the previous API