nx 23.2.0-beta.1 → 23.2.0-beta.2
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/dist/src/analytics/analytics.d.ts +6 -0
- package/dist/src/analytics/analytics.js +7 -1
- package/dist/src/analytics/index.d.ts +1 -1
- package/dist/src/analytics/index.js +2 -1
- package/dist/src/command-line/init/implementation/angular/integrated-workspace.js +2 -5
- package/dist/src/command-line/init/implementation/angular/legacy-angular-versions.js +3 -0
- package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +4 -1
- package/dist/src/command-line/migrate/migrate.js +4 -0
- package/dist/src/command-line/nx-cloud/connect/view-logs.js +2 -0
- package/dist/src/command-line/show/show-target/inputs.js +50 -153
- package/dist/src/command-line/show/show-target/outputs.js +48 -173
- package/dist/src/command-line/show/show-target/utils.d.ts +28 -0
- package/dist/src/command-line/show/show-target/utils.js +83 -3
- package/dist/src/command-line/yargs-utils/shared-options.d.ts +1 -1
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/daemon/server/handle-tasks-execution-hooks.d.ts +1 -1
- package/dist/src/daemon/server/server.js +7 -4
- package/dist/src/devkit-internals.d.ts +1 -0
- package/dist/src/devkit-internals.js +5 -2
- package/dist/src/hasher/check-task-files.d.ts +86 -0
- package/dist/src/hasher/check-task-files.js +378 -0
- package/dist/src/native/index.d.ts +25 -2
- package/dist/src/native/native-bindings.js +2 -0
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/plugins/js/lock-file/utils/pnpm-normalizer.js +3 -0
- package/dist/src/project-graph/build-project-graph.js +7 -1
- package/dist/src/project-graph/plugins/loaded-nx-plugin.js +1 -0
- package/dist/src/project-graph/project-graph.js +3 -0
- package/dist/src/tasks-runner/life-cycle.d.ts +2 -2
- package/dist/src/tasks-runner/life-cycle.js +2 -2
- package/dist/src/tasks-runner/pseudo-terminal.d.ts +1 -1
- package/dist/src/tasks-runner/pseudo-terminal.js +2 -2
- package/dist/src/tasks-runner/task-orchestrator.d.ts +4 -1
- package/dist/src/tasks-runner/task-orchestrator.js +23 -6
- package/dist/src/utils/acknowledge-build-scripts.js +7 -5
- package/package.json +11 -11
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { EventDimensions } from '../native';
|
|
2
2
|
export declare const customDimensions: EventDimensions;
|
|
3
3
|
export type EventParameters = Partial<Record<EventDimensions[keyof EventDimensions], string | number | boolean>>;
|
|
4
|
+
/**
|
|
5
|
+
* Fraction of sessions that report perf spans. Stamping this rate on a
|
|
6
|
+
* measure's detail (as the sampleRate dimension) opts it into sampling; see
|
|
7
|
+
* is_sampled_in in native/telemetry/service.rs. Multiply GA counts by 1/rate.
|
|
8
|
+
*/
|
|
9
|
+
export declare const PERF_SPAN_SAMPLE_RATE = 0.1;
|
|
4
10
|
export declare function startAnalytics(): Promise<void>;
|
|
5
11
|
export declare function reportNxAddCommand(packageName: string, version: string): void;
|
|
6
12
|
export declare function reportNxGenerateCommand(generator: string): void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.customDimensions = void 0;
|
|
3
|
+
exports.PERF_SPAN_SAMPLE_RATE = exports.customDimensions = void 0;
|
|
4
4
|
exports.startAnalytics = startAnalytics;
|
|
5
5
|
exports.reportNxAddCommand = reportNxAddCommand;
|
|
6
6
|
exports.reportNxGenerateCommand = reportNxGenerateCommand;
|
|
@@ -42,6 +42,12 @@ exports.customDimensions = native_1.IS_WASM
|
|
|
42
42
|
? null
|
|
43
43
|
: (getEventDimensions?.() ?? null);
|
|
44
44
|
let _telemetryInitialized = false;
|
|
45
|
+
/**
|
|
46
|
+
* Fraction of sessions that report perf spans. Stamping this rate on a
|
|
47
|
+
* measure's detail (as the sampleRate dimension) opts it into sampling; see
|
|
48
|
+
* is_sampled_in in native/telemetry/service.rs. Multiply GA counts by 1/rate.
|
|
49
|
+
*/
|
|
50
|
+
exports.PERF_SPAN_SAMPLE_RATE = 0.1;
|
|
45
51
|
async function startAnalytics() {
|
|
46
52
|
// Analytics not supported on WASM
|
|
47
53
|
if (native_1.IS_WASM) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { customDimensions, EventParameters, startAnalytics, reportNxAddCommand, reportNxGenerateCommand, reportCommandRunEvent, reportEvent, flushAnalytics, } from './analytics';
|
|
1
|
+
export { customDimensions, EventParameters, PERF_SPAN_SAMPLE_RATE, startAnalytics, reportNxAddCommand, reportNxGenerateCommand, reportCommandRunEvent, reportEvent, flushAnalytics, } from './analytics';
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.flushAnalytics = exports.reportEvent = exports.reportCommandRunEvent = exports.reportNxGenerateCommand = exports.reportNxAddCommand = exports.startAnalytics = exports.customDimensions = void 0;
|
|
3
|
+
exports.flushAnalytics = exports.reportEvent = exports.reportCommandRunEvent = exports.reportNxGenerateCommand = exports.reportNxAddCommand = exports.startAnalytics = exports.PERF_SPAN_SAMPLE_RATE = exports.customDimensions = void 0;
|
|
4
4
|
var analytics_1 = require("./analytics");
|
|
5
5
|
Object.defineProperty(exports, "customDimensions", { enumerable: true, get: function () { return analytics_1.customDimensions; } });
|
|
6
|
+
Object.defineProperty(exports, "PERF_SPAN_SAMPLE_RATE", { enumerable: true, get: function () { return analytics_1.PERF_SPAN_SAMPLE_RATE; } });
|
|
6
7
|
Object.defineProperty(exports, "startAnalytics", { enumerable: true, get: function () { return analytics_1.startAnalytics; } });
|
|
7
8
|
Object.defineProperty(exports, "reportNxAddCommand", { enumerable: true, get: function () { return analytics_1.reportNxAddCommand; } });
|
|
8
9
|
Object.defineProperty(exports, "reportNxGenerateCommand", { enumerable: true, get: function () { return analytics_1.reportNxGenerateCommand; } });
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.setupIntegratedWorkspace = setupIntegratedWorkspace;
|
|
4
|
-
const child_process_1 = require("
|
|
5
|
-
const package_manager_1 = require("../../../../utils/package-manager");
|
|
4
|
+
const child_process_1 = require("../../../../utils/child-process");
|
|
6
5
|
function setupIntegratedWorkspace() {
|
|
7
|
-
|
|
8
|
-
(0, child_process_1.execSync)(`${pmc.exec} nx g @nx/angular:ng-add`, {
|
|
6
|
+
(0, child_process_1.runNxSync)(`g @nx/angular:ng-add`, {
|
|
9
7
|
stdio: [0, 1, 2],
|
|
10
|
-
windowsHide: true,
|
|
11
8
|
});
|
|
12
9
|
}
|
|
@@ -107,6 +107,9 @@ async function getLegacyMigrationFunctionIfApplicable(repoRoot, options) {
|
|
|
107
107
|
unscopedPkgName,
|
|
108
108
|
}, pmc);
|
|
109
109
|
output_1.output.log({ title: '📝 Setting up workspace' });
|
|
110
|
+
// Intentionally not runNxSync: legacyMigrationCommand is either the Angular
|
|
111
|
+
// CLI (`ng g ...:ng-add`) or a version-pinned `nx@<version> init`, neither
|
|
112
|
+
// of which is the local nx that runNxSync would resolve.
|
|
110
113
|
(0, child_process_1.execSync)(`${pmc.exec} ${legacyMigrationCommand}`, {
|
|
111
114
|
stdio: [0, 1, 2],
|
|
112
115
|
windowsHide: true,
|
|
@@ -69,7 +69,10 @@ function generateDotNxSetup(version) {
|
|
|
69
69
|
(0, tree_1.flushChanges)(host.root, changes);
|
|
70
70
|
// Ensure that the dot-nx installation is available.
|
|
71
71
|
// This is needed when using a global nx with dot-nx, otherwise running any nx command using global command will fail due to missing modules.
|
|
72
|
-
//
|
|
72
|
+
// Intentionally not runNxSync: when the repo has a package.json it would run
|
|
73
|
+
// `<pm> exec nx` instead of the wrapper, but this call must run the
|
|
74
|
+
// just-written wrapper itself so it bootstraps .nx/installation.
|
|
75
|
+
// Pipe stderr so failures surface in telemetry instead of bare "Command failed".
|
|
73
76
|
try {
|
|
74
77
|
(0, child_process_1.execSync)(getDotNxWrapperVersionCommand(), {
|
|
75
78
|
stdio: ['ignore', 'ignore', 'pipe'],
|
|
@@ -2307,6 +2307,10 @@ async function runMigration() {
|
|
|
2307
2307
|
process.env.npm_config_registry.match(/^https:\/\/registry\.(npmjs\.org|yarnpkg\.com)/)) {
|
|
2308
2308
|
delete process.env.npm_config_registry;
|
|
2309
2309
|
}
|
|
2310
|
+
// Intentionally not runNxSync: `p` is an nx CLI freshly installed into a
|
|
2311
|
+
// temp dir by nxCliPath() (latest, or NX_MIGRATE_CLI_VERSION), so
|
|
2312
|
+
// migrations run with an up-to-date migrate implementation instead of
|
|
2313
|
+
// the workspace's current nx.
|
|
2310
2314
|
return runOrReturnExitCode(() => (0, child_process_1.execSync)(`${p} _migrate ${process.argv.slice(3).join(' ')}`, {
|
|
2311
2315
|
stdio: ['inherit', 'inherit', 'inherit'],
|
|
2312
2316
|
windowsHide: true,
|
|
@@ -39,6 +39,8 @@ async function viewLogs() {
|
|
|
39
39
|
return 1;
|
|
40
40
|
}
|
|
41
41
|
const pmc = (0, package_manager_1.getPackageManagerCommand)();
|
|
42
|
+
// Intentionally not runNxSync: this invokes the separate `nx-cloud` binary,
|
|
43
|
+
// not the nx CLI that runNxSync resolves.
|
|
42
44
|
(0, child_process_1.execSync)(`${pmc.exec} nx-cloud upload-and-show-run-details`, {
|
|
43
45
|
stdio: [0, 1, 2],
|
|
44
46
|
windowsHide: true,
|
|
@@ -1,185 +1,82 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.showTargetInputsHandler = showTargetInputsHandler;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
4
|
+
const check_task_files_1 = require("../../../hasher/check-task-files");
|
|
5
|
+
const utils_1 = require("../../../tasks-runner/utils");
|
|
6
|
+
const utils_2 = require("./utils");
|
|
7
7
|
// ── Handler ─────────────────────────────────────────────────────────
|
|
8
8
|
async function showTargetInputsHandler(args) {
|
|
9
|
-
const t = await (0,
|
|
10
|
-
const
|
|
11
|
-
if (
|
|
12
|
-
renderCustomHasherWarning(
|
|
9
|
+
const t = await (0, utils_2.resolveTarget)(args);
|
|
10
|
+
const { projectName, targetName, configuration } = t;
|
|
11
|
+
if ((0, utils_2.hasCustomHasher)(projectName, targetName, t.graph)) {
|
|
12
|
+
renderCustomHasherWarning(projectName, targetName, args);
|
|
13
13
|
process.exitCode = 1;
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
16
|
-
const
|
|
16
|
+
const taskId = (0, utils_1.createTaskId)(projectName, targetName, configuration);
|
|
17
|
+
const hashInputs = await (0, check_task_files_1.getTaskRawInputs)(taskId, {
|
|
18
|
+
projectGraph: t.graph,
|
|
19
|
+
nxJson: t.nxJson,
|
|
20
|
+
});
|
|
21
|
+
if (!hashInputs) {
|
|
22
|
+
throw new Error(`Could not find hash plan for task "${taskId}".`);
|
|
23
|
+
}
|
|
17
24
|
if (args.check !== undefined) {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
renderBatchCheckInputs(results, t.projectName, t.targetName);
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
for (const data of results)
|
|
25
|
-
renderCheckInput(data);
|
|
26
|
-
}
|
|
27
|
-
for (const data of results) {
|
|
28
|
-
process.exitCode ||=
|
|
29
|
-
data.isInput || data.containedInputFiles.length ? 0 : 1;
|
|
30
|
-
}
|
|
25
|
+
const results = await checkInputs(taskId, args.check, hashInputs);
|
|
26
|
+
(0, utils_2.renderCheckResults)(results, projectName, targetName, 'input');
|
|
27
|
+
(0, utils_2.setCheckExitCode)(results);
|
|
31
28
|
return;
|
|
32
29
|
}
|
|
33
|
-
renderInputs({ project:
|
|
30
|
+
renderInputs({ project: projectName, target: targetName, ...hashInputs }, t.node.data.targets[targetName].inputs, args);
|
|
34
31
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
32
|
+
// ── Data resolution ─────────────────────────────────────────────────
|
|
33
|
+
async function checkInputs(taskId, check, hashInputs) {
|
|
34
|
+
// checkFilesAreInputs matches environment/runtime/external names against the
|
|
35
|
+
// raw argument and paths against the workspace-relative form, so both are
|
|
36
|
+
// passed through — it has no cwd of its own.
|
|
37
|
+
const candidates = (0, utils_2.deduplicateFolderEntries)(check).map((value) => ({
|
|
38
|
+
value,
|
|
39
|
+
path: (0, utils_2.normalizePath)(value),
|
|
40
|
+
}));
|
|
41
|
+
const { categories } = await (0, check_task_files_1.checkFilesAreInputs)(taskId, candidates);
|
|
42
|
+
return candidates.map(({ value, path }) => {
|
|
43
|
+
const category = categories.get(value);
|
|
44
|
+
return {
|
|
45
|
+
value,
|
|
46
|
+
file: path,
|
|
47
|
+
matched: !!category,
|
|
48
|
+
category,
|
|
49
|
+
contained: category ? [] : (0, utils_2.pathsUnder)(path, hashInputs.files),
|
|
50
|
+
};
|
|
44
51
|
});
|
|
45
|
-
const targetConfig = graph.nodes[projectName]?.data?.targets?.[targetName];
|
|
46
|
-
const effectiveConfig = configuration ?? targetConfig?.defaultConfiguration;
|
|
47
|
-
const taskId = effectiveConfig
|
|
48
|
-
? `${projectName}:${targetName}:${effectiveConfig}`
|
|
49
|
-
: `${projectName}:${targetName}`;
|
|
50
|
-
const result = plan[taskId];
|
|
51
|
-
if (!result) {
|
|
52
|
-
throw new Error(`Could not find hash plan for task "${taskId}". Available tasks: ${Object.keys(plan).join(', ')}`);
|
|
53
|
-
}
|
|
54
|
-
return result;
|
|
55
|
-
}
|
|
56
|
-
function resolveCheckFromInputs(rawValue, projectName, targetName, inputs) {
|
|
57
|
-
for (const [category, arr] of [
|
|
58
|
-
['environment', inputs.environment],
|
|
59
|
-
['runtime', inputs.runtime],
|
|
60
|
-
['external', inputs.external],
|
|
61
|
-
['depOutputs', inputs.depOutputs],
|
|
62
|
-
]) {
|
|
63
|
-
if (arr.includes(rawValue)) {
|
|
64
|
-
return {
|
|
65
|
-
value: rawValue,
|
|
66
|
-
file: rawValue,
|
|
67
|
-
project: projectName,
|
|
68
|
-
target: targetName,
|
|
69
|
-
isInput: true,
|
|
70
|
-
matchedCategory: category,
|
|
71
|
-
containedInputFiles: [],
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
const fileToCheck = (0, utils_1.normalizePath)(rawValue);
|
|
76
|
-
const isFile = inputs.files.includes(fileToCheck);
|
|
77
|
-
let containedInputFiles = [];
|
|
78
|
-
if (!isFile) {
|
|
79
|
-
if (fileToCheck === '') {
|
|
80
|
-
containedInputFiles = inputs.files;
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
const dirPrefix = fileToCheck.endsWith('/')
|
|
84
|
-
? fileToCheck
|
|
85
|
-
: fileToCheck + '/';
|
|
86
|
-
containedInputFiles = inputs.files.filter((f) => f.startsWith(dirPrefix));
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return {
|
|
90
|
-
value: rawValue,
|
|
91
|
-
file: fileToCheck,
|
|
92
|
-
project: projectName,
|
|
93
|
-
target: targetName,
|
|
94
|
-
isInput: isFile,
|
|
95
|
-
matchedCategory: isFile || containedInputFiles.length > 0
|
|
96
|
-
? 'files'
|
|
97
|
-
: null,
|
|
98
|
-
containedInputFiles,
|
|
99
|
-
};
|
|
100
52
|
}
|
|
101
53
|
// ── Render ──────────────────────────────────────────────────────────
|
|
102
54
|
function renderInputs(data, configuredInputs, args) {
|
|
103
55
|
if (args.json) {
|
|
104
|
-
|
|
105
|
-
const result = {};
|
|
106
|
-
for (const [k, v] of Object.entries(jsonData)) {
|
|
107
|
-
if (Array.isArray(v) && v.length === 0)
|
|
108
|
-
continue;
|
|
109
|
-
result[k] = v;
|
|
110
|
-
}
|
|
111
|
-
console.log(JSON.stringify(result, null, 2));
|
|
56
|
+
(0, utils_2.printJson)(data);
|
|
112
57
|
return;
|
|
113
58
|
}
|
|
114
|
-
const c = (0,
|
|
59
|
+
const c = (0, utils_2.pc)();
|
|
115
60
|
console.log(`${c.bold('Inputs for')} ${c.cyan(data.project)}:${c.green(data.target)}`);
|
|
116
|
-
if (configuredInputs
|
|
117
|
-
(0,
|
|
118
|
-
}
|
|
119
|
-
(0, utils_1.printList)('External dependencies', [...data.external].sort());
|
|
120
|
-
(0, utils_1.printList)('Runtime inputs', [...data.runtime].sort());
|
|
121
|
-
(0, utils_1.printList)('Environment variables', [...data.environment].sort());
|
|
122
|
-
(0, utils_1.printList)(`Files (${data.files.length})`, [...data.files, ...data.depOutputs].sort());
|
|
123
|
-
}
|
|
124
|
-
function renderCheckInput(data) {
|
|
125
|
-
const c = (0, utils_1.pc)();
|
|
126
|
-
const categoryLabel = data.matchedCategory
|
|
127
|
-
? ` (${data.matchedCategory})`
|
|
128
|
-
: '';
|
|
129
|
-
if (data.isInput) {
|
|
130
|
-
console.log(`${c.green('✓')} ${c.bold(data.value)} is an input for ${c.cyan(data.project)}:${c.green(data.target)}${categoryLabel}`);
|
|
131
|
-
}
|
|
132
|
-
else if (data.containedInputFiles.length > 0) {
|
|
133
|
-
console.log(`${c.yellow('~')} ${c.bold(data.file)} is a directory containing ${c.bold(String(data.containedInputFiles.length))} input file(s) for ${c.cyan(data.project)}:${c.green(data.target)}`);
|
|
134
|
-
for (const f of [...data.containedInputFiles].sort())
|
|
135
|
-
console.log(` ${f}`);
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
console.log(`${c.red('✗')} ${c.bold(data.value)} is ${c.red('not')} an input for ${c.cyan(data.project)}:${c.green(data.target)}`);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
function renderBatchCheckInputs(results, projectName, targetName) {
|
|
142
|
-
const c = (0, utils_1.pc)();
|
|
143
|
-
const label = `${c.cyan(projectName)}:${c.green(targetName)}`;
|
|
144
|
-
const matched = [];
|
|
145
|
-
const directories = [];
|
|
146
|
-
const unmatched = [];
|
|
147
|
-
for (const r of results) {
|
|
148
|
-
if (r.isInput) {
|
|
149
|
-
matched.push(r.value);
|
|
150
|
-
}
|
|
151
|
-
else if (r.containedInputFiles.length > 0) {
|
|
152
|
-
directories.push({ value: r.file, count: r.containedInputFiles.length });
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
unmatched.push(r.value);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
if (matched.length > 0 || directories.length > 0) {
|
|
159
|
-
console.log(`\n${c.green('✓')} These arguments were inputs for ${label}:`);
|
|
160
|
-
for (const v of matched)
|
|
161
|
-
console.log(` ${v}`);
|
|
162
|
-
for (const d of directories) {
|
|
163
|
-
console.log(` ${d.value} (directory containing ${d.count} input files)`);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
if (unmatched.length > 0) {
|
|
167
|
-
console.log(`\n${c.red('✗')} These arguments were ${c.red('not')} inputs for ${label}:`);
|
|
168
|
-
for (const v of unmatched)
|
|
169
|
-
console.log(` ${v}`);
|
|
61
|
+
if (configuredInputs?.length) {
|
|
62
|
+
(0, utils_2.printList)('Configured inputs', configuredInputs.map((i) => typeof i === 'string' ? i : JSON.stringify(i)));
|
|
170
63
|
}
|
|
64
|
+
(0, utils_2.printList)('External dependencies', [...data.external].sort());
|
|
65
|
+
(0, utils_2.printList)('Runtime inputs', [...data.runtime].sort());
|
|
66
|
+
(0, utils_2.printList)('Environment variables', [...data.environment].sort());
|
|
67
|
+
(0, utils_2.printList)(`Files (${data.files.length})`, [...data.files, ...data.depOutputs].sort());
|
|
171
68
|
}
|
|
172
69
|
function renderCustomHasherWarning(projectName, targetName, args) {
|
|
173
|
-
const c = (0,
|
|
174
|
-
const label = `${c.cyan(projectName)}:${c.green(targetName)}`;
|
|
70
|
+
const c = (0, utils_2.pc)();
|
|
175
71
|
if (args.json) {
|
|
176
|
-
|
|
72
|
+
(0, utils_2.printJson)({
|
|
177
73
|
project: projectName,
|
|
178
74
|
target: targetName,
|
|
179
75
|
warning: 'This target uses a custom hasher. Configured inputs do not affect the cache hash.',
|
|
180
|
-
}
|
|
76
|
+
});
|
|
181
77
|
return;
|
|
182
78
|
}
|
|
79
|
+
const label = `${c.cyan(projectName)}:${c.green(targetName)}`;
|
|
183
80
|
console.log(`\n${c.yellow('⚠')} ${label} uses a ${c.yellow('custom hasher')}.`);
|
|
184
81
|
console.log(` Configured inputs do not affect the cache hash for this target.`);
|
|
185
82
|
console.log(` The executor's hasher determines what is included in the hash.`);
|
|
@@ -1,195 +1,70 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.showTargetOutputsHandler = showTargetOutputsHandler;
|
|
4
|
+
const check_task_files_1 = require("../../../hasher/check-task-files");
|
|
4
5
|
const utils_1 = require("../../../tasks-runner/utils");
|
|
5
|
-
const workspace_root_1 = require("../../../utils/workspace-root");
|
|
6
6
|
const utils_2 = require("./utils");
|
|
7
7
|
// ── Handler ─────────────────────────────────────────────────────────
|
|
8
8
|
async function showTargetOutputsHandler(args) {
|
|
9
9
|
const t = await (0, utils_2.resolveTarget)(args);
|
|
10
|
-
const
|
|
10
|
+
const { projectName, targetName, configuration } = t;
|
|
11
|
+
const taskId = (0, utils_1.createTaskId)(projectName, targetName, configuration);
|
|
12
|
+
const outputs = await (0, check_task_files_1.getTaskOutputs)(taskId, {
|
|
13
|
+
projectGraph: t.graph,
|
|
14
|
+
nxJson: t.nxJson,
|
|
15
|
+
});
|
|
11
16
|
if (args.check !== undefined) {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
renderBatchCheckOutputs(results, outputsData.project, outputsData.target);
|
|
16
|
-
}
|
|
17
|
-
else {
|
|
18
|
-
for (const data of results)
|
|
19
|
-
renderCheckOutput(data);
|
|
20
|
-
}
|
|
21
|
-
for (const data of results) {
|
|
22
|
-
process.exitCode ||=
|
|
23
|
-
data.matchedOutput ||
|
|
24
|
-
data.containedOutputPaths.length ||
|
|
25
|
-
data.containedExpandedOutputs.length
|
|
26
|
-
? 0
|
|
27
|
-
: 1;
|
|
28
|
-
}
|
|
17
|
+
const results = await checkOutputs(taskId, args.check, outputs);
|
|
18
|
+
(0, utils_2.renderCheckResults)(results, projectName, targetName, 'output');
|
|
19
|
+
(0, utils_2.setCheckExitCode)(results);
|
|
29
20
|
return;
|
|
30
21
|
}
|
|
31
|
-
renderOutputs(
|
|
22
|
+
renderOutputs(projectName, targetName, outputs, args);
|
|
32
23
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
24
|
+
// ── Data resolution ─────────────────────────────────────────────────
|
|
25
|
+
async function checkOutputs(taskId, check, { resolved, expanded }) {
|
|
26
|
+
const checkItems = (0, utils_2.deduplicateFolderEntries)(check);
|
|
27
|
+
const paths = checkItems.map(utils_2.normalizePath);
|
|
28
|
+
// checkFilesAreOutputs handles exact, directory-prefix and glob matching (and
|
|
29
|
+
// `!` exclusions) through the same native engine the task runner uses.
|
|
30
|
+
const { matched } = await (0, check_task_files_1.checkFilesAreOutputs)(taskId, paths);
|
|
31
|
+
const matchedPaths = new Set(matched);
|
|
32
|
+
return checkItems.map((value, i) => {
|
|
33
|
+
const path = paths[i];
|
|
34
|
+
const isMatch = matchedPaths.has(path);
|
|
35
|
+
return {
|
|
36
|
+
value,
|
|
37
|
+
file: path,
|
|
38
|
+
matched: isMatch,
|
|
39
|
+
contained: isMatch
|
|
40
|
+
? []
|
|
41
|
+
: [
|
|
42
|
+
...new Set([
|
|
43
|
+
...(0, utils_2.pathsUnder)(path, resolved),
|
|
44
|
+
...(0, utils_2.pathsUnder)(path, expanded),
|
|
45
|
+
]),
|
|
46
|
+
],
|
|
47
|
+
};
|
|
52
48
|
});
|
|
53
|
-
let expandedOutputs;
|
|
54
|
-
try {
|
|
55
|
-
const { expandOutputs } = require('../../../native');
|
|
56
|
-
expandedOutputs = expandOutputs(workspace_root_1.workspaceRoot, resolvedOutputs);
|
|
57
|
-
}
|
|
58
|
-
catch {
|
|
59
|
-
expandedOutputs = resolvedOutputs;
|
|
60
|
-
}
|
|
61
|
-
return {
|
|
62
|
-
project: projectName,
|
|
63
|
-
target: targetName,
|
|
64
|
-
outputPaths: resolvedOutputs,
|
|
65
|
-
expandedOutputs,
|
|
66
|
-
unresolvedOutputs,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
function resolveCheckOutputData(rawFileToCheck, outputsData) {
|
|
70
|
-
const fileToCheck = (0, utils_2.normalizePath)(rawFileToCheck);
|
|
71
|
-
const { outputPaths, expandedOutputs } = outputsData;
|
|
72
|
-
let matchedOutput = null;
|
|
73
|
-
for (const outputPath of outputPaths) {
|
|
74
|
-
const normalizedOutput = outputPath.replace(/\\/g, '/');
|
|
75
|
-
if (fileToCheck === normalizedOutput ||
|
|
76
|
-
fileToCheck.startsWith(normalizedOutput + '/')) {
|
|
77
|
-
matchedOutput = outputPath;
|
|
78
|
-
break;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
if (!matchedOutput && expandedOutputs.includes(fileToCheck)) {
|
|
82
|
-
matchedOutput = fileToCheck;
|
|
83
|
-
}
|
|
84
|
-
let containedOutputPaths = [];
|
|
85
|
-
let containedExpandedOutputs = [];
|
|
86
|
-
if (!matchedOutput) {
|
|
87
|
-
if (fileToCheck === '') {
|
|
88
|
-
containedOutputPaths = [...outputPaths];
|
|
89
|
-
containedExpandedOutputs = [...expandedOutputs];
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
const dirPrefix = fileToCheck.endsWith('/')
|
|
93
|
-
? fileToCheck
|
|
94
|
-
: fileToCheck + '/';
|
|
95
|
-
containedOutputPaths = outputPaths.filter((o) => o.replace(/\\/g, '/').startsWith(dirPrefix));
|
|
96
|
-
containedExpandedOutputs = expandedOutputs.filter((o) => o.replace(/\\/g, '/').startsWith(dirPrefix));
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
return {
|
|
100
|
-
value: rawFileToCheck,
|
|
101
|
-
file: fileToCheck,
|
|
102
|
-
project: outputsData.project,
|
|
103
|
-
target: outputsData.target,
|
|
104
|
-
matchedOutput,
|
|
105
|
-
containedOutputPaths,
|
|
106
|
-
containedExpandedOutputs,
|
|
107
|
-
};
|
|
108
49
|
}
|
|
109
50
|
// ── Render ──────────────────────────────────────────────────────────
|
|
110
|
-
function renderOutputs(
|
|
51
|
+
function renderOutputs(project, target, { resolved, expanded, unresolved }, args) {
|
|
111
52
|
if (args.json) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
console.log(JSON.stringify(result, null, 2));
|
|
53
|
+
(0, utils_2.printJson)({
|
|
54
|
+
project,
|
|
55
|
+
target,
|
|
56
|
+
outputPaths: resolved,
|
|
57
|
+
expandedOutputs: expanded,
|
|
58
|
+
unresolvedOutputs: unresolved,
|
|
59
|
+
});
|
|
120
60
|
return;
|
|
121
61
|
}
|
|
122
62
|
const c = (0, utils_2.pc)();
|
|
123
|
-
console.log(`${c.bold('Output paths for')} ${c.cyan(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
if (
|
|
128
|
-
(0, utils_2.printList)('Resolved outputs', data.expandedOutputs);
|
|
129
|
-
}
|
|
130
|
-
if (data.unresolvedOutputs.length > 0) {
|
|
131
|
-
(0, utils_2.printList)(`${c.yellow('Unresolved outputs')} (option not set)`, data.unresolvedOutputs);
|
|
132
|
-
}
|
|
133
|
-
if (data.outputPaths.length === 0 && data.unresolvedOutputs.length === 0) {
|
|
63
|
+
console.log(`${c.bold('Output paths for')} ${c.cyan(project)}:${c.green(target)}`);
|
|
64
|
+
(0, utils_2.printList)('Configured outputs', resolved);
|
|
65
|
+
(0, utils_2.printList)('Resolved outputs', expanded);
|
|
66
|
+
(0, utils_2.printList)(`${c.yellow('Unresolved outputs')} (option not set)`, unresolved);
|
|
67
|
+
if (resolved.length === 0 && unresolved.length === 0) {
|
|
134
68
|
console.log(`\n No outputs configured for this target.`);
|
|
135
69
|
}
|
|
136
70
|
}
|
|
137
|
-
function renderCheckOutput(data) {
|
|
138
|
-
const c = (0, utils_2.pc)();
|
|
139
|
-
const displayPath = data.value || data.file;
|
|
140
|
-
if (data.matchedOutput) {
|
|
141
|
-
console.log(`${c.green('✓')} ${c.bold(displayPath)} is an output of ${c.cyan(data.project)}:${c.green(data.target)}`);
|
|
142
|
-
}
|
|
143
|
-
else if (data.containedOutputPaths.length > 0 ||
|
|
144
|
-
data.containedExpandedOutputs.length > 0) {
|
|
145
|
-
const uniquePaths = new Set([
|
|
146
|
-
...data.containedOutputPaths,
|
|
147
|
-
...data.containedExpandedOutputs,
|
|
148
|
-
]);
|
|
149
|
-
console.log(`${c.yellow('~')} ${c.bold(displayPath)} is a directory containing ${c.bold(String(uniquePaths.size))} output path(s) for ${c.cyan(data.project)}:${c.green(data.target)}`);
|
|
150
|
-
const extraExpanded = data.containedExpandedOutputs.filter((o) => !data.containedOutputPaths.includes(o));
|
|
151
|
-
if (extraExpanded.length > 0) {
|
|
152
|
-
(0, utils_2.printList)('Expanded outputs', extraExpanded);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
console.log(`${c.red('✗')} ${c.bold(displayPath)} is ${c.red('not')} an output of ${c.cyan(data.project)}:${c.green(data.target)}`);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
function renderBatchCheckOutputs(results, projectName, targetName) {
|
|
160
|
-
const c = (0, utils_2.pc)();
|
|
161
|
-
const label = `${c.cyan(projectName)}:${c.green(targetName)}`;
|
|
162
|
-
const matched = [];
|
|
163
|
-
const directories = [];
|
|
164
|
-
const unmatched = [];
|
|
165
|
-
for (const r of results) {
|
|
166
|
-
if (r.matchedOutput) {
|
|
167
|
-
matched.push(r.value);
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
170
|
-
const uniqueCount = new Set([
|
|
171
|
-
...r.containedOutputPaths,
|
|
172
|
-
...r.containedExpandedOutputs,
|
|
173
|
-
]).size;
|
|
174
|
-
if (uniqueCount > 0) {
|
|
175
|
-
directories.push({ value: r.file, count: uniqueCount });
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
unmatched.push(r.value);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
if (matched.length > 0 || directories.length > 0) {
|
|
183
|
-
console.log(`\n${c.green('✓')} These arguments were outputs of ${label}:`);
|
|
184
|
-
for (const v of matched)
|
|
185
|
-
console.log(` ${v}`);
|
|
186
|
-
for (const d of directories) {
|
|
187
|
-
console.log(` ${d.value} (directory containing ${d.count} output paths)`);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
if (unmatched.length > 0) {
|
|
191
|
-
console.log(`\n${c.red('✗')} These arguments were ${c.red('not')} outputs of ${label}:`);
|
|
192
|
-
for (const v of unmatched)
|
|
193
|
-
console.log(` ${v}`);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
@@ -24,3 +24,31 @@ export declare function normalizePath(p: string): string;
|
|
|
24
24
|
export declare function deduplicateFolderEntries(items: string[]): string[];
|
|
25
25
|
export declare function pc(): any;
|
|
26
26
|
export declare function printList(header: string, items: unknown[], prefix?: string): void;
|
|
27
|
+
export declare function printJson(data: Record<string, unknown>): void;
|
|
28
|
+
/** The paths that live under `dir`. An empty `dir` is the workspace root. */
|
|
29
|
+
export declare function pathsUnder(dir: string, paths: string[]): string[];
|
|
30
|
+
export interface CheckResult {
|
|
31
|
+
/** The argument as the user typed it. */
|
|
32
|
+
value: string;
|
|
33
|
+
/** Workspace-relative form of `value`. */
|
|
34
|
+
file: string;
|
|
35
|
+
matched: boolean;
|
|
36
|
+
/** Which rule matched, when the caller can name one. */
|
|
37
|
+
category?: string;
|
|
38
|
+
/** Matches found underneath `value`, when it is a directory. */
|
|
39
|
+
contained: string[];
|
|
40
|
+
}
|
|
41
|
+
declare const NOUNS: {
|
|
42
|
+
readonly input: {
|
|
43
|
+
readonly preposition: 'for';
|
|
44
|
+
readonly contained: 'input file';
|
|
45
|
+
};
|
|
46
|
+
readonly output: {
|
|
47
|
+
readonly preposition: 'of';
|
|
48
|
+
readonly contained: 'output path';
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
type CheckNoun = keyof typeof NOUNS;
|
|
52
|
+
export declare function renderCheckResults(results: CheckResult[], project: string, target: string, noun: CheckNoun): void;
|
|
53
|
+
export declare function setCheckExitCode(results: CheckResult[]): void;
|
|
54
|
+
export {};
|