nx 23.0.0-beta.21 → 23.0.0-beta.22
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/adapter/compat.d.ts +1 -1
- package/dist/src/adapter/compat.js +1 -0
- package/dist/src/command-line/examples.js +4 -4
- package/dist/src/command-line/migrate/agentic/prompts/generic-validation.d.ts +5 -0
- package/dist/src/command-line/migrate/agentic/prompts/generic-validation.js +1 -0
- package/dist/src/command-line/migrate/agentic/prompts/hybrid-prompt-migration.d.ts +5 -0
- package/dist/src/command-line/migrate/agentic/prompts/hybrid-prompt-migration.js +1 -0
- package/dist/src/command-line/migrate/agentic/prompts/prompt-migration.d.ts +5 -0
- package/dist/src/command-line/migrate/agentic/prompts/prompt-migration.js +1 -0
- package/dist/src/command-line/migrate/agentic/prompts/shared-rendering.d.ts +1 -0
- package/dist/src/command-line/migrate/agentic/prompts/shared-rendering.js +15 -0
- package/dist/src/command-line/migrate/agentic/run-step.d.ts +7 -0
- package/dist/src/command-line/migrate/agentic/run-step.js +3 -1
- package/dist/src/command-line/migrate/agentic/select.js +120 -32
- package/dist/src/command-line/migrate/command-object.d.ts +42 -0
- package/dist/src/command-line/migrate/command-object.js +37 -7
- package/dist/src/command-line/migrate/migrate-config.d.ts +27 -0
- package/dist/src/command-line/migrate/migrate-config.js +103 -0
- package/dist/src/command-line/migrate/migrate.d.ts +37 -2
- package/dist/src/command-line/migrate/migrate.js +97 -8
- package/dist/src/command-line/release/changelog/version-plan-filtering.d.ts +3 -1
- package/dist/src/command-line/release/changelog/version-plan-filtering.js +7 -3
- package/dist/src/command-line/release/changelog.d.ts +7 -0
- package/dist/src/command-line/release/changelog.js +22 -9
- package/dist/src/command-line/release/release.js +65 -55
- package/dist/src/command-line/release/utils/git.d.ts +6 -0
- package/dist/src/command-line/release/utils/git.js +33 -0
- package/dist/src/command-line/release/version/derive-specifier-from-conventional-commits.js +3 -2
- package/dist/src/command-line/release/version.d.ts +3 -0
- package/dist/src/command-line/release/version.js +13 -3
- package/dist/src/config/misc-interfaces.d.ts +8 -0
- package/dist/src/config/nx-json.d.ts +49 -0
- package/dist/src/core/graph/main.js +1 -1
- 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/lock-file.d.ts +5 -0
- package/dist/src/plugins/js/lock-file/lock-file.js +34 -24
- package/dist/src/plugins/js/project-graph/affected/lock-file-changes.d.ts +2 -4
- package/dist/src/plugins/js/project-graph/affected/lock-file-changes.js +121 -43
- package/dist/src/project-graph/file-utils.d.ts +7 -0
- package/dist/src/project-graph/file-utils.js +78 -10
- package/dist/src/tasks-runner/init-tasks-runner.d.ts +2 -2
- package/dist/src/tasks-runner/init-tasks-runner.js +6 -6
- package/dist/src/tasks-runner/task-orchestrator.d.ts +2 -2
- package/dist/src/tasks-runner/task-orchestrator.js +6 -6
- package/migrations.json +18 -9
- package/package.json +11 -11
- package/schemas/nx-schema.json +41 -0
|
Binary file
|
|
Binary file
|
|
@@ -8,6 +8,7 @@ import { RawProjectGraphDependency } from '../../../project-graph/project-graph-
|
|
|
8
8
|
import { PackageJson } from '../../../utils/package-json';
|
|
9
9
|
import { PackageManager } from '../../../utils/package-manager';
|
|
10
10
|
export declare const LOCKFILES: string[];
|
|
11
|
+
export declare const AUTO_AFFECTED_LOCK_FILES: readonly ["yarn.lock", "package-lock.json", "pnpm-lock.yaml", "pnpm-lock.yml", "bun.lockb", "bun.lock"];
|
|
11
12
|
/**
|
|
12
13
|
* Parses lock file and maps dependencies and metadata to {@link LockFileGraph}
|
|
13
14
|
*/
|
|
@@ -15,6 +16,10 @@ export declare function getLockFileNodes(packageManager: PackageManager, content
|
|
|
15
16
|
nodes: Record<string, ProjectGraphExternalNode>;
|
|
16
17
|
keyMap: Map<string, any>;
|
|
17
18
|
};
|
|
19
|
+
export declare function getLockFileNodesForName(lockFile: string, contents: string, lockFileHash: string, packageJson?: PackageJson): {
|
|
20
|
+
nodes: Record<string, ProjectGraphExternalNode>;
|
|
21
|
+
keyMap: Map<string, any>;
|
|
22
|
+
};
|
|
18
23
|
/**
|
|
19
24
|
* Parses lock file and maps dependencies and metadata to {@link LockFileGraph}
|
|
20
25
|
*/
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* It encapsulates the package manager specific logic and implementation details.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.LOCKFILES = void 0;
|
|
7
|
+
exports.AUTO_AFFECTED_LOCK_FILES = exports.LOCKFILES = void 0;
|
|
8
8
|
exports.getLockFileNodes = getLockFileNodes;
|
|
9
|
+
exports.getLockFileNodesForName = getLockFileNodesForName;
|
|
9
10
|
exports.getLockFileDependencies = getLockFileDependencies;
|
|
10
11
|
exports.lockFileExists = lockFileExists;
|
|
11
12
|
exports.getLockFileName = getLockFileName;
|
|
@@ -28,6 +29,7 @@ const yarn_parser_1 = require("./yarn-parser");
|
|
|
28
29
|
const YARN_LOCK_FILE = 'yarn.lock';
|
|
29
30
|
const NPM_LOCK_FILE = 'package-lock.json';
|
|
30
31
|
const PNPM_LOCK_FILE = 'pnpm-lock.yaml';
|
|
32
|
+
const PNPM_LOCK_FILE_LEGACY = 'pnpm-lock.yml';
|
|
31
33
|
exports.LOCKFILES = [
|
|
32
34
|
YARN_LOCK_FILE,
|
|
33
35
|
NPM_LOCK_FILE,
|
|
@@ -35,6 +37,14 @@ exports.LOCKFILES = [
|
|
|
35
37
|
bun_parser_1.BUN_LOCK_FILE,
|
|
36
38
|
bun_parser_1.BUN_TEXT_LOCK_FILE,
|
|
37
39
|
];
|
|
40
|
+
exports.AUTO_AFFECTED_LOCK_FILES = [
|
|
41
|
+
YARN_LOCK_FILE,
|
|
42
|
+
NPM_LOCK_FILE,
|
|
43
|
+
PNPM_LOCK_FILE,
|
|
44
|
+
PNPM_LOCK_FILE_LEGACY,
|
|
45
|
+
bun_parser_1.BUN_LOCK_FILE,
|
|
46
|
+
bun_parser_1.BUN_TEXT_LOCK_FILE,
|
|
47
|
+
];
|
|
38
48
|
const YARN_LOCK_PATH = (0, node_path_1.join)(workspace_root_1.workspaceRoot, YARN_LOCK_FILE);
|
|
39
49
|
const NPM_LOCK_PATH = (0, node_path_1.join)(workspace_root_1.workspaceRoot, NPM_LOCK_FILE);
|
|
40
50
|
const PNPM_LOCK_PATH = (0, node_path_1.join)(workspace_root_1.workspaceRoot, PNPM_LOCK_FILE);
|
|
@@ -45,29 +55,10 @@ const BUN_TEXT_LOCK_PATH = (0, node_path_1.join)(workspace_root_1.workspaceRoot,
|
|
|
45
55
|
*/
|
|
46
56
|
function getLockFileNodes(packageManager, contents, lockFileHash, context) {
|
|
47
57
|
try {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (packageManager === 'pnpm') {
|
|
53
|
-
return (0, pnpm_parser_1.getPnpmLockfileNodes)(contents, lockFileHash);
|
|
54
|
-
}
|
|
55
|
-
if (packageManager === 'npm') {
|
|
56
|
-
return (0, npm_parser_1.getNpmLockfileNodes)(contents, lockFileHash);
|
|
57
|
-
}
|
|
58
|
-
if (packageManager === 'bun') {
|
|
59
|
-
const lockFilePath = getLockFilePath(packageManager);
|
|
60
|
-
if (lockFilePath.endsWith(bun_parser_1.BUN_TEXT_LOCK_FILE)) {
|
|
61
|
-
// Use new text-based parser
|
|
62
|
-
const nodes = (0, bun_parser_1.getBunTextLockfileNodes)(contents, lockFileHash);
|
|
63
|
-
return { nodes, keyMap: new Map() };
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
// Fallback to yarn parser for binary format
|
|
67
|
-
const packageJson = (0, fileutils_1.readJsonFile)((0, node_path_1.join)(context.workspaceRoot, 'package.json'));
|
|
68
|
-
return (0, yarn_parser_1.getYarnLockfileNodes)(contents, lockFileHash, packageJson);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
58
|
+
const packageJson = packageManager === 'yarn' || packageManager === 'bun'
|
|
59
|
+
? (0, fileutils_1.readJsonFile)((0, node_path_1.join)(context.workspaceRoot, 'package.json'))
|
|
60
|
+
: undefined;
|
|
61
|
+
return getLockFileNodesForName(getLockFileName(packageManager), contents, lockFileHash, packageJson);
|
|
71
62
|
}
|
|
72
63
|
catch (e) {
|
|
73
64
|
if (!isPostInstallProcess()) {
|
|
@@ -80,6 +71,25 @@ function getLockFileNodes(packageManager, contents, lockFileHash, context) {
|
|
|
80
71
|
}
|
|
81
72
|
throw new Error(`Unknown package manager: ${packageManager}`);
|
|
82
73
|
}
|
|
74
|
+
function getLockFileNodesForName(lockFile, contents, lockFileHash, packageJson) {
|
|
75
|
+
if (lockFile === YARN_LOCK_FILE || lockFile === bun_parser_1.BUN_LOCK_FILE) {
|
|
76
|
+
// yarn-parser only reads optional fields plus an unused `name` for the
|
|
77
|
+
// synthetic root workspace node, which is identical across base/head and
|
|
78
|
+
// therefore irrelevant for affected diffing.
|
|
79
|
+
return (0, yarn_parser_1.getYarnLockfileNodes)(contents, lockFileHash, packageJson ?? {});
|
|
80
|
+
}
|
|
81
|
+
if (lockFile === PNPM_LOCK_FILE || lockFile === PNPM_LOCK_FILE_LEGACY) {
|
|
82
|
+
return (0, pnpm_parser_1.getPnpmLockfileNodes)(contents, lockFileHash);
|
|
83
|
+
}
|
|
84
|
+
if (lockFile === NPM_LOCK_FILE) {
|
|
85
|
+
return (0, npm_parser_1.getNpmLockfileNodes)(contents, lockFileHash);
|
|
86
|
+
}
|
|
87
|
+
if (lockFile === bun_parser_1.BUN_TEXT_LOCK_FILE) {
|
|
88
|
+
const nodes = (0, bun_parser_1.getBunTextLockfileNodes)(contents, lockFileHash);
|
|
89
|
+
return { nodes, keyMap: new Map() };
|
|
90
|
+
}
|
|
91
|
+
throw new Error(`Unknown lock file: ${lockFile}`);
|
|
92
|
+
}
|
|
83
93
|
/**
|
|
84
94
|
* Parses lock file and maps dependencies and metadata to {@link LockFileGraph}
|
|
85
95
|
*/
|
|
@@ -1,5 +1,3 @@
|
|
|
1
1
|
import { TouchedProjectLocator } from '../../../../project-graph/affected/affected-project-graph-models';
|
|
2
|
-
import { WholeFileChange } from '../../../../project-graph/file-utils';
|
|
3
|
-
|
|
4
|
-
export declare const PNPM_LOCK_FILES: string[];
|
|
5
|
-
export declare const getTouchedProjectsFromLockFile: TouchedProjectLocator<WholeFileChange | JsonChange>;
|
|
2
|
+
import { LockFileChange, WholeFileChange } from '../../../../project-graph/file-utils';
|
|
3
|
+
export declare const getTouchedProjectsFromLockFile: TouchedProjectLocator<WholeFileChange | LockFileChange>;
|
|
@@ -1,26 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getTouchedProjectsFromLockFile =
|
|
4
|
-
const
|
|
5
|
-
const json_diff_1 = require("../../../../utils/json-diff");
|
|
3
|
+
exports.getTouchedProjectsFromLockFile = void 0;
|
|
4
|
+
const file_utils_1 = require("../../../../project-graph/file-utils");
|
|
6
5
|
const config_1 = require("../../utils/config");
|
|
7
6
|
const find_matching_projects_1 = require("../../../../utils/find-matching-projects");
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
'yarn.lock',
|
|
13
|
-
'bun.lockb',
|
|
14
|
-
'bun.lock',
|
|
15
|
-
];
|
|
16
|
-
const getTouchedProjectsFromLockFile = (fileChanges, projectGraphNodes) => {
|
|
17
|
-
const nxJson = (0, configuration_1.readNxJson)();
|
|
7
|
+
const file_hasher_1 = require("../../../../hasher/file-hasher");
|
|
8
|
+
const output_1 = require("../../../../utils/output");
|
|
9
|
+
const lock_file_1 = require("../../lock-file/lock-file");
|
|
10
|
+
const getTouchedProjectsFromLockFile = (fileChanges, projectGraphNodes, nxJson, packageJson, projectGraph) => {
|
|
18
11
|
const { projectsAffectedByDependencyUpdates } = (0, config_1.jsPluginConfig)(nxJson);
|
|
19
|
-
const changedLockFile = fileChanges.find((f) =>
|
|
12
|
+
const changedLockFile = fileChanges.find((f) => lock_file_1.AUTO_AFFECTED_LOCK_FILES.includes(f.file));
|
|
20
13
|
if (projectsAffectedByDependencyUpdates === 'auto') {
|
|
21
|
-
|
|
22
|
-
const changedProjectNames = getProjectsNamesFromPaths(projectGraphNodes, changedProjectPaths);
|
|
23
|
-
return changedProjectNames;
|
|
14
|
+
return getAutoAffected(changedLockFile, projectGraphNodes, projectGraph, packageJson);
|
|
24
15
|
}
|
|
25
16
|
else if (Array.isArray(projectsAffectedByDependencyUpdates)) {
|
|
26
17
|
return (0, find_matching_projects_1.findMatchingProjects)(projectsAffectedByDependencyUpdates, projectGraphNodes);
|
|
@@ -32,41 +23,128 @@ const getTouchedProjectsFromLockFile = (fileChanges, projectGraphNodes) => {
|
|
|
32
23
|
};
|
|
33
24
|
exports.getTouchedProjectsFromLockFile = getTouchedProjectsFromLockFile;
|
|
34
25
|
/**
|
|
35
|
-
*
|
|
26
|
+
* In auto mode, parse the lock file at the base and head revisions
|
|
27
|
+
* using Nx's existing lock file parsers, then diff the resulting
|
|
28
|
+
* external-node maps to determine which packages actually changed.
|
|
29
|
+
*
|
|
30
|
+
* Returns external node names (e.g. "npm:lodash@4.17.21") so the
|
|
31
|
+
* graph reversal in filterAffected can walk back to workspace projects.
|
|
36
32
|
*/
|
|
37
|
-
|
|
33
|
+
function getAutoAffected(changedLockFile, projectGraphNodes, projectGraph, packageJson) {
|
|
34
|
+
const allProjectNames = Object.values(projectGraphNodes).map((p) => p.name);
|
|
38
35
|
if (!changedLockFile) {
|
|
39
36
|
return [];
|
|
40
37
|
}
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
38
|
+
const changes = changedLockFile.getChanges();
|
|
39
|
+
// A WholeFileChange means we were unable to read both revisions of
|
|
40
|
+
// the lock file (e.g. missing base revision, git error). Fall back
|
|
41
|
+
// to marking all projects affected.
|
|
42
|
+
if (!changes.every(file_utils_1.isLockFileChange)) {
|
|
43
|
+
return allProjectNames;
|
|
44
|
+
}
|
|
45
|
+
const changedPackageNames = getChangedPackageNames(changedLockFile.file, changes, packageJson);
|
|
46
|
+
if (changedPackageNames === null) {
|
|
47
|
+
return allProjectNames;
|
|
48
|
+
}
|
|
49
|
+
if (changedPackageNames.size === 0) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
// Look up the changed packages in the project graph's external nodes
|
|
53
|
+
// and return the external node names. The graph reversal in
|
|
54
|
+
// filterAffected walks from these nodes to workspace projects.
|
|
55
|
+
const { touchedNodeNames, missingPackageNames } = findExternalNodesByPackageName(changedPackageNames, projectGraph.externalNodes ?? {});
|
|
56
|
+
if (missingPackageNames.size > 0) {
|
|
57
|
+
return allProjectNames;
|
|
58
|
+
}
|
|
59
|
+
return touchedNodeNames;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Parse the base and head revisions of the lock file with Nx's
|
|
63
|
+
* existing parsers and diff the resulting package -> version maps.
|
|
64
|
+
*
|
|
65
|
+
* Returns the set of changed package names, or null if parsing
|
|
66
|
+
* failed (in which case the caller should fall back to all projects).
|
|
67
|
+
*/
|
|
68
|
+
function getChangedPackageNames(file, changes, packageJson) {
|
|
69
|
+
try {
|
|
70
|
+
const changed = new Set();
|
|
71
|
+
// calculateFileChanges emits a single LockFileChange per lock file, but
|
|
72
|
+
// the iteration keeps the contract open in case multiple ranges are ever
|
|
73
|
+
// emitted for the same file.
|
|
74
|
+
for (const change of changes) {
|
|
75
|
+
const baseFingerprints = collectPackageFingerprints((0, lock_file_1.getLockFileNodesForName)(file, change.baseContent, (0, file_hasher_1.hashArray)([change.baseContent]), packageJson).nodes);
|
|
76
|
+
const headFingerprints = collectPackageFingerprints((0, lock_file_1.getLockFileNodesForName)(file, change.headContent, (0, file_hasher_1.hashArray)([change.headContent]), packageJson).nodes);
|
|
77
|
+
for (const [name, fingerprints] of headFingerprints) {
|
|
78
|
+
const baseSet = baseFingerprints.get(name);
|
|
79
|
+
if (!baseSet || !setsEqual(baseSet, fingerprints)) {
|
|
80
|
+
changed.add(name);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
for (const name of baseFingerprints.keys()) {
|
|
84
|
+
if (!headFingerprints.has(name)) {
|
|
85
|
+
changed.add(name);
|
|
86
|
+
}
|
|
48
87
|
}
|
|
49
88
|
}
|
|
89
|
+
return changed;
|
|
50
90
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
91
|
+
catch (e) {
|
|
92
|
+
output_1.output.warn({
|
|
93
|
+
title: `Failed to parse "${file}" for projectsAffectedByDependencyUpdates "auto" mode. All projects will be marked as affected.`,
|
|
94
|
+
bodyLines: [e instanceof Error ? e.message : String(e)],
|
|
95
|
+
});
|
|
96
|
+
return null;
|
|
56
97
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Build a map of packageName -> set of versions present in the
|
|
101
|
+
* external-node record returned by a lock-file parser. We include both
|
|
102
|
+
* version and hash so patched/tarball/integrity-only changes still
|
|
103
|
+
* count as lockfile changes even when the semver stays the same.
|
|
104
|
+
*/
|
|
105
|
+
function collectPackageFingerprints(nodes) {
|
|
106
|
+
const fingerprints = new Map();
|
|
107
|
+
for (const node of Object.values(nodes ?? {})) {
|
|
108
|
+
const name = node.data?.packageName;
|
|
109
|
+
if (!name)
|
|
110
|
+
continue;
|
|
111
|
+
const fingerprint = JSON.stringify({
|
|
112
|
+
version: node.data.version ?? '',
|
|
113
|
+
hash: node.data.hash ?? '',
|
|
67
114
|
});
|
|
115
|
+
let set = fingerprints.get(name);
|
|
116
|
+
if (!set) {
|
|
117
|
+
set = new Set();
|
|
118
|
+
fingerprints.set(name, set);
|
|
119
|
+
}
|
|
120
|
+
set.add(fingerprint);
|
|
68
121
|
}
|
|
69
|
-
|
|
70
|
-
|
|
122
|
+
return fingerprints;
|
|
123
|
+
}
|
|
124
|
+
function setsEqual(a, b) {
|
|
125
|
+
if (a.size !== b.size)
|
|
126
|
+
return false;
|
|
127
|
+
for (const value of a) {
|
|
128
|
+
if (!b.has(value))
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Given a set of package names, find all matching external node names
|
|
135
|
+
* in the project graph.
|
|
136
|
+
*/
|
|
137
|
+
function findExternalNodesByPackageName(packageNames, externalNodes) {
|
|
138
|
+
const touchedNodeNames = [];
|
|
139
|
+
const matchedPackageNames = new Set();
|
|
140
|
+
for (const [name, node] of Object.entries(externalNodes)) {
|
|
141
|
+
if (packageNames.has(node.data.packageName)) {
|
|
142
|
+
touchedNodeNames.push(name);
|
|
143
|
+
matchedPackageNames.add(node.data.packageName);
|
|
144
|
+
}
|
|
71
145
|
}
|
|
146
|
+
return {
|
|
147
|
+
touchedNodeNames,
|
|
148
|
+
missingPackageNames: new Set(Array.from(packageNames).filter((name) => !matchedPackageNames.has(name))),
|
|
149
|
+
};
|
|
72
150
|
}
|
|
@@ -13,8 +13,15 @@ export declare class WholeFileChange implements Change {
|
|
|
13
13
|
export declare class DeletedFileChange implements Change {
|
|
14
14
|
type: string;
|
|
15
15
|
}
|
|
16
|
+
export declare class LockFileChange implements Change {
|
|
17
|
+
baseContent: string;
|
|
18
|
+
headContent: string;
|
|
19
|
+
type: string;
|
|
20
|
+
constructor(baseContent: string, headContent: string);
|
|
21
|
+
}
|
|
16
22
|
export declare function isWholeFileChange(change: Change): change is WholeFileChange;
|
|
17
23
|
export declare function isDeletedFileChange(change: Change): change is DeletedFileChange;
|
|
24
|
+
export declare function isLockFileChange(change: Change): change is LockFileChange;
|
|
18
25
|
export declare function calculateFileChanges(files: string[], nxArgs?: NxArgs, readFileAtRevision?: {
|
|
19
26
|
(f: string, r: string | void): string;
|
|
20
27
|
}, ignore?: ReturnType<typeof ignore>): FileChange[];
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TEN_MEGABYTES = exports.DeletedFileChange = exports.WholeFileChange = void 0;
|
|
3
|
+
exports.TEN_MEGABYTES = exports.LockFileChange = exports.DeletedFileChange = exports.WholeFileChange = void 0;
|
|
4
4
|
exports.isWholeFileChange = isWholeFileChange;
|
|
5
5
|
exports.isDeletedFileChange = isDeletedFileChange;
|
|
6
|
+
exports.isLockFileChange = isLockFileChange;
|
|
6
7
|
exports.calculateFileChanges = calculateFileChanges;
|
|
7
8
|
exports.defaultFileRead = defaultFileRead;
|
|
8
9
|
exports.readPackageJson = readPackageJson;
|
|
9
10
|
const child_process_1 = require("child_process");
|
|
10
11
|
const fs_1 = require("fs");
|
|
12
|
+
const os_1 = require("os");
|
|
11
13
|
const path_1 = require("path");
|
|
12
14
|
const fileutils_1 = require("../utils/fileutils");
|
|
13
15
|
const ignore_1 = require("../utils/ignore");
|
|
@@ -25,16 +27,36 @@ class DeletedFileChange {
|
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
exports.DeletedFileChange = DeletedFileChange;
|
|
30
|
+
class LockFileChange {
|
|
31
|
+
constructor(baseContent, headContent) {
|
|
32
|
+
this.baseContent = baseContent;
|
|
33
|
+
this.headContent = headContent;
|
|
34
|
+
this.type = 'LockFileChange';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.LockFileChange = LockFileChange;
|
|
28
38
|
function isWholeFileChange(change) {
|
|
29
39
|
return change.type === 'WholeFileChange';
|
|
30
40
|
}
|
|
31
41
|
function isDeletedFileChange(change) {
|
|
32
42
|
return change.type === 'WholeFileDeleted';
|
|
33
43
|
}
|
|
44
|
+
function isLockFileChange(change) {
|
|
45
|
+
return change.type === 'LockFileChange';
|
|
46
|
+
}
|
|
47
|
+
const TEXT_LOCK_FILES = new Set([
|
|
48
|
+
'yarn.lock',
|
|
49
|
+
'package-lock.json',
|
|
50
|
+
'pnpm-lock.yaml',
|
|
51
|
+
'pnpm-lock.yml',
|
|
52
|
+
'bun.lock',
|
|
53
|
+
]);
|
|
54
|
+
const BINARY_LOCK_FILES = new Set(['bun.lockb']);
|
|
34
55
|
function calculateFileChanges(files, nxArgs, readFileAtRevision = defaultReadFileAtRevision, ignore = (0, ignore_1.getIgnoreObject)()) {
|
|
35
56
|
files = files.filter((f) => !ignore.ignores(f));
|
|
36
57
|
return files.map((f) => {
|
|
37
58
|
const ext = (0, path_1.extname)(f);
|
|
59
|
+
const basename = f.split('/').pop() ?? f;
|
|
38
60
|
return {
|
|
39
61
|
file: f,
|
|
40
62
|
getChanges: () => {
|
|
@@ -47,6 +69,16 @@ function calculateFileChanges(files, nxArgs, readFileAtRevision = defaultReadFil
|
|
|
47
69
|
if (nxArgs.files && nxArgs.files.includes(f)) {
|
|
48
70
|
return [new WholeFileChange()];
|
|
49
71
|
}
|
|
72
|
+
if (TEXT_LOCK_FILES.has(basename) || BINARY_LOCK_FILES.has(basename)) {
|
|
73
|
+
try {
|
|
74
|
+
const atBase = readLockFileAtRevision(f, basename, nxArgs.base, readFileAtRevision);
|
|
75
|
+
const atHead = readLockFileAtRevision(f, basename, nxArgs.head, readFileAtRevision);
|
|
76
|
+
return [new LockFileChange(atBase, atHead)];
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return [new WholeFileChange()];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
50
82
|
switch (ext) {
|
|
51
83
|
case '.json':
|
|
52
84
|
try {
|
|
@@ -75,18 +107,17 @@ function calculateFileChanges(files, nxArgs, readFileAtRevision = defaultReadFil
|
|
|
75
107
|
};
|
|
76
108
|
});
|
|
77
109
|
}
|
|
110
|
+
function readLockFileAtRevision(file, lockFileName, revision, readFileAtRevision) {
|
|
111
|
+
if (lockFileName === 'bun.lockb' &&
|
|
112
|
+
readFileAtRevision === defaultReadFileAtRevision) {
|
|
113
|
+
return defaultReadBunLockFileAtRevision(file, revision);
|
|
114
|
+
}
|
|
115
|
+
return readFileAtRevision(file, revision);
|
|
116
|
+
}
|
|
78
117
|
exports.TEN_MEGABYTES = 1024 * 10000;
|
|
79
118
|
function defaultReadFileAtRevision(file, revision) {
|
|
80
119
|
try {
|
|
81
|
-
const
|
|
82
|
-
const gitRepositoryPath = (0, child_process_1.execSync)('git rev-parse --show-toplevel', {
|
|
83
|
-
windowsHide: true,
|
|
84
|
-
})
|
|
85
|
-
.toString()
|
|
86
|
-
.trim();
|
|
87
|
-
const filePathInGitRepository = (0, path_1.relative)(gitRepositoryPath, fileFullPath)
|
|
88
|
-
.split(path_1.sep)
|
|
89
|
-
.join('/');
|
|
120
|
+
const filePathInGitRepository = getFilePathInGitRepository(file);
|
|
90
121
|
return !revision
|
|
91
122
|
? (0, fs_1.readFileSync)(file, 'utf-8')
|
|
92
123
|
: (0, child_process_1.execSync)(`git show ${revision}:${filePathInGitRepository}`, {
|
|
@@ -101,6 +132,43 @@ function defaultReadFileAtRevision(file, revision) {
|
|
|
101
132
|
return '';
|
|
102
133
|
}
|
|
103
134
|
}
|
|
135
|
+
function defaultReadBunLockFileAtRevision(file, revision) {
|
|
136
|
+
if (!revision) {
|
|
137
|
+
return (0, child_process_1.execFileSync)('bun', [(0, path_1.join)(workspace_root_1.workspaceRoot, file)], {
|
|
138
|
+
encoding: 'utf-8',
|
|
139
|
+
maxBuffer: exports.TEN_MEGABYTES,
|
|
140
|
+
windowsHide: true,
|
|
141
|
+
}).trim();
|
|
142
|
+
}
|
|
143
|
+
const filePathInGitRepository = getFilePathInGitRepository(file);
|
|
144
|
+
const tempDirectory = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'nx-bun-lock-'));
|
|
145
|
+
const tempLockfilePath = (0, path_1.join)(tempDirectory, 'bun.lockb');
|
|
146
|
+
try {
|
|
147
|
+
const lockFileContents = (0, child_process_1.execFileSync)('git', ['show', `${revision}:${filePathInGitRepository}`], {
|
|
148
|
+
maxBuffer: exports.TEN_MEGABYTES,
|
|
149
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
150
|
+
windowsHide: true,
|
|
151
|
+
});
|
|
152
|
+
(0, fs_1.writeFileSync)(tempLockfilePath, lockFileContents);
|
|
153
|
+
return (0, child_process_1.execFileSync)('bun', [tempLockfilePath], {
|
|
154
|
+
encoding: 'utf-8',
|
|
155
|
+
maxBuffer: exports.TEN_MEGABYTES,
|
|
156
|
+
windowsHide: true,
|
|
157
|
+
}).trim();
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
(0, fs_1.rmSync)(tempDirectory, { force: true, recursive: true });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function getFilePathInGitRepository(file) {
|
|
164
|
+
const fileFullPath = `${workspace_root_1.workspaceRoot}${path_1.sep}${file}`;
|
|
165
|
+
const gitRepositoryPath = (0, child_process_1.execSync)('git rev-parse --show-toplevel', {
|
|
166
|
+
windowsHide: true,
|
|
167
|
+
})
|
|
168
|
+
.toString()
|
|
169
|
+
.trim();
|
|
170
|
+
return (0, path_1.relative)(gitRepositoryPath, fileFullPath).split(path_1.sep).join('/');
|
|
171
|
+
}
|
|
104
172
|
function defaultFileRead(filePath) {
|
|
105
173
|
return (0, fs_1.readFileSync)((0, path_1.join)(workspace_root_1.workspaceRoot, filePath), 'utf-8');
|
|
106
174
|
}
|
|
@@ -3,5 +3,5 @@ import { Task, TaskGraph } from '../config/task-graph';
|
|
|
3
3
|
import { LifeCycle, TaskResult } from './life-cycle';
|
|
4
4
|
import type { ProjectGraph } from '../config/project-graph';
|
|
5
5
|
import { RunningTask } from './running-tasks/running-task';
|
|
6
|
-
export declare function runDiscreteTasks(tasks: Task[], projectGraph: ProjectGraph,
|
|
7
|
-
export declare function runContinuousTasks(tasks: Task[], projectGraph: ProjectGraph,
|
|
6
|
+
export declare function runDiscreteTasks(tasks: Task[], projectGraph: ProjectGraph, fullTaskGraph: TaskGraph, nxJson: NxJsonConfiguration, lifeCycle: LifeCycle): Promise<Array<Promise<TaskResult[]>>>;
|
|
7
|
+
export declare function runContinuousTasks(tasks: Task[], projectGraph: ProjectGraph, fullTaskGraph: TaskGraph, nxJson: NxJsonConfiguration, lifeCycle: LifeCycle): Promise<Record<string, Promise<RunningTask>>>;
|
|
@@ -10,7 +10,7 @@ const task_orchestrator_1 = require("./task-orchestrator");
|
|
|
10
10
|
const create_task_hasher_1 = require("../hasher/create-task-hasher");
|
|
11
11
|
const client_1 = require("../daemon/client/client");
|
|
12
12
|
const task_results_life_cycle_1 = require("./life-cycles/task-results-life-cycle");
|
|
13
|
-
async function createOrchestrator(tasks, projectGraph,
|
|
13
|
+
async function createOrchestrator(tasks, projectGraph, fullTaskGraph, nxJson, lifeCycle) {
|
|
14
14
|
(0, dotenv_1.loadRootEnvFiles)();
|
|
15
15
|
const invokeRunnerTerminalLifecycle = new invoke_runner_terminal_output_life_cycle_1.InvokeRunnerTerminalOutputLifeCycle(tasks);
|
|
16
16
|
const taskResultsLifecycle = new task_results_life_cycle_1.TaskResultsLifeCycle();
|
|
@@ -42,13 +42,13 @@ async function createOrchestrator(tasks, projectGraph, taskGraphForHashing, nxJs
|
|
|
42
42
|
lifeCycle: compositedLifeCycle,
|
|
43
43
|
};
|
|
44
44
|
(0, run_command_1.setEnvVarsBasedOnArgs)(nxArgs, true);
|
|
45
|
-
const orchestrator = new task_orchestrator_1.TaskOrchestrator(hasher, null, tasks, projectGraph, taskGraph, nxJson, nxArgs, false, client_1.daemonClient, undefined,
|
|
45
|
+
const orchestrator = new task_orchestrator_1.TaskOrchestrator(hasher, null, tasks, projectGraph, taskGraph, nxJson, nxArgs, false, client_1.daemonClient, undefined, fullTaskGraph);
|
|
46
46
|
await orchestrator.init();
|
|
47
47
|
orchestrator.processAllScheduledTasks();
|
|
48
48
|
return orchestrator;
|
|
49
49
|
}
|
|
50
|
-
async function runDiscreteTasks(tasks, projectGraph,
|
|
51
|
-
const orchestrator = await createOrchestrator(tasks, projectGraph,
|
|
50
|
+
async function runDiscreteTasks(tasks, projectGraph, fullTaskGraph, nxJson, lifeCycle) {
|
|
51
|
+
const orchestrator = await createOrchestrator(tasks, projectGraph, fullTaskGraph, nxJson, lifeCycle);
|
|
52
52
|
let groupId = 0;
|
|
53
53
|
let nextBatch = orchestrator.nextBatch();
|
|
54
54
|
const batchResults = [];
|
|
@@ -77,8 +77,8 @@ async function runDiscreteTasks(tasks, projectGraph, taskGraphForHashing, nxJson
|
|
|
77
77
|
});
|
|
78
78
|
return [...batchResults, ...taskResults];
|
|
79
79
|
}
|
|
80
|
-
async function runContinuousTasks(tasks, projectGraph,
|
|
81
|
-
const orchestrator = await createOrchestrator(tasks, projectGraph,
|
|
80
|
+
async function runContinuousTasks(tasks, projectGraph, fullTaskGraph, nxJson, lifeCycle) {
|
|
81
|
+
const orchestrator = await createOrchestrator(tasks, projectGraph, fullTaskGraph, nxJson, lifeCycle);
|
|
82
82
|
return tasks.reduce((current, task, index) => {
|
|
83
83
|
current[task.id] = orchestrator.startContinuousTask(task, index);
|
|
84
84
|
return current;
|
|
@@ -21,7 +21,7 @@ export declare class TaskOrchestrator {
|
|
|
21
21
|
private readonly bail;
|
|
22
22
|
private readonly daemon;
|
|
23
23
|
private readonly outputStyle;
|
|
24
|
-
private readonly
|
|
24
|
+
private readonly fullTaskGraph;
|
|
25
25
|
private taskDetails;
|
|
26
26
|
private cache;
|
|
27
27
|
private readonly tuiEnabled;
|
|
@@ -49,7 +49,7 @@ export declare class TaskOrchestrator {
|
|
|
49
49
|
private discreteTaskExitHandled;
|
|
50
50
|
private continuousTaskExitHandled;
|
|
51
51
|
private cleanupPromise;
|
|
52
|
-
constructor(hasher: TaskHasher, initiatingProject: string | undefined, initiatingTasks: Task[], projectGraph: ProjectGraph, taskGraph: TaskGraph, nxJson: NxJsonConfiguration, options: NxArgs & DefaultTasksRunnerOptions, bail: boolean, daemon: DaemonClient, outputStyle: string,
|
|
52
|
+
constructor(hasher: TaskHasher, initiatingProject: string | undefined, initiatingTasks: Task[], projectGraph: ProjectGraph, taskGraph: TaskGraph, nxJson: NxJsonConfiguration, options: NxArgs & DefaultTasksRunnerOptions, bail: boolean, daemon: DaemonClient, outputStyle: string, fullTaskGraph?: TaskGraph);
|
|
53
53
|
init(): Promise<void>;
|
|
54
54
|
run(): Promise<{
|
|
55
55
|
[k: string]: TaskStatus;
|
|
@@ -39,7 +39,7 @@ function resolveBatchTaskStatus(result) {
|
|
|
39
39
|
}
|
|
40
40
|
class TaskOrchestrator {
|
|
41
41
|
// endregion internal state
|
|
42
|
-
constructor(hasher, initiatingProject, initiatingTasks, projectGraph, taskGraph, nxJson, options, bail, daemon, outputStyle,
|
|
42
|
+
constructor(hasher, initiatingProject, initiatingTasks, projectGraph, taskGraph, nxJson, options, bail, daemon, outputStyle, fullTaskGraph = taskGraph) {
|
|
43
43
|
this.hasher = hasher;
|
|
44
44
|
this.initiatingProject = initiatingProject;
|
|
45
45
|
this.initiatingTasks = initiatingTasks;
|
|
@@ -50,7 +50,7 @@ class TaskOrchestrator {
|
|
|
50
50
|
this.bail = bail;
|
|
51
51
|
this.daemon = daemon;
|
|
52
52
|
this.outputStyle = outputStyle;
|
|
53
|
-
this.
|
|
53
|
+
this.fullTaskGraph = fullTaskGraph;
|
|
54
54
|
this.taskDetails = (0, hash_task_1.getTaskDetails)();
|
|
55
55
|
this.cache = (0, cache_1.getCache)(this.options);
|
|
56
56
|
this.tuiEnabled = (0, is_tui_enabled_1.isTuiEnabled)();
|
|
@@ -185,7 +185,7 @@ class TaskOrchestrator {
|
|
|
185
185
|
for (const task of unhashed) {
|
|
186
186
|
perTaskEnvs[task.id] = (0, task_env_1.getTaskSpecificEnv)(task, this.projectGraph);
|
|
187
187
|
}
|
|
188
|
-
await (0, hash_task_1.hashTasks)(this.hasher, this.projectGraph, this.
|
|
188
|
+
await (0, hash_task_1.hashTasks)(this.hasher, this.projectGraph, this.fullTaskGraph, perTaskEnvs, this.taskDetails, unhashed);
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
191
|
// 2. Bulk-resolve cache hits before processTask — avoids N
|
|
@@ -257,7 +257,7 @@ class TaskOrchestrator {
|
|
|
257
257
|
const task = this.taskGraph.tasks[taskId];
|
|
258
258
|
const taskSpecificEnv = (0, task_env_1.getTaskSpecificEnv)(task, this.projectGraph);
|
|
259
259
|
if (!task.hash) {
|
|
260
|
-
await (0, hash_task_1.hashTask)(this.hasher, this.projectGraph, this.
|
|
260
|
+
await (0, hash_task_1.hashTask)(this.hasher, this.projectGraph, this.fullTaskGraph, task, taskSpecificEnv, this.taskDetails);
|
|
261
261
|
}
|
|
262
262
|
await this.options.lifeCycle.scheduleTask(task);
|
|
263
263
|
return taskSpecificEnv;
|
|
@@ -474,7 +474,7 @@ class TaskOrchestrator {
|
|
|
474
474
|
for (const task of tasks) {
|
|
475
475
|
perTaskEnvs[task.id] = (0, task_env_1.getTaskSpecificEnv)(task, this.projectGraph);
|
|
476
476
|
}
|
|
477
|
-
await (0, hash_task_1.hashTasks)(this.hasher, this.projectGraph, this.
|
|
477
|
+
await (0, hash_task_1.hashTasks)(this.hasher, this.projectGraph, this.fullTaskGraph, perTaskEnvs, this.taskDetails, tasks);
|
|
478
478
|
}
|
|
479
479
|
async applyFromCacheOrRunBatch(doNotSkipCache, batch, groupId) {
|
|
480
480
|
const applyFromCacheOrRunBatchStart = perf_hooks_1.performance.mark('TaskOrchestrator-apply-from-cache-or-run-batch:start');
|
|
@@ -542,7 +542,7 @@ class TaskOrchestrator {
|
|
|
542
542
|
async runBatch(batch, env, groupId) {
|
|
543
543
|
const runBatchStart = perf_hooks_1.performance.mark('TaskOrchestrator-run-batch:start');
|
|
544
544
|
try {
|
|
545
|
-
const batchProcess = await this.forkedProcessTaskRunner.forkProcessForBatch(batch, this.projectGraph, this.
|
|
545
|
+
const batchProcess = await this.forkedProcessTaskRunner.forkProcessForBatch(batch, this.projectGraph, this.fullTaskGraph, env);
|
|
546
546
|
// Stream output from batch process to the batch
|
|
547
547
|
batchProcess.onOutput((output) => {
|
|
548
548
|
this.options.lifeCycle.appendBatchOutput?.(batch.id, output);
|