nx 19.8.0-canary.20240917-5b34ea5 → 19.8.0-canary.20240918-eb61254
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/package.json +12 -12
- package/schemas/nx-schema.json +2 -2
- package/src/command-line/import/import.js +9 -4
- package/src/command-line/import/utils/prepare-source-repo.js +7 -35
- package/src/command-line/init/init-v2.d.ts +1 -1
- package/src/command-line/init/init-v2.js +10 -4
- package/src/command-line/release/command-object.d.ts +2 -2
- package/src/command-line/release/config/config.js +8 -2
- package/src/command-line/release/utils/git.d.ts +2 -2
- package/src/command-line/release/utils/git.js +12 -2
- package/src/command-line/release/utils/shared.d.ts +1 -1
- package/src/command-line/release/version.js +4 -0
- package/src/config/nx-json.d.ts +13 -5
- package/src/native/nx.wasm32-wasi.wasm +0 -0
- package/src/tasks-runner/init-tasks-runner.d.ts +1 -1
- package/src/tasks-runner/init-tasks-runner.js +5 -3
- package/src/tasks-runner/life-cycles/invoke-runner-terminal-output-life-cycle.d.ts +0 -2
- package/src/tasks-runner/life-cycles/invoke-runner-terminal-output-life-cycle.js +0 -5
- package/src/tasks-runner/life-cycles/static-run-many-terminal-output-life-cycle.d.ts +2 -6
- package/src/tasks-runner/life-cycles/static-run-one-terminal-output-life-cycle.d.ts +2 -6
- package/src/tasks-runner/life-cycles/store-run-information-life-cycle.d.ts +2 -7
- package/src/tasks-runner/life-cycles/task-profiling-life-cycle.d.ts +2 -7
- package/src/tasks-runner/life-cycles/task-results-life-cycle.d.ts +6 -0
- package/src/tasks-runner/life-cycles/task-results-life-cycle.js +17 -0
- package/src/tasks-runner/life-cycles/task-timings-life-cycle.d.ts +2 -7
- package/src/tasks-runner/run-command.d.ts +12 -2
- package/src/tasks-runner/run-command.js +50 -59
- package/src/tasks-runner/task-orchestrator.d.ts +0 -1
- package/src/tasks-runner/task-orchestrator.js +3 -6
- package/src/utils/git-utils.d.ts +4 -2
- package/src/utils/git-utils.index-filter.d.ts +0 -0
- package/src/utils/git-utils.index-filter.js +20 -0
- package/src/utils/git-utils.js +48 -13
- package/src/utils/git-utils.tree-filter.d.ts +11 -0
- package/src/utils/git-utils.tree-filter.js +43 -0
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "nx",
|
3
|
-
"version": "19.8.0-canary.
|
3
|
+
"version": "19.8.0-canary.20240918-eb61254",
|
4
4
|
"private": false,
|
5
5
|
"description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.",
|
6
6
|
"repository": {
|
@@ -71,7 +71,7 @@
|
|
71
71
|
"yargs-parser": "21.1.1",
|
72
72
|
"node-machine-id": "1.1.12",
|
73
73
|
"ora": "5.3.0",
|
74
|
-
"@nrwl/tao": "19.8.0-canary.
|
74
|
+
"@nrwl/tao": "19.8.0-canary.20240918-eb61254"
|
75
75
|
},
|
76
76
|
"peerDependencies": {
|
77
77
|
"@swc-node/register": "^1.8.0",
|
@@ -86,16 +86,16 @@
|
|
86
86
|
}
|
87
87
|
},
|
88
88
|
"optionalDependencies": {
|
89
|
-
"@nx/nx-darwin-x64": "19.8.0-canary.
|
90
|
-
"@nx/nx-darwin-arm64": "19.8.0-canary.
|
91
|
-
"@nx/nx-linux-x64-gnu": "19.8.0-canary.
|
92
|
-
"@nx/nx-linux-x64-musl": "19.8.0-canary.
|
93
|
-
"@nx/nx-win32-x64-msvc": "19.8.0-canary.
|
94
|
-
"@nx/nx-linux-arm64-gnu": "19.8.0-canary.
|
95
|
-
"@nx/nx-linux-arm64-musl": "19.8.0-canary.
|
96
|
-
"@nx/nx-linux-arm-gnueabihf": "19.8.0-canary.
|
97
|
-
"@nx/nx-win32-arm64-msvc": "19.8.0-canary.
|
98
|
-
"@nx/nx-freebsd-x64": "19.8.0-canary.
|
89
|
+
"@nx/nx-darwin-x64": "19.8.0-canary.20240918-eb61254",
|
90
|
+
"@nx/nx-darwin-arm64": "19.8.0-canary.20240918-eb61254",
|
91
|
+
"@nx/nx-linux-x64-gnu": "19.8.0-canary.20240918-eb61254",
|
92
|
+
"@nx/nx-linux-x64-musl": "19.8.0-canary.20240918-eb61254",
|
93
|
+
"@nx/nx-win32-x64-msvc": "19.8.0-canary.20240918-eb61254",
|
94
|
+
"@nx/nx-linux-arm64-gnu": "19.8.0-canary.20240918-eb61254",
|
95
|
+
"@nx/nx-linux-arm64-musl": "19.8.0-canary.20240918-eb61254",
|
96
|
+
"@nx/nx-linux-arm-gnueabihf": "19.8.0-canary.20240918-eb61254",
|
97
|
+
"@nx/nx-win32-arm64-msvc": "19.8.0-canary.20240918-eb61254",
|
98
|
+
"@nx/nx-freebsd-x64": "19.8.0-canary.20240918-eb61254"
|
99
99
|
},
|
100
100
|
"nx-migrations": {
|
101
101
|
"migrations": "./migrations.json",
|
package/schemas/nx-schema.json
CHANGED
@@ -634,7 +634,7 @@
|
|
634
634
|
"description": "Custom git commit message to use when committing the changes made by this command"
|
635
635
|
},
|
636
636
|
"commitArgs": {
|
637
|
-
"type": "string",
|
637
|
+
"type": ["string", "array"],
|
638
638
|
"description": "Additional arguments (added after the --message argument, which may or may not be customized with --git-commit-message) to pass to the `git commit` command invoked behind the scenes"
|
639
639
|
},
|
640
640
|
"stageChanges": {
|
@@ -650,7 +650,7 @@
|
|
650
650
|
"description": "Custom git tag message to use when tagging the changes made by this command. This defaults to be the same value as the tag itself."
|
651
651
|
},
|
652
652
|
"tagArgs": {
|
653
|
-
"type": "string",
|
653
|
+
"type": ["string", "array"],
|
654
654
|
"description": "Additional arguments to pass to the `git tag` command invoked behind the scenes"
|
655
655
|
}
|
656
656
|
}
|
@@ -25,7 +25,12 @@ const needs_install_1 = require("./utils/needs-install");
|
|
25
25
|
const file_utils_1 = require("../../project-graph/file-utils");
|
26
26
|
const importRemoteName = '__tmp_nx_import__';
|
27
27
|
async function importHandler(options) {
|
28
|
+
process.env.NX_RUNNING_NX_IMPORT = 'true';
|
28
29
|
let { sourceRepository, ref, source, destination } = options;
|
30
|
+
const destinationGitClient = new git_utils_1.GitRepository(process.cwd());
|
31
|
+
if (await destinationGitClient.hasUncommittedChanges()) {
|
32
|
+
throw new Error(`You have uncommitted changes in the destination repository. Commit or revert the changes and try again.`);
|
33
|
+
}
|
29
34
|
output_1.output.log({
|
30
35
|
title: 'Nx will walk you through the process of importing code from the source repository into this repository:',
|
31
36
|
bodyLines: [
|
@@ -120,7 +125,6 @@ async function importHandler(options) {
|
|
120
125
|
throw new Error(`The destination directory must be a relative path in this repository.`);
|
121
126
|
}
|
122
127
|
const absDestination = (0, path_1.join)(process.cwd(), destination);
|
123
|
-
const destinationGitClient = new git_utils_1.GitRepository(process.cwd());
|
124
128
|
await assertDestinationEmpty(destinationGitClient, absDestination);
|
125
129
|
const tempImportBranch = getTempImportBranch(ref);
|
126
130
|
await sourceGitClient.addFetchRemote(importRemoteName, ref);
|
@@ -152,7 +156,7 @@ async function importHandler(options) {
|
|
152
156
|
const pmc = (0, package_manager_1.getPackageManagerCommand)();
|
153
157
|
const nxJson = (0, nx_json_1.readNxJson)(workspace_root_1.workspaceRoot);
|
154
158
|
(0, workspace_context_1.resetWorkspaceContext)();
|
155
|
-
const { plugins, updatePackageScripts } = await (0, init_v2_1.detectPlugins)(nxJson, options.interactive);
|
159
|
+
const { plugins, updatePackageScripts } = await (0, init_v2_1.detectPlugins)(nxJson, options.interactive, true);
|
156
160
|
if (packageManager !== sourcePackageManager) {
|
157
161
|
output_1.output.warn({
|
158
162
|
title: `Mismatched package managers`,
|
@@ -232,8 +236,9 @@ async function importHandler(options) {
|
|
232
236
|
title: `Merging these changes into ${(0, command_line_utils_1.getBaseRef)(nxJson)}`,
|
233
237
|
bodyLines: [
|
234
238
|
`MERGE these changes when merging these changes.`,
|
235
|
-
`Do NOT squash
|
236
|
-
`If you
|
239
|
+
`Do NOT squash these commits when merging these changes.`,
|
240
|
+
`If you rebase, make sure to use "--rebase-merges" to preserve merge commits.`,
|
241
|
+
`To UNDO these changes, run "git reset HEAD~1 --hard"`,
|
237
242
|
],
|
238
243
|
});
|
239
244
|
}
|
@@ -3,46 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.prepareSourceRepo = prepareSourceRepo;
|
4
4
|
const createSpinner = require("ora");
|
5
5
|
const path_1 = require("path");
|
6
|
-
const promises_1 = require("node:fs/promises");
|
7
6
|
async function prepareSourceRepo(gitClient, ref, source, relativeDestination, tempImportBranch, sourceRemoteUrl) {
|
8
7
|
const spinner = createSpinner().start(`Fetching ${ref} from ${sourceRemoteUrl}`);
|
9
8
|
const relativeSourceDir = (0, path_1.relative)(gitClient.root, (0, path_1.join)(gitClient.root, source));
|
10
|
-
if (
|
11
|
-
|
12
|
-
|
13
|
-
await gitClient.filterRepo(relativeSourceDir);
|
14
|
-
}
|
15
|
-
else {
|
16
|
-
spinner.start(`Filtering git history to only include files in ${relativeSourceDir} (this might take a few minutes -- install git-filter-repo for faster performance)`);
|
17
|
-
await gitClient.filterBranch(relativeSourceDir, tempImportBranch);
|
18
|
-
}
|
19
|
-
spinner.succeed(`Filtered git history to only include files in ${relativeSourceDir}`);
|
9
|
+
if (await gitClient.hasFilterRepoInstalled()) {
|
10
|
+
spinner.start(`Filtering git history to only include files in ${relativeSourceDir}`);
|
11
|
+
await gitClient.filterRepo(relativeSourceDir, relativeDestination);
|
20
12
|
}
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
const files = await gitClient.getGitFiles('.');
|
25
|
-
try {
|
26
|
-
await (0, promises_1.rm)(destinationInSource, {
|
27
|
-
recursive: true,
|
28
|
-
});
|
13
|
+
else {
|
14
|
+
spinner.start(`Filtering git history to only include files in ${relativeSourceDir} (this might take a few minutes -- install git-filter-repo for faster performance)`);
|
15
|
+
await gitClient.filterBranch(relativeSourceDir, relativeDestination, tempImportBranch);
|
29
16
|
}
|
30
|
-
|
31
|
-
await (0, promises_1.mkdir)(destinationInSource, { recursive: true });
|
32
|
-
for (const file of files) {
|
33
|
-
spinner.start(`Moving files and git history to ${destinationInSource}: ${file}`);
|
34
|
-
const newPath = (0, path_1.join)(destinationInSource, file);
|
35
|
-
await (0, promises_1.mkdir)((0, path_1.dirname)(newPath), { recursive: true });
|
36
|
-
try {
|
37
|
-
await gitClient.move(file, newPath);
|
38
|
-
}
|
39
|
-
catch {
|
40
|
-
await wait(100);
|
41
|
-
await gitClient.move(file, newPath);
|
42
|
-
}
|
43
|
-
}
|
44
|
-
await gitClient.commit(`chore(repo): move ${source} to ${relativeDestination} to prepare to be imported`);
|
45
|
-
await gitClient.amendCommit();
|
17
|
+
spinner.succeed(`Filtered git history to only include files in ${relativeSourceDir}`);
|
46
18
|
spinner.succeed(`${sourceRemoteUrl} has been prepared to be imported into this workspace on a temporary branch: ${tempImportBranch} in ${gitClient.root}`);
|
47
19
|
}
|
48
20
|
function wait(ms) {
|
@@ -8,7 +8,7 @@ export interface InitArgs {
|
|
8
8
|
}
|
9
9
|
export declare function installPlugins(repoRoot: string, plugins: string[], pmc: PackageManagerCommands, updatePackageScripts: boolean): void;
|
10
10
|
export declare function initHandler(options: InitArgs): Promise<void>;
|
11
|
-
export declare function detectPlugins(nxJson: NxJsonConfiguration, interactive: boolean): Promise<{
|
11
|
+
export declare function detectPlugins(nxJson: NxJsonConfiguration, interactive: boolean, includeAngularCli?: boolean): Promise<{
|
12
12
|
plugins: string[];
|
13
13
|
updatePackageScripts: boolean;
|
14
14
|
}>;
|
@@ -127,8 +127,8 @@ const npmPackageToPluginMap = {
|
|
127
127
|
'react-native': '@nx/react-native',
|
128
128
|
'@remix-run/dev': '@nx/remix',
|
129
129
|
};
|
130
|
-
async function detectPlugins(nxJson, interactive) {
|
131
|
-
let files = ['package.json'].concat(
|
130
|
+
async function detectPlugins(nxJson, interactive, includeAngularCli) {
|
131
|
+
let files = ['package.json'].concat((0, workspace_context_1.globWithWorkspaceContextSync)(process.cwd(), ['**/*/package.json']));
|
132
132
|
const currentPlugins = new Set((nxJson.plugins ?? []).map((p) => {
|
133
133
|
const plugin = typeof p === 'string' ? p : p.plugin;
|
134
134
|
return (0, get_package_name_from_import_path_1.getPackageNameFromImportPath)(plugin);
|
@@ -149,13 +149,19 @@ async function detectPlugins(nxJson, interactive) {
|
|
149
149
|
...packageJson.dependencies,
|
150
150
|
...packageJson.devDependencies,
|
151
151
|
};
|
152
|
-
|
152
|
+
const _npmPackageToPluginMap = {
|
153
|
+
...npmPackageToPluginMap,
|
154
|
+
};
|
155
|
+
if (includeAngularCli) {
|
156
|
+
_npmPackageToPluginMap['@angular/cli'] = '@nx/angular';
|
157
|
+
}
|
158
|
+
for (const [dep, plugin] of Object.entries(_npmPackageToPluginMap)) {
|
153
159
|
if (deps[dep]) {
|
154
160
|
detectedPlugins.add(plugin);
|
155
161
|
}
|
156
162
|
}
|
157
163
|
}
|
158
|
-
let gradlewFiles = ['gradlew', 'gradlew.bat'].concat(
|
164
|
+
let gradlewFiles = ['gradlew', 'gradlew.bat'].concat((0, workspace_context_1.globWithWorkspaceContextSync)(process.cwd(), [
|
159
165
|
'**/gradlew',
|
160
166
|
'**/gradlew.bat',
|
161
167
|
]));
|
@@ -14,10 +14,10 @@ interface GitCommitAndTagOptions {
|
|
14
14
|
stageChanges?: boolean;
|
15
15
|
gitCommit?: boolean;
|
16
16
|
gitCommitMessage?: string;
|
17
|
-
gitCommitArgs?: string;
|
17
|
+
gitCommitArgs?: string | string[];
|
18
18
|
gitTag?: boolean;
|
19
19
|
gitTagMessage?: string;
|
20
|
-
gitTagArgs?: string;
|
20
|
+
gitTagArgs?: string | string[];
|
21
21
|
}
|
22
22
|
export type VersionOptions = NxReleaseArgs & GitCommitAndTagOptions & VersionPlanArgs & FirstReleaseArgs & {
|
23
23
|
specifier?: string;
|
@@ -155,6 +155,7 @@ async function createNxReleaseConfig(projectGraph, projectFileMap, userConfig =
|
|
155
155
|
conventionalCommits: false,
|
156
156
|
generator: '@nx/js:release-version',
|
157
157
|
generatorOptions: {},
|
158
|
+
groupPreVersionCommand: '',
|
158
159
|
},
|
159
160
|
changelog: {
|
160
161
|
createRelease: false,
|
@@ -206,7 +207,9 @@ async function createNxReleaseConfig(projectGraph, projectFileMap, userConfig =
|
|
206
207
|
WORKSPACE_DEFAULTS.versionPlans);
|
207
208
|
const rootConventionalCommitsConfig = deepMergeDefaults([WORKSPACE_DEFAULTS.conventionalCommits], fillUnspecifiedConventionalCommitsProperties(normalizeConventionalCommitsConfig(userConfig.conventionalCommits)));
|
208
209
|
// these options are not supported at the group level, only the root/command level
|
209
|
-
const rootVersionWithoutGlobalOptions = {
|
210
|
+
const rootVersionWithoutGlobalOptions = {
|
211
|
+
...rootVersionConfig,
|
212
|
+
};
|
210
213
|
delete rootVersionWithoutGlobalOptions.git;
|
211
214
|
delete rootVersionWithoutGlobalOptions.preVersionCommand;
|
212
215
|
// Apply conventionalCommits shorthand to the final group defaults if explicitly configured in the original user config
|
@@ -316,7 +319,10 @@ async function createNxReleaseConfig(projectGraph, projectFileMap, userConfig =
|
|
316
319
|
projects: matchingProjects,
|
317
320
|
version: deepMergeDefaults(
|
318
321
|
// First apply any group level defaults, then apply actual root level config, then group level config
|
319
|
-
[
|
322
|
+
[
|
323
|
+
GROUP_DEFAULTS.version,
|
324
|
+
{ ...rootVersionWithoutGlobalOptions, groupPreVersionCommand: '' },
|
325
|
+
], releaseGroup.version),
|
320
326
|
// If the user has set any changelog config at all, including at the root level, then use one set of defaults, otherwise default to false for the whole feature
|
321
327
|
changelog: releaseGroup.changelog || rootChangelogConfig.projectChangelogs
|
322
328
|
? deepMergeDefaults(groupChangelogDefaults, releaseGroup.changelog || {})
|
@@ -37,7 +37,7 @@ export declare function gitAdd({ changedFiles, deletedFiles, dryRun, verbose, lo
|
|
37
37
|
}): Promise<string>;
|
38
38
|
export declare function gitCommit({ messages, additionalArgs, dryRun, verbose, logFn, }: {
|
39
39
|
messages: string[];
|
40
|
-
additionalArgs?: string;
|
40
|
+
additionalArgs?: string | string[];
|
41
41
|
dryRun?: boolean;
|
42
42
|
verbose?: boolean;
|
43
43
|
logFn?: (message: string) => void;
|
@@ -45,7 +45,7 @@ export declare function gitCommit({ messages, additionalArgs, dryRun, verbose, l
|
|
45
45
|
export declare function gitTag({ tag, message, additionalArgs, dryRun, verbose, logFn, }: {
|
46
46
|
tag: string;
|
47
47
|
message?: string;
|
48
|
-
additionalArgs?: string;
|
48
|
+
additionalArgs?: string | string[];
|
49
49
|
dryRun?: boolean;
|
50
50
|
verbose?: boolean;
|
51
51
|
logFn?: (message: string) => void;
|
@@ -188,7 +188,12 @@ async function gitCommit({ messages, additionalArgs, dryRun, verbose, logFn, })
|
|
188
188
|
commandArgs.push('--message', message);
|
189
189
|
}
|
190
190
|
if (additionalArgs) {
|
191
|
-
|
191
|
+
if (Array.isArray(additionalArgs)) {
|
192
|
+
commandArgs.push(...additionalArgs);
|
193
|
+
}
|
194
|
+
else {
|
195
|
+
commandArgs.push(...additionalArgs.split(' '));
|
196
|
+
}
|
192
197
|
}
|
193
198
|
if (verbose) {
|
194
199
|
logFn(dryRun
|
@@ -224,7 +229,12 @@ async function gitTag({ tag, message, additionalArgs, dryRun, verbose, logFn, })
|
|
224
229
|
message || tag,
|
225
230
|
];
|
226
231
|
if (additionalArgs) {
|
227
|
-
|
232
|
+
if (Array.isArray(additionalArgs)) {
|
233
|
+
commandArgs.push(...additionalArgs);
|
234
|
+
}
|
235
|
+
else {
|
236
|
+
commandArgs.push(...additionalArgs.split(' '));
|
237
|
+
}
|
228
238
|
}
|
229
239
|
if (verbose) {
|
230
240
|
logFn(dryRun
|
@@ -45,7 +45,7 @@ export declare function commitChanges({ changedFiles, deletedFiles, isDryRun, is
|
|
45
45
|
isDryRun?: boolean;
|
46
46
|
isVerbose?: boolean;
|
47
47
|
gitCommitMessages?: string[];
|
48
|
-
gitCommitArgs?: string;
|
48
|
+
gitCommitArgs?: string | string[];
|
49
49
|
}): Promise<void>;
|
50
50
|
export declare function createCommitMessageValues(releaseGroups: ReleaseGroupWithName[], releaseGroupToFilteredProjects: Map<ReleaseGroupWithName, Set<string>>, versionData: VersionData, commitMessage: string): string[];
|
51
51
|
export declare function createGitTagValues(releaseGroups: ReleaseGroupWithName[], releaseGroupToFilteredProjects: Map<ReleaseGroupWithName, Set<string>>, versionData: VersionData): string[];
|
@@ -207,6 +207,10 @@ function createAPI(overrideReleaseConfig) {
|
|
207
207
|
*/
|
208
208
|
for (const releaseGroup of releaseGroups) {
|
209
209
|
const releaseGroupName = releaseGroup.name;
|
210
|
+
runPreVersionCommand(releaseGroup.version.groupPreVersionCommand, {
|
211
|
+
dryRun: args.dryRun,
|
212
|
+
verbose: args.verbose,
|
213
|
+
});
|
210
214
|
const projectBatches = (0, batch_projects_by_generator_config_1.batchProjectsByGeneratorConfig)(projectGraph, releaseGroup,
|
211
215
|
// Batch based on all projects within the release group
|
212
216
|
releaseGroup.projects);
|
package/src/config/nx-json.d.ts
CHANGED
@@ -101,9 +101,9 @@ export interface NxReleaseGitConfiguration {
|
|
101
101
|
*/
|
102
102
|
commitMessage?: string;
|
103
103
|
/**
|
104
|
-
* Additional arguments (added after the --message argument, which may or may not be customized with --git-commit-message) to pass to the `git commit` command invoked behind the scenes
|
104
|
+
* Additional arguments (added after the --message argument, which may or may not be customized with --git-commit-message) to pass to the `git commit` command invoked behind the scenes. May be a string or array of strings.
|
105
105
|
*/
|
106
|
-
commitArgs?: string;
|
106
|
+
commitArgs?: string | string[];
|
107
107
|
/**
|
108
108
|
* Whether or not to stage the changes made by this command. Always treated as true if commit is true.
|
109
109
|
*/
|
@@ -117,9 +117,9 @@ export interface NxReleaseGitConfiguration {
|
|
117
117
|
*/
|
118
118
|
tagMessage?: string;
|
119
119
|
/**
|
120
|
-
* Additional arguments to pass to the `git tag` command invoked behind the scenes
|
120
|
+
* Additional arguments to pass to the `git tag` command invoked behind the scenes. . May be a string or array of strings.
|
121
121
|
*/
|
122
|
-
tagArgs?: string;
|
122
|
+
tagArgs?: string | string[];
|
123
123
|
}
|
124
124
|
export interface NxReleaseConventionalCommitsConfiguration {
|
125
125
|
types?: Record<string,
|
@@ -179,7 +179,15 @@ export interface NxReleaseConfiguration {
|
|
179
179
|
*
|
180
180
|
* NOTE: git configuration is not supported at the group level, only the root/command level
|
181
181
|
*/
|
182
|
-
version?: NxReleaseVersionConfiguration
|
182
|
+
version?: NxReleaseVersionConfiguration & {
|
183
|
+
/**
|
184
|
+
* A command to run after validation of nx release configuration, but before versioning begins.
|
185
|
+
* Used for preparing build artifacts. If --dry-run is passed, the command is still executed, but
|
186
|
+
* with the NX_DRY_RUN environment variable set to 'true'.
|
187
|
+
* It will run in addition to the global `preVersionCommand`
|
188
|
+
*/
|
189
|
+
groupPreVersionCommand?: string;
|
190
|
+
};
|
183
191
|
/**
|
184
192
|
* Project changelogs are disabled by default.
|
185
193
|
*
|
Binary file
|
@@ -39,7 +39,7 @@ async function initTasksRunner(nxArgs) {
|
|
39
39
|
return acc;
|
40
40
|
}, {}),
|
41
41
|
};
|
42
|
-
const
|
42
|
+
const taskResults = await (0, run_command_1.invokeTasksRunner)({
|
43
43
|
tasks: opts.tasks,
|
44
44
|
projectGraph,
|
45
45
|
taskGraph,
|
@@ -50,9 +50,11 @@ async function initTasksRunner(nxArgs) {
|
|
50
50
|
initiatingProject: null,
|
51
51
|
});
|
52
52
|
return {
|
53
|
-
status
|
53
|
+
status: Object.values(taskResults).some((taskResult) => taskResult.status === 'failure' || taskResult.status === 'skipped')
|
54
|
+
? 1
|
55
|
+
: 0,
|
54
56
|
taskGraph,
|
55
|
-
taskResults
|
57
|
+
taskResults,
|
56
58
|
};
|
57
59
|
},
|
58
60
|
};
|
@@ -5,11 +5,9 @@ export declare class InvokeRunnerTerminalOutputLifeCycle implements LifeCycle {
|
|
5
5
|
private readonly tasks;
|
6
6
|
failedTasks: Task[];
|
7
7
|
cachedTasks: Task[];
|
8
|
-
private taskResults;
|
9
8
|
constructor(tasks: Task[]);
|
10
9
|
startCommand(): void;
|
11
10
|
endCommand(): void;
|
12
11
|
endTasks(taskResults: TaskResult[]): void;
|
13
12
|
printTaskTerminalOutput(task: Task, cacheStatus: TaskStatus, terminalOutput: string): void;
|
14
|
-
getTaskResults(): Record<string, TaskResult>;
|
15
13
|
}
|
@@ -8,7 +8,6 @@ class InvokeRunnerTerminalOutputLifeCycle {
|
|
8
8
|
this.tasks = tasks;
|
9
9
|
this.failedTasks = [];
|
10
10
|
this.cachedTasks = [];
|
11
|
-
this.taskResults = {};
|
12
11
|
}
|
13
12
|
startCommand() {
|
14
13
|
output_1.output.log({
|
@@ -46,7 +45,6 @@ class InvokeRunnerTerminalOutputLifeCycle {
|
|
46
45
|
}
|
47
46
|
endTasks(taskResults) {
|
48
47
|
for (let t of taskResults) {
|
49
|
-
this.taskResults[t.task.id] = t;
|
50
48
|
if (t.status === 'failure') {
|
51
49
|
this.failedTasks.push(t.task);
|
52
50
|
}
|
@@ -65,8 +63,5 @@ class InvokeRunnerTerminalOutputLifeCycle {
|
|
65
63
|
const args = (0, utils_1.getPrintableCommandArgsForTask)(task);
|
66
64
|
output_1.output.logCommandOutput(args.join(' '), cacheStatus, terminalOutput);
|
67
65
|
}
|
68
|
-
getTaskResults() {
|
69
|
-
return this.taskResults;
|
70
|
-
}
|
71
66
|
}
|
72
67
|
exports.InvokeRunnerTerminalOutputLifeCycle = InvokeRunnerTerminalOutputLifeCycle;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { TaskStatus } from '../tasks-runner';
|
2
|
-
import type { LifeCycle } from '../life-cycle';
|
2
|
+
import type { LifeCycle, TaskResult } from '../life-cycle';
|
3
3
|
import { Task } from '../../config/task-graph';
|
4
4
|
/**
|
5
5
|
* The following life cycle's outputs are static, meaning no previous content
|
@@ -24,10 +24,6 @@ export declare class StaticRunManyTerminalOutputLifeCycle implements LifeCycle {
|
|
24
24
|
startCommand(): void;
|
25
25
|
endCommand(): void;
|
26
26
|
private skippedTasks;
|
27
|
-
endTasks(taskResults:
|
28
|
-
task: Task;
|
29
|
-
status: TaskStatus;
|
30
|
-
code: number;
|
31
|
-
}[]): void;
|
27
|
+
endTasks(taskResults: TaskResult[]): void;
|
32
28
|
printTaskTerminalOutput(task: Task, cacheStatus: TaskStatus, terminalOutput: string): void;
|
33
29
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { TaskStatus } from '../tasks-runner';
|
2
|
-
import type { LifeCycle } from '../life-cycle';
|
2
|
+
import type { LifeCycle, TaskResult } from '../life-cycle';
|
3
3
|
import { Task } from '../../config/task-graph';
|
4
4
|
/**
|
5
5
|
* The following life cycle's outputs are static, meaning no previous content
|
@@ -23,10 +23,6 @@ export declare class StaticRunOneTerminalOutputLifeCycle implements LifeCycle {
|
|
23
23
|
});
|
24
24
|
startCommand(): void;
|
25
25
|
endCommand(): void;
|
26
|
-
endTasks(taskResults:
|
27
|
-
task: Task;
|
28
|
-
status: TaskStatus;
|
29
|
-
code: number;
|
30
|
-
}[]): void;
|
26
|
+
endTasks(taskResults: TaskResult[]): void;
|
31
27
|
printTaskTerminalOutput(task: Task, status: TaskStatus, terminalOutput: string): void;
|
32
28
|
}
|
@@ -1,6 +1,5 @@
|
|
1
|
-
import { LifeCycle } from '../../tasks-runner/life-cycle';
|
1
|
+
import { LifeCycle, TaskResult } from '../../tasks-runner/life-cycle';
|
2
2
|
import { Task } from '../../config/task-graph';
|
3
|
-
import { TaskStatus } from '../../tasks-runner/tasks-runner';
|
4
3
|
export declare class StoreRunInformationLifeCycle implements LifeCycle {
|
5
4
|
private readonly command;
|
6
5
|
private readonly storeFile;
|
@@ -10,11 +9,7 @@ export declare class StoreRunInformationLifeCycle implements LifeCycle {
|
|
10
9
|
private taskResults;
|
11
10
|
constructor(command?: string, storeFile?: typeof storeFileFunction, now?: () => string);
|
12
11
|
startTasks(tasks: Task[]): void;
|
13
|
-
endTasks(taskResults:
|
14
|
-
task: Task;
|
15
|
-
status: TaskStatus;
|
16
|
-
code: number;
|
17
|
-
}>): void;
|
12
|
+
endTasks(taskResults: TaskResult[]): void;
|
18
13
|
startCommand(): void;
|
19
14
|
endCommand(): any;
|
20
15
|
}
|
@@ -1,5 +1,4 @@
|
|
1
|
-
import { LifeCycle, TaskMetadata } from '../life-cycle';
|
2
|
-
import { TaskStatus } from '../tasks-runner';
|
1
|
+
import { LifeCycle, TaskMetadata, TaskResult } from '../life-cycle';
|
3
2
|
import { Task } from '../../config/task-graph';
|
4
3
|
export declare class TaskProfilingLifeCycle implements LifeCycle {
|
5
4
|
private timings;
|
@@ -8,11 +7,7 @@ export declare class TaskProfilingLifeCycle implements LifeCycle {
|
|
8
7
|
private registeredGroups;
|
9
8
|
constructor(_profileFile: string);
|
10
9
|
startTasks(tasks: Task[], { groupId }: TaskMetadata): void;
|
11
|
-
endTasks(taskResults:
|
12
|
-
task: Task;
|
13
|
-
status: TaskStatus;
|
14
|
-
code: number;
|
15
|
-
}>, metadata: TaskMetadata): void;
|
10
|
+
endTasks(taskResults: TaskResult[], metadata: TaskMetadata): void;
|
16
11
|
endCommand(): void;
|
17
12
|
private recordTaskCompletions;
|
18
13
|
private registerGroup;
|
@@ -0,0 +1,17 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.TaskResultsLifeCycle = void 0;
|
4
|
+
class TaskResultsLifeCycle {
|
5
|
+
constructor() {
|
6
|
+
this.taskResults = {};
|
7
|
+
}
|
8
|
+
endTasks(taskResults) {
|
9
|
+
for (let t of taskResults) {
|
10
|
+
this.taskResults[t.task.id] = t;
|
11
|
+
}
|
12
|
+
}
|
13
|
+
getTaskResults() {
|
14
|
+
return this.taskResults;
|
15
|
+
}
|
16
|
+
}
|
17
|
+
exports.TaskResultsLifeCycle = TaskResultsLifeCycle;
|
@@ -1,13 +1,8 @@
|
|
1
1
|
import { Task } from '../../config/task-graph';
|
2
|
-
import { LifeCycle } from '../life-cycle';
|
3
|
-
import { TaskStatus } from '../tasks-runner';
|
2
|
+
import { LifeCycle, TaskResult } from '../life-cycle';
|
4
3
|
export declare class TaskTimingsLifeCycle implements LifeCycle {
|
5
4
|
private timings;
|
6
5
|
startTasks(tasks: Task[]): void;
|
7
|
-
endTasks(taskResults:
|
8
|
-
task: Task;
|
9
|
-
status: TaskStatus;
|
10
|
-
code: number;
|
11
|
-
}>): void;
|
6
|
+
endTasks(taskResults: TaskResult[]): void;
|
12
7
|
endCommand(): void;
|
13
8
|
}
|
@@ -3,7 +3,7 @@ import { ProjectGraph, ProjectGraphProjectNode } from '../config/project-graph';
|
|
3
3
|
import { Task, TaskGraph } from '../config/task-graph';
|
4
4
|
import { TargetDependencyConfig } from '../config/workspace-json-project-json';
|
5
5
|
import { NxArgs } from '../utils/command-line-utils';
|
6
|
-
import { LifeCycle } from './life-cycle';
|
6
|
+
import { LifeCycle, TaskResult } from './life-cycle';
|
7
7
|
import { TasksRunner } from './tasks-runner';
|
8
8
|
export declare function runCommand(projectsToRun: ProjectGraphProjectNode[], currentProjectGraph: ProjectGraph, { nxJson }: {
|
9
9
|
nxJson: NxJsonConfiguration;
|
@@ -11,6 +11,14 @@ export declare function runCommand(projectsToRun: ProjectGraphProjectNode[], cur
|
|
11
11
|
excludeTaskDependencies: boolean;
|
12
12
|
loadDotEnvFiles: boolean;
|
13
13
|
}): Promise<NodeJS.Process['exitCode']>;
|
14
|
+
export declare function runCommandForTasks(projectsToRun: ProjectGraphProjectNode[], currentProjectGraph: ProjectGraph, { nxJson }: {
|
15
|
+
nxJson: NxJsonConfiguration;
|
16
|
+
}, nxArgs: NxArgs, overrides: any, initiatingProject: string | null, extraTargetDependencies: Record<string, (TargetDependencyConfig | string)[]>, extraOptions: {
|
17
|
+
excludeTaskDependencies: boolean;
|
18
|
+
loadDotEnvFiles: boolean;
|
19
|
+
}): Promise<{
|
20
|
+
[id: string]: TaskResult;
|
21
|
+
}>;
|
14
22
|
export declare function invokeTasksRunner({ tasks, projectGraph, taskGraph, lifeCycle, nxJson, nxArgs, loadDotEnvFiles, initiatingProject, }: {
|
15
23
|
tasks: Task[];
|
16
24
|
projectGraph: ProjectGraph;
|
@@ -20,7 +28,9 @@ export declare function invokeTasksRunner({ tasks, projectGraph, taskGraph, life
|
|
20
28
|
nxArgs: NxArgs;
|
21
29
|
loadDotEnvFiles: boolean;
|
22
30
|
initiatingProject: string | null;
|
23
|
-
}): Promise<
|
31
|
+
}): Promise<{
|
32
|
+
[id: string]: TaskResult;
|
33
|
+
}>;
|
24
34
|
export declare function getRunner(nxArgs: NxArgs, nxJson: NxJsonConfiguration): {
|
25
35
|
tasksRunner: TasksRunner;
|
26
36
|
runnerOptions: any;
|
@@ -1,6 +1,7 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
exports.runCommand = runCommand;
|
4
|
+
exports.runCommandForTasks = runCommandForTasks;
|
4
5
|
exports.invokeTasksRunner = invokeTasksRunner;
|
5
6
|
exports.getRunner = getRunner;
|
6
7
|
exports.getRunnerOptions = getRunnerOptions;
|
@@ -31,6 +32,7 @@ const task_history_life_cycle_1 = require("./life-cycles/task-history-life-cycle
|
|
31
32
|
const task_history_life_cycle_old_1 = require("./life-cycles/task-history-life-cycle-old");
|
32
33
|
const task_profiling_life_cycle_1 = require("./life-cycles/task-profiling-life-cycle");
|
33
34
|
const task_timings_life_cycle_1 = require("./life-cycles/task-timings-life-cycle");
|
35
|
+
const task_results_life_cycle_1 = require("./life-cycles/task-results-life-cycle");
|
34
36
|
const task_graph_utils_1 = require("./task-graph-utils");
|
35
37
|
const utils_1 = require("./utils");
|
36
38
|
const chalk = require("chalk");
|
@@ -99,25 +101,31 @@ function createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies,
|
|
99
101
|
}
|
100
102
|
async function runCommand(projectsToRun, currentProjectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
|
101
103
|
const status = await (0, handle_errors_1.handleErrors)(process.env.NX_VERBOSE_LOGGING === 'true', async () => {
|
102
|
-
const
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
const status = await invokeTasksRunner({
|
107
|
-
tasks,
|
108
|
-
projectGraph,
|
109
|
-
taskGraph,
|
110
|
-
lifeCycle,
|
111
|
-
nxJson,
|
112
|
-
nxArgs,
|
113
|
-
loadDotEnvFiles: extraOptions.loadDotEnvFiles,
|
114
|
-
initiatingProject,
|
115
|
-
});
|
116
|
-
await renderIsDone;
|
117
|
-
return status;
|
104
|
+
const taskResults = await runCommandForTasks(projectsToRun, currentProjectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions);
|
105
|
+
return Object.values(taskResults).some((taskResult) => taskResult.status === 'failure' || taskResult.status === 'skipped')
|
106
|
+
? 1
|
107
|
+
: 0;
|
118
108
|
});
|
119
109
|
return status;
|
120
110
|
}
|
111
|
+
async function runCommandForTasks(projectsToRun, currentProjectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
|
112
|
+
const projectNames = projectsToRun.map((t) => t.name);
|
113
|
+
const { projectGraph, taskGraph } = await ensureWorkspaceIsInSyncAndGetGraphs(currentProjectGraph, nxJson, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions);
|
114
|
+
const tasks = Object.values(taskGraph.tasks);
|
115
|
+
const { lifeCycle, renderIsDone } = await getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks, nxArgs, nxJson, overrides);
|
116
|
+
const taskResults = await invokeTasksRunner({
|
117
|
+
tasks,
|
118
|
+
projectGraph,
|
119
|
+
taskGraph,
|
120
|
+
lifeCycle,
|
121
|
+
nxJson,
|
122
|
+
nxArgs,
|
123
|
+
loadDotEnvFiles: extraOptions.loadDotEnvFiles,
|
124
|
+
initiatingProject,
|
125
|
+
});
|
126
|
+
await renderIsDone;
|
127
|
+
return taskResults;
|
128
|
+
}
|
121
129
|
async function ensureWorkspaceIsInSyncAndGetGraphs(projectGraph, nxJson, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions) {
|
122
130
|
let taskGraph = createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies ?? {}, projectNames, nxArgs, overrides, extraOptions);
|
123
131
|
if (nxArgs.skipSync) {
|
@@ -359,9 +367,14 @@ async function invokeTasksRunner({ tasks, projectGraph, taskGraph, lifeCycle, nx
|
|
359
367
|
// to submit everything that is known in advance to Nx Cloud to run in
|
360
368
|
// a distributed fashion
|
361
369
|
await (0, hash_task_1.hashTasksThatDoNotDependOnOutputsOfOtherTasks)(hasher, projectGraph, taskGraph, nxJson);
|
362
|
-
const
|
370
|
+
const taskResultsLifecycle = new task_results_life_cycle_1.TaskResultsLifeCycle();
|
371
|
+
const compositedLifeCycle = new life_cycle_1.CompositeLifeCycle([
|
372
|
+
...constructLifeCycles(lifeCycle),
|
373
|
+
taskResultsLifecycle,
|
374
|
+
]);
|
375
|
+
let promiseOrObservable = tasksRunner(tasks, {
|
363
376
|
...runnerOptions,
|
364
|
-
lifeCycle:
|
377
|
+
lifeCycle: compositedLifeCycle,
|
365
378
|
}, {
|
366
379
|
initiatingProject: nxArgs.outputStyle === 'compact' ? null : initiatingProject,
|
367
380
|
projectGraph,
|
@@ -418,15 +431,11 @@ async function invokeTasksRunner({ tasks, projectGraph, taskGraph, lifeCycle, nx
|
|
418
431
|
},
|
419
432
|
daemon: client_1.daemonClient,
|
420
433
|
});
|
421
|
-
let anyFailures;
|
422
434
|
if (promiseOrObservable.subscribe) {
|
423
|
-
|
424
|
-
}
|
425
|
-
else {
|
426
|
-
// simply await the promise
|
427
|
-
anyFailures = await anyFailuresInPromise(promiseOrObservable);
|
435
|
+
promiseOrObservable = convertObservableToPromise(promiseOrObservable);
|
428
436
|
}
|
429
|
-
|
437
|
+
await promiseOrObservable;
|
438
|
+
return taskResultsLifecycle.getTaskResults();
|
430
439
|
}
|
431
440
|
function constructLifeCycles(lifeCycle) {
|
432
441
|
const lifeCycles = [];
|
@@ -445,41 +454,23 @@ function constructLifeCycles(lifeCycle) {
|
|
445
454
|
}
|
446
455
|
return lifeCycles;
|
447
456
|
}
|
448
|
-
function
|
449
|
-
const res = {};
|
450
|
-
Object.keys(defaults ?? {}).forEach((k) => {
|
451
|
-
res[k] = defaults[k].dependsOn;
|
452
|
-
});
|
453
|
-
if (deps) {
|
454
|
-
Object.keys(deps).forEach((k) => {
|
455
|
-
if (res[k]) {
|
456
|
-
res[k] = [...res[k], deps[k]];
|
457
|
-
}
|
458
|
-
else {
|
459
|
-
res[k] = deps[k];
|
460
|
-
}
|
461
|
-
});
|
462
|
-
return res;
|
463
|
-
}
|
464
|
-
}
|
465
|
-
async function anyFailuresInPromise(promise) {
|
466
|
-
return Object.values(await promise).some((v) => v === 'failure' || v === 'skipped');
|
467
|
-
}
|
468
|
-
async function anyFailuresInObservable(obs) {
|
457
|
+
async function convertObservableToPromise(obs) {
|
469
458
|
return await new Promise((res) => {
|
470
|
-
let
|
471
|
-
obs.subscribe(
|
472
|
-
|
473
|
-
|
474
|
-
}
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
459
|
+
let tasksResults = {};
|
460
|
+
obs.subscribe({
|
461
|
+
next: (t) => {
|
462
|
+
tasksResults[t.task.id] = t.success ? 'success' : 'failure';
|
463
|
+
},
|
464
|
+
error: (error) => {
|
465
|
+
output_1.output.error({
|
466
|
+
title: 'Unhandled error in task executor',
|
467
|
+
});
|
468
|
+
console.error(error);
|
469
|
+
res(tasksResults);
|
470
|
+
},
|
471
|
+
complete: () => {
|
472
|
+
res(tasksResults);
|
473
|
+
},
|
483
474
|
});
|
484
475
|
});
|
485
476
|
}
|
@@ -46,7 +46,7 @@ class TaskOrchestrator {
|
|
46
46
|
this.tasksSchedule.init(),
|
47
47
|
]);
|
48
48
|
// initial scheduling
|
49
|
-
await this.scheduleNextTasks();
|
49
|
+
await this.tasksSchedule.scheduleNextTasks();
|
50
50
|
perf_hooks_1.performance.mark('task-execution:start');
|
51
51
|
const threads = [];
|
52
52
|
process.stdout.setMaxListeners(this.options.parallel + events_1.defaultMaxListeners);
|
@@ -68,6 +68,7 @@ class TaskOrchestrator {
|
|
68
68
|
}
|
69
69
|
const doNotSkipCache = this.options.skipNxCache === false ||
|
70
70
|
this.options.skipNxCache === undefined;
|
71
|
+
this.processAllScheduledTasks();
|
71
72
|
const batch = this.tasksSchedule.nextBatch();
|
72
73
|
if (batch) {
|
73
74
|
const groupId = this.closeGroup();
|
@@ -376,15 +377,11 @@ class TaskOrchestrator {
|
|
376
377
|
status,
|
377
378
|
};
|
378
379
|
}));
|
379
|
-
await this.scheduleNextTasks();
|
380
|
+
await this.tasksSchedule.scheduleNextTasks();
|
380
381
|
// release blocked threads
|
381
382
|
this.waitingForTasks.forEach((f) => f(null));
|
382
383
|
this.waitingForTasks.length = 0;
|
383
384
|
}
|
384
|
-
async scheduleNextTasks() {
|
385
|
-
await this.tasksSchedule.scheduleNextTasks();
|
386
|
-
this.processAllScheduledTasks();
|
387
|
-
}
|
388
385
|
complete(taskResults) {
|
389
386
|
this.tasksSchedule.complete(taskResults.map(({ taskId }) => taskId));
|
390
387
|
for (const { taskId, status } of taskResults) {
|
package/src/utils/git-utils.d.ts
CHANGED
@@ -7,6 +7,7 @@ export declare class GitRepository {
|
|
7
7
|
root: string;
|
8
8
|
constructor(directory: string);
|
9
9
|
getGitRootPath(cwd: string): string;
|
10
|
+
hasUncommittedChanges(): Promise<boolean>;
|
10
11
|
addFetchRemote(remoteName: string, branch: string): Promise<string>;
|
11
12
|
showStat(): Promise<string>;
|
12
13
|
listBranches(): Promise<string[]>;
|
@@ -25,10 +26,11 @@ export declare class GitRepository {
|
|
25
26
|
deleteGitRemote(name: string): Promise<string>;
|
26
27
|
addGitRemote(name: string, url: string): Promise<string>;
|
27
28
|
hasFilterRepoInstalled(): Promise<boolean>;
|
28
|
-
filterRepo(
|
29
|
-
filterBranch(
|
29
|
+
filterRepo(source: string, destination: string): Promise<void>;
|
30
|
+
filterBranch(source: string, destination: string, branchName: string): Promise<void>;
|
30
31
|
private execAsync;
|
31
32
|
private quotePath;
|
33
|
+
private quoteArg;
|
32
34
|
}
|
33
35
|
/**
|
34
36
|
* This is currently duplicated in Nx Console. Please let @MaxKless know if you make changes here.
|
File without changes
|
@@ -0,0 +1,20 @@
|
|
1
|
+
/**
|
2
|
+
* This is meant to be used with `git filter-branch --index-filter` to rewrite
|
3
|
+
* history such that only commits related to the subdirectory is kept.
|
4
|
+
*
|
5
|
+
* Example:
|
6
|
+
* NX_IMPORT_SOURCE=<source> git filter-branch --index-filter 'node git-utils.index-filter.js' --prune-empty -- --all
|
7
|
+
*/
|
8
|
+
try {
|
9
|
+
const { execSync } = require('child_process');
|
10
|
+
// NOTE: Using env vars because Windows PowerShell has its own handling of quotes (") messes up quotes in args, even if escaped.
|
11
|
+
const src = process.env.NX_IMPORT_SOURCE;
|
12
|
+
execSync('git read-tree --empty', { stdio: 'inherit' });
|
13
|
+
execSync(`git reset ${process.env.GIT_COMMIT} -- "${src}"`, {
|
14
|
+
stdio: 'inherit',
|
15
|
+
});
|
16
|
+
}
|
17
|
+
catch (error) {
|
18
|
+
console.error(`Error executing Git commands: ${error}`);
|
19
|
+
process.exit(1);
|
20
|
+
}
|
package/src/utils/git-utils.js
CHANGED
@@ -40,6 +40,10 @@ class GitRepository {
|
|
40
40
|
.toString()
|
41
41
|
.trim();
|
42
42
|
}
|
43
|
+
async hasUncommittedChanges() {
|
44
|
+
const data = await this.execAsync(`git status --porcelain`);
|
45
|
+
return data.trim() !== '';
|
46
|
+
}
|
43
47
|
async addFetchRemote(remoteName, branch) {
|
44
48
|
return await this.execAsync(`git config --add remote.${remoteName}.fetch "+refs/heads/${branch}:refs/remotes/${remoteName}/${branch}"`);
|
45
49
|
}
|
@@ -105,32 +109,63 @@ class GitRepository {
|
|
105
109
|
}
|
106
110
|
// git-filter-repo is much faster than filter-branch, but needs to be installed by user
|
107
111
|
// Use `hasFilterRepoInstalled` to check if it's installed
|
108
|
-
async filterRepo(
|
109
|
-
// filter-repo requires POSIX path to work
|
110
|
-
const
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
112
|
+
async filterRepo(source, destination) {
|
113
|
+
// NOTE: filter-repo requires POSIX path to work
|
114
|
+
const sourcePosixPath = source.split(path_1.sep).join(path_1.posix.sep);
|
115
|
+
const destinationPosixPath = destination.split(path_1.sep).join(path_1.posix.sep);
|
116
|
+
await this.execAsync(`git filter-repo -f ${source !== '' ? `--path ${this.quotePath(sourcePosixPath)}` : ''} ${source !== destination
|
117
|
+
? `--path-rename ${this.quotePath(sourcePosixPath, true)}:${this.quotePath(destinationPosixPath, true)}`
|
118
|
+
: ''}`);
|
119
|
+
}
|
120
|
+
async filterBranch(source, destination, branchName) {
|
116
121
|
// We need non-ASCII file names to not be quoted, or else filter-branch will exclude them.
|
117
122
|
await this.execAsync(`git config core.quotepath false`);
|
118
|
-
|
123
|
+
// NOTE: filter-repo requires POSIX path to work
|
124
|
+
const sourcePosixPath = source.split(path_1.sep).join(path_1.posix.sep);
|
125
|
+
const destinationPosixPath = destination.split(path_1.sep).join(path_1.posix.sep);
|
126
|
+
// First, if the source is not a root project, then only include commits relevant to the subdirectory.
|
127
|
+
if (source !== '') {
|
128
|
+
const indexFilterCommand = this.quoteArg(`node ${(0, path_1.join)(__dirname, 'git-utils.index-filter.js')}`);
|
129
|
+
await this.execAsync(`git filter-branch -f --index-filter ${indexFilterCommand} --prune-empty -- ${branchName}`, {
|
130
|
+
NX_IMPORT_SOURCE: sourcePosixPath,
|
131
|
+
NX_IMPORT_DESTINATION: destinationPosixPath,
|
132
|
+
});
|
133
|
+
}
|
134
|
+
// Then, move files to their new location if necessary.
|
135
|
+
if (source === '' || source !== destination) {
|
136
|
+
const treeFilterCommand = this.quoteArg(`node ${(0, path_1.join)(__dirname, 'git-utils.tree-filter.js')}`);
|
137
|
+
await this.execAsync(`git filter-branch -f --tree-filter ${treeFilterCommand} -- ${branchName}`, {
|
138
|
+
NX_IMPORT_SOURCE: sourcePosixPath,
|
139
|
+
NX_IMPORT_DESTINATION: destinationPosixPath,
|
140
|
+
});
|
141
|
+
}
|
119
142
|
}
|
120
|
-
execAsync(command) {
|
143
|
+
execAsync(command, env) {
|
121
144
|
return execAsync(command, {
|
122
145
|
cwd: this.root,
|
123
146
|
maxBuffer: 10 * 1024 * 1024,
|
147
|
+
env: {
|
148
|
+
...process.env,
|
149
|
+
...env,
|
150
|
+
},
|
124
151
|
});
|
125
152
|
}
|
126
|
-
quotePath(path) {
|
153
|
+
quotePath(path, ensureTrailingSlash) {
|
154
|
+
return this.quoteArg(ensureTrailingSlash && path !== '' && !path.endsWith('/')
|
155
|
+
? `${path}/`
|
156
|
+
: path);
|
157
|
+
}
|
158
|
+
quoteArg(arg) {
|
127
159
|
return process.platform === 'win32'
|
128
160
|
? // Windows/CMD only understands double-quotes, single-quotes are treated as part of the file name
|
129
161
|
// Bash and other shells will substitute `$` in file names with a variable value.
|
130
|
-
`"${
|
162
|
+
`"${arg
|
163
|
+
// Need to keep two slashes for Windows or else the path will be invalid.
|
164
|
+
// e.g. 'C:\Users\bob\projects\repo' is invalid, but 'C:\\Users\\bob\\projects\\repo' is valid
|
165
|
+
.replaceAll('\\', '\\\\')}"`
|
131
166
|
: // e.g. `git mv "$$file.txt" "libs/a/$$file.txt"` will not work since `$$` is swapped with the PID of the last process.
|
132
167
|
// Using single-quotes prevents this substitution.
|
133
|
-
`'${
|
168
|
+
`'${arg}'`;
|
134
169
|
}
|
135
170
|
}
|
136
171
|
exports.GitRepository = GitRepository;
|
@@ -0,0 +1,11 @@
|
|
1
|
+
/**
|
2
|
+
* This is meant to be used with `git filter-branch --tree-filter` to rewrite
|
3
|
+
* history to only include commits related to the source project folder. If the
|
4
|
+
* destination folder is different, this script also moves the files over.
|
5
|
+
*
|
6
|
+
* Example:
|
7
|
+
* NX_IMPORT_SOURCE=<source> NX_IMPORT_DESTINATION=<destination> git filter-branch --tree-filter 'node git-utils.tree-filter.js' --prune-empty -- --all
|
8
|
+
*/
|
9
|
+
declare const execSync: any;
|
10
|
+
declare const existsSync: any, mkdirSync: any, renameSync: any, rmSync: any;
|
11
|
+
declare const posix: any;
|
@@ -0,0 +1,43 @@
|
|
1
|
+
/**
|
2
|
+
* This is meant to be used with `git filter-branch --tree-filter` to rewrite
|
3
|
+
* history to only include commits related to the source project folder. If the
|
4
|
+
* destination folder is different, this script also moves the files over.
|
5
|
+
*
|
6
|
+
* Example:
|
7
|
+
* NX_IMPORT_SOURCE=<source> NX_IMPORT_DESTINATION=<destination> git filter-branch --tree-filter 'node git-utils.tree-filter.js' --prune-empty -- --all
|
8
|
+
*/
|
9
|
+
const { execSync } = require('child_process');
|
10
|
+
const { existsSync, mkdirSync, renameSync, rmSync } = require('fs');
|
11
|
+
// NOTE: The path passed to `git filter-branch` is POSIX, so we need to use the `posix` module.
|
12
|
+
const { posix } = require('path');
|
13
|
+
try {
|
14
|
+
// NOTE: Using env vars because Windows PowerShell has its own handling of quotes (") messes up quotes in args, even if escaped.
|
15
|
+
const src = process.env.NX_IMPORT_SOURCE;
|
16
|
+
const dest = process.env.NX_IMPORT_DESTINATION;
|
17
|
+
const files = execSync(`git ls-files -z ${src}`)
|
18
|
+
.toString()
|
19
|
+
.trim()
|
20
|
+
.split('\x00')
|
21
|
+
.map((s) => s.trim())
|
22
|
+
.filter(Boolean);
|
23
|
+
for (const file of files) {
|
24
|
+
if (src === '' || file.startsWith(src)) {
|
25
|
+
// If source and destination are the same, then keep the file as is.
|
26
|
+
if (src === dest)
|
27
|
+
continue;
|
28
|
+
const destFile = posix.join(dest, file.replace(src, ''));
|
29
|
+
const dir = posix.dirname(destFile);
|
30
|
+
if (!existsSync(dir))
|
31
|
+
mkdirSync(dir, { recursive: true });
|
32
|
+
renameSync(file, destFile);
|
33
|
+
}
|
34
|
+
else {
|
35
|
+
// If not matching the source we are filtering, remove it.
|
36
|
+
rmSync(file);
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
catch (error) {
|
41
|
+
console.error(`Error executing Git commands: ${error}`);
|
42
|
+
process.exit(1);
|
43
|
+
}
|