nx 19.6.0-beta.2 → 19.6.0-beta.4

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.
Files changed (38) hide show
  1. package/package.json +12 -12
  2. package/schemas/nx-schema.json +30 -4
  3. package/src/command-line/import/command-object.d.ts +2 -0
  4. package/src/command-line/import/command-object.js +38 -0
  5. package/src/command-line/import/import.d.ts +21 -0
  6. package/src/command-line/import/import.js +173 -0
  7. package/src/command-line/import/utils/merge-remote-source.d.ts +2 -0
  8. package/src/command-line/import/utils/merge-remote-source.js +14 -0
  9. package/src/command-line/import/utils/needs-install.d.ts +3 -0
  10. package/src/command-line/import/utils/needs-install.js +31 -0
  11. package/src/command-line/import/utils/prepare-source-repo.d.ts +2 -0
  12. package/src/command-line/import/utils/prepare-source-repo.js +104 -0
  13. package/src/command-line/init/init-v2.d.ts +7 -0
  14. package/src/command-line/init/init-v2.js +48 -15
  15. package/src/command-line/nx-commands.js +33 -31
  16. package/src/command-line/release/changelog.js +9 -9
  17. package/src/command-line/release/command-object.d.ts +12 -3
  18. package/src/command-line/release/command-object.js +16 -1
  19. package/src/command-line/release/config/config.js +4 -2
  20. package/src/command-line/release/config/filter-release-groups.d.ts +2 -2
  21. package/src/command-line/release/config/filter-release-groups.js +1 -1
  22. package/src/command-line/release/config/version-plans.d.ts +1 -1
  23. package/src/command-line/release/config/version-plans.js +12 -12
  24. package/src/command-line/release/plan-check.d.ts +4 -0
  25. package/src/command-line/release/plan-check.js +225 -0
  26. package/src/command-line/release/plan.js +1 -1
  27. package/src/command-line/release/release.js +3 -3
  28. package/src/command-line/release/version.js +1 -1
  29. package/src/command-line/yargs-utils/shared-options.d.ts +1 -1
  30. package/src/config/nx-json.d.ts +9 -2
  31. package/src/native/nx.wasm32-wasi.wasm +0 -0
  32. package/src/utils/command-line-utils.d.ts +1 -0
  33. package/src/utils/command-line-utils.js +6 -3
  34. package/src/utils/git-utils.d.ts +35 -0
  35. package/src/utils/git-utils.js +111 -0
  36. package/src/utils/package-manager.js +1 -1
  37. package/src/utils/squash.d.ts +1 -0
  38. package/src/utils/squash.js +12 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nx",
3
- "version": "19.6.0-beta.2",
3
+ "version": "19.6.0-beta.4",
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.6.0-beta.2"
74
+ "@nrwl/tao": "19.6.0-beta.4"
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.6.0-beta.2",
90
- "@nx/nx-darwin-arm64": "19.6.0-beta.2",
91
- "@nx/nx-linux-x64-gnu": "19.6.0-beta.2",
92
- "@nx/nx-linux-x64-musl": "19.6.0-beta.2",
93
- "@nx/nx-win32-x64-msvc": "19.6.0-beta.2",
94
- "@nx/nx-linux-arm64-gnu": "19.6.0-beta.2",
95
- "@nx/nx-linux-arm64-musl": "19.6.0-beta.2",
96
- "@nx/nx-linux-arm-gnueabihf": "19.6.0-beta.2",
97
- "@nx/nx-win32-arm64-msvc": "19.6.0-beta.2",
98
- "@nx/nx-freebsd-x64": "19.6.0-beta.2"
89
+ "@nx/nx-darwin-x64": "19.6.0-beta.4",
90
+ "@nx/nx-darwin-arm64": "19.6.0-beta.4",
91
+ "@nx/nx-linux-x64-gnu": "19.6.0-beta.4",
92
+ "@nx/nx-linux-x64-musl": "19.6.0-beta.4",
93
+ "@nx/nx-win32-x64-msvc": "19.6.0-beta.4",
94
+ "@nx/nx-linux-arm64-gnu": "19.6.0-beta.4",
95
+ "@nx/nx-linux-arm64-musl": "19.6.0-beta.4",
96
+ "@nx/nx-linux-arm-gnueabihf": "19.6.0-beta.4",
97
+ "@nx/nx-win32-arm64-msvc": "19.6.0-beta.4",
98
+ "@nx/nx-freebsd-x64": "19.6.0-beta.4"
99
99
  },
100
100
  "nx-migrations": {
101
101
  "migrations": "./migrations.json",
@@ -186,8 +186,15 @@
186
186
  "type": "string"
187
187
  },
188
188
  "versionPlans": {
189
- "type": "boolean",
190
- "description": "Enables using version plans as a specifier source for versioning and to determine changes for changelog generation."
189
+ "oneOf": [
190
+ {
191
+ "$ref": "#/definitions/NxReleaseVersionPlansConfiguration"
192
+ },
193
+ {
194
+ "type": "boolean",
195
+ "description": "Enables using version plans as a specifier source for versioning and to determine changes for changelog generation."
196
+ }
197
+ ]
191
198
  }
192
199
  },
193
200
  "required": ["projects"]
@@ -239,8 +246,15 @@
239
246
  "$ref": "#/definitions/NxReleaseVersionConfiguration"
240
247
  },
241
248
  "versionPlans": {
242
- "type": "boolean",
243
- "description": "Enables using version plans as a specifier source for versioning and to determine changes for changelog generation."
249
+ "oneOf": [
250
+ {
251
+ "$ref": "#/definitions/NxReleaseVersionPlansConfiguration"
252
+ },
253
+ {
254
+ "type": "boolean",
255
+ "description": "Enables using version plans as a specifier source for versioning and to determine changes for changelog generation."
256
+ }
257
+ ]
244
258
  },
245
259
  "releaseTagPattern": {
246
260
  "type": "string"
@@ -698,6 +712,18 @@
698
712
  }
699
713
  }
700
714
  },
715
+ "NxReleaseVersionPlansConfiguration": {
716
+ "type": "object",
717
+ "properties": {
718
+ "ignorePatternsForPlanCheck": {
719
+ "type": "array",
720
+ "items": {
721
+ "type": "string"
722
+ },
723
+ "description": "Changes to files matching any of these optional patterns will be excluded from the affected project logic within the `nx release plan:check` command. This is useful for ignoring files that are not relevant to the versioning process, such as documentation or configuration files."
724
+ }
725
+ }
726
+ },
701
727
  "ChangelogRenderOptions": {
702
728
  "type": "object",
703
729
  "additionalProperties": true
@@ -0,0 +1,2 @@
1
+ import { CommandModule } from 'yargs';
2
+ export declare const yargsImportCommand: CommandModule;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.yargsImportCommand = void 0;
4
+ const documentation_1 = require("../yargs-utils/documentation");
5
+ const shared_options_1 = require("../yargs-utils/shared-options");
6
+ const params_1 = require("../../utils/params");
7
+ exports.yargsImportCommand = {
8
+ command: 'import [sourceRemoteUrl] [destination]',
9
+ describe: false,
10
+ builder: (yargs) => (0, documentation_1.linkToNxDevAndExamples)((0, shared_options_1.withVerbose)(yargs
11
+ .positional('sourceRemoteUrl', {
12
+ type: 'string',
13
+ description: 'The remote URL of the source to import',
14
+ })
15
+ .positional('destination', {
16
+ type: 'string',
17
+ description: 'The directory in the current workspace to import into',
18
+ })
19
+ .option('source', {
20
+ type: 'string',
21
+ description: 'The directory in the source repository to import from',
22
+ })
23
+ .option('ref', {
24
+ type: 'string',
25
+ description: 'The branch from the source repository to import',
26
+ })
27
+ .option('interactive', {
28
+ type: 'boolean',
29
+ description: 'Interactive mode',
30
+ default: true,
31
+ })), 'import'),
32
+ handler: async (args) => {
33
+ const exitCode = await (0, params_1.handleErrors)(args.verbose ?? process.env.NX_VERBOSE_LOGGING === 'true', async () => {
34
+ return (await Promise.resolve().then(() => require('./import'))).importHandler(args);
35
+ });
36
+ process.exit(exitCode);
37
+ },
38
+ };
@@ -0,0 +1,21 @@
1
+ export interface ImportOptions {
2
+ /**
3
+ * The remote URL of the repository to import
4
+ */
5
+ sourceRemoteUrl: string;
6
+ /**
7
+ * The branch or reference to import
8
+ */
9
+ ref: string;
10
+ /**
11
+ * The directory in the source repo to import
12
+ */
13
+ source: string;
14
+ /**
15
+ * The directory in the destination repo to import into
16
+ */
17
+ destination: string;
18
+ verbose: boolean;
19
+ interactive: boolean;
20
+ }
21
+ export declare function importHandler(options: ImportOptions): Promise<void>;
@@ -0,0 +1,173 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.importHandler = importHandler;
4
+ const path_1 = require("path");
5
+ const git_utils_1 = require("../../utils/git-utils");
6
+ const promises_1 = require("node:fs/promises");
7
+ const tmp_1 = require("tmp");
8
+ const enquirer_1 = require("enquirer");
9
+ const output_1 = require("../../utils/output");
10
+ const createSpinner = require("ora");
11
+ const init_v2_1 = require("../init/init-v2");
12
+ const nx_json_1 = require("../../config/nx-json");
13
+ const workspace_root_1 = require("../../utils/workspace-root");
14
+ const package_manager_1 = require("../../utils/package-manager");
15
+ const workspace_context_1 = require("../../utils/workspace-context");
16
+ const utils_1 = require("../init/implementation/utils");
17
+ const command_line_utils_1 = require("../../utils/command-line-utils");
18
+ const prepare_source_repo_1 = require("./utils/prepare-source-repo");
19
+ const merge_remote_source_1 = require("./utils/merge-remote-source");
20
+ const needs_install_1 = require("./utils/needs-install");
21
+ const importRemoteName = '__tmp_nx_import__';
22
+ async function importHandler(options) {
23
+ let { sourceRemoteUrl, ref, source, destination } = options;
24
+ output_1.output.log({
25
+ title: 'Nx will walk you through the process of importing code from another repository into this workspace:',
26
+ bodyLines: [
27
+ `1. Nx will clone the other repository into a temporary directory`,
28
+ `2. Code to be imported will be moved to the same directory it will be imported into on a temporary branch`,
29
+ `3. The code will be merged into the current branch in this workspace`,
30
+ `4. Nx will recommend plugins to integrate tools used in the imported code with Nx`,
31
+ `5. The code will be successfully imported into this workspace`,
32
+ '',
33
+ `Git history will be preserved during this process`,
34
+ ],
35
+ });
36
+ const tempImportDirectory = (0, path_1.join)(tmp_1.tmpdir, 'nx-import');
37
+ if (!sourceRemoteUrl) {
38
+ sourceRemoteUrl = (await (0, enquirer_1.prompt)([
39
+ {
40
+ type: 'input',
41
+ name: 'sourceRemoteUrl',
42
+ message: 'What is the URL of the repository you want to import? (This can be a local git repository or a git remote URL)',
43
+ required: true,
44
+ },
45
+ ])).sourceRemoteUrl;
46
+ }
47
+ try {
48
+ const maybeLocalDirectory = await (0, promises_1.stat)(sourceRemoteUrl);
49
+ if (maybeLocalDirectory.isDirectory()) {
50
+ sourceRemoteUrl = (0, path_1.resolve)(sourceRemoteUrl);
51
+ }
52
+ }
53
+ catch (e) {
54
+ // It's a remote url
55
+ }
56
+ const sourceRepoPath = (0, path_1.join)(tempImportDirectory, 'repo');
57
+ const spinner = createSpinner(`Cloning ${sourceRemoteUrl} into a temporary directory: ${sourceRepoPath}`).start();
58
+ try {
59
+ await (0, promises_1.rm)(tempImportDirectory, { recursive: true });
60
+ }
61
+ catch { }
62
+ await (0, promises_1.mkdir)(tempImportDirectory, { recursive: true });
63
+ let sourceGitClient;
64
+ try {
65
+ sourceGitClient = await (0, git_utils_1.cloneFromUpstream)(sourceRemoteUrl, sourceRepoPath, {
66
+ originName: importRemoteName,
67
+ });
68
+ }
69
+ catch (e) {
70
+ spinner.fail(`Failed to clone ${sourceRemoteUrl} into ${sourceRepoPath}`);
71
+ let errorMessage = `Failed to clone ${sourceRemoteUrl} into ${sourceRepoPath}. Please double check the remote and try again.\n${e.message}`;
72
+ throw new Error(errorMessage);
73
+ }
74
+ spinner.succeed(`Cloned into ${sourceRepoPath}`);
75
+ if (!ref) {
76
+ const branchChoices = await sourceGitClient.listBranches();
77
+ ref = (await (0, enquirer_1.prompt)([
78
+ {
79
+ type: 'autocomplete',
80
+ name: 'ref',
81
+ message: `Which branch do you want to import?`,
82
+ choices: branchChoices,
83
+ /**
84
+ * Limit the number of choices so that it fits on screen
85
+ */
86
+ limit: process.stdout.rows - 3,
87
+ required: true,
88
+ },
89
+ ])).ref;
90
+ }
91
+ if (!source) {
92
+ source = (await (0, enquirer_1.prompt)([
93
+ {
94
+ type: 'input',
95
+ name: 'source',
96
+ message: `Which directory do you want to import into this workspace? (leave blank to import the entire repository)`,
97
+ },
98
+ ])).source;
99
+ }
100
+ if (!destination) {
101
+ destination = (await (0, enquirer_1.prompt)([
102
+ {
103
+ type: 'input',
104
+ name: 'destination',
105
+ message: 'Where in this workspace should the code be imported into?',
106
+ required: true,
107
+ },
108
+ ])).destination;
109
+ }
110
+ const absSource = (0, path_1.join)(sourceRepoPath, source);
111
+ const absDestination = (0, path_1.join)(process.cwd(), destination);
112
+ try {
113
+ await (0, promises_1.stat)(absSource);
114
+ }
115
+ catch (e) {
116
+ throw new Error(`The source directory ${source} does not exist in ${sourceRemoteUrl}. Please double check to make sure it exists.`);
117
+ }
118
+ const destinationGitClient = new git_utils_1.GitRepository(process.cwd());
119
+ await assertDestinationEmpty(destinationGitClient, absDestination);
120
+ const tempImportBranch = getTempImportBranch(ref);
121
+ const packageManager = (0, package_manager_1.detectPackageManager)(workspace_root_1.workspaceRoot);
122
+ const originalPackageWorkspaces = await (0, needs_install_1.getPackagesInPackageManagerWorkspace)(packageManager);
123
+ const relativeDestination = (0, path_1.relative)(destinationGitClient.root, absDestination);
124
+ await (0, prepare_source_repo_1.prepareSourceRepo)(sourceGitClient, ref, source, relativeDestination, tempImportBranch, sourceRemoteUrl, importRemoteName);
125
+ await createTemporaryRemote(destinationGitClient, (0, path_1.join)(sourceRepoPath, '.git'), importRemoteName);
126
+ await (0, merge_remote_source_1.mergeRemoteSource)(destinationGitClient, sourceRemoteUrl, tempImportBranch, destination, importRemoteName, ref);
127
+ spinner.start('Cleaning up temporary files and remotes');
128
+ await (0, promises_1.rm)(tempImportDirectory, { recursive: true });
129
+ await destinationGitClient.deleteGitRemote(importRemoteName);
130
+ spinner.succeed('Cleaned up temporary files and remotes');
131
+ const pmc = (0, package_manager_1.getPackageManagerCommand)();
132
+ const nxJson = (0, nx_json_1.readNxJson)(workspace_root_1.workspaceRoot);
133
+ (0, workspace_context_1.resetWorkspaceContext)();
134
+ const { plugins, updatePackageScripts } = await (0, init_v2_1.detectPlugins)(nxJson, options.interactive);
135
+ if (plugins.length > 0) {
136
+ output_1.output.log({ title: 'Installing Plugins' });
137
+ (0, init_v2_1.installPlugins)(workspace_root_1.workspaceRoot, plugins, pmc, updatePackageScripts);
138
+ await destinationGitClient.amendCommit();
139
+ }
140
+ else if (await (0, needs_install_1.needsInstall)(packageManager, originalPackageWorkspaces)) {
141
+ output_1.output.log({
142
+ title: 'Installing dependencies for imported code',
143
+ });
144
+ (0, utils_1.runInstall)(workspace_root_1.workspaceRoot, (0, package_manager_1.getPackageManagerCommand)(packageManager));
145
+ await destinationGitClient.amendCommit();
146
+ }
147
+ console.log(await destinationGitClient.showStat());
148
+ output_1.output.log({
149
+ title: `Merging these changes into ${(0, command_line_utils_1.getBaseRef)(nxJson)}`,
150
+ bodyLines: [
151
+ `MERGE these changes when merging these changes.`,
152
+ `Do NOT squash and do NOT rebase these changes when merging these changes.`,
153
+ `If you would like to UNDO these changes, run "git reset HEAD~1 --hard"`,
154
+ ],
155
+ });
156
+ }
157
+ async function assertDestinationEmpty(gitClient, absDestination) {
158
+ const files = await gitClient.getGitFiles(absDestination);
159
+ if (files.length > 0) {
160
+ throw new Error(`Destination directory ${absDestination} is not empty. Please make sure it is empty before importing into it.`);
161
+ }
162
+ }
163
+ function getTempImportBranch(sourceBranch) {
164
+ return `__nx_tmp_import__/${sourceBranch}`;
165
+ }
166
+ async function createTemporaryRemote(destinationGitClient, sourceRemoteUrl, remoteName) {
167
+ try {
168
+ await destinationGitClient.deleteGitRemote(remoteName);
169
+ }
170
+ catch { }
171
+ await destinationGitClient.addGitRemote(remoteName, sourceRemoteUrl);
172
+ await destinationGitClient.fetch(remoteName);
173
+ }
@@ -0,0 +1,2 @@
1
+ import { GitRepository } from '../../../utils/git-utils';
2
+ export declare function mergeRemoteSource(destinationGitClient: GitRepository, sourceRemoteUrl: string, tempBranch: string, destination: string, remoteName: string, branchName: string): Promise<void>;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mergeRemoteSource = mergeRemoteSource;
4
+ const createSpinner = require("ora");
5
+ async function mergeRemoteSource(destinationGitClient, sourceRemoteUrl, tempBranch, destination, remoteName, branchName) {
6
+ const spinner = createSpinner();
7
+ spinner.start(`Merging ${branchName} from ${sourceRemoteUrl} into ${destination}`);
8
+ spinner.start(`Fetching ${tempBranch} from ${remoteName}`);
9
+ await destinationGitClient.fetch(remoteName, tempBranch);
10
+ spinner.succeed(`Fetched ${tempBranch} from ${remoteName}`);
11
+ spinner.start(`Merging files and git history from ${branchName} from ${sourceRemoteUrl} into ${destination}`);
12
+ await destinationGitClient.mergeUnrelatedHistories(`${remoteName}/${tempBranch}`, `feat(repo): merge ${branchName} from ${sourceRemoteUrl}`);
13
+ spinner.succeed(`Merged files and git history from ${branchName} from ${sourceRemoteUrl} into ${destination}`);
14
+ }
@@ -0,0 +1,3 @@
1
+ import { PackageManager } from '../../../utils/package-manager';
2
+ export declare function getPackagesInPackageManagerWorkspace(packageManager: PackageManager): Promise<Set<string>>;
3
+ export declare function needsInstall(packageManager: PackageManager, originalPackagesInPackageManagerWorkspaces: Set<string>): Promise<boolean>;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPackagesInPackageManagerWorkspace = getPackagesInPackageManagerWorkspace;
4
+ exports.needsInstall = needsInstall;
5
+ const package_manager_1 = require("../../../utils/package-manager");
6
+ const workspace_root_1 = require("../../../utils/workspace-root");
7
+ const package_json_1 = require("../../../plugins/package-json");
8
+ const workspace_context_1 = require("../../../utils/workspace-context");
9
+ async function getPackagesInPackageManagerWorkspace(packageManager) {
10
+ if (!(0, package_manager_1.isWorkspacesEnabled)(packageManager, workspace_root_1.workspaceRoot)) {
11
+ return new Set();
12
+ }
13
+ const patterns = (0, package_json_1.getGlobPatternsFromPackageManagerWorkspaces)(workspace_root_1.workspaceRoot);
14
+ return new Set(await (0, workspace_context_1.globWithWorkspaceContext)(workspace_root_1.workspaceRoot, patterns));
15
+ }
16
+ async function needsInstall(packageManager, originalPackagesInPackageManagerWorkspaces) {
17
+ if (!(0, package_manager_1.isWorkspacesEnabled)(packageManager, workspace_root_1.workspaceRoot)) {
18
+ return false;
19
+ }
20
+ const updatedPackagesInPackageManagerWorkspaces = await getPackagesInPackageManagerWorkspace(packageManager);
21
+ if (updatedPackagesInPackageManagerWorkspaces.size !==
22
+ originalPackagesInPackageManagerWorkspaces.size) {
23
+ return true;
24
+ }
25
+ for (const pkg of updatedPackagesInPackageManagerWorkspaces) {
26
+ if (!originalPackagesInPackageManagerWorkspaces.has(pkg)) {
27
+ return true;
28
+ }
29
+ }
30
+ return false;
31
+ }
@@ -0,0 +1,2 @@
1
+ import { GitRepository } from '../../../utils/git-utils';
2
+ export declare function prepareSourceRepo(gitClient: GitRepository, ref: string, source: string, relativeDestination: string, tempImportBranch: string, sourceRemoteUrl: string, originName: string): Promise<void>;
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.prepareSourceRepo = prepareSourceRepo;
4
+ const createSpinner = require("ora");
5
+ const path_1 = require("path");
6
+ const promises_1 = require("node:fs/promises");
7
+ async function prepareSourceRepo(gitClient, ref, source, relativeDestination, tempImportBranch, sourceRemoteUrl, originName) {
8
+ const spinner = createSpinner().start(`Fetching ${ref} from ${sourceRemoteUrl}`);
9
+ await gitClient.addFetchRemote(originName, ref);
10
+ await gitClient.fetch(originName, ref);
11
+ spinner.succeed(`Fetched ${ref} from ${sourceRemoteUrl}`);
12
+ spinner.start(`Checking out a temporary branch, ${tempImportBranch} based on ${ref}`);
13
+ await gitClient.checkout(tempImportBranch, {
14
+ new: true,
15
+ base: `${originName}/${ref}`,
16
+ });
17
+ spinner.succeed(`Created a ${tempImportBranch} branch based on ${ref}`);
18
+ const relativeSourceDir = (0, path_1.relative)(gitClient.root, (0, path_1.join)(gitClient.root, source));
19
+ const destinationInSource = (0, path_1.join)(gitClient.root, relativeDestination);
20
+ spinner.start(`Moving files and git history to ${destinationInSource}`);
21
+ if (relativeSourceDir === '') {
22
+ const files = await gitClient.getGitFiles('.');
23
+ try {
24
+ await (0, promises_1.rm)(destinationInSource, {
25
+ recursive: true,
26
+ });
27
+ }
28
+ catch { }
29
+ await (0, promises_1.mkdir)(destinationInSource, { recursive: true });
30
+ const gitignores = new Set();
31
+ for (const file of files) {
32
+ if ((0, path_1.basename)(file) === '.gitignore') {
33
+ gitignores.add(file);
34
+ continue;
35
+ }
36
+ spinner.start(`Moving files and git history to ${destinationInSource}: ${file}`);
37
+ const newPath = (0, path_1.join)(destinationInSource, file);
38
+ await (0, promises_1.mkdir)((0, path_1.dirname)(newPath), { recursive: true });
39
+ try {
40
+ await gitClient.move(file, newPath);
41
+ }
42
+ catch {
43
+ await wait(100);
44
+ await gitClient.move(file, newPath);
45
+ }
46
+ }
47
+ await gitClient.commit(`chore(repo): move ${source} to ${relativeDestination} to prepare to be imported`);
48
+ for (const gitignore of gitignores) {
49
+ await gitClient.move(gitignore, (0, path_1.join)(destinationInSource, gitignore));
50
+ }
51
+ await gitClient.amendCommit();
52
+ for (const gitignore of gitignores) {
53
+ await (0, promises_1.copyFile)((0, path_1.join)(destinationInSource, gitignore), (0, path_1.join)(gitClient.root, gitignore));
54
+ }
55
+ }
56
+ else {
57
+ let needsSquash = false;
58
+ const needsMove = destinationInSource !== (0, path_1.join)(gitClient.root, source);
59
+ if (needsMove) {
60
+ try {
61
+ await (0, promises_1.rm)(destinationInSource, {
62
+ recursive: true,
63
+ });
64
+ await gitClient.commit('chore(repo): prepare for import');
65
+ needsSquash = true;
66
+ }
67
+ catch { }
68
+ await (0, promises_1.mkdir)(destinationInSource, { recursive: true });
69
+ }
70
+ const files = await gitClient.getGitFiles('.');
71
+ for (const file of files) {
72
+ if (file === '.gitignore') {
73
+ continue;
74
+ }
75
+ spinner.start(`Moving files and git history to ${destinationInSource}: ${file}`);
76
+ if (!(0, path_1.relative)(source, file).startsWith('..')) {
77
+ if (needsMove) {
78
+ const newPath = (0, path_1.join)(destinationInSource, file);
79
+ await (0, promises_1.mkdir)((0, path_1.dirname)(newPath), { recursive: true });
80
+ try {
81
+ await gitClient.move(file, newPath);
82
+ }
83
+ catch {
84
+ await wait(100);
85
+ await gitClient.move(file, newPath);
86
+ }
87
+ }
88
+ }
89
+ else {
90
+ await (0, promises_1.rm)((0, path_1.join)(gitClient.root, file), {
91
+ recursive: true,
92
+ });
93
+ }
94
+ }
95
+ await gitClient.commit('chore(repo): prepare for import 2');
96
+ if (needsSquash) {
97
+ await gitClient.squashLastTwoCommits();
98
+ }
99
+ }
100
+ spinner.succeed(`${sourceRemoteUrl} has been prepared to be imported into this workspace on a temporary branch: ${tempImportBranch} in ${gitClient.root}`);
101
+ }
102
+ function wait(ms) {
103
+ return new Promise((resolve) => setTimeout(resolve, ms));
104
+ }
@@ -1,7 +1,14 @@
1
+ import { PackageManagerCommands } from '../../utils/package-manager';
2
+ import { NxJsonConfiguration } from '../../config/nx-json';
1
3
  export interface InitArgs {
2
4
  interactive: boolean;
3
5
  nxCloud?: boolean;
4
6
  useDotNxInstallation?: boolean;
5
7
  integrated?: boolean;
6
8
  }
9
+ export declare function installPlugins(repoRoot: string, plugins: string[], pmc: PackageManagerCommands, updatePackageScripts: boolean): void;
7
10
  export declare function initHandler(options: InitArgs): Promise<void>;
11
+ export declare function detectPlugins(nxJson: NxJsonConfiguration, interactive: boolean): Promise<{
12
+ plugins: string[];
13
+ updatePackageScripts: boolean;
14
+ }>;
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.installPlugins = installPlugins;
3
4
  exports.initHandler = initHandler;
5
+ exports.detectPlugins = detectPlugins;
4
6
  const fs_1 = require("fs");
5
7
  const semver_1 = require("semver");
6
8
  const output_1 = require("../../utils/output");
@@ -17,6 +19,22 @@ const workspace_context_1 = require("../../utils/workspace-context");
17
19
  const connect_to_nx_cloud_1 = require("../connect/connect-to-nx-cloud");
18
20
  const add_nx_to_npm_repo_1 = require("./implementation/add-nx-to-npm-repo");
19
21
  const add_nx_to_monorepo_1 = require("./implementation/add-nx-to-monorepo");
22
+ const nx_json_1 = require("../../config/nx-json");
23
+ const get_package_name_from_import_path_1 = require("../../utils/get-package-name-from-import-path");
24
+ function installPlugins(repoRoot, plugins, pmc, updatePackageScripts) {
25
+ if (plugins.length === 0) {
26
+ return;
27
+ }
28
+ (0, utils_1.addDepsToPackageJson)(repoRoot, plugins);
29
+ (0, utils_1.runInstall)(repoRoot, pmc);
30
+ output_1.output.log({ title: '🔨 Configuring plugins' });
31
+ for (const plugin of plugins) {
32
+ (0, child_process_2.execSync)(`${pmc.exec} nx g ${plugin}:init --keepExistingVersions ${updatePackageScripts ? '--updatePackageScripts' : ''} --no-interactive`, {
33
+ stdio: [0, 1, 2],
34
+ cwd: repoRoot,
35
+ });
36
+ }
37
+ }
20
38
  async function initHandler(options) {
21
39
  process.env.NX_RUNNING_NX_INIT = 'true';
22
40
  const version = process.env.NX_VERSION ?? ((0, semver_1.prerelease)(versions_1.nxVersion) ? 'next' : 'latest');
@@ -31,7 +49,8 @@ async function initHandler(options) {
31
49
  console.log('Setting Nx up installation in `.nx`. You can run Nx commands like: `./nx.bat --help`');
32
50
  }
33
51
  (0, add_nx_scripts_1.generateDotNxSetup)(version);
34
- const { plugins } = await detectPlugins();
52
+ const nxJson = (0, nx_json_1.readNxJson)(process.cwd());
53
+ const { plugins } = await detectPlugins(nxJson, options.interactive);
35
54
  plugins.forEach((plugin) => {
36
55
  (0, child_process_1.runNxSync)(`add ${plugin}`, {
37
56
  stdio: 'inherit',
@@ -52,8 +71,6 @@ async function initHandler(options) {
52
71
  });
53
72
  return;
54
73
  }
55
- output_1.output.log({ title: '🧐 Checking dependencies' });
56
- const { plugins, updatePackageScripts } = await detectPlugins();
57
74
  const packageJson = (0, fileutils_1.readJsonFile)('package.json');
58
75
  if ((0, utils_1.isMonorepo)(packageJson)) {
59
76
  await (0, add_nx_to_monorepo_1.addNxToMonorepo)({
@@ -76,18 +93,11 @@ async function initHandler(options) {
76
93
  const pmc = (0, package_manager_1.getPackageManagerCommand)();
77
94
  (0, utils_1.createNxJsonFile)(repoRoot, [], [], {});
78
95
  (0, utils_1.updateGitIgnore)(repoRoot);
79
- (0, utils_1.addDepsToPackageJson)(repoRoot, plugins);
96
+ const nxJson = (0, nx_json_1.readNxJson)(repoRoot);
97
+ output_1.output.log({ title: '🧐 Checking dependencies' });
98
+ const { plugins, updatePackageScripts } = await detectPlugins(nxJson, options.interactive);
80
99
  output_1.output.log({ title: '📦 Installing Nx' });
81
- (0, utils_1.runInstall)(repoRoot, pmc);
82
- if (plugins.length > 0) {
83
- output_1.output.log({ title: '🔨 Configuring plugins' });
84
- for (const plugin of plugins) {
85
- (0, child_process_2.execSync)(`${pmc.exec} nx g ${plugin}:init --keepExistingVersions ${updatePackageScripts ? '--updatePackageScripts' : ''} --no-interactive`, {
86
- stdio: [0, 1, 2],
87
- cwd: repoRoot,
88
- });
89
- }
90
- }
100
+ installPlugins(repoRoot, plugins, pmc, updatePackageScripts);
91
101
  if (useNxCloud) {
92
102
  output_1.output.log({ title: '🛠️ Setting up Nx Cloud' });
93
103
  await (0, utils_1.initCloud)('nx-init');
@@ -117,8 +127,12 @@ const npmPackageToPluginMap = {
117
127
  'react-native': '@nx/react-native',
118
128
  '@remix-run/dev': '@nx/remix',
119
129
  };
120
- async function detectPlugins() {
130
+ async function detectPlugins(nxJson, interactive) {
121
131
  let files = ['package.json'].concat(await (0, workspace_context_1.globWithWorkspaceContext)(process.cwd(), ['**/*/package.json']));
132
+ const currentPlugins = new Set((nxJson.plugins ?? []).map((p) => {
133
+ const plugin = typeof p === 'string' ? p : p.plugin;
134
+ return (0, get_package_name_from_import_path_1.getPackageNameFromImportPath)(plugin);
135
+ }));
122
136
  const detectedPlugins = new Set();
123
137
  for (const file of files) {
124
138
  if (!(0, fs_1.existsSync)(file))
@@ -144,6 +158,12 @@ async function detectPlugins() {
144
158
  if ((0, fs_1.existsSync)('gradlew') || (0, fs_1.existsSync)('gradlew.bat')) {
145
159
  detectedPlugins.add('@nx/gradle');
146
160
  }
161
+ // Remove existing plugins
162
+ for (const plugin of detectedPlugins) {
163
+ if (currentPlugins.has(plugin)) {
164
+ detectedPlugins.delete(plugin);
165
+ }
166
+ }
147
167
  const plugins = Array.from(detectedPlugins);
148
168
  if (plugins.length === 0) {
149
169
  return {
@@ -151,6 +171,19 @@ async function detectPlugins() {
151
171
  updatePackageScripts: false,
152
172
  };
153
173
  }
174
+ if (!interactive) {
175
+ output_1.output.log({
176
+ title: `Recommended Plugins:`,
177
+ bodyLines: [
178
+ `Adding these Nx plugins to integrate with the tools used in your workspace:`,
179
+ ...plugins.map((p) => `- ${p}`),
180
+ ],
181
+ });
182
+ return {
183
+ plugins,
184
+ updatePackageScripts: true,
185
+ };
186
+ }
154
187
  output_1.output.log({
155
188
  title: `Recommended Plugins:`,
156
189
  bodyLines: [