diff --git a/README.md b/README.md index 72a536d7159..a7b2fb64b95 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/rigs/heft-web-rig](./rigs/heft-web-rig/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-web-rig.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-web-rig) | [changelog](./rigs/heft-web-rig/CHANGELOG.md) | [@rushstack/heft-web-rig](https://www.npmjs.com/package/@rushstack/heft-web-rig) | | [/rush-plugins/rush-amazon-s3-build-cache-plugin](./rush-plugins/rush-amazon-s3-build-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-amazon-s3-build-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-amazon-s3-build-cache-plugin) | | [@rushstack/rush-amazon-s3-build-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-amazon-s3-build-cache-plugin) | | [/rush-plugins/rush-azure-storage-build-cache-plugin](./rush-plugins/rush-azure-storage-build-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-azure-storage-build-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-azure-storage-build-cache-plugin) | | [@rushstack/rush-azure-storage-build-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-azure-storage-build-cache-plugin) | +| [/rush-plugins/rush-buildxl-graph-plugin](./rush-plugins/rush-buildxl-graph-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-buildxl-graph-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-buildxl-graph-plugin) | | [@rushstack/rush-buildxl-graph-plugin](https://www.npmjs.com/package/@rushstack/rush-buildxl-graph-plugin) | | [/rush-plugins/rush-http-build-cache-plugin](./rush-plugins/rush-http-build-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-http-build-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-http-build-cache-plugin) | | [@rushstack/rush-http-build-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-http-build-cache-plugin) | | [/rush-plugins/rush-redis-cobuild-plugin](./rush-plugins/rush-redis-cobuild-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-redis-cobuild-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-redis-cobuild-plugin) | | [@rushstack/rush-redis-cobuild-plugin](https://www.npmjs.com/package/@rushstack/rush-redis-cobuild-plugin) | | [/rush-plugins/rush-resolver-cache-plugin](./rush-plugins/rush-resolver-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-resolver-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-resolver-cache-plugin) | | [@rushstack/rush-resolver-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-resolver-cache-plugin) | @@ -205,7 +206,6 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/rigs/decoupled-local-node-rig](./rigs/decoupled-local-node-rig/) | A rig package for Node.js projects that build using Heft inside the RushStack repository, but are dependencies of @rushstack/heft-node-rig or local-node-rig. | | [/rigs/local-node-rig](./rigs/local-node-rig/) | A rig package for Node.js projects that build using Heft inside the RushStack repository. | | [/rigs/local-web-rig](./rigs/local-web-rig/) | A rig package for Web projects that build using Heft inside the RushStack repository. | -| [/rush-plugins/rush-buildxl-graph-plugin](./rush-plugins/rush-buildxl-graph-plugin/) | Rush plugin for generating a BuildXL graph. | | [/rush-plugins/rush-litewatch-plugin](./rush-plugins/rush-litewatch-plugin/) | An experimental alternative approach for multi-project watch mode | | [/vscode-extensions/rush-vscode-command-webview](./vscode-extensions/rush-vscode-command-webview/) | Part of the Rush Stack VSCode extension, provides a UI for invoking Rush commands | | [/vscode-extensions/rush-vscode-extension](./vscode-extensions/rush-vscode-extension/) | Enhanced experience for monorepos that use the Rush Stack toolchain | diff --git a/common/changes/@microsoft/rush/rush-buildxl-graph-plugin-fixes_2025-04-24-20-38.json b/common/changes/@microsoft/rush/rush-buildxl-graph-plugin-fixes_2025-04-24-20-38.json new file mode 100644 index 00000000000..bd7ff97cb34 --- /dev/null +++ b/common/changes/@microsoft/rush/rush-buildxl-graph-plugin-fixes_2025-04-24-20-38.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/rush", + "comment": "", + "type": "none" + } + ], + "packageName": "@microsoft/rush" +} \ No newline at end of file diff --git a/common/reviews/api/rush-buildxl-graph-plugin.api.md b/common/reviews/api/rush-buildxl-graph-plugin.api.md index d99d7fdfbb5..dbec0c82af6 100644 --- a/common/reviews/api/rush-buildxl-graph-plugin.api.md +++ b/common/reviews/api/rush-buildxl-graph-plugin.api.md @@ -35,12 +35,12 @@ export interface IDropGraphPluginOptions { // @public (undocumented) export interface IGraphNode { + cacheable?: false; command: string; dependencies: string[]; id: string; package: string; task: string; - uncacheable?: true; workingDirectory: string; } diff --git a/rush-plugins/rush-buildxl-graph-plugin/package.json b/rush-plugins/rush-buildxl-graph-plugin/package.json index ff920ee574d..408a4b9a44e 100644 --- a/rush-plugins/rush-buildxl-graph-plugin/package.json +++ b/rush-plugins/rush-buildxl-graph-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/rush-buildxl-graph-plugin", - "version": "5.148.0", + "version": "5.153.0", "description": "Rush plugin for generating a BuildXL graph.", "repository": { "type": "git", diff --git a/rush-plugins/rush-buildxl-graph-plugin/src/GraphProcessor.ts b/rush-plugins/rush-buildxl-graph-plugin/src/GraphProcessor.ts index ed6ce8fc189..fd4edf05461 100644 --- a/rush-plugins/rush-buildxl-graph-plugin/src/GraphProcessor.ts +++ b/rush-plugins/rush-buildxl-graph-plugin/src/GraphProcessor.ts @@ -68,9 +68,9 @@ export interface IGraphNode { dependencies: string[]; /** - * If true, the Pip is uncacheable + * If false, the Pip is uncacheable */ - uncacheable?: true; + cacheable?: false; } interface IGraphNodeInternal extends Omit { @@ -90,12 +90,14 @@ const REQUIRED_FIELDS: Array = [ ]; /* - * Try to get the operation id, return undefined if it fails + * Get the operation id */ -export function getOperationId(operation: Pick): string { - const task: string = operation.associatedPhase.name; - const project: string = operation.associatedProject.packageName; - return `${project}#${task}`; +export function getOperationId(operation: Operation): string { + const { + associatedPhase: { name: task }, + associatedProject: { packageName } + } = operation; + return `${packageName}#${task}`; } export class GraphProcessor { @@ -151,14 +153,6 @@ export class GraphProcessor { return isValid; } - /* - * Get the operation id - */ - public getOperationId(operation: Operation): string { - const result: string = getOperationId(operation); - return result; - } - /* * remove all entries with empty commands * if an entry has a dependency with an empty command, it should inherit the dependencies of the empty command @@ -209,30 +203,35 @@ export class GraphProcessor { * Convert an operation into a graph node */ private _operationAsHashedEntry(operation: Operation): IGraphNodeInternal { - const dependencies: Set = new Set(); - for (const element of operation.dependencies.values()) { - const id: string | undefined = this.getOperationId(element); - if (id) { - dependencies.add(id); - } - } + const { + runner, + associatedPhase: { name: task }, + associatedProject: { + // "package" is a reserved word + packageName, + projectFolder: workingDirectory + }, + settings, + dependencies: operationDependencies + } = operation; - const { runner } = operation; - if (!runner) { - throw new Error(`Operation does not have a runner assigned`); + const dependencies: Set = new Set(); + for (const dependency of operationDependencies.values()) { + const id: string = getOperationId(dependency); + dependencies.add(id); } const node: Partial = { id: getOperationId(operation), - task: operation.associatedPhase.name, - package: operation.associatedProject.packageName, + task, + package: packageName, dependencies, - workingDirectory: operation.associatedProject.projectFolder, - command: (runner as Partial>).commandToRun + workingDirectory, + command: (runner as Partial>)?.commandToRun }; - if (operation.settings?.disableBuildCacheForOperation) { - node.uncacheable = true; + if (settings?.disableBuildCacheForOperation) { + node.cacheable = false; } const missingFields: (keyof IGraphNodeInternal)[] = []; @@ -249,7 +248,7 @@ export class GraphProcessor { } // the runner is a no-op if and only if the command is empty - if (operation.isNoOp !== !node.command) { + if (!!runner?.isNoOp !== !node.command) { this._logger.emitError( new Error(`${node.id}: Operation runner isNoOp does not match commandToRun existence`) ); diff --git a/rush-plugins/rush-buildxl-graph-plugin/src/test/GraphProcessor.test.ts b/rush-plugins/rush-buildxl-graph-plugin/src/test/GraphProcessor.test.ts index 30903b208fb..ad83eaa7d5f 100644 --- a/rush-plugins/rush-buildxl-graph-plugin/src/test/GraphProcessor.test.ts +++ b/rush-plugins/rush-buildxl-graph-plugin/src/test/GraphProcessor.test.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { type IOperationRunner, Operation } from '@rushstack/rush-sdk'; +import type { IOperationRunner, Operation } from '@rushstack/rush-sdk'; +import type { ShellOperationRunner } from '@rushstack/rush-sdk/lib/logic/operations/ShellOperationRunner'; import { Terminal, NoOpTerminalProvider } from '@rushstack/terminal'; import { GraphProcessor, type IGraphNode } from '../GraphProcessor'; @@ -15,16 +16,6 @@ function sortGraphNodes(graphNodes: IGraphNode[]): IGraphNode[] { return graphNodes.sort((a, b) => (a.id === b.id ? 0 : a.id < b.id ? -1 : 1)); } -function getDebugOperationMap(): Operation[] { - const cloned: typeof debugGraph.OperationMap = JSON.parse(JSON.stringify(debugGraph.OperationMap)); - - return cloned.map((op) => { - // Operation has getters - Object.setPrototypeOf(op, Operation.prototype); - return op as unknown as Operation; - }); -} - describe(GraphProcessor.name, () => { let exampleGraph: readonly IGraphNode[]; let graphParser: GraphProcessor; @@ -48,7 +39,9 @@ describe(GraphProcessor.name, () => { }); it('should process debug-graph.json into graph.json', () => { - let prunedGraph: IGraphNode[] = graphParser.processOperations(new Set(getDebugOperationMap())); + let prunedGraph: IGraphNode[] = graphParser.processOperations( + new Set(debugGraph.OperationMap as unknown as Operation[]) + ); prunedGraph = sortGraphNodes(prunedGraph); expect(prunedGraph).toEqual(exampleGraph); @@ -57,7 +50,7 @@ describe(GraphProcessor.name, () => { }); it('should fail if the input schema is invalid', () => { - const clonedOperationMap: Operation[] = getDebugOperationMap(); + const clonedOperationMap: Operation[] = JSON.parse(JSON.stringify(debugGraph.OperationMap)); (clonedOperationMap[0].dependencies as unknown as Operation[]).push({ incorrectPhase: { name: 'incorrectPhase' }, incorrectProject: { packageName: 'incorrectProject' } @@ -69,13 +62,11 @@ describe(GraphProcessor.name, () => { }); it('should fail if isNoOp mismatches a command', () => { - const clonedOperationMap: Operation[] = getDebugOperationMap(); - const runner: IOperationRunner | undefined = clonedOperationMap[0].runner; - if (!runner) { - throw new Error('runner is undefined'); - } - (runner as IOperationRunner & { isNoOp: boolean }).isNoOp = true; - (runner as IOperationRunner & { commandToRun?: string }).commandToRun = 'echo "hello world"'; + const clonedOperationMap: Operation[] = JSON.parse(JSON.stringify(debugGraph.OperationMap)); + (clonedOperationMap[0].runner as IOperationRunner & { isNoOp: boolean }).isNoOp = true; + ( + clonedOperationMap[0].runner as unknown as ShellOperationRunner & { commandToRun: string } + ).commandToRun = 'echo "hello world"'; const operations: Set = new Set(clonedOperationMap); graphParser.processOperations(operations); expect(emittedErrors).not.toEqual([]); diff --git a/rush.json b/rush.json index c6f332c3d97..146045231bf 100644 --- a/rush.json +++ b/rush.json @@ -1283,9 +1283,8 @@ { "packageName": "@rushstack/rush-buildxl-graph-plugin", "projectFolder": "rush-plugins/rush-buildxl-graph-plugin", - "reviewCategory": "libraries" - // For now - // "versionPolicyName": "rush" + "reviewCategory": "libraries", + "versionPolicyName": "rush" }, { "packageName": "@rushstack/rush-http-build-cache-plugin",