nx 23.1.0 → 23.2.0-beta.1
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/bin/nx.js +1 -1
- package/dist/src/ai/configure-ai-agents-disclaimer.d.ts +5 -0
- package/dist/src/ai/configure-ai-agents-disclaimer.js +31 -0
- package/dist/src/command-line/add/add.js +8 -1
- package/dist/src/command-line/import/import.js +1 -1
- package/dist/src/command-line/init/ai-agent-prompts.d.ts +1 -1
- package/dist/src/command-line/init/ai-agent-prompts.js +7 -6
- package/dist/src/command-line/init/command-object.js +10 -2
- package/dist/src/command-line/init/configure-plugins.js +3 -2
- package/dist/src/command-line/init/implementation/add-nx-to-monorepo.js +4 -2
- package/dist/src/command-line/init/implementation/add-nx-to-nest.js +4 -3
- package/dist/src/command-line/init/implementation/add-nx-to-npm-repo.js +4 -3
- package/dist/src/command-line/init/implementation/add-nx-to-turborepo.js +4 -3
- package/dist/src/command-line/init/implementation/angular/index.js +4 -2
- package/dist/src/command-line/init/implementation/utils.d.ts +3 -3
- package/dist/src/command-line/init/implementation/utils.js +22 -3
- package/dist/src/command-line/migrate/execute-migration.d.ts +72 -0
- package/dist/src/command-line/migrate/execute-migration.js +389 -0
- package/dist/src/command-line/migrate/migrate-ui-api.js +17 -12
- package/dist/src/command-line/migrate/migrate.d.ts +14 -45
- package/dist/src/command-line/migrate/migrate.js +58 -375
- package/dist/src/command-line/release/utils/git.js +6 -2
- package/dist/src/command-line/release/utils/release-graph.d.ts +2 -2
- package/dist/src/command-line/release/utils/shared.d.ts +2 -2
- package/dist/src/command-line/show/show-target/info.js +11 -2
- package/dist/src/commands-runner/create-command-graph.js +5 -0
- package/dist/src/config/nx-json.d.ts +1 -1
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/daemon/client/client.d.ts +0 -2
- package/dist/src/daemon/client/client.js +17 -19
- package/dist/src/devkit-internals.d.ts +2 -0
- package/dist/src/devkit-internals.js +7 -1
- package/dist/src/generators/utils/nx-json.js +13 -3
- package/dist/src/native/index.d.ts +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/npm-parser.js +71 -27
- package/dist/src/plugins/js/lock-file/pnpm-parser.js +46 -15
- package/dist/src/plugins/js/lock-file/project-graph-pruning.js +1 -1
- package/dist/src/plugins/js/lock-file/yarn-parser.js +32 -5
- package/dist/src/plugins/js/utils/register.d.ts +18 -0
- package/dist/src/plugins/js/utils/register.js +81 -0
- package/dist/src/plugins/js/utils/typescript.d.ts +9 -0
- package/dist/src/plugins/js/utils/typescript.js +15 -0
- package/dist/src/project-graph/error-types.js +41 -1
- package/dist/src/project-graph/file-utils.js +6 -1
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +4 -0
- package/dist/src/project-graph/plugins/transpiler.js +4 -0
- package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.d.ts +9 -12
- package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.js +77 -61
- package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.d.ts +1 -1
- package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.js +1 -1
- package/dist/src/project-graph/utils/project-configuration-utils.js +4 -6
- package/dist/src/tasks-runner/life-cycles/performance-analysis.d.ts +11 -4
- package/dist/src/tasks-runner/life-cycles/performance-analysis.js +15 -6
- package/dist/src/tasks-runner/life-cycles/performance-life-cycle.js +5 -4
- package/dist/src/tasks-runner/life-cycles/performance-report.d.ts +18 -8
- package/dist/src/tasks-runner/life-cycles/performance-report.js +66 -29
- package/dist/src/tasks-runner/run-command.js +5 -3
- package/dist/src/utils/acknowledge-build-scripts.d.ts +13 -0
- package/dist/src/utils/acknowledge-build-scripts.js +100 -0
- package/dist/src/utils/catalog/manager-utils.d.ts +1 -2
- package/dist/src/utils/catalog/manager-utils.js +22 -5
- package/dist/src/utils/catalog/pnpm-manager.d.ts +1 -0
- package/dist/src/utils/catalog/pnpm-manager.js +3 -15
- package/dist/src/utils/catalog/yarn-manager.d.ts +1 -0
- package/dist/src/utils/catalog/yarn-manager.js +3 -15
- package/dist/src/utils/command-line-utils.js +30 -20
- package/dist/src/utils/git-revision.d.ts +12 -0
- package/dist/src/utils/git-revision.js +25 -0
- package/dist/src/utils/git-utils.d.ts +2 -3
- package/dist/src/utils/git-utils.js +101 -47
- package/dist/src/utils/min-release-age/behavior/pnpm.js +9 -7
- package/dist/src/utils/package-manager.js +6 -2
- package/dist/src/utils/provenance.js +12 -2
- package/migrations.json +7 -1
- package/package.json +11 -11
- package/dist/src/migrations/update-17-3-0/nx-release-path.d.ts +0 -3
- package/dist/src/migrations/update-17-3-0/nx-release-path.js +0 -47
|
@@ -11,6 +11,7 @@ const yargs_parser_1 = tslib_1.__importDefault(require("yargs-parser"));
|
|
|
11
11
|
const file_utils_1 = require("../project-graph/file-utils");
|
|
12
12
|
const output_1 = require("./output");
|
|
13
13
|
const child_process_1 = require("child_process");
|
|
14
|
+
const git_revision_1 = require("./git-revision");
|
|
14
15
|
const workspace_root_1 = require("./workspace-root");
|
|
15
16
|
const shared_options_1 = require("../command-line/yargs-utils/shared-options");
|
|
16
17
|
function createOverrides(__overrides_unparsed__ = []) {
|
|
@@ -192,30 +193,27 @@ function parseFiles(options) {
|
|
|
192
193
|
}
|
|
193
194
|
}
|
|
194
195
|
function getUncommittedFiles() {
|
|
195
|
-
return parseGitOutput(
|
|
196
|
+
return parseGitOutput([
|
|
197
|
+
'diff',
|
|
198
|
+
'--name-only',
|
|
199
|
+
'--no-renames',
|
|
200
|
+
'--relative',
|
|
201
|
+
'HEAD',
|
|
202
|
+
'.',
|
|
203
|
+
]);
|
|
196
204
|
}
|
|
197
205
|
function getUntrackedFiles() {
|
|
198
|
-
return parseGitOutput(
|
|
206
|
+
return parseGitOutput(['ls-files', '--others', '--exclude-standard']);
|
|
199
207
|
}
|
|
200
208
|
function getMergeBase(base, head = 'HEAD') {
|
|
209
|
+
(0, git_revision_1.assertValidGitRevision)(base);
|
|
210
|
+
(0, git_revision_1.assertValidGitRevision)(head);
|
|
201
211
|
try {
|
|
202
|
-
return (
|
|
203
|
-
maxBuffer: file_utils_1.TEN_MEGABYTES,
|
|
204
|
-
cwd: workspace_root_1.workspaceRoot,
|
|
205
|
-
stdio: 'pipe',
|
|
206
|
-
windowsHide: true,
|
|
207
|
-
})
|
|
208
|
-
.toString()
|
|
209
|
-
.trim();
|
|
212
|
+
return runGit(['merge-base', base, head]).toString().trim();
|
|
210
213
|
}
|
|
211
214
|
catch {
|
|
212
215
|
try {
|
|
213
|
-
return (
|
|
214
|
-
maxBuffer: file_utils_1.TEN_MEGABYTES,
|
|
215
|
-
cwd: workspace_root_1.workspaceRoot,
|
|
216
|
-
stdio: 'pipe',
|
|
217
|
-
windowsHide: true,
|
|
218
|
-
})
|
|
216
|
+
return runGit(['merge-base', '--fork-point', base, head])
|
|
219
217
|
.toString()
|
|
220
218
|
.trim();
|
|
221
219
|
}
|
|
@@ -225,15 +223,27 @@ function getMergeBase(base, head = 'HEAD') {
|
|
|
225
223
|
}
|
|
226
224
|
}
|
|
227
225
|
function getFilesUsingBaseAndHead(base, head) {
|
|
228
|
-
|
|
226
|
+
(0, git_revision_1.assertValidGitRevision)(base);
|
|
227
|
+
(0, git_revision_1.assertValidGitRevision)(head);
|
|
228
|
+
return parseGitOutput([
|
|
229
|
+
'diff',
|
|
230
|
+
'--name-only',
|
|
231
|
+
'--no-renames',
|
|
232
|
+
'--relative',
|
|
233
|
+
base,
|
|
234
|
+
head,
|
|
235
|
+
]);
|
|
229
236
|
}
|
|
230
|
-
function
|
|
231
|
-
return (0, child_process_1.
|
|
237
|
+
function runGit(args) {
|
|
238
|
+
return (0, child_process_1.execFileSync)('git', args, {
|
|
232
239
|
maxBuffer: file_utils_1.TEN_MEGABYTES,
|
|
233
240
|
cwd: workspace_root_1.workspaceRoot,
|
|
234
241
|
stdio: 'pipe',
|
|
235
242
|
windowsHide: true,
|
|
236
|
-
})
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
function parseGitOutput(args) {
|
|
246
|
+
return runGit(args)
|
|
237
247
|
.toString('utf-8')
|
|
238
248
|
.split('\n')
|
|
239
249
|
.map((a) => a.trim())
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git parses any argument beginning with `-` as an option rather than a
|
|
3
|
+
* revision, so a flag-shaped revision could smuggle options such as
|
|
4
|
+
* `--upload-pack` into the git commands Nx runs.
|
|
5
|
+
*/
|
|
6
|
+
export declare function assertValidGitRevision(revision: string): void;
|
|
7
|
+
/**
|
|
8
|
+
* For refs Nx itself recorded from `git rev-parse` and later read back off
|
|
9
|
+
* disk, where anything other than a commit sha means the value was tampered
|
|
10
|
+
* with rather than that the user picked an unusual revision.
|
|
11
|
+
*/
|
|
12
|
+
export declare function assertValidGitSha(sha: string): void;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assertValidGitRevision = assertValidGitRevision;
|
|
4
|
+
exports.assertValidGitSha = assertValidGitSha;
|
|
5
|
+
/**
|
|
6
|
+
* Git parses any argument beginning with `-` as an option rather than a
|
|
7
|
+
* revision, so a flag-shaped revision could smuggle options such as
|
|
8
|
+
* `--upload-pack` into the git commands Nx runs.
|
|
9
|
+
*/
|
|
10
|
+
function assertValidGitRevision(revision) {
|
|
11
|
+
if (revision.startsWith('-')) {
|
|
12
|
+
throw new Error(`Invalid git revision: "${revision}". Git revisions cannot start with "-".`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const COMMIT_SHA = /^[0-9a-f]{7,40}$/i;
|
|
16
|
+
/**
|
|
17
|
+
* For refs Nx itself recorded from `git rev-parse` and later read back off
|
|
18
|
+
* disk, where anything other than a commit sha means the value was tampered
|
|
19
|
+
* with rather than that the user picked an unusual revision.
|
|
20
|
+
*/
|
|
21
|
+
function assertValidGitSha(sha) {
|
|
22
|
+
if (!COMMIT_SHA.test(sha)) {
|
|
23
|
+
throw new Error(`Invalid git commit sha: "${sha}". Expected a hexadecimal commit sha.`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -28,9 +28,7 @@ export declare class GitRepository {
|
|
|
28
28
|
hasFilterRepoInstalled(): Promise<boolean>;
|
|
29
29
|
filterRepo(source: string, destination: string): Promise<void>;
|
|
30
30
|
filterBranch(source: string, destination: string, branchName: string): Promise<void>;
|
|
31
|
-
private
|
|
32
|
-
private quotePath;
|
|
33
|
-
private quoteArg;
|
|
31
|
+
private execGit;
|
|
34
32
|
}
|
|
35
33
|
export interface VcsRemoteInfo {
|
|
36
34
|
domain: string;
|
|
@@ -39,6 +37,7 @@ export interface VcsRemoteInfo {
|
|
|
39
37
|
export declare function parseVcsRemoteUrl(url: string): VcsRemoteInfo | null;
|
|
40
38
|
export declare function getVcsRemoteInfo(directory?: string): VcsRemoteInfo | null;
|
|
41
39
|
export declare function isGitRepository(directory?: string): boolean;
|
|
40
|
+
export declare function getGitCurrentBranch(directory?: string): string | null;
|
|
42
41
|
export declare function hasUncommittedChanges(directory?: string): boolean;
|
|
43
42
|
export declare function getUncommittedChangesSnapshot(directory?: string): string;
|
|
44
43
|
export declare function commitChanges(commitMessage: string, directory?: string): string | null;
|
|
@@ -5,6 +5,7 @@ exports.cloneFromUpstream = cloneFromUpstream;
|
|
|
5
5
|
exports.parseVcsRemoteUrl = parseVcsRemoteUrl;
|
|
6
6
|
exports.getVcsRemoteInfo = getVcsRemoteInfo;
|
|
7
7
|
exports.isGitRepository = isGitRepository;
|
|
8
|
+
exports.getGitCurrentBranch = getGitCurrentBranch;
|
|
8
9
|
exports.hasUncommittedChanges = hasUncommittedChanges;
|
|
9
10
|
exports.getUncommittedChangesSnapshot = getUncommittedChangesSnapshot;
|
|
10
11
|
exports.commitChanges = commitChanges;
|
|
@@ -16,9 +17,9 @@ const crypto = tslib_1.__importStar(require("crypto"));
|
|
|
16
17
|
const fs = tslib_1.__importStar(require("fs"));
|
|
17
18
|
const path_1 = require("path");
|
|
18
19
|
const logger_1 = require("./logger");
|
|
19
|
-
function
|
|
20
|
+
function execFileAsync(file, args, execOptions) {
|
|
20
21
|
return new Promise((res, rej) => {
|
|
21
|
-
(0, child_process_1.
|
|
22
|
+
(0, child_process_1.execFile)(file, args, { ...execOptions, windowsHide: true }, (err, stdout) => {
|
|
22
23
|
if (err) {
|
|
23
24
|
return rej(err);
|
|
24
25
|
}
|
|
@@ -29,7 +30,14 @@ function execAsync(command, execOptions) {
|
|
|
29
30
|
async function cloneFromUpstream(url, destination, { originName, depth } = {
|
|
30
31
|
originName: 'origin',
|
|
31
32
|
}) {
|
|
32
|
-
await
|
|
33
|
+
await execFileAsync('git', [
|
|
34
|
+
'clone',
|
|
35
|
+
url,
|
|
36
|
+
destination,
|
|
37
|
+
...(depth ? ['--depth', `${depth}`] : []),
|
|
38
|
+
'--origin',
|
|
39
|
+
originName,
|
|
40
|
+
], {
|
|
33
41
|
cwd: (0, path_1.dirname)(destination),
|
|
34
42
|
maxBuffer: 10 * 1024 * 1024,
|
|
35
43
|
});
|
|
@@ -41,7 +49,7 @@ class GitRepository {
|
|
|
41
49
|
this.root = this.getGitRootPath(this.directory);
|
|
42
50
|
}
|
|
43
51
|
getGitRootPath(cwd) {
|
|
44
|
-
return (0, child_process_1.
|
|
52
|
+
return (0, child_process_1.execFileSync)('git', ['rev-parse', '--show-toplevel'], {
|
|
45
53
|
cwd,
|
|
46
54
|
windowsHide: true,
|
|
47
55
|
})
|
|
@@ -49,17 +57,22 @@ class GitRepository {
|
|
|
49
57
|
.trim();
|
|
50
58
|
}
|
|
51
59
|
async hasUncommittedChanges() {
|
|
52
|
-
const data = await this.
|
|
60
|
+
const data = await this.execGit(['status', '--porcelain']);
|
|
53
61
|
return data.trim() !== '';
|
|
54
62
|
}
|
|
55
63
|
async addFetchRemote(remoteName, branch) {
|
|
56
|
-
return await this.
|
|
64
|
+
return await this.execGit([
|
|
65
|
+
'config',
|
|
66
|
+
'--add',
|
|
67
|
+
`remote.${remoteName}.fetch`,
|
|
68
|
+
`+refs/heads/${branch}:refs/remotes/${remoteName}/${branch}`,
|
|
69
|
+
]);
|
|
57
70
|
}
|
|
58
71
|
async showStat() {
|
|
59
|
-
return await this.
|
|
72
|
+
return await this.execGit(['show', '--stat']);
|
|
60
73
|
}
|
|
61
74
|
async listBranches() {
|
|
62
|
-
return (await this.
|
|
75
|
+
return (await this.execGit(['ls-remote', '--heads', '--quiet']))
|
|
63
76
|
.trim()
|
|
64
77
|
.split('\n')
|
|
65
78
|
.map((s) => s
|
|
@@ -70,45 +83,58 @@ class GitRepository {
|
|
|
70
83
|
async getGitFiles(path) {
|
|
71
84
|
// Use -z to return file names exactly as they are stored in git, separated by NULL (\x00) character.
|
|
72
85
|
// This avoids problems with special characters in file names.
|
|
73
|
-
return (await this.
|
|
86
|
+
return (await this.execGit(['ls-files', '-z', '--', path]))
|
|
74
87
|
.trim()
|
|
75
88
|
.split('\x00')
|
|
76
89
|
.map((s) => s.trim())
|
|
77
90
|
.filter(Boolean);
|
|
78
91
|
}
|
|
79
92
|
async reset(ref) {
|
|
80
|
-
return await this.
|
|
93
|
+
return await this.execGit(['reset', '--hard', ref]);
|
|
81
94
|
}
|
|
82
95
|
async mergeUnrelatedHistories(ref, message) {
|
|
83
|
-
return await this.
|
|
96
|
+
return await this.execGit([
|
|
97
|
+
'merge',
|
|
98
|
+
ref,
|
|
99
|
+
'-X',
|
|
100
|
+
'ours',
|
|
101
|
+
'--allow-unrelated-histories',
|
|
102
|
+
'-m',
|
|
103
|
+
message,
|
|
104
|
+
]);
|
|
84
105
|
}
|
|
85
106
|
async fetch(remote, ref) {
|
|
86
|
-
return await this.
|
|
107
|
+
return await this.execGit(['fetch', remote, ...(ref ? [ref] : [])]);
|
|
87
108
|
}
|
|
88
109
|
async checkout(branch, opts) {
|
|
89
|
-
return await this.
|
|
110
|
+
return await this.execGit([
|
|
111
|
+
'checkout',
|
|
112
|
+
...(opts.new ? ['-b'] : []),
|
|
113
|
+
branch,
|
|
114
|
+
...(opts.base ? [opts.base] : []),
|
|
115
|
+
]);
|
|
90
116
|
}
|
|
91
117
|
async move(path, destination) {
|
|
92
|
-
return await this.
|
|
118
|
+
return await this.execGit(['mv', '--', path, destination]);
|
|
93
119
|
}
|
|
94
120
|
async push(ref, remoteName) {
|
|
95
|
-
return await this.
|
|
121
|
+
return await this.execGit(['push', '-u', '-f', remoteName, ref]);
|
|
96
122
|
}
|
|
97
123
|
async commit(message) {
|
|
98
|
-
return await this.
|
|
124
|
+
return await this.execGit(['commit', '-am', message]);
|
|
99
125
|
}
|
|
100
126
|
async amendCommit() {
|
|
101
|
-
return await this.
|
|
127
|
+
return await this.execGit(['commit', '--amend', '-a', '--no-edit']);
|
|
102
128
|
}
|
|
103
129
|
async deleteGitRemote(name) {
|
|
104
|
-
return await this.
|
|
130
|
+
return await this.execGit(['remote', 'rm', name]);
|
|
105
131
|
}
|
|
106
132
|
async addGitRemote(name, url) {
|
|
107
|
-
return await this.
|
|
133
|
+
return await this.execGit(['remote', 'add', name, url]);
|
|
108
134
|
}
|
|
109
135
|
async hasFilterRepoInstalled() {
|
|
110
136
|
try {
|
|
111
|
-
await this.
|
|
137
|
+
await this.execGit(['filter-repo', '--help']);
|
|
112
138
|
return true;
|
|
113
139
|
}
|
|
114
140
|
catch {
|
|
@@ -121,35 +147,57 @@ class GitRepository {
|
|
|
121
147
|
// NOTE: filter-repo requires POSIX path to work
|
|
122
148
|
const sourcePosixPath = source.split(path_1.sep).join(path_1.posix.sep);
|
|
123
149
|
const destinationPosixPath = destination.split(path_1.sep).join(path_1.posix.sep);
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
150
|
+
const sourcePath = ensureTrailingSlash(sourcePosixPath);
|
|
151
|
+
const destinationPath = ensureTrailingSlash(destinationPosixPath);
|
|
152
|
+
await this.execGit([
|
|
153
|
+
'filter-repo',
|
|
154
|
+
'-f',
|
|
155
|
+
...(source !== '' ? ['--path', sourcePosixPath] : []),
|
|
156
|
+
...(source !== destination
|
|
157
|
+
? ['--path-rename', `${sourcePath}:${destinationPath}`]
|
|
158
|
+
: []),
|
|
159
|
+
]);
|
|
127
160
|
}
|
|
128
161
|
async filterBranch(source, destination, branchName) {
|
|
129
162
|
// We need non-ASCII file names to not be quoted, or else filter-branch will exclude them.
|
|
130
|
-
await this.
|
|
163
|
+
await this.execGit(['config', 'core.quotepath', 'false']);
|
|
131
164
|
// NOTE: filter-repo requires POSIX path to work
|
|
132
165
|
const sourcePosixPath = source.split(path_1.sep).join(path_1.posix.sep);
|
|
133
166
|
const destinationPosixPath = destination.split(path_1.sep).join(path_1.posix.sep);
|
|
134
167
|
// First, if the source is not a root project, then only include commits relevant to the subdirectory.
|
|
135
168
|
if (source !== '') {
|
|
136
|
-
const indexFilterCommand =
|
|
137
|
-
await this.
|
|
169
|
+
const indexFilterCommand = `node ${quoteForShell((0, path_1.join)(__dirname, 'git-utils.index-filter.js'))}`;
|
|
170
|
+
await this.execGit([
|
|
171
|
+
'filter-branch',
|
|
172
|
+
'-f',
|
|
173
|
+
'--index-filter',
|
|
174
|
+
indexFilterCommand,
|
|
175
|
+
'--prune-empty',
|
|
176
|
+
'--',
|
|
177
|
+
branchName,
|
|
178
|
+
], {
|
|
138
179
|
NX_IMPORT_SOURCE: sourcePosixPath,
|
|
139
180
|
NX_IMPORT_DESTINATION: destinationPosixPath,
|
|
140
181
|
});
|
|
141
182
|
}
|
|
142
183
|
// Then, move files to their new location if necessary.
|
|
143
184
|
if (source === '' || source !== destination) {
|
|
144
|
-
const treeFilterCommand =
|
|
145
|
-
await this.
|
|
185
|
+
const treeFilterCommand = `node ${quoteForShell((0, path_1.join)(__dirname, 'git-utils.tree-filter.js'))}`;
|
|
186
|
+
await this.execGit([
|
|
187
|
+
'filter-branch',
|
|
188
|
+
'-f',
|
|
189
|
+
'--tree-filter',
|
|
190
|
+
treeFilterCommand,
|
|
191
|
+
'--',
|
|
192
|
+
branchName,
|
|
193
|
+
], {
|
|
146
194
|
NX_IMPORT_SOURCE: sourcePosixPath,
|
|
147
195
|
NX_IMPORT_DESTINATION: destinationPosixPath,
|
|
148
196
|
});
|
|
149
197
|
}
|
|
150
198
|
}
|
|
151
|
-
|
|
152
|
-
return
|
|
199
|
+
execGit(args, env) {
|
|
200
|
+
return execFileAsync('git', args, {
|
|
153
201
|
cwd: this.root,
|
|
154
202
|
maxBuffer: 10 * 1024 * 1024,
|
|
155
203
|
env: {
|
|
@@ -158,25 +206,14 @@ class GitRepository {
|
|
|
158
206
|
},
|
|
159
207
|
});
|
|
160
208
|
}
|
|
161
|
-
quotePath(path, ensureTrailingSlash) {
|
|
162
|
-
return this.quoteArg(ensureTrailingSlash && path !== '' && !path.endsWith('/')
|
|
163
|
-
? `${path}/`
|
|
164
|
-
: path);
|
|
165
|
-
}
|
|
166
|
-
quoteArg(arg) {
|
|
167
|
-
return process.platform === 'win32'
|
|
168
|
-
? // Windows/CMD only understands double-quotes, single-quotes are treated as part of the file name
|
|
169
|
-
// Bash and other shells will substitute `$` in file names with a variable value.
|
|
170
|
-
`"${arg
|
|
171
|
-
// Need to keep two slashes for Windows or else the path will be invalid.
|
|
172
|
-
// e.g. 'C:\Users\bob\projects\repo' is invalid, but 'C:\\Users\\bob\\projects\\repo' is valid
|
|
173
|
-
.replaceAll('\\', '\\\\')}"`
|
|
174
|
-
: // e.g. `git mv "$$file.txt" "libs/a/$$file.txt"` will not work since `$$` is swapped with the PID of the last process.
|
|
175
|
-
// Using single-quotes prevents this substitution.
|
|
176
|
-
`'${arg}'`;
|
|
177
|
-
}
|
|
178
209
|
}
|
|
179
210
|
exports.GitRepository = GitRepository;
|
|
211
|
+
function ensureTrailingSlash(path) {
|
|
212
|
+
return path !== '' && !path.endsWith('/') ? `${path}/` : path;
|
|
213
|
+
}
|
|
214
|
+
function quoteForShell(arg) {
|
|
215
|
+
return `'${arg.replaceAll("'", "'\"'\"'")}'`;
|
|
216
|
+
}
|
|
180
217
|
function parseVcsRemoteUrl(url) {
|
|
181
218
|
// Remove whitespace and handle common URL formats
|
|
182
219
|
const cleanUrl = url.trim();
|
|
@@ -273,6 +310,23 @@ function isGitRepository(directory) {
|
|
|
273
310
|
return false;
|
|
274
311
|
}
|
|
275
312
|
}
|
|
313
|
+
// Checked-out branch name, or null when there isn't one to act on: a detached
|
|
314
|
+
// HEAD reports the literal "HEAD" (treated as no branch), and any git error
|
|
315
|
+
// (not a repo, no commits yet) also yields null.
|
|
316
|
+
function getGitCurrentBranch(directory) {
|
|
317
|
+
try {
|
|
318
|
+
const branch = (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD', {
|
|
319
|
+
encoding: 'utf8',
|
|
320
|
+
cwd: directory,
|
|
321
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
322
|
+
windowsHide: true,
|
|
323
|
+
}).trim();
|
|
324
|
+
return branch && branch !== 'HEAD' ? branch : null;
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
276
330
|
// Sync companion to `GitRepository.hasUncommittedChanges` for callers that
|
|
277
331
|
// can't drop into the async class (e.g. the migrate orchestrator, which
|
|
278
332
|
// branches on this before spawning subprocesses synchronously).
|
|
@@ -88,15 +88,17 @@ function readPnpmConfigList(root) {
|
|
|
88
88
|
return null;
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
-
// Extracts the cooldown keys from pnpm's reported config. pnpm reports
|
|
92
|
-
//
|
|
93
|
-
//
|
|
91
|
+
// Extracts the cooldown keys from pnpm's reported config. pnpm 11 reports them
|
|
92
|
+
// camelCase; pnpm 10 reported them kebab-case, so read both forms. The exclude
|
|
93
|
+
// list comes back as a JSON array (set in a yaml surface) or a comma-joined
|
|
94
|
+
// string (set via .npmrc / env).
|
|
94
95
|
function parseCooldownConfig(config) {
|
|
96
|
+
const read = (camelKey, kebabKey) => config[camelKey] ?? config[kebabKey];
|
|
95
97
|
return {
|
|
96
|
-
windowMinutes: toNumber(
|
|
97
|
-
excludes: parseExcludeValue(
|
|
98
|
-
strictExplicit: toBoolean(
|
|
99
|
-
ignoreMissingTimeExplicit: toBoolean(
|
|
98
|
+
windowMinutes: toNumber(read('minimumReleaseAge', 'minimum-release-age')) ?? undefined,
|
|
99
|
+
excludes: parseExcludeValue(read('minimumReleaseAgeExclude', 'minimum-release-age-exclude')),
|
|
100
|
+
strictExplicit: toBoolean(read('minimumReleaseAgeStrict', 'minimum-release-age-strict')),
|
|
101
|
+
ignoreMissingTimeExplicit: toBoolean(read('minimumReleaseAgeIgnoreMissingTime', 'minimum-release-age-ignore-missing-time')),
|
|
100
102
|
};
|
|
101
103
|
}
|
|
102
104
|
function parseExcludeValue(value) {
|
|
@@ -165,8 +165,12 @@ function getPackageManagerCommand(packageManager = detectPackageManager(), root
|
|
|
165
165
|
install: 'pnpm install --no-frozen-lockfile', // explicitly disable in case of CI
|
|
166
166
|
ciInstall: 'pnpm install --frozen-lockfile',
|
|
167
167
|
updateLockFile: 'pnpm install --lockfile-only',
|
|
168
|
-
add: isPnpmWorkspace
|
|
169
|
-
|
|
168
|
+
add: isPnpmWorkspace
|
|
169
|
+
? 'pnpm add -w --config.frozen-lockfile=false'
|
|
170
|
+
: 'pnpm add --config.frozen-lockfile=false',
|
|
171
|
+
addDev: isPnpmWorkspace
|
|
172
|
+
? 'pnpm add -Dw --config.frozen-lockfile=false'
|
|
173
|
+
: 'pnpm add -D --config.frozen-lockfile=false',
|
|
170
174
|
rm: 'pnpm rm',
|
|
171
175
|
exec: modernPnpm ? 'pnpm exec' : 'pnpx',
|
|
172
176
|
dlx: modernPnpm ? 'pnpm dlx' : 'pnpx',
|
|
@@ -22,8 +22,18 @@ async function ensurePackageHasProvenance(packageName, packageVersion) {
|
|
|
22
22
|
}
|
|
23
23
|
try {
|
|
24
24
|
const result = await (0, package_manager_1.packageRegistryView)(packageName, packageVersion, '--json --silent');
|
|
25
|
-
const
|
|
26
|
-
|
|
25
|
+
const parsed = JSON.parse(result);
|
|
26
|
+
// `npm view <pkg>@<spec> --json` returns a bare object on npm <= 11 but an
|
|
27
|
+
// array on npm 12 and pnpm, even for a single resolved version. A version
|
|
28
|
+
// range matches several versions and the registry lists all of them
|
|
29
|
+
// (including deprecated ones the installer skips), so we cannot tell which
|
|
30
|
+
// one will actually be installed; refuse rather than verify the wrong
|
|
31
|
+
// artifact.
|
|
32
|
+
if (Array.isArray(parsed) && parsed.length > 1) {
|
|
33
|
+
throw new ProvenanceError(packageName, packageVersion, 'Provenance can only be verified for a single version, but this version resolved to multiple candidates. Specify an exact version.');
|
|
34
|
+
}
|
|
35
|
+
const npmViewResult = Array.isArray(parsed) ? parsed[0] : parsed;
|
|
36
|
+
const attURL = npmViewResult?.dist?.attestations?.url;
|
|
27
37
|
if (!attURL)
|
|
28
38
|
throw new ProvenanceError(packageName, packageVersion, 'No attestation URL found');
|
|
29
39
|
const response = await fetch(attURL);
|
package/migrations.json
CHANGED
|
@@ -160,7 +160,13 @@
|
|
|
160
160
|
"cli": "nx",
|
|
161
161
|
"version": "22.6.0-rc.0",
|
|
162
162
|
"description": "Adds .claude/settings.local.json to .gitignore",
|
|
163
|
-
"implementation": "./dist/src/migrations/update-
|
|
163
|
+
"implementation": "./dist/src/migrations/update-22-6-0/add-claude-settings-local-to-git-ignore"
|
|
164
|
+
},
|
|
165
|
+
"22-6-0-enable-analytics-prompt": {
|
|
166
|
+
"cli": "nx",
|
|
167
|
+
"version": "22.6.0-beta.11",
|
|
168
|
+
"description": "Prompts to enable usage analytics",
|
|
169
|
+
"implementation": "./dist/src/migrations/update-22-6-0/enable-analytics-prompt"
|
|
164
170
|
},
|
|
165
171
|
"22-7-0-add-self-healing-to-gitignore": {
|
|
166
172
|
"cli": "nx",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nx",
|
|
3
|
-
"version": "23.
|
|
3
|
+
"version": "23.2.0-beta.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.",
|
|
@@ -176,16 +176,16 @@
|
|
|
176
176
|
}
|
|
177
177
|
},
|
|
178
178
|
"optionalDependencies": {
|
|
179
|
-
"@nx/nx-darwin-arm64": "23.
|
|
180
|
-
"@nx/nx-darwin-x64": "23.
|
|
181
|
-
"@nx/nx-freebsd-x64": "23.
|
|
182
|
-
"@nx/nx-linux-arm-gnueabihf": "23.
|
|
183
|
-
"@nx/nx-linux-arm64-gnu": "23.
|
|
184
|
-
"@nx/nx-linux-arm64-musl": "23.
|
|
185
|
-
"@nx/nx-linux-x64-gnu": "23.
|
|
186
|
-
"@nx/nx-linux-x64-musl": "23.
|
|
187
|
-
"@nx/nx-win32-arm64-msvc": "23.
|
|
188
|
-
"@nx/nx-win32-x64-msvc": "23.
|
|
179
|
+
"@nx/nx-darwin-arm64": "23.2.0-beta.1",
|
|
180
|
+
"@nx/nx-darwin-x64": "23.2.0-beta.1",
|
|
181
|
+
"@nx/nx-freebsd-x64": "23.2.0-beta.1",
|
|
182
|
+
"@nx/nx-linux-arm-gnueabihf": "23.2.0-beta.1",
|
|
183
|
+
"@nx/nx-linux-arm64-gnu": "23.2.0-beta.1",
|
|
184
|
+
"@nx/nx-linux-arm64-musl": "23.2.0-beta.1",
|
|
185
|
+
"@nx/nx-linux-x64-gnu": "23.2.0-beta.1",
|
|
186
|
+
"@nx/nx-linux-x64-musl": "23.2.0-beta.1",
|
|
187
|
+
"@nx/nx-win32-arm64-msvc": "23.2.0-beta.1",
|
|
188
|
+
"@nx/nx-win32-x64-msvc": "23.2.0-beta.1"
|
|
189
189
|
},
|
|
190
190
|
"nx-migrations": {
|
|
191
191
|
"migrations": "./migrations.json",
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.default = nxReleasePath;
|
|
4
|
-
exports.visitNotIgnoredFiles = visitNotIgnoredFiles;
|
|
5
|
-
const node_path_1 = require("node:path");
|
|
6
|
-
const ignore_1 = require("../../utils/ignore");
|
|
7
|
-
function nxReleasePath(tree) {
|
|
8
|
-
visitNotIgnoredFiles(tree, '', (file) => {
|
|
9
|
-
const contents = tree.read(file).toString('utf-8');
|
|
10
|
-
if (
|
|
11
|
-
// the deep import usage should be replaced by the new location
|
|
12
|
-
contents.includes('nx/src/command-line/release') ||
|
|
13
|
-
// changelog-renderer has moved into nx/release
|
|
14
|
-
contents.includes('nx/changelog-renderer')) {
|
|
15
|
-
const finalContents = contents
|
|
16
|
-
// replace instances of old changelog renderer location
|
|
17
|
-
.replace(/nx\/changelog-renderer/g, 'nx/release/changelog-renderer')
|
|
18
|
-
// replace instances of deep import for programmatic API (only perform the replacement if an actual import by checking for trailing ' or ")
|
|
19
|
-
.replace(/nx\/src\/command-line\/release(['"])/g, 'nx/release$1');
|
|
20
|
-
tree.write(file, finalContents);
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
// Adapted from devkit
|
|
25
|
-
function visitNotIgnoredFiles(tree, dirPath = tree.root, visitor) {
|
|
26
|
-
const ig = (0, ignore_1.getIgnoreObject)();
|
|
27
|
-
dirPath = normalizePathRelativeToRoot(dirPath, tree.root);
|
|
28
|
-
if (dirPath !== '' && ig?.ignores(dirPath)) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
for (const child of tree.children(dirPath)) {
|
|
32
|
-
const fullPath = (0, node_path_1.join)(dirPath, child);
|
|
33
|
-
if (ig?.ignores(fullPath)) {
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
if (tree.isFile(fullPath)) {
|
|
37
|
-
visitor(fullPath);
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
visitNotIgnoredFiles(tree, fullPath, visitor);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
// Copied from devkit
|
|
45
|
-
function normalizePathRelativeToRoot(path, root) {
|
|
46
|
-
return (0, node_path_1.relative)(root, (0, node_path_1.join)(root, path)).split(node_path_1.sep).join('/');
|
|
47
|
-
}
|