@rushstack/rush-buildxl-graph-plugin 5.153.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +24 -0
- package/dist/rush-buildxl-graph-plugin.d.ts +100 -0
- package/lib/DropBuildGraphPlugin.d.ts +32 -0
- package/lib/DropBuildGraphPlugin.d.ts.map +1 -0
- package/lib/DropBuildGraphPlugin.js +99 -0
- package/lib/DropBuildGraphPlugin.js.map +1 -0
- package/lib/GraphProcessor.d.ts +72 -0
- package/lib/GraphProcessor.d.ts.map +1 -0
- package/lib/GraphProcessor.js +148 -0
- package/lib/GraphProcessor.js.map +1 -0
- package/lib/debugGraphFiltering.d.ts +3 -0
- package/lib/debugGraphFiltering.d.ts.map +1 -0
- package/lib/debugGraphFiltering.js +96 -0
- package/lib/debugGraphFiltering.js.map +1 -0
- package/lib/dropGraph.d.ts +10 -0
- package/lib/dropGraph.d.ts.map +1 -0
- package/lib/dropGraph.js +56 -0
- package/lib/dropGraph.js.map +1 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +7 -0
- package/lib/index.js.map +1 -0
- package/lib/schemas/rush-buildxl-graph-plugin.schema.json +15 -0
- package/lib/tsdoc-metadata.json +11 -0
- package/package.json +31 -0
- package/rush-plugin-manifest.json +11 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
@rushstack/rush-buildxl-graph-plugin
|
|
2
|
+
|
|
3
|
+
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
|
|
5
|
+
MIT License
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
8
|
+
a copy of this software and associated documentation files (the
|
|
9
|
+
"Software"), to deal in the Software without restriction, including
|
|
10
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
11
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
12
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
13
|
+
the following conditions:
|
|
14
|
+
|
|
15
|
+
The above copyright notice and this permission notice shall be
|
|
16
|
+
included in all copies or substantial portions of the Software.
|
|
17
|
+
|
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
19
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
20
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
21
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
22
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
23
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
24
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { IRushPlugin } from '@rushstack/rush-sdk';
|
|
2
|
+
import { RushConfiguration } from '@rushstack/rush-sdk';
|
|
3
|
+
import { RushSession } from '@rushstack/rush-sdk';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This plugin is used to drop the build graph to a file for BuildXL to consume.
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
declare class DropBuildGraphPlugin implements IRushPlugin {
|
|
10
|
+
readonly pluginName: string;
|
|
11
|
+
private readonly _buildXLCommandNames;
|
|
12
|
+
constructor(options: IDropGraphPluginOptions);
|
|
13
|
+
apply(session: RushSession, rushConfiguration: RushConfiguration): void;
|
|
14
|
+
}
|
|
15
|
+
export default DropBuildGraphPlugin;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* This is the type that represents the schema of the drop file
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
export declare interface IBuildXLRushGraph {
|
|
22
|
+
nodes: IGraphNode[];
|
|
23
|
+
repoSettings: {
|
|
24
|
+
commonTempFolder: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @public
|
|
30
|
+
*/
|
|
31
|
+
export declare interface IDropGraphPluginOptions {
|
|
32
|
+
/**
|
|
33
|
+
* The names of the commands that will be used to run BuildXL
|
|
34
|
+
*/
|
|
35
|
+
buildXLCommandNames: string[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @example
|
|
40
|
+
* ```
|
|
41
|
+
* {
|
|
42
|
+
* "id": "@rushstack/node-core-library#_phase:build",
|
|
43
|
+
* "task": "_phase:build",
|
|
44
|
+
* "package": "@rushstack/node-core-library",
|
|
45
|
+
* "dependencies": [
|
|
46
|
+
* "@rushstack/eslint-patch#_phase:build",
|
|
47
|
+
* "@rushstack/eslint-plugin#_phase:build",
|
|
48
|
+
* "@rushstack/eslint-plugin-packlets#_phase:build",
|
|
49
|
+
* "@rushstack/eslint-plugin-security#_phase:build"
|
|
50
|
+
* ],
|
|
51
|
+
* "workingDirectory": "/repo/libraries/node-core-library",
|
|
52
|
+
* "command": "heft run --only build -- --clean --production --drop-graph ./src/examples/graph.json"
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* See https://github.com/microsoft/BuildXL/blob/adf025c1b96b8106984928df3e9c30c8331bc8d6/Public/Src/Tools/JavaScript/Tool.RushGraphBuilder/src/RushBuildPluginGraph.ts
|
|
57
|
+
*
|
|
58
|
+
* @public
|
|
59
|
+
*/
|
|
60
|
+
export declare interface IGraphNode {
|
|
61
|
+
/**
|
|
62
|
+
* The unique id of the Pip
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* `@rushstack/node-core-library#_phase:build`
|
|
66
|
+
*/
|
|
67
|
+
id: string;
|
|
68
|
+
/**
|
|
69
|
+
* The command to run during the Pip
|
|
70
|
+
*/
|
|
71
|
+
command: string;
|
|
72
|
+
/**
|
|
73
|
+
* The working directory of the Pip
|
|
74
|
+
*/
|
|
75
|
+
workingDirectory: string;
|
|
76
|
+
/**
|
|
77
|
+
* The project name associated with the Pip
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* `@rushstack/node-core-library`
|
|
81
|
+
*/
|
|
82
|
+
package: string;
|
|
83
|
+
/**
|
|
84
|
+
* The task name of the Pip
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* `_phase:build`
|
|
88
|
+
*/
|
|
89
|
+
task: string;
|
|
90
|
+
/**
|
|
91
|
+
* The IDs of the dependencies of the Pip. These are the {@link IGraphNode.id} properties of other Pips.
|
|
92
|
+
*/
|
|
93
|
+
dependencies: string[];
|
|
94
|
+
/**
|
|
95
|
+
* If false, the Pip is uncacheable
|
|
96
|
+
*/
|
|
97
|
+
cacheable?: false;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export { }
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type IRushPlugin, type RushConfiguration, type RushSession } from '@rushstack/rush-sdk';
|
|
2
|
+
import type { IGraphNode } from './GraphProcessor';
|
|
3
|
+
/**
|
|
4
|
+
* This is the type that represents the schema of the drop file
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
7
|
+
export interface IBuildXLRushGraph {
|
|
8
|
+
nodes: IGraphNode[];
|
|
9
|
+
repoSettings: {
|
|
10
|
+
commonTempFolder: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
export interface IDropGraphPluginOptions {
|
|
17
|
+
/**
|
|
18
|
+
* The names of the commands that will be used to run BuildXL
|
|
19
|
+
*/
|
|
20
|
+
buildXLCommandNames: string[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* This plugin is used to drop the build graph to a file for BuildXL to consume.
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
export declare class DropBuildGraphPlugin implements IRushPlugin {
|
|
27
|
+
readonly pluginName: string;
|
|
28
|
+
private readonly _buildXLCommandNames;
|
|
29
|
+
constructor(options: IDropGraphPluginOptions);
|
|
30
|
+
apply(session: RushSession, rushConfiguration: RushConfiguration): void;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=DropBuildGraphPlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DropBuildGraphPlugin.d.ts","sourceRoot":"","sources":["../src/DropBuildGraphPlugin.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,WAAW,EAEhB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,YAAY,EAAE;QACZ,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,mBAAmB,EAAE,MAAM,EAAE,CAAC;CAC/B;AAID;;;GAGG;AACH,qBAAa,oBAAqB,YAAW,WAAW;IACtD,SAAgB,UAAU,EAAE,MAAM,CAAe;IACjD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAW;gBAE7B,OAAO,EAAE,uBAAuB;IAI5C,KAAK,CAAC,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,iBAAiB,GAAG,IAAI;CAyD/E"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
3
|
+
// See LICENSE in the project root for license information.
|
|
4
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
5
|
+
if (k2 === undefined) k2 = k;
|
|
6
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
7
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
9
|
+
}
|
|
10
|
+
Object.defineProperty(o, k2, desc);
|
|
11
|
+
}) : (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
o[k2] = m[k];
|
|
14
|
+
}));
|
|
15
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
16
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
17
|
+
}) : function(o, v) {
|
|
18
|
+
o["default"] = v;
|
|
19
|
+
});
|
|
20
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
21
|
+
var ownKeys = function(o) {
|
|
22
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
23
|
+
var ar = [];
|
|
24
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
25
|
+
return ar;
|
|
26
|
+
};
|
|
27
|
+
return ownKeys(o);
|
|
28
|
+
};
|
|
29
|
+
return function (mod) {
|
|
30
|
+
if (mod && mod.__esModule) return mod;
|
|
31
|
+
var result = {};
|
|
32
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
33
|
+
__setModuleDefault(result, mod);
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
})();
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.DropBuildGraphPlugin = void 0;
|
|
39
|
+
const rush_sdk_1 = require("@rushstack/rush-sdk");
|
|
40
|
+
const ts_command_line_1 = require("@rushstack/ts-command-line");
|
|
41
|
+
const PLUGIN_NAME = 'DropBuildGraphPlugin';
|
|
42
|
+
const DROP_GRAPH_PARAMETER_LONG_NAME = '--drop-graph';
|
|
43
|
+
/**
|
|
44
|
+
* This plugin is used to drop the build graph to a file for BuildXL to consume.
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
47
|
+
class DropBuildGraphPlugin {
|
|
48
|
+
constructor(options) {
|
|
49
|
+
this.pluginName = PLUGIN_NAME;
|
|
50
|
+
this._buildXLCommandNames = options.buildXLCommandNames;
|
|
51
|
+
}
|
|
52
|
+
apply(session, rushConfiguration) {
|
|
53
|
+
async function handleCreateOperationsForCommandAsync(commandName, operations, context) {
|
|
54
|
+
// TODO: Introduce an API to allow plugins to register command line options for arbitrary, existing commands
|
|
55
|
+
// in a repo
|
|
56
|
+
const dropGraphParameter = context.customParameters.get(DROP_GRAPH_PARAMETER_LONG_NAME);
|
|
57
|
+
if (!dropGraphParameter) {
|
|
58
|
+
// TODO: Introduce an API to allow plugins to register command line options for arbitrary, existing commands
|
|
59
|
+
// in a repo
|
|
60
|
+
throw new Error(`The ${DROP_GRAPH_PARAMETER_LONG_NAME} parameter needs to be defined in "${rush_sdk_1.RushConstants.commandLineFilename}" ` +
|
|
61
|
+
`and associated with the action "${commandName}"`);
|
|
62
|
+
}
|
|
63
|
+
else if (dropGraphParameter.kind !== ts_command_line_1.CommandLineParameterKind.String) {
|
|
64
|
+
throw new Error(`The ${DROP_GRAPH_PARAMETER_LONG_NAME} parameter must be a string parameter`);
|
|
65
|
+
}
|
|
66
|
+
const dropGraphPath = dropGraphParameter === null || dropGraphParameter === void 0 ? void 0 : dropGraphParameter.value;
|
|
67
|
+
if (dropGraphPath) {
|
|
68
|
+
const { dropGraphAsync } = await Promise.resolve().then(() => __importStar(require('./dropGraph')));
|
|
69
|
+
const isValid = await dropGraphAsync({
|
|
70
|
+
operations,
|
|
71
|
+
context,
|
|
72
|
+
dropGraphPath,
|
|
73
|
+
rushConfiguration,
|
|
74
|
+
logger: session.getLogger(PLUGIN_NAME)
|
|
75
|
+
});
|
|
76
|
+
if (!isValid) {
|
|
77
|
+
throw new Error('Failed to validate the graph');
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
// If the --drop-graph flag is present, we want to exit the process after dropping the graph
|
|
81
|
+
return new Set();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
return operations;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const buildXLCommandName of this._buildXLCommandNames) {
|
|
89
|
+
session.hooks.runPhasedCommand.for(buildXLCommandName).tap(PLUGIN_NAME, (command) => {
|
|
90
|
+
command.hooks.createOperations.tapPromise({
|
|
91
|
+
name: PLUGIN_NAME,
|
|
92
|
+
stage: Number.MAX_SAFE_INTEGER // Run this after other plugins have created all operations
|
|
93
|
+
}, async (operations, context) => await handleCreateOperationsForCommandAsync(command.actionName, operations, context));
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.DropBuildGraphPlugin = DropBuildGraphPlugin;
|
|
99
|
+
//# sourceMappingURL=DropBuildGraphPlugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DropBuildGraphPlugin.js","sourceRoot":"","sources":["../src/DropBuildGraphPlugin.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAE3D,kDAQ6B;AAC7B,gEAAuG;AAIvG,MAAM,WAAW,GAA2B,sBAAsB,CAAC;AAuBnE,MAAM,8BAA8B,GAAmB,cAAc,CAAC;AAEtE;;;GAGG;AACH,MAAa,oBAAoB;IAI/B,YAAmB,OAAgC;QAHnC,eAAU,GAAW,WAAW,CAAC;QAI/C,IAAI,CAAC,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAC1D,CAAC;IAEM,KAAK,CAAC,OAAoB,EAAE,iBAAoC;QACrE,KAAK,UAAU,qCAAqC,CAClD,WAAmB,EACnB,UAA0B,EAC1B,OAAiC;YAEjC,4GAA4G;YAC5G,YAAY;YACZ,MAAM,kBAAkB,GAA2C,OAAO,CAAC,gBAAgB,CAAC,GAAG,CAC7F,8BAA8B,CACD,CAAC;YAChC,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBACxB,4GAA4G;gBAC5G,YAAY;gBACZ,MAAM,IAAI,KAAK,CACb,OAAO,8BAA8B,sCAAsC,wBAAa,CAAC,mBAAmB,IAAI;oBAC9G,mCAAmC,WAAW,GAAG,CACpD,CAAC;YACJ,CAAC;iBAAM,IAAI,kBAAkB,CAAC,IAAI,KAAK,0CAAwB,CAAC,MAAM,EAAE,CAAC;gBACvE,MAAM,IAAI,KAAK,CAAC,OAAO,8BAA8B,uCAAuC,CAAC,CAAC;YAChG,CAAC;YAED,MAAM,aAAa,GAAuB,kBAAkB,aAAlB,kBAAkB,uBAAlB,kBAAkB,CAAE,KAAK,CAAC;YACpE,IAAI,aAAa,EAAE,CAAC;gBAClB,MAAM,EAAE,cAAc,EAAE,GAAG,wDAAa,aAAa,GAAC,CAAC;gBACvD,MAAM,OAAO,GAAY,MAAM,cAAc,CAAC;oBAC5C,UAAU;oBACV,OAAO;oBACP,aAAa;oBACb,iBAAiB;oBACjB,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC;iBACvC,CAAC,CAAC;gBAEH,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;gBAClD,CAAC;qBAAM,CAAC;oBACN,4FAA4F;oBAC5F,OAAO,IAAI,GAAG,EAAE,CAAC;gBACnB,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,OAAO,UAAU,CAAC;YACpB,CAAC;QACH,CAAC;QAED,KAAK,MAAM,kBAAkB,IAAI,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC3D,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,OAAuB,EAAE,EAAE;gBAClG,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,UAAU,CACvC;oBACE,IAAI,EAAE,WAAW;oBACjB,KAAK,EAAE,MAAM,CAAC,gBAAgB,CAAC,2DAA2D;iBAC3F,EACD,KAAK,EAAE,UAA0B,EAAE,OAAiC,EAAE,EAAE,CACtE,MAAM,qCAAqC,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,CAAC,CACvF,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF;AAjED,oDAiEC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport {\n RushConstants,\n type ICreateOperationsContext,\n type IPhasedCommand,\n type IRushPlugin,\n type Operation,\n type RushConfiguration,\n type RushSession\n} from '@rushstack/rush-sdk';\nimport { CommandLineParameterKind, type CommandLineStringParameter } from '@rushstack/ts-command-line';\n\nimport type { IGraphNode } from './GraphProcessor';\n\nconst PLUGIN_NAME: 'DropBuildGraphPlugin' = 'DropBuildGraphPlugin';\n\n/**\n * This is the type that represents the schema of the drop file\n * @public\n */\nexport interface IBuildXLRushGraph {\n nodes: IGraphNode[];\n repoSettings: {\n commonTempFolder: string;\n };\n}\n\n/**\n * @public\n */\nexport interface IDropGraphPluginOptions {\n /**\n * The names of the commands that will be used to run BuildXL\n */\n buildXLCommandNames: string[];\n}\n\nconst DROP_GRAPH_PARAMETER_LONG_NAME: '--drop-graph' = '--drop-graph';\n\n/**\n * This plugin is used to drop the build graph to a file for BuildXL to consume.\n * @public\n */\nexport class DropBuildGraphPlugin implements IRushPlugin {\n public readonly pluginName: string = PLUGIN_NAME;\n private readonly _buildXLCommandNames: string[];\n\n public constructor(options: IDropGraphPluginOptions) {\n this._buildXLCommandNames = options.buildXLCommandNames;\n }\n\n public apply(session: RushSession, rushConfiguration: RushConfiguration): void {\n async function handleCreateOperationsForCommandAsync(\n commandName: string,\n operations: Set<Operation>,\n context: ICreateOperationsContext\n ): Promise<Set<Operation>> {\n // TODO: Introduce an API to allow plugins to register command line options for arbitrary, existing commands\n // in a repo\n const dropGraphParameter: CommandLineStringParameter | undefined = context.customParameters.get(\n DROP_GRAPH_PARAMETER_LONG_NAME\n ) as CommandLineStringParameter;\n if (!dropGraphParameter) {\n // TODO: Introduce an API to allow plugins to register command line options for arbitrary, existing commands\n // in a repo\n throw new Error(\n `The ${DROP_GRAPH_PARAMETER_LONG_NAME} parameter needs to be defined in \"${RushConstants.commandLineFilename}\" ` +\n `and associated with the action \"${commandName}\"`\n );\n } else if (dropGraphParameter.kind !== CommandLineParameterKind.String) {\n throw new Error(`The ${DROP_GRAPH_PARAMETER_LONG_NAME} parameter must be a string parameter`);\n }\n\n const dropGraphPath: string | undefined = dropGraphParameter?.value;\n if (dropGraphPath) {\n const { dropGraphAsync } = await import('./dropGraph');\n const isValid: boolean = await dropGraphAsync({\n operations,\n context,\n dropGraphPath,\n rushConfiguration,\n logger: session.getLogger(PLUGIN_NAME)\n });\n\n if (!isValid) {\n throw new Error('Failed to validate the graph');\n } else {\n // If the --drop-graph flag is present, we want to exit the process after dropping the graph\n return new Set();\n }\n } else {\n return operations;\n }\n }\n\n for (const buildXLCommandName of this._buildXLCommandNames) {\n session.hooks.runPhasedCommand.for(buildXLCommandName).tap(PLUGIN_NAME, (command: IPhasedCommand) => {\n command.hooks.createOperations.tapPromise(\n {\n name: PLUGIN_NAME,\n stage: Number.MAX_SAFE_INTEGER // Run this after other plugins have created all operations\n },\n async (operations: Set<Operation>, context: ICreateOperationsContext) =>\n await handleCreateOperationsForCommandAsync(command.actionName, operations, context)\n );\n });\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { Operation, ILogger } from '@rushstack/rush-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* @example
|
|
4
|
+
* ```
|
|
5
|
+
* {
|
|
6
|
+
* "id": "@rushstack/node-core-library#_phase:build",
|
|
7
|
+
* "task": "_phase:build",
|
|
8
|
+
* "package": "@rushstack/node-core-library",
|
|
9
|
+
* "dependencies": [
|
|
10
|
+
* "@rushstack/eslint-patch#_phase:build",
|
|
11
|
+
* "@rushstack/eslint-plugin#_phase:build",
|
|
12
|
+
* "@rushstack/eslint-plugin-packlets#_phase:build",
|
|
13
|
+
* "@rushstack/eslint-plugin-security#_phase:build"
|
|
14
|
+
* ],
|
|
15
|
+
* "workingDirectory": "/repo/libraries/node-core-library",
|
|
16
|
+
* "command": "heft run --only build -- --clean --production --drop-graph ./src/examples/graph.json"
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* See https://github.com/microsoft/BuildXL/blob/adf025c1b96b8106984928df3e9c30c8331bc8d6/Public/Src/Tools/JavaScript/Tool.RushGraphBuilder/src/RushBuildPluginGraph.ts
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
export interface IGraphNode {
|
|
25
|
+
/**
|
|
26
|
+
* The unique id of the Pip
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* `@rushstack/node-core-library#_phase:build`
|
|
30
|
+
*/
|
|
31
|
+
id: string;
|
|
32
|
+
/**
|
|
33
|
+
* The command to run during the Pip
|
|
34
|
+
*/
|
|
35
|
+
command: string;
|
|
36
|
+
/**
|
|
37
|
+
* The working directory of the Pip
|
|
38
|
+
*/
|
|
39
|
+
workingDirectory: string;
|
|
40
|
+
/**
|
|
41
|
+
* The project name associated with the Pip
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* `@rushstack/node-core-library`
|
|
45
|
+
*/
|
|
46
|
+
package: string;
|
|
47
|
+
/**
|
|
48
|
+
* The task name of the Pip
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* `_phase:build`
|
|
52
|
+
*/
|
|
53
|
+
task: string;
|
|
54
|
+
/**
|
|
55
|
+
* The IDs of the dependencies of the Pip. These are the {@link IGraphNode.id} properties of other Pips.
|
|
56
|
+
*/
|
|
57
|
+
dependencies: string[];
|
|
58
|
+
/**
|
|
59
|
+
* If false, the Pip is uncacheable
|
|
60
|
+
*/
|
|
61
|
+
cacheable?: false;
|
|
62
|
+
}
|
|
63
|
+
export declare function getOperationId(operation: Operation): string;
|
|
64
|
+
export declare class GraphProcessor {
|
|
65
|
+
private readonly _logger;
|
|
66
|
+
constructor(logger: ILogger);
|
|
67
|
+
processOperations(operations: Set<Operation>): IGraphNode[];
|
|
68
|
+
validateGraph(entries: readonly Readonly<IGraphNode>[]): boolean;
|
|
69
|
+
private _pruneNoOps;
|
|
70
|
+
private _operationAsHashedEntry;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=GraphProcessor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GraphProcessor.d.ts","sourceRoot":"","sources":["../src/GraphProcessor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAI9D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,UAAU;IACzB;;;;;OAKG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,gBAAgB,EAAE,MAAM,CAAC;IAEzB;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,YAAY,EAAE,MAAM,EAAE,CAAC;IAEvB;;OAEG;IACH,SAAS,CAAC,EAAE,KAAK,CAAC;CACnB;AAqBD,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAM3D;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;gBAEf,MAAM,EAAE,OAAO;IAO3B,iBAAiB,CAAC,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,GAAG,UAAU,EAAE;IAe3D,aAAa,CAAC,OAAO,EAAE,SAAS,QAAQ,CAAC,UAAU,CAAC,EAAE,GAAG,OAAO;IAgCvE,OAAO,CAAC,WAAW;IA6CnB,OAAO,CAAC,uBAAuB;CAsDhC"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
3
|
+
// See LICENSE in the project root for license information.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.GraphProcessor = void 0;
|
|
6
|
+
exports.getOperationId = getOperationId;
|
|
7
|
+
const terminal_1 = require("@rushstack/terminal");
|
|
8
|
+
const REQUIRED_FIELDS = [
|
|
9
|
+
// command is absent because it is not required
|
|
10
|
+
'id',
|
|
11
|
+
'task',
|
|
12
|
+
'package',
|
|
13
|
+
'dependencies',
|
|
14
|
+
'workingDirectory'
|
|
15
|
+
];
|
|
16
|
+
/*
|
|
17
|
+
* Get the operation id
|
|
18
|
+
*/
|
|
19
|
+
function getOperationId(operation) {
|
|
20
|
+
const { associatedPhase: { name: task }, associatedProject: { packageName } } = operation;
|
|
21
|
+
return `${packageName}#${task}`;
|
|
22
|
+
}
|
|
23
|
+
class GraphProcessor {
|
|
24
|
+
constructor(logger) {
|
|
25
|
+
this._logger = logger;
|
|
26
|
+
}
|
|
27
|
+
/*
|
|
28
|
+
* Convert the operationMap into an array of graph nodes with empty commands pruned
|
|
29
|
+
*/
|
|
30
|
+
processOperations(operations) {
|
|
31
|
+
const nodeMap = new Map();
|
|
32
|
+
for (const operation of operations) {
|
|
33
|
+
const entry = this._operationAsHashedEntry(operation);
|
|
34
|
+
nodeMap.set(entry.id, entry);
|
|
35
|
+
}
|
|
36
|
+
return this._pruneNoOps(nodeMap);
|
|
37
|
+
}
|
|
38
|
+
/*
|
|
39
|
+
* Validate that all dependencies exist
|
|
40
|
+
* Validate that all nodes have a non-empty command
|
|
41
|
+
* Print a message to the logger, and return true if the graph is valid
|
|
42
|
+
*/
|
|
43
|
+
validateGraph(entries) {
|
|
44
|
+
const entryIDs = new Set(entries.map((entry) => entry.id));
|
|
45
|
+
let isValid = true;
|
|
46
|
+
for (const entry of entries) {
|
|
47
|
+
for (const depId of entry.dependencies) {
|
|
48
|
+
if (!entryIDs.has(depId)) {
|
|
49
|
+
this._logger.emitError(new Error(`${entry.id} has a dependency on ${depId} which does not exist`));
|
|
50
|
+
isValid = false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (!entry.command) {
|
|
54
|
+
this._logger.emitError(new Error(`There is an empty command in ${entry.id}`));
|
|
55
|
+
isValid = false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (isValid) {
|
|
59
|
+
this._logger.terminal.writeLine(terminal_1.Colorize.green('All nodes have non-empty commands and dependencies which exist'));
|
|
60
|
+
}
|
|
61
|
+
const totalEdges = entries.reduce((acc, entry) => acc + entry.dependencies.length, 0);
|
|
62
|
+
this._logger.terminal.writeLine(`Graph has ${entries.length} nodes, ${totalEdges} edges`);
|
|
63
|
+
return isValid;
|
|
64
|
+
}
|
|
65
|
+
/*
|
|
66
|
+
* remove all entries with empty commands
|
|
67
|
+
* if an entry has a dependency with an empty command, it should inherit the dependencies of the empty command
|
|
68
|
+
*/
|
|
69
|
+
_pruneNoOps(inputNodeMap) {
|
|
70
|
+
// Cache for the non-empty upstream dependencies of each operation
|
|
71
|
+
const nonEmptyDependenciesByOperation = new Map();
|
|
72
|
+
function getNonEmptyDependencies(node) {
|
|
73
|
+
// If we've already computed this, return the cached result
|
|
74
|
+
let nonEmptyDependencies = nonEmptyDependenciesByOperation.get(node);
|
|
75
|
+
if (!nonEmptyDependencies) {
|
|
76
|
+
nonEmptyDependencies = new Set();
|
|
77
|
+
nonEmptyDependenciesByOperation.set(node, nonEmptyDependencies);
|
|
78
|
+
for (const dependencyID of node.dependencies) {
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
80
|
+
if (!inputNodeMap.get(dependencyID).command) {
|
|
81
|
+
// If the dependency is empty, recursively inherit its non-empty dependencies
|
|
82
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
83
|
+
for (const deepDependency of getNonEmptyDependencies(inputNodeMap.get(dependencyID))) {
|
|
84
|
+
nonEmptyDependencies.add(deepDependency);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
nonEmptyDependencies.add(dependencyID);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return nonEmptyDependencies;
|
|
93
|
+
}
|
|
94
|
+
const result = [];
|
|
95
|
+
for (const node of inputNodeMap.values()) {
|
|
96
|
+
const command = node.command;
|
|
97
|
+
if (command) {
|
|
98
|
+
const nonEmptyDependencySet = getNonEmptyDependencies(node);
|
|
99
|
+
result.push({
|
|
100
|
+
...node,
|
|
101
|
+
dependencies: Array.from(nonEmptyDependencySet),
|
|
102
|
+
command: command
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
/*
|
|
109
|
+
* Convert an operation into a graph node
|
|
110
|
+
*/
|
|
111
|
+
_operationAsHashedEntry(operation) {
|
|
112
|
+
const { runner, associatedPhase: { name: task }, associatedProject: {
|
|
113
|
+
// "package" is a reserved word
|
|
114
|
+
packageName, projectFolder: workingDirectory }, settings, dependencies: operationDependencies } = operation;
|
|
115
|
+
const dependencies = new Set();
|
|
116
|
+
for (const dependency of operationDependencies.values()) {
|
|
117
|
+
const id = getOperationId(dependency);
|
|
118
|
+
dependencies.add(id);
|
|
119
|
+
}
|
|
120
|
+
const node = {
|
|
121
|
+
id: getOperationId(operation),
|
|
122
|
+
task,
|
|
123
|
+
package: packageName,
|
|
124
|
+
dependencies,
|
|
125
|
+
workingDirectory,
|
|
126
|
+
command: runner === null || runner === void 0 ? void 0 : runner.commandToRun
|
|
127
|
+
};
|
|
128
|
+
if (settings === null || settings === void 0 ? void 0 : settings.disableBuildCacheForOperation) {
|
|
129
|
+
node.cacheable = false;
|
|
130
|
+
}
|
|
131
|
+
const missingFields = [];
|
|
132
|
+
for (const requiredField of REQUIRED_FIELDS) {
|
|
133
|
+
if (!node[requiredField]) {
|
|
134
|
+
missingFields.push(requiredField);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (missingFields.length > 0) {
|
|
138
|
+
this._logger.emitError(new Error(`Operation is missing required fields ${missingFields.join(', ')}: ${JSON.stringify(node)}`));
|
|
139
|
+
}
|
|
140
|
+
// the runner is a no-op if and only if the command is empty
|
|
141
|
+
if (!!(runner === null || runner === void 0 ? void 0 : runner.isNoOp) !== !node.command) {
|
|
142
|
+
this._logger.emitError(new Error(`${node.id}: Operation runner isNoOp does not match commandToRun existence`));
|
|
143
|
+
}
|
|
144
|
+
return node;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
exports.GraphProcessor = GraphProcessor;
|
|
148
|
+
//# sourceMappingURL=GraphProcessor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GraphProcessor.js","sourceRoot":"","sources":["../src/GraphProcessor.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { Operation, ILogger } from '@rushstack/rush-sdk';\nimport type { ShellOperationRunner } from '@rushstack/rush-sdk/lib/logic/operations/ShellOperationRunner';\nimport { Colorize } from '@rushstack/terminal';\n\n/**\n * @example\n * ```\n * {\n * \"id\": \"@rushstack/node-core-library#_phase:build\",\n * \"task\": \"_phase:build\",\n * \"package\": \"@rushstack/node-core-library\",\n * \"dependencies\": [\n * \"@rushstack/eslint-patch#_phase:build\",\n * \"@rushstack/eslint-plugin#_phase:build\",\n * \"@rushstack/eslint-plugin-packlets#_phase:build\",\n * \"@rushstack/eslint-plugin-security#_phase:build\"\n * ],\n * \"workingDirectory\": \"/repo/libraries/node-core-library\",\n * \"command\": \"heft run --only build -- --clean --production --drop-graph ./src/examples/graph.json\"\n * }\n * ```\n *\n * See https://github.com/microsoft/BuildXL/blob/adf025c1b96b8106984928df3e9c30c8331bc8d6/Public/Src/Tools/JavaScript/Tool.RushGraphBuilder/src/RushBuildPluginGraph.ts\n *\n * @public\n */\nexport interface IGraphNode {\n /**\n * The unique id of the Pip\n *\n * @example\n * `@rushstack/node-core-library#_phase:build`\n */\n id: string;\n\n /**\n * The command to run during the Pip\n */\n command: string;\n\n /**\n * The working directory of the Pip\n */\n workingDirectory: string;\n\n /**\n * The project name associated with the Pip\n *\n * @example\n * `@rushstack/node-core-library`\n */\n package: string;\n\n /**\n * The task name of the Pip\n *\n * @example\n * `_phase:build`\n */\n task: string;\n\n /**\n * The IDs of the dependencies of the Pip. These are the {@link IGraphNode.id} properties of other Pips.\n */\n dependencies: string[];\n\n /**\n * If false, the Pip is uncacheable\n */\n cacheable?: false;\n}\n\ninterface IGraphNodeInternal extends Omit<IGraphNode, 'dependencies' | 'command'> {\n dependencies: ReadonlySet<string>;\n command: string | undefined;\n}\n\ntype NodeMap = ReadonlyMap<string, IGraphNodeInternal>;\n\nconst REQUIRED_FIELDS: Array<keyof IGraphNodeInternal> = [\n // command is absent because it is not required\n 'id',\n 'task',\n 'package',\n 'dependencies',\n 'workingDirectory'\n];\n\n/*\n * Get the operation id\n */\nexport function getOperationId(operation: Operation): string {\n const {\n associatedPhase: { name: task },\n associatedProject: { packageName }\n } = operation;\n return `${packageName}#${task}`;\n}\n\nexport class GraphProcessor {\n private readonly _logger: ILogger;\n\n public constructor(logger: ILogger) {\n this._logger = logger;\n }\n\n /*\n * Convert the operationMap into an array of graph nodes with empty commands pruned\n */\n public processOperations(operations: Set<Operation>): IGraphNode[] {\n const nodeMap: Map<string, IGraphNodeInternal> = new Map();\n for (const operation of operations) {\n const entry: IGraphNodeInternal = this._operationAsHashedEntry(operation);\n nodeMap.set(entry.id, entry);\n }\n\n return this._pruneNoOps(nodeMap);\n }\n\n /*\n * Validate that all dependencies exist\n * Validate that all nodes have a non-empty command\n * Print a message to the logger, and return true if the graph is valid\n */\n public validateGraph(entries: readonly Readonly<IGraphNode>[]): boolean {\n const entryIDs: Set<string> = new Set(entries.map((entry) => entry.id));\n let isValid: boolean = true;\n for (const entry of entries) {\n for (const depId of entry.dependencies) {\n if (!entryIDs.has(depId)) {\n this._logger.emitError(new Error(`${entry.id} has a dependency on ${depId} which does not exist`));\n isValid = false;\n }\n }\n\n if (!entry.command) {\n this._logger.emitError(new Error(`There is an empty command in ${entry.id}`));\n isValid = false;\n }\n }\n\n if (isValid) {\n this._logger.terminal.writeLine(\n Colorize.green('All nodes have non-empty commands and dependencies which exist')\n );\n }\n\n const totalEdges: number = entries.reduce((acc, entry) => acc + entry.dependencies.length, 0);\n this._logger.terminal.writeLine(`Graph has ${entries.length} nodes, ${totalEdges} edges`);\n return isValid;\n }\n\n /*\n * remove all entries with empty commands\n * if an entry has a dependency with an empty command, it should inherit the dependencies of the empty command\n */\n private _pruneNoOps(inputNodeMap: NodeMap): IGraphNode[] {\n // Cache for the non-empty upstream dependencies of each operation\n const nonEmptyDependenciesByOperation: Map<IGraphNodeInternal, Set<string>> = new Map();\n function getNonEmptyDependencies(node: IGraphNodeInternal): ReadonlySet<string> {\n // If we've already computed this, return the cached result\n let nonEmptyDependencies: Set<string> | undefined = nonEmptyDependenciesByOperation.get(node);\n if (!nonEmptyDependencies) {\n nonEmptyDependencies = new Set();\n nonEmptyDependenciesByOperation.set(node, nonEmptyDependencies);\n for (const dependencyID of node.dependencies) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n if (!inputNodeMap.get(dependencyID)!.command) {\n // If the dependency is empty, recursively inherit its non-empty dependencies\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n for (const deepDependency of getNonEmptyDependencies(inputNodeMap.get(dependencyID)!)) {\n nonEmptyDependencies.add(deepDependency);\n }\n } else {\n nonEmptyDependencies.add(dependencyID);\n }\n }\n }\n\n return nonEmptyDependencies;\n }\n\n const result: IGraphNode[] = [];\n for (const node of inputNodeMap.values()) {\n const command: string | undefined = node.command;\n if (command) {\n const nonEmptyDependencySet: ReadonlySet<string> = getNonEmptyDependencies(node);\n result.push({\n ...node,\n dependencies: Array.from(nonEmptyDependencySet),\n command: command\n });\n }\n }\n\n return result;\n }\n\n /*\n * Convert an operation into a graph node\n */\n private _operationAsHashedEntry(operation: Operation): IGraphNodeInternal {\n const {\n runner,\n associatedPhase: { name: task },\n associatedProject: {\n // \"package\" is a reserved word\n packageName,\n projectFolder: workingDirectory\n },\n settings,\n dependencies: operationDependencies\n } = operation;\n\n const dependencies: Set<string> = new Set();\n for (const dependency of operationDependencies.values()) {\n const id: string = getOperationId(dependency);\n dependencies.add(id);\n }\n\n const node: Partial<IGraphNodeInternal> = {\n id: getOperationId(operation),\n task,\n package: packageName,\n dependencies,\n workingDirectory,\n command: (runner as Partial<Pick<ShellOperationRunner, 'commandToRun'>>)?.commandToRun\n };\n\n if (settings?.disableBuildCacheForOperation) {\n node.cacheable = false;\n }\n\n const missingFields: (keyof IGraphNodeInternal)[] = [];\n for (const requiredField of REQUIRED_FIELDS) {\n if (!node[requiredField]) {\n missingFields.push(requiredField);\n }\n }\n\n if (missingFields.length > 0) {\n this._logger.emitError(\n new Error(`Operation is missing required fields ${missingFields.join(', ')}: ${JSON.stringify(node)}`)\n );\n }\n\n // the runner is a no-op if and only if the command is empty\n if (!!runner?.isNoOp !== !node.command) {\n this._logger.emitError(\n new Error(`${node.id}: Operation runner isNoOp does not match commandToRun existence`)\n );\n }\n\n return node as IGraphNodeInternal;\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debugGraphFiltering.d.ts","sourceRoot":"","sources":["../src/debugGraphFiltering.ts"],"names":[],"mappings":"AAoCA,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,EAAE,QAAQ,GAAE,OAAe,GAAG,MAAM,CAkCvG;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,EAAE,UAAU,GAAE,OAAe,GAAG,MAAM,CA4B3G"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
3
|
+
// See LICENSE in the project root for license information.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.filterObjectForDebug = filterObjectForDebug;
|
|
6
|
+
exports.filterObjectForTesting = filterObjectForTesting;
|
|
7
|
+
const GraphProcessor_1 = require("./GraphProcessor");
|
|
8
|
+
const BANNED_KEYS = new Set([
|
|
9
|
+
'packageJsonEditor',
|
|
10
|
+
'_packageJson',
|
|
11
|
+
'_subspaces',
|
|
12
|
+
'subspace',
|
|
13
|
+
'rushConfiguration',
|
|
14
|
+
'_rushConfiguration',
|
|
15
|
+
'associatedParameters',
|
|
16
|
+
'_dependencyProjects'
|
|
17
|
+
]);
|
|
18
|
+
const ALLOWED_KEYS = new Set([
|
|
19
|
+
'associatedPhase',
|
|
20
|
+
'name',
|
|
21
|
+
'associatedProject',
|
|
22
|
+
'packageName',
|
|
23
|
+
'projectFolder',
|
|
24
|
+
'dependencies',
|
|
25
|
+
'runner',
|
|
26
|
+
'commandToRun',
|
|
27
|
+
'isNoOp'
|
|
28
|
+
]);
|
|
29
|
+
/*
|
|
30
|
+
* Filter Rush's build graph to remove repetitive and unimportant information. Useful if the schema ever changes, or needs to.
|
|
31
|
+
* Due to the fact that it includes all properties that are not banned, it is not guaranteed to be stable across versions.
|
|
32
|
+
* Should not be part of the critical path.
|
|
33
|
+
* @param obj - the object to filter
|
|
34
|
+
* @param depth - the maximum depth to recurse
|
|
35
|
+
* @param simplify - if true, will replace embedded operations with their operation id
|
|
36
|
+
*/
|
|
37
|
+
function filterObjectForDebug(obj, depth = 10, simplify = false) {
|
|
38
|
+
const output = {};
|
|
39
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
40
|
+
if (BANNED_KEYS.has(key)) {
|
|
41
|
+
output[key] = `${key} truncated`;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
else if (typeof value === 'function') {
|
|
45
|
+
output[key] = `${key}()`;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
else if (value instanceof Set) {
|
|
49
|
+
output[key] = filterObjectForDebug(Array.from(value), Math.min(depth - 1, 5), true);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
else if (value instanceof Object) {
|
|
53
|
+
if (depth <= 0) {
|
|
54
|
+
output[key] = `${key} too deep`;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (simplify) {
|
|
58
|
+
const operationId = (0, GraphProcessor_1.getOperationId)(value);
|
|
59
|
+
if (operationId) {
|
|
60
|
+
output[key] = operationId;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
output[key] = filterObjectForDebug(value, depth - 1);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
output[key] = value;
|
|
68
|
+
}
|
|
69
|
+
return output;
|
|
70
|
+
}
|
|
71
|
+
function filterObjectForTesting(obj, depth = 10, ignoreSets = false) {
|
|
72
|
+
const output = {};
|
|
73
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
74
|
+
if (!ALLOWED_KEYS.has(key) && !key.match(/^\d+$/)) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
else if (value instanceof Set) {
|
|
78
|
+
if (!ignoreSets) {
|
|
79
|
+
// Don't need sets inside sets
|
|
80
|
+
output[key] = Array.from(value).map((subValue) => filterObjectForTesting(subValue, Math.min(depth - 1, 5), true));
|
|
81
|
+
}
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
else if (value instanceof Object) {
|
|
85
|
+
if (depth <= 0) {
|
|
86
|
+
output[key] = `${key} too deep`;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
output[key] = filterObjectForTesting(value, depth - 1, ignoreSets);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
output[key] = value;
|
|
93
|
+
}
|
|
94
|
+
return output;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=debugGraphFiltering.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debugGraphFiltering.js","sourceRoot":"","sources":["../src/debugGraphFiltering.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { getOperationId } from './GraphProcessor';\n\nconst BANNED_KEYS: ReadonlySet<string> = new Set([\n 'packageJsonEditor',\n '_packageJson',\n '_subspaces',\n 'subspace',\n 'rushConfiguration',\n '_rushConfiguration',\n 'associatedParameters',\n '_dependencyProjects'\n]);\n\nconst ALLOWED_KEYS: ReadonlySet<string> = new Set([\n 'associatedPhase',\n 'name',\n 'associatedProject',\n 'packageName',\n 'projectFolder',\n 'dependencies',\n 'runner',\n 'commandToRun',\n 'isNoOp'\n]);\n\n/*\n * Filter Rush's build graph to remove repetitive and unimportant information. Useful if the schema ever changes, or needs to.\n * Due to the fact that it includes all properties that are not banned, it is not guaranteed to be stable across versions.\n * Should not be part of the critical path.\n * @param obj - the object to filter\n * @param depth - the maximum depth to recurse\n * @param simplify - if true, will replace embedded operations with their operation id\n */\nexport function filterObjectForDebug(obj: object, depth: number = 10, simplify: boolean = false): object {\n const output: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (BANNED_KEYS.has(key)) {\n output[key] = `${key} truncated`;\n continue;\n } else if (typeof value === 'function') {\n output[key] = `${key}()`;\n continue;\n } else if (value instanceof Set) {\n output[key] = filterObjectForDebug(Array.from(value), Math.min(depth - 1, 5), true);\n continue;\n } else if (value instanceof Object) {\n if (depth <= 0) {\n output[key] = `${key} too deep`;\n continue;\n }\n\n if (simplify) {\n const operationId: string | undefined = getOperationId(value);\n if (operationId) {\n output[key] = operationId;\n continue;\n }\n }\n\n output[key] = filterObjectForDebug(value, depth - 1);\n continue;\n }\n\n output[key] = value;\n }\n\n return output;\n}\n\nexport function filterObjectForTesting(obj: object, depth: number = 10, ignoreSets: boolean = false): object {\n const output: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (!ALLOWED_KEYS.has(key) && !key.match(/^\\d+$/)) {\n continue;\n } else if (value instanceof Set) {\n if (!ignoreSets) {\n // Don't need sets inside sets\n output[key] = Array.from(value).map((subValue) =>\n filterObjectForTesting(subValue, Math.min(depth - 1, 5), true)\n );\n }\n\n continue;\n } else if (value instanceof Object) {\n if (depth <= 0) {\n output[key] = `${key} too deep`;\n continue;\n }\n\n output[key] = filterObjectForTesting(value, depth - 1, ignoreSets);\n continue;\n }\n\n output[key] = value;\n }\n\n return output;\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ICreateOperationsContext, ILogger, Operation, RushConfiguration } from '@rushstack/rush-sdk';
|
|
2
|
+
export interface IDropGraphOptions {
|
|
3
|
+
operations: Set<Operation>;
|
|
4
|
+
context: ICreateOperationsContext;
|
|
5
|
+
dropGraphPath: string;
|
|
6
|
+
rushConfiguration: RushConfiguration;
|
|
7
|
+
logger: ILogger;
|
|
8
|
+
}
|
|
9
|
+
export declare function dropGraphAsync(options: IDropGraphOptions): Promise<boolean>;
|
|
10
|
+
//# sourceMappingURL=dropGraph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dropGraph.d.ts","sourceRoot":"","sources":["../src/dropGraph.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,wBAAwB,EAAE,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAO3G,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;IAC3B,OAAO,EAAE,wBAAwB,CAAC;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,MAAM,EAAE,OAAO,CAAC;CACjB;AAID,wBAAsB,cAAc,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAqDjF"}
|
package/lib/dropGraph.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
3
|
+
// See LICENSE in the project root for license information.
|
|
4
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6
|
+
};
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.dropGraphAsync = dropGraphAsync;
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const node_core_library_1 = require("@rushstack/node-core-library");
|
|
11
|
+
const GraphProcessor_1 = require("./GraphProcessor");
|
|
12
|
+
const debugGraphFiltering_1 = require("./debugGraphFiltering");
|
|
13
|
+
const DEBUG_RUSH_BUILD_GRAPH_ENV_VAR_NAME = 'DEBUG_RUSH_BUILD_GRAPH';
|
|
14
|
+
async function dropGraphAsync(options) {
|
|
15
|
+
const { operations, context, dropGraphPath, rushConfiguration: { commonTempFolder }, logger } = options;
|
|
16
|
+
if (process.env[DEBUG_RUSH_BUILD_GRAPH_ENV_VAR_NAME]) {
|
|
17
|
+
let filterFn;
|
|
18
|
+
const debugValue = process.env[DEBUG_RUSH_BUILD_GRAPH_ENV_VAR_NAME];
|
|
19
|
+
switch (process.env.DEBUG_RUSH_BUILD_GRAPH) {
|
|
20
|
+
case 'test': {
|
|
21
|
+
filterFn = debugGraphFiltering_1.filterObjectForTesting;
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
case 'full': {
|
|
25
|
+
filterFn = debugGraphFiltering_1.filterObjectForDebug;
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
default: {
|
|
29
|
+
throw new Error(`Invalid value for ${DEBUG_RUSH_BUILD_GRAPH_ENV_VAR_NAME}: ${debugValue}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (filterFn) {
|
|
33
|
+
const graphOut = [];
|
|
34
|
+
for (const operation of operations.keys()) {
|
|
35
|
+
graphOut.push(filterFn(operation));
|
|
36
|
+
}
|
|
37
|
+
const debugOutput = {
|
|
38
|
+
OperationMap: graphOut,
|
|
39
|
+
ICreateOperationsContext: filterFn(context)
|
|
40
|
+
};
|
|
41
|
+
const debugPathOut = `${path_1.default.dirname(dropGraphPath)}/debug-${path_1.default.basename(dropGraphPath)}`;
|
|
42
|
+
await node_core_library_1.JsonFile.saveAsync(debugOutput, debugPathOut, { ensureFolderExists: true });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const graphProcessor = new GraphProcessor_1.GraphProcessor(logger);
|
|
46
|
+
const nodes = graphProcessor.processOperations(operations);
|
|
47
|
+
const buildXLGraph = {
|
|
48
|
+
nodes,
|
|
49
|
+
repoSettings: {
|
|
50
|
+
commonTempFolder
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
await node_core_library_1.JsonFile.saveAsync(buildXLGraph, dropGraphPath, { ensureFolderExists: true });
|
|
54
|
+
return graphProcessor.validateGraph(buildXLGraph.nodes);
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=dropGraph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dropGraph.js","sourceRoot":"","sources":["../src/dropGraph.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;;;AAoB3D,wCAqDC;AAvED,gDAAwB;AAExB,oEAAwD;AAGxD,qDAAmE;AACnE,+DAAqF;AAUrF,MAAM,mCAAmC,GAA6B,wBAAwB,CAAC;AAExF,KAAK,UAAU,cAAc,CAAC,OAA0B;IAC7D,MAAM,EACJ,UAAU,EACV,OAAO,EACP,aAAa,EACb,iBAAiB,EAAE,EAAE,gBAAgB,EAAE,EACvC,MAAM,EACP,GAAG,OAAO,CAAC;IACZ,IAAI,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,EAAE,CAAC;QACrD,IAAI,QAA+D,CAAC;QACpE,MAAM,UAAU,GAAuB,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;QACxF,QAAQ,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,CAAC;YAC3C,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,QAAQ,GAAG,4CAAsB,CAAC;gBAClC,MAAM;YACR,CAAC;YAED,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,QAAQ,GAAG,0CAAoB,CAAC;gBAChC,MAAM;YACR,CAAC;YAED,OAAO,CAAC,CAAC,CAAC;gBACR,MAAM,IAAI,KAAK,CAAC,qBAAqB,mCAAmC,KAAK,UAAU,EAAE,CAAC,CAAC;YAC7F,CAAC;QACH,CAAC;QAED,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,QAAQ,GAAc,EAAE,CAAC;YAC/B,KAAK,MAAM,SAAS,IAAI,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC;gBAC1C,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;YACrC,CAAC;YAED,MAAM,WAAW,GAAY;gBAC3B,YAAY,EAAE,QAAQ;gBACtB,wBAAwB,EAAE,QAAQ,CAAC,OAAO,CAAC;aAC5C,CAAC;YACF,MAAM,YAAY,GAAW,GAAG,cAAI,CAAC,OAAO,CAAC,aAAa,CAAC,UAAU,cAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YACpG,MAAM,4BAAQ,CAAC,SAAS,CAAC,WAAW,EAAE,YAAY,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC;QACpF,CAAC;IACH,CAAC;IAED,MAAM,cAAc,GAAmB,IAAI,+BAAc,CAAC,MAAM,CAAC,CAAC;IAClE,MAAM,KAAK,GAAiB,cAAc,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;IACzE,MAAM,YAAY,GAAsB;QACtC,KAAK;QACL,YAAY,EAAE;YACZ,gBAAgB;SACjB;KACF,CAAC;IAEF,MAAM,4BAAQ,CAAC,SAAS,CAAC,YAAY,EAAE,aAAa,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC;IACpF,OAAO,cAAc,CAAC,aAAa,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport path from 'path';\nimport type { ICreateOperationsContext, ILogger, Operation, RushConfiguration } from '@rushstack/rush-sdk';\nimport { JsonFile } from '@rushstack/node-core-library';\n\nimport type { IBuildXLRushGraph } from './DropBuildGraphPlugin';\nimport { type IGraphNode, GraphProcessor } from './GraphProcessor';\nimport { filterObjectForDebug, filterObjectForTesting } from './debugGraphFiltering';\n\nexport interface IDropGraphOptions {\n operations: Set<Operation>;\n context: ICreateOperationsContext;\n dropGraphPath: string;\n rushConfiguration: RushConfiguration;\n logger: ILogger;\n}\n\nconst DEBUG_RUSH_BUILD_GRAPH_ENV_VAR_NAME: 'DEBUG_RUSH_BUILD_GRAPH' = 'DEBUG_RUSH_BUILD_GRAPH';\n\nexport async function dropGraphAsync(options: IDropGraphOptions): Promise<boolean> {\n const {\n operations,\n context,\n dropGraphPath,\n rushConfiguration: { commonTempFolder },\n logger\n } = options;\n if (process.env[DEBUG_RUSH_BUILD_GRAPH_ENV_VAR_NAME]) {\n let filterFn: ((obj: object, depth?: number) => object) | undefined;\n const debugValue: string | undefined = process.env[DEBUG_RUSH_BUILD_GRAPH_ENV_VAR_NAME];\n switch (process.env.DEBUG_RUSH_BUILD_GRAPH) {\n case 'test': {\n filterFn = filterObjectForTesting;\n break;\n }\n\n case 'full': {\n filterFn = filterObjectForDebug;\n break;\n }\n\n default: {\n throw new Error(`Invalid value for ${DEBUG_RUSH_BUILD_GRAPH_ENV_VAR_NAME}: ${debugValue}`);\n }\n }\n\n if (filterFn) {\n const graphOut: unknown[] = [];\n for (const operation of operations.keys()) {\n graphOut.push(filterFn(operation));\n }\n\n const debugOutput: unknown = {\n OperationMap: graphOut,\n ICreateOperationsContext: filterFn(context)\n };\n const debugPathOut: string = `${path.dirname(dropGraphPath)}/debug-${path.basename(dropGraphPath)}`;\n await JsonFile.saveAsync(debugOutput, debugPathOut, { ensureFolderExists: true });\n }\n }\n\n const graphProcessor: GraphProcessor = new GraphProcessor(logger);\n const nodes: IGraphNode[] = graphProcessor.processOperations(operations);\n const buildXLGraph: IBuildXLRushGraph = {\n nodes,\n repoSettings: {\n commonTempFolder\n }\n };\n\n await JsonFile.saveAsync(buildXLGraph, dropGraphPath, { ensureFolderExists: true });\n return graphProcessor.validateGraph(buildXLGraph.nodes);\n}\n"]}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { IBuildXLRushGraph } from './DropBuildGraphPlugin';
|
|
2
|
+
export type { IGraphNode } from './GraphProcessor';
|
|
3
|
+
export type { IDropGraphPluginOptions } from './DropBuildGraphPlugin';
|
|
4
|
+
import { DropBuildGraphPlugin } from './DropBuildGraphPlugin';
|
|
5
|
+
export default DropBuildGraphPlugin;
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,YAAY,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,YAAY,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,eAAe,oBAAoB,CAAC"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
3
|
+
// See LICENSE in the project root for license information.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
const DropBuildGraphPlugin_1 = require("./DropBuildGraphPlugin");
|
|
6
|
+
exports.default = DropBuildGraphPlugin_1.DropBuildGraphPlugin;
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;AAK3D,iEAA8D;AAC9D,kBAAe,2CAAoB,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nexport type { IBuildXLRushGraph } from './DropBuildGraphPlugin';\nexport type { IGraphNode } from './GraphProcessor';\nexport type { IDropGraphPluginOptions } from './DropBuildGraphPlugin';\nimport { DropBuildGraphPlugin } from './DropBuildGraphPlugin';\nexport default DropBuildGraphPlugin;\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
3
|
+
"title": "Configuration for the BuildXL graph drop plugin.",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"required": ["buildXLCommandNames"],
|
|
6
|
+
"properties": {
|
|
7
|
+
"buildXLCommandNames": {
|
|
8
|
+
"type": "array",
|
|
9
|
+
"description": "The names of the commands that will be used to run BuildXL",
|
|
10
|
+
"items": {
|
|
11
|
+
"type": "string"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// This file is read by tools that parse documentation comments conforming to the TSDoc standard.
|
|
2
|
+
// It should be published with your NPM package. It should not be tracked by Git.
|
|
3
|
+
{
|
|
4
|
+
"tsdocVersion": "0.12",
|
|
5
|
+
"toolPackages": [
|
|
6
|
+
{
|
|
7
|
+
"packageName": "@microsoft/api-extractor",
|
|
8
|
+
"packageVersion": "7.52.5"
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rushstack/rush-buildxl-graph-plugin",
|
|
3
|
+
"version": "5.153.0",
|
|
4
|
+
"description": "Rush plugin for generating a BuildXL graph.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/microsoft/rushstack",
|
|
8
|
+
"directory": "rush-plugins/rush-buildxl-graph-plugin"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://rushjs.io",
|
|
11
|
+
"main": "lib/index.js",
|
|
12
|
+
"types": "lib/index.d.ts",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@rushstack/node-core-library": "5.13.0",
|
|
16
|
+
"@rushstack/ts-command-line": "5.0.0",
|
|
17
|
+
"@rushstack/terminal": "0.15.2",
|
|
18
|
+
"@rushstack/rush-sdk": "5.153.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@microsoft/rush-lib": "5.153.0",
|
|
22
|
+
"@rushstack/heft": "0.73.2",
|
|
23
|
+
"local-node-rig": "1.0.0"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "heft build --clean",
|
|
27
|
+
"start": "heft test --clean --watch",
|
|
28
|
+
"_phase:build": "heft run --only build -- --clean",
|
|
29
|
+
"_phase:test": "heft run --only test -- --clean"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugin-manifest.schema.json",
|
|
3
|
+
"plugins": [
|
|
4
|
+
{
|
|
5
|
+
"pluginName": "rush-buildxl-graph-plugin",
|
|
6
|
+
"description": "Plugin for providing access to Rush build graph.",
|
|
7
|
+
"entryPoint": "lib/index.js",
|
|
8
|
+
"optionsSchema": "lib/schemas/rush-buildxl-graph-plugin.schema.json"
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|