Commit aceb1fe
authored
[rush] (BREAKING CHANGE) Overhaul watch-mode to facilitate orchestration (#5378)
## 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
- `PhasedCommandHooks` now has only two hooks: `createOperationsAsync` and `onGraphCreatedAsync`. All other hooks have been moved to `OperationGraphHooks`, accessible via `operationGraph.hooks` inside the `onGraphCreatedAsync` callback.
- `createOperations` is now `createOperationsAsync`, and the properties on the `ICreateOperationsContext` parameter have changed: `isInitial`, `projectsInUnknownState`, `phaseOriginal`, and `invalidateOperation` have been removed; `generateFullGraph` and `includePhaseDeps` have been added.
- All manipulation of the runtime graph and taps into the build process are now in the `OperationGraphHooks` class. Tap `operationGraph.hooks` for:
- `configureIteration` — synchronous hook to select which operations run in the next iteration
- `beforeExecuteIterationAsync` — replaces `beforeExecuteOperationsAsync`
- `afterExecuteIterationAsync` — replaces `afterExecuteOperationsAsync`
- `beforeExecuteOperationAsync` — moved from `PhasedCommandHooks`
- `afterExecuteOperationAsync` — moved from `PhasedCommandHooks`
- `createEnvironmentForOperation` — moved from `PhasedCommandHooks`
- `beforeLog` — moved from `PhasedCommandHooks`; now invoked by the graph before writing telemetry
- `onIdle` — replaces `waitingForChanges` (moved from `PhasedCommandHooks`)
- `onExecutionStatesUpdated`, `onEnableStatesChanged`, `onIterationScheduled`, `onGraphStateChanged`, `onInvalidateOperations` — new hooks
- `IOperationRunnerContext` now includes `getInvalidateCallback()`, which returns a lightweight `(reason: string) => void` callback that marks the current operation for re-execution. This replaces the previous `invalidateOperation` on `ICreateOperationsContext` and removes the need for runners to capture an `IOperationGraph` reference.
- `IOperationRunner.executeAsync` now takes an optional second parameter `lastState?: IOperationLastState`, providing the previous execution result to inform incremental behavior (e.g. choosing an initial vs. incremental command).
- `IBaseOperationExecutionResult.getStateHashComponents()` now returns a structured `IOperationStateHashComponents` interface (`{ dependencies, local, config }`) instead of a flat `ReadonlyArray<string>`.
- `IBaseOperationExecutionResult.metadataFolderPath` is now `string` (was `string | undefined`).
## Details
The new lifecycle of a Rush phased command is that the command first invokes `createOperationsAsync` to create the session-long operation graph. This set of operations is then passed into `onGraphCreatedAsync`, which constructs an `IOperationGraph` that owns the lifecycle of the execution session.
There is a new watch option `includeAllProjectsInWatchGraph` (in `command-line.json`) that, if set to true, will cause Rush to build the graph with all projects in `rush.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 to `IOperationGraph.invalidateOperations()`, without the runner needing access to the graph or `Operation` object. The `IPCOperationRunner` uses this internally to handle `requestRun` IPC messages from child processes.
### Error handling
Operation runner errors are now uniformly caught and wrapped in `OperationError` by `OperationExecutionRecord.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 `IOperationGraph` API contract (633 tests passing).
Manual validation via the rushstack repo's `rush start` command 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`, `IOperationGraph` API, and `IOperationRunner` contract
- `docs/rush/plugin-migration-guide.md` — hook-by-hook migration guide for plugin authors upgrading from the previous API1 parent ac09470 commit aceb1fe
80 files changed
Lines changed: 7543 additions & 4810 deletions
File tree
- apps/rush
- src
- common
- changes/@microsoft/rush
- config
- rush-plugins
- rush
- subspaces/default
- reviews/api
- docs/rush
- libraries
- rush-lib/src
- api
- cli
- parsing
- test
- scriptActions
- logic
- buildCache
- operations
- test
- __snapshots__
- pluginFramework
- schemas
- utilities
- test
- rush-sdk/src/test/__snapshots__
- rush-plugins
- rush-bridge-cache-plugin/src
- rush-buildxl-graph-plugin/src
- examples
- test
- rush-serve-plugin
- src
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
| 51 | + | |
51 | 52 | | |
52 | 53 | | |
53 | 54 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
| 32 | + | |
32 | 33 | | |
33 | 34 | | |
34 | 35 | | |
| |||
Lines changed: 10 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
245 | 245 | | |
246 | 246 | | |
247 | 247 | | |
248 | | - | |
| 248 | + | |
249 | 249 | | |
250 | 250 | | |
251 | 251 | | |
252 | 252 | | |
253 | 253 | | |
254 | 254 | | |
255 | 255 | | |
256 | | - | |
257 | | - | |
| 256 | + | |
| 257 | + | |
258 | 258 | | |
259 | 259 | | |
260 | 260 | | |
261 | 261 | | |
262 | 262 | | |
263 | 263 | | |
264 | 264 | | |
265 | | - | |
| 265 | + | |
| 266 | + | |
266 | 267 | | |
267 | 268 | | |
268 | 269 | | |
| |||
494 | 495 | | |
495 | 496 | | |
496 | 497 | | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
497 | 506 | | |
498 | 507 | | |
499 | 508 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
88 | 88 | | |
89 | 89 | | |
90 | 90 | | |
91 | | - | |
| 91 | + | |
92 | 92 | | |
93 | 93 | | |
94 | 94 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
382 | 382 | | |
383 | 383 | | |
384 | 384 | | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
385 | 389 | | |
386 | 390 | | |
387 | 391 | | |
| |||
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
0 commit comments