From 86dd385a529111e31d5208602bcc1ad0b73836ea Mon Sep 17 00:00:00 2001 From: Emily Xiong Date: Fri, 31 Mar 2023 18:10:44 -0400 Subject: [PATCH 1/3] feat(core): update create-nx-plugin to generate cli library --- docs/generated/manifests/menus.json | 8 + docs/generated/manifests/packages.json | 9 + docs/generated/packages-metadata.json | 9 + .../nx-plugin/generators/create-package.json | 84 ++++++++ .../packages/nx-plugin/generators/preset.json | 5 + .../packages/workspace/generators/preset.json | 1 + e2e/nx-plugin/src/nx-plugin.test.ts | 28 ++- .../src/create-nx-plugin.test.ts | 10 +- .../create-nx-plugin/bin/create-nx-plugin.ts | 59 +++--- .../bin/create-nx-workspace.ts | 1 + packages/create-nx-workspace/package.json | 2 - packages/create-nx-workspace/project.json | 2 +- ...tions.d.ts => create-workspace-options.ts} | 1 + .../src/create-workspace.ts | 2 +- .../utils/preset/get-third-party-preset.ts | 5 +- .../typescript/add-tslib-dependencies.ts | 2 +- packages/nx-plugin/generators.json | 10 + packages/nx-plugin/generators.ts | 1 + packages/nx-plugin/index.ts | 0 .../nx-plugin/src/executors/e2e/e2e.impl.ts | 2 +- .../create-package/create-package.spec.ts | 125 ++++++++++++ .../create-package/create-package.ts | 184 ++++++++++++++++++ .../bin/index.ts__tmpl__ | 17 ++ .../files/e2e/__name__.spec.ts__tmpl__ | 36 ++++ .../src/generators/create-package/schema.d.ts | 16 ++ .../src/generators/create-package/schema.json | 78 ++++++++ .../create-package/utils/normalize-schema.ts | 44 +++++ .../src/generators/e2e-project/e2e.ts | 2 +- .../__fileName__/generator.ts__tmpl__ | 5 +- .../nx-plugin/src/generators/plugin/plugin.ts | 78 ++++---- .../src/generators/preset/generator.ts | 31 ++- .../src/generators/preset/schema.d.ts | 1 + .../src/generators/preset/schema.json | 5 + .../src/utils/testing-utils/async-commands.ts | 8 +- .../src/utils/testing-utils/commands.ts | 9 +- .../utils/testing-utils/create-package-cli.ts | 39 ++++ .../src/utils/testing-utils/index.ts | 1 + .../src/utils/testing-utils/nx-project.ts | 6 +- .../src/utils/testing-utils/utils.ts | 4 +- .../with-module-federation.ts | 2 +- .../src/generators/new/generate-preset.ts | 6 +- .../src/generators/preset/schema.json | 3 +- 42 files changed, 849 insertions(+), 92 deletions(-) create mode 100644 docs/generated/packages/nx-plugin/generators/create-package.json rename packages/create-nx-workspace/src/{create-workspace-options.d.ts => create-workspace-options.ts} (96%) delete mode 100644 packages/nx-plugin/index.ts create mode 100644 packages/nx-plugin/src/generators/create-package/create-package.spec.ts create mode 100644 packages/nx-plugin/src/generators/create-package/create-package.ts create mode 100644 packages/nx-plugin/src/generators/create-package/files/create-framework-package/bin/index.ts__tmpl__ create mode 100644 packages/nx-plugin/src/generators/create-package/files/e2e/__name__.spec.ts__tmpl__ create mode 100644 packages/nx-plugin/src/generators/create-package/schema.d.ts create mode 100644 packages/nx-plugin/src/generators/create-package/schema.json create mode 100644 packages/nx-plugin/src/generators/create-package/utils/normalize-schema.ts create mode 100644 packages/nx-plugin/src/utils/testing-utils/create-package-cli.ts diff --git a/docs/generated/manifests/menus.json b/docs/generated/manifests/menus.json index 639615962c0a0..3323b69313f88 100644 --- a/docs/generated/manifests/menus.json +++ b/docs/generated/manifests/menus.json @@ -5595,6 +5595,14 @@ "isExternal": false, "disableCollapsible": false }, + { + "id": "create-package", + "path": "/packages/nx-plugin/generators/create-package", + "name": "create-package", + "children": [], + "isExternal": false, + "disableCollapsible": false + }, { "id": "e2e-project", "path": "/packages/nx-plugin/generators/e2e-project", diff --git a/docs/generated/manifests/packages.json b/docs/generated/manifests/packages.json index 0677bcc53f8a0..8d547cf0ecd2e 100644 --- a/docs/generated/manifests/packages.json +++ b/docs/generated/manifests/packages.json @@ -1832,6 +1832,15 @@ "path": "/packages/nx-plugin/generators/plugin", "type": "generator" }, + "/packages/nx-plugin/generators/create-package": { + "description": "Create a framework package that uses Nx CLI", + "file": "generated/packages/nx-plugin/generators/create-package.json", + "hidden": false, + "name": "create-package", + "originalFilePath": "/packages/nx-plugin/src/generators/create-package/schema.json", + "path": "/packages/nx-plugin/generators/create-package", + "type": "generator" + }, "/packages/nx-plugin/generators/e2e-project": { "description": "Create a E2E application for a Nx Plugin.", "file": "generated/packages/nx-plugin/generators/e2e-project.json", diff --git a/docs/generated/packages-metadata.json b/docs/generated/packages-metadata.json index 687e95d7bb48b..81e87d4cf8bd5 100644 --- a/docs/generated/packages-metadata.json +++ b/docs/generated/packages-metadata.json @@ -1810,6 +1810,15 @@ "path": "nx-plugin/generators/plugin", "type": "generator" }, + { + "description": "Create a framework package that uses Nx CLI", + "file": "generated/packages/nx-plugin/generators/create-package.json", + "hidden": false, + "name": "create-package", + "originalFilePath": "/packages/nx-plugin/src/generators/create-package/schema.json", + "path": "nx-plugin/generators/create-package", + "type": "generator" + }, { "description": "Create a E2E application for a Nx Plugin.", "file": "generated/packages/nx-plugin/generators/e2e-project.json", diff --git a/docs/generated/packages/nx-plugin/generators/create-package.json b/docs/generated/packages/nx-plugin/generators/create-package.json new file mode 100644 index 0000000000000..eee1fea878be0 --- /dev/null +++ b/docs/generated/packages/nx-plugin/generators/create-package.json @@ -0,0 +1,84 @@ +{ + "name": "create-package", + "factory": "./src/generators/create-package/create-package", + "schema": { + "$schema": "http://json-schema.org/schema", + "cli": "nx", + "$id": "NxPluginCreatePackage", + "title": "Create a framework package", + "description": "Create a framework package that uses Nx CLI.", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The package name of cli, e.g. `create-framework-package`. Note this must be a valid NPM name to be published.", + "$default": { "$source": "argv", "index": 0 }, + "x-priority": "important" + }, + "project": { + "type": "string", + "description": "The name of the generator project.", + "alias": "p", + "$default": { "$source": "projectName" }, + "x-prompt": "What is the name of the project for the generator?", + "x-priority": "important" + }, + "unitTestRunner": { + "type": "string", + "enum": ["jest", "none"], + "description": "Test runner to use for unit tests.", + "default": "jest" + }, + "directory": { + "type": "string", + "description": "A directory where the app is placed." + }, + "linter": { + "description": "The tool to use for running lint checks.", + "type": "string", + "enum": ["eslint"], + "default": "eslint" + }, + "tags": { + "type": "string", + "description": "Add tags to the library (used for linting).", + "alias": "t" + }, + "skipFormat": { + "description": "Skip formatting files.", + "type": "boolean", + "default": false, + "x-priority": "internal" + }, + "skipTsConfig": { + "type": "boolean", + "default": false, + "description": "Do not update tsconfig.json for development experience.", + "x-priority": "internal" + }, + "setParserOptionsProject": { + "type": "boolean", + "description": "Whether or not to configure the ESLint `parserOptions.project` option. We do not do this by default for lint performance reasons.", + "default": false + }, + "compiler": { + "type": "string", + "enum": ["tsc", "swc"], + "default": "tsc", + "description": "The compiler used by the build and test targets." + }, + "importPath": { + "type": "string", + "description": "How the plugin will be published, like `create-framework-app`. Note this must be a valid NPM name. Will use name if not provided." + } + }, + "required": ["name", "project"], + "presets": [] + }, + "description": "Create a framework package that uses Nx CLI", + "implementation": "/packages/nx-plugin/src/generators/create-package/create-package.ts", + "aliases": [], + "hidden": false, + "path": "/packages/nx-plugin/src/generators/create-package/schema.json", + "type": "generator" +} diff --git a/docs/generated/packages/nx-plugin/generators/preset.json b/docs/generated/packages/nx-plugin/generators/preset.json index 2253d562ca9d0..bf7c16ce8c2ba 100644 --- a/docs/generated/packages/nx-plugin/generators/preset.json +++ b/docs/generated/packages/nx-plugin/generators/preset.json @@ -13,6 +13,11 @@ "type": "string", "description": "Plugin name", "aliases": ["name"] + }, + "cliName": { + "type": "string", + "description": "Name of cli command to create workspace with plugin", + "aliases": ["name"] } }, "required": ["pluginName"], diff --git a/docs/generated/packages/workspace/generators/preset.json b/docs/generated/packages/workspace/generators/preset.json index 3b27e1e85f98d..427407fc59892 100644 --- a/docs/generated/packages/workspace/generators/preset.json +++ b/docs/generated/packages/workspace/generators/preset.json @@ -87,6 +87,7 @@ "default": false } }, + "required": ["preset", "name"], "presets": [] }, "description": "Create application in an empty workspace.", diff --git a/e2e/nx-plugin/src/nx-plugin.test.ts b/e2e/nx-plugin/src/nx-plugin.test.ts index 139b767ae3453..c5ec429bd31d3 100644 --- a/e2e/nx-plugin/src/nx-plugin.test.ts +++ b/e2e/nx-plugin/src/nx-plugin.test.ts @@ -5,7 +5,6 @@ import { createFile, expectTestsPass, getPackageManagerCommand, - killPorts, newProject, readJson, readProjectConfig, @@ -410,4 +409,31 @@ describe('Nx Plugin', () => { expect(pluginProject.tags).toEqual(['e2etag', 'e2ePackage']); }, 90000); }); + + it('should be able to generate a create-package plugin ', async () => { + const plugin = uniq('plugin'); + const createAppName = `create-${plugin}-app`; + runCLI(`generate @nrwl/nx-plugin:plugin ${plugin}`); + runCLI( + `generate @nrwl/nx-plugin:create-package ${createAppName} --project=${plugin}` + ); + + const buildResults = runCLI(`build ${createAppName}`); + expect(buildResults).toContain('Done compiling TypeScript files'); + + checkFilesExist( + `libs/${plugin}/src/generators/preset`, + `libs/${createAppName}`, + `dist/libs/${createAppName}/bin/index.js` + ); + }); + + it('should throw an error when run create-package for an invalid plugin ', async () => { + const plugin = uniq('plugin'); + expect(() => + runCLI( + `generate @nrwl/nx-plugin:create-package ${plugin} --project=invalid-plugin` + ) + ).toThrow(); + }); }); diff --git a/e2e/workspace-create/src/create-nx-plugin.test.ts b/e2e/workspace-create/src/create-nx-plugin.test.ts index 54686dc769d4b..312606ba4fe37 100644 --- a/e2e/workspace-create/src/create-nx-plugin.test.ts +++ b/e2e/workspace-create/src/create-nx-plugin.test.ts @@ -31,7 +31,7 @@ describe('create-nx-plugin', () => { runCLI(`build ${pluginName}`); - checkFilesExist(`dist/package.json`); + checkFilesExist(`dist/package.json`, `dist/src/index.js`); runCLI( `generate @nrwl/nx-plugin:generator ${generatorName} --project=${pluginName}` @@ -45,7 +45,13 @@ describe('create-nx-plugin', () => { checkFilesExist( `dist/package.json`, `dist/generators.json`, - `dist/executors.json` + `dist/executors.json`, + `dist/src/index.js` ); + + runCLI(`build create-${pluginName}-package`); + checkFilesExist(`dist/create-${pluginName}-package/bin/index.js`); + + expect(() => runCLI(`e2e e2e`)).not.toThrow(); }); }); diff --git a/packages/create-nx-plugin/bin/create-nx-plugin.ts b/packages/create-nx-plugin/bin/create-nx-plugin.ts index dc0e7f1497ecb..2114aa52f36ed 100644 --- a/packages/create-nx-plugin/bin/create-nx-plugin.ts +++ b/packages/create-nx-plugin/bin/create-nx-plugin.ts @@ -43,34 +43,34 @@ export const yargsDecorator = { const nxVersion = require('../package.json').version; -function determinePluginName(parsedArgs: CreateNxPluginArguments) { +async function determinePluginName( + parsedArgs: CreateNxPluginArguments +): Promise { if (parsedArgs.pluginName) { return Promise.resolve(parsedArgs.pluginName); } - return enquirer - .prompt([ - { - name: 'pluginName', - message: `Plugin name `, - type: 'input', - validate: (s) => (s.length ? true : 'Name cannot be empty'), - }, - ]) - .then((a: { pluginName: string }) => { - if (!a.pluginName) { - output.error({ - title: 'Invalid name', - bodyLines: [`Name cannot be empty`], - }); - process.exit(1); - } - return a.pluginName; + const results = await enquirer.prompt<{ pluginName: string }>([ + { + name: 'pluginName', + message: `Plugin name `, + type: 'input', + validate: (s_1) => (s_1.length ? true : 'Name cannot be empty'), + }, + ]); + if (!results.pluginName) { + output.error({ + title: 'Invalid name', + bodyLines: [`Name cannot be empty`], }); + process.exit(1); + } + return results.pluginName; } interface CreateNxPluginArguments { pluginName: string; + cliName?: string; packageManager: PackageManager; ci: CI; allPrompts: boolean; @@ -89,11 +89,16 @@ export const commandsObject: yargs.Argv = yargs 'Create a new Nx plugin workspace', (yargs) => withOptions( - yargs.positional('pluginName', { - describe: chalk.dim`Plugin name`, - type: 'string', - alias: ['name'], - }), + yargs + .positional('pluginName', { + describe: chalk.dim`Plugin name`, + type: 'string', + alias: ['name'], + }) + .option('cliName', { + describe: 'Name of the CLI package to create workspace with plugin', + type: 'string', + }), withNxCloud, withCI, withAllPrompts, @@ -164,19 +169,19 @@ async function normalizeArgsMiddleware( argv: yargs.Arguments ): Promise { try { - const name = await determinePluginName(argv); + const pluginName = await determinePluginName(argv); const packageManager = await determinePackageManager(argv); const defaultBase = await determineDefaultBase(argv); const nxCloud = await determineNxCloud(argv); const ci = await determineCI(argv, nxCloud); Object.assign(argv, { - name, + pluginName, nxCloud, packageManager, defaultBase, ci, - }); + } as Partial); } catch (e) { console.error(e); process.exit(1); diff --git a/packages/create-nx-workspace/bin/create-nx-workspace.ts b/packages/create-nx-workspace/bin/create-nx-workspace.ts index 59ae99baf5dc6..644f2a3983bb5 100644 --- a/packages/create-nx-workspace/bin/create-nx-workspace.ts +++ b/packages/create-nx-workspace/bin/create-nx-workspace.ts @@ -221,6 +221,7 @@ async function normalizeArgsMiddleware( } else if (monorepoStyle === 'node-standalone') { preset = Preset.NodeStandalone; } else { + // when choose integrated monorepo, further prompt for preset preset = await determinePreset(argv); } } else if (argv.preset === 'react') { diff --git a/packages/create-nx-workspace/package.json b/packages/create-nx-workspace/package.json index f1d06d338f7bb..4fdf734b9879d 100644 --- a/packages/create-nx-workspace/package.json +++ b/packages/create-nx-workspace/package.json @@ -27,8 +27,6 @@ "bugs": { "url": "https://github.com/nrwl/nx/issues" }, - "main": "./index.js", - "typings": "./index.d.ts", "homepage": "https://nx.dev", "dependencies": { "chalk": "^4.1.0", diff --git a/packages/create-nx-workspace/project.json b/packages/create-nx-workspace/project.json index aca86797a0e23..c47979257ee8a 100644 --- a/packages/create-nx-workspace/project.json +++ b/packages/create-nx-workspace/project.json @@ -8,7 +8,7 @@ "build-base": { "executor": "@nrwl/js:tsc", "options": { - "main": "packages/create-nx-workspace/bin/create-nx-workspace.ts", + "main": "packages/create-nx-workspace/index.ts", "assets": [ { "input": "packages/create-nx-workspace", diff --git a/packages/create-nx-workspace/src/create-workspace-options.d.ts b/packages/create-nx-workspace/src/create-workspace-options.ts similarity index 96% rename from packages/create-nx-workspace/src/create-workspace-options.d.ts rename to packages/create-nx-workspace/src/create-workspace-options.ts index 1b14c13ac0830..3ada0b0678176 100644 --- a/packages/create-nx-workspace/src/create-workspace-options.d.ts +++ b/packages/create-nx-workspace/src/create-workspace-options.ts @@ -1,4 +1,5 @@ import { PackageManager } from './utils/package-manager'; +import { CI } from './utils/ci/ci-list'; export interface CreateWorkspaceOptions { name: string; // Workspace name (e.g. org name) diff --git a/packages/create-nx-workspace/src/create-workspace.ts b/packages/create-nx-workspace/src/create-workspace.ts index cb9a0bccf05b5..d31221311004f 100644 --- a/packages/create-nx-workspace/src/create-workspace.ts +++ b/packages/create-nx-workspace/src/create-workspace.ts @@ -60,7 +60,7 @@ export async function createWorkspace( nxCloud && nxCloudInstallRes?.code === 0 ); } - if (!skipGit) { + if (!skipGit && commit) { try { await initializeGitRepo(directory, { defaultBase, commit }); } catch (e) { diff --git a/packages/create-nx-workspace/src/utils/preset/get-third-party-preset.ts b/packages/create-nx-workspace/src/utils/preset/get-third-party-preset.ts index 182bbf30c7358..4b5aa13a6b532 100644 --- a/packages/create-nx-workspace/src/utils/preset/get-third-party-preset.ts +++ b/packages/create-nx-workspace/src/utils/preset/get-third-party-preset.ts @@ -5,18 +5,19 @@ import { isKnownPreset } from './preset'; /** * This function is used to check if a preset is a third party preset. * @param preset - * @returns null if the preset is a known Nx preset or preset does not exist, the normalized preset otherwise. + * @returns null if the preset is a known Nx preset or preset does not exist, the package name of preset otherwise. */ export async function getThirdPartyPreset( preset?: string ): Promise { if (preset && !isKnownPreset(preset)) { + // extract the package name from the preset const packageName = preset.match(/.+@/) ? preset[0] + preset.substring(1).split('@')[0] : preset; const validateResult = validateNpmPackage(packageName); if (validateResult.validForNewPackages) { - return Promise.resolve(preset); + return Promise.resolve(packageName); } else { //! Error here output.error({ diff --git a/packages/js/src/utils/typescript/add-tslib-dependencies.ts b/packages/js/src/utils/typescript/add-tslib-dependencies.ts index 1c7ef65bbdd4f..366018f67eec7 100644 --- a/packages/js/src/utils/typescript/add-tslib-dependencies.ts +++ b/packages/js/src/utils/typescript/add-tslib-dependencies.ts @@ -2,7 +2,7 @@ import { addDependenciesToPackageJson, Tree } from '@nx/devkit'; import { tsLibVersion } from '../versions'; export function addTsLibDependencies(tree: Tree) { - addDependenciesToPackageJson( + return addDependenciesToPackageJson( tree, { tslib: tsLibVersion, diff --git a/packages/nx-plugin/generators.json b/packages/nx-plugin/generators.json index 3d13c99a32cb0..ca43c9bbb4b0d 100644 --- a/packages/nx-plugin/generators.json +++ b/packages/nx-plugin/generators.json @@ -8,6 +8,11 @@ "schema": "./src/generators/plugin/schema.json", "description": "Create a Nx Plugin." }, + "create-package": { + "factory": "./src/generators/create-package/create-package", + "schema": "./src/generators/create-package/schema.json", + "description": "Create a framework package that uses Nx CLI" + }, "e2e-project": { "factory": "./src/generators/e2e-project/e2e", "schema": "./src/generators/e2e-project/schema.json", @@ -47,6 +52,11 @@ "schema": "./src/generators/plugin/schema.json", "description": "Create a Nx Plugin." }, + "create-package": { + "factory": "./src/generators/create-package/create-package#createPackageSchematic", + "schema": "./src/generators/create-package/schema.json", + "description": "Create a framework package that uses Nx CLI" + }, "e2e-project": { "factory": "./src/generators/e2e-project/e2e#e2eProjectSchematic", "schema": "./src/generators/e2e-project/schema.json", diff --git a/packages/nx-plugin/generators.ts b/packages/nx-plugin/generators.ts index a5c482e0a9580..d2d89360fe8f4 100644 --- a/packages/nx-plugin/generators.ts +++ b/packages/nx-plugin/generators.ts @@ -1,3 +1,4 @@ +export * from './src/generators/create-package/create-package'; export * from './src/generators/e2e-project/e2e'; export * from './src/generators/executor/executor'; export * from './src/generators/generator/generator'; diff --git a/packages/nx-plugin/index.ts b/packages/nx-plugin/index.ts deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/packages/nx-plugin/src/executors/e2e/e2e.impl.ts b/packages/nx-plugin/src/executors/e2e/e2e.impl.ts index 75678f9f00b7c..9d0f5bae29060 100644 --- a/packages/nx-plugin/src/executors/e2e/e2e.impl.ts +++ b/packages/nx-plugin/src/executors/e2e/e2e.impl.ts @@ -59,7 +59,7 @@ async function runTests( context: ExecutorContext ): Promise { const { success } = await jestExecutor( - { ...jestOptions, watch: false }, + { ...jestOptions, watch: false, runInBand: true }, context ); diff --git a/packages/nx-plugin/src/generators/create-package/create-package.spec.ts b/packages/nx-plugin/src/generators/create-package/create-package.spec.ts new file mode 100644 index 0000000000000..ca8cdb5ecb619 --- /dev/null +++ b/packages/nx-plugin/src/generators/create-package/create-package.spec.ts @@ -0,0 +1,125 @@ +import { + joinPathFragments, + readJson, + readProjectConfiguration, + Tree, +} from '@nrwl/devkit'; +import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; +import { Linter } from '@nrwl/linter'; +import pluginGenerator from '../plugin/plugin'; +import { createPackageGenerator } from './create-package'; +import { CreatePackageSchema } from './schema'; + +const getSchema: ( + overrides?: Partial +) => CreatePackageSchema = (overrides = {}) => ({ + name: 'create-package', + project: 'my-plugin', + compiler: 'tsc', + skipTsConfig: false, + skipFormat: false, + skipLintChecks: false, + linter: Linter.EsLint, + unitTestRunner: 'jest', + minimal: true, + ...overrides, +}); + +describe('NxPlugin Create Package Generator', () => { + let tree: Tree; + + beforeEach(async () => { + tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); + await pluginGenerator(tree, { + name: 'my-plugin', + compiler: 'tsc', + skipTsConfig: false, + skipFormat: false, + skipLintChecks: false, + linter: Linter.EsLint, + unitTestRunner: 'jest', + }); + }); + + it('should update the project.json file', async () => { + await createPackageGenerator(tree, getSchema()); + const project = readProjectConfiguration(tree, 'create-package'); + expect(project.root).toEqual('libs/create-package'); + expect(project.sourceRoot).toEqual('libs/create-package/bin'); + expect(project.targets.build).toEqual({ + executor: '@nrwl/js:tsc', + outputs: ['{options.outputPath}'], + options: { + outputPath: 'dist/libs/create-package', + tsConfig: 'libs/create-package/tsconfig.lib.json', + main: 'libs/create-package/bin/index.ts', + assets: [], + buildableProjectDepsInPackageJsonType: 'dependencies', + }, + }); + }); + + it('should place the create-package plugin in a directory', async () => { + await createPackageGenerator( + tree, + getSchema({ + directory: 'plugins', + } as Partial) + ); + const project = readProjectConfiguration(tree, 'plugins-create-package'); + expect(project.root).toEqual('libs/plugins/create-package'); + }); + + it('should specify tsc as compiler', async () => { + await createPackageGenerator( + tree, + getSchema({ + compiler: 'tsc', + }) + ); + + const { build } = readProjectConfiguration(tree, 'create-package').targets; + + expect(build.executor).toEqual('@nrwl/js:tsc'); + }); + + it('should specify swc as compiler', async () => { + await createPackageGenerator( + tree, + getSchema({ + compiler: 'swc', + }) + ); + + const { build } = readProjectConfiguration(tree, 'create-package').targets; + + expect(build.executor).toEqual('@nrwl/js:swc'); + }); + + it("should use name as default for the package.json's name", async () => { + await createPackageGenerator(tree, getSchema()); + + const { root } = readProjectConfiguration(tree, 'create-package'); + const { name } = readJson<{ name: string }>( + tree, + joinPathFragments(root, 'package.json') + ); + + expect(name).toEqual('create-package'); + }); + + it('should use importPath as the package.json name', async () => { + await createPackageGenerator( + tree, + getSchema({ importPath: '@my-company/create-package' }) + ); + + const { root } = readProjectConfiguration(tree, 'create-package'); + const { name } = readJson<{ name: string }>( + tree, + joinPathFragments(root, 'package.json') + ); + + expect(name).toEqual('@my-company/create-package'); + }); +}); diff --git a/packages/nx-plugin/src/generators/create-package/create-package.ts b/packages/nx-plugin/src/generators/create-package/create-package.ts new file mode 100644 index 0000000000000..298e06df69acf --- /dev/null +++ b/packages/nx-plugin/src/generators/create-package/create-package.ts @@ -0,0 +1,184 @@ +import { + addDependenciesToPackageJson, + readProjectConfiguration, + Tree, + generateFiles, + readJson, + convertNxGenerator, + formatFiles, + updateProjectConfiguration, +} from '@nrwl/devkit'; +import { libraryGenerator as jsLibraryGenerator } from '@nrwl/js'; +import { join } from 'path'; +import { nxVersion } from '../../utils/versions'; +import generatorGenerator from '../generator/generator'; +import { CreatePackageSchema } from './schema'; +import { NormalizedSchema, normalizeSchema } from './utils/normalize-schema'; + +export async function createPackageGenerator( + host: Tree, + schema: CreatePackageSchema +) { + const options = normalizeSchema(host, schema); + const pluginPackageName = await addPresetGenerator(host, { + ...options, + skipFormat: true, + }); + + const installTask = addDependenciesToPackageJson( + host, + {}, + { + 'create-nx-workspace': nxVersion, + } + ); + + await createCliPackage(host, options, pluginPackageName); + addTestsToE2eProject(host, options, pluginPackageName); + + if (!options.skipFormat) { + await formatFiles(host); + } + + return installTask; +} + +/** + * Add a preset generator to the plugin if it doesn't exist + * @param host + * @param schema + * @returns package name of the plugin + */ +async function addPresetGenerator( + host: Tree, + schema: NormalizedSchema +): Promise { + const { root: projectRoot } = readProjectConfiguration(host, schema.project); + if (!host.exists(`${projectRoot}/src/generators/preset`)) { + await generatorGenerator(host, { + name: 'preset', + project: schema.project, + unitTestRunner: schema.unitTestRunner, + }); + } + + return readJson(host, join(projectRoot, 'package.json'))?.name; +} + +async function createCliPackage( + host: Tree, + options: NormalizedSchema, + pluginPackageName: string +) { + await jsLibraryGenerator(host, { + ...options, + rootProject: false, + config: 'project', + buildable: true, + publishable: true, + bundler: options.bundler, + importPath: options.importPath, + }); + + host.delete(join(options.projectRoot, 'src')); + + // Add the bin entry to the package.json + const packageJsonPath = join(options.projectRoot, 'package.json'); + const packageJson = readJson(host, packageJsonPath); + packageJson.bin = { + [options.name]: './bin/index.js', + }; + packageJson.dependencies = { + 'create-nx-workspace': nxVersion, + }; + host.write(packageJsonPath, JSON.stringify(packageJson)); + + // update project build target to use the bin entry + const projectConfiguration = readProjectConfiguration( + host, + options.projectName + ); + projectConfiguration.sourceRoot = join(options.projectRoot, 'bin'); + projectConfiguration.targets.build.options.main = join( + options.projectRoot, + 'bin/index.ts' + ); + projectConfiguration.targets.build.options.buildableProjectDepsInPackageJsonType = + 'dependencies'; + updateProjectConfiguration(host, options.projectName, projectConfiguration); + + // Add bin files to tsconfg.lib.json + const tsConfigPath = join(options.projectRoot, 'tsconfig.lib.json'); + const tsConfig = readJson(host, tsConfigPath); + tsConfig.include.push('bin/**/*.ts'); + host.write(tsConfigPath, JSON.stringify(tsConfig)); + + generateFiles( + host, + join(__dirname, './files/create-framework-package'), + options.projectRoot, + { + ...options, + preset: pluginPackageName, + tmpl: '', + } + ); +} + +function getE2eProjectConfiguration(host: Tree, e2eProjectName: string) { + try { + return readProjectConfiguration(host, e2eProjectName); + } catch (e) { + return; + } +} + +/** + * Add a test file to plugin e2e project + * @param host + * @param options + * @returns + */ +function addTestsToE2eProject( + host: Tree, + options: NormalizedSchema, + pluginPackageName: string +) { + const pluginProjectConfiguration = readProjectConfiguration( + host, + options.project + ); + const pluginOutputPath = + pluginProjectConfiguration.targets.build.options.outputPath; + + const cliProjectConfiguration = readProjectConfiguration( + host, + options.projectName + ); + const cliOutputPath = + cliProjectConfiguration.targets.build.options.outputPath; + + const e2eProjectConfiguration = + getE2eProjectConfiguration(host, 'e2e') ?? + getE2eProjectConfiguration(host, `${options.project}-e2e`); + if (!e2eProjectConfiguration) { + return; // e2e project does not exist, do not add tests + } + generateFiles( + host, + join(__dirname, './files/e2e'), + e2eProjectConfiguration.sourceRoot, + { + ...options, + pluginPackageName, + pluginOutputPath, + cliOutputPath, + tmpl: '', + } + ); +} + +export default createPackageGenerator; +export const createPackageSchematic = convertNxGenerator( + createPackageGenerator +); diff --git a/packages/nx-plugin/src/generators/create-package/files/create-framework-package/bin/index.ts__tmpl__ b/packages/nx-plugin/src/generators/create-package/files/create-framework-package/bin/index.ts__tmpl__ new file mode 100644 index 0000000000000..06b25a34bf3a0 --- /dev/null +++ b/packages/nx-plugin/src/generators/create-package/files/create-framework-package/bin/index.ts__tmpl__ @@ -0,0 +1,17 @@ +#!/usr/bin/env node + +import { createWorkspace } from 'create-nx-workspace'; + +async function main() { + const name = process.argv[2]; // TODO: use libraries like yargs or enquirer to set your workspace name + // TODO: update below to customize the workspace + await createWorkspace('<%= preset %>', { + name, + nxCloud: false, + packageManager: 'npm', + }); + + console.log(`Successfully created the workspace: ${name}.`); +} + +main(); \ No newline at end of file diff --git a/packages/nx-plugin/src/generators/create-package/files/e2e/__name__.spec.ts__tmpl__ b/packages/nx-plugin/src/generators/create-package/files/e2e/__name__.spec.ts__tmpl__ new file mode 100644 index 0000000000000..e73b45d135b4a --- /dev/null +++ b/packages/nx-plugin/src/generators/create-package/files/e2e/__name__.spec.ts__tmpl__ @@ -0,0 +1,36 @@ +import { + ensureNxProject, + uniq, + runCreatePackageCli, + runNxCommandAsync +} from '@nrwl/nx-plugin/testing'; + +describe('<%= name %> e2e', () => { + // Setting up individual workspaces per + // test can cause e2e runs to take a long time. + // For this reason, we recommend each suite only + // consumes 1 workspace. The tests should each operate + // on a unique project in the workspace, such that they + // are not dependant on one another. + beforeAll(() => { + ensureNxProject('<%= pluginPackageName %>', '<%= pluginOutputPath %>'); + }); + + afterAll(() => { + // `nx reset` kills the daemon, and performs + // some work which can help clean up e2e leftovers + runNxCommandAsync('reset'); + }); + + it('should run <%= name %>', () => { + const project = uniq('<%= name %>'); + const result = runCreatePackageCli( + '<%= pluginPackageName %>', + '<%= pluginOutputPath %>', + '<%= name %>', + '<%= cliOutputPath %>', + project + ); + expect(result).toContain('Successfully created'); + }, 120000); +}); diff --git a/packages/nx-plugin/src/generators/create-package/schema.d.ts b/packages/nx-plugin/src/generators/create-package/schema.d.ts new file mode 100644 index 0000000000000..b1c97caf33079 --- /dev/null +++ b/packages/nx-plugin/src/generators/create-package/schema.d.ts @@ -0,0 +1,16 @@ +export interface CreatePackageSchema { + name: string; + project: string; + + // options to create cli package, passed to js library generator + directory?: string; + skipTsConfig: boolean; + skipFormat: boolean; + tags?: string; + unitTestRunner: 'jest' | 'none'; + linter: Linter; + setParserOptionsProject?: boolean; + compiler: 'swc' | 'tsc'; + importPath?: string; + rootProject?: boolean; +} diff --git a/packages/nx-plugin/src/generators/create-package/schema.json b/packages/nx-plugin/src/generators/create-package/schema.json new file mode 100644 index 0000000000000..1ee36f38b6d69 --- /dev/null +++ b/packages/nx-plugin/src/generators/create-package/schema.json @@ -0,0 +1,78 @@ +{ + "$schema": "http://json-schema.org/schema", + "cli": "nx", + "$id": "NxPluginCreatePackage", + "title": "Create a framework package", + "description": "Create a framework package that uses Nx CLI.", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The package name of cli, e.g. `create-framework-package`. Note this must be a valid NPM name to be published.", + "$default": { + "$source": "argv", + "index": 0 + }, + "x-priority": "important" + }, + "project": { + "type": "string", + "description": "The name of the generator project.", + "alias": "p", + "$default": { + "$source": "projectName" + }, + "x-prompt": "What is the name of the project for the generator?", + "x-priority": "important" + }, + "unitTestRunner": { + "type": "string", + "enum": ["jest", "none"], + "description": "Test runner to use for unit tests.", + "default": "jest" + }, + "directory": { + "type": "string", + "description": "A directory where the app is placed." + }, + "linter": { + "description": "The tool to use for running lint checks.", + "type": "string", + "enum": ["eslint"], + "default": "eslint" + }, + "tags": { + "type": "string", + "description": "Add tags to the library (used for linting).", + "alias": "t" + }, + "skipFormat": { + "description": "Skip formatting files.", + "type": "boolean", + "default": false, + "x-priority": "internal" + }, + "skipTsConfig": { + "type": "boolean", + "default": false, + "description": "Do not update tsconfig.json for development experience.", + "x-priority": "internal" + }, + "setParserOptionsProject": { + "type": "boolean", + "description": "Whether or not to configure the ESLint `parserOptions.project` option. We do not do this by default for lint performance reasons.", + "default": false + }, + "compiler": { + "type": "string", + "enum": ["tsc", "swc"], + "default": "tsc", + "description": "The compiler used by the build and test targets." + }, + "importPath": { + "type": "string", + "description": "How the plugin will be published, like `create-framework-app`. Note this must be a valid NPM name. Will use name if not provided." + } + }, + "required": ["name", "project"] +} diff --git a/packages/nx-plugin/src/generators/create-package/utils/normalize-schema.ts b/packages/nx-plugin/src/generators/create-package/utils/normalize-schema.ts new file mode 100644 index 0000000000000..67f4febc15024 --- /dev/null +++ b/packages/nx-plugin/src/generators/create-package/utils/normalize-schema.ts @@ -0,0 +1,44 @@ +import { + extractLayoutDirectory, + getWorkspaceLayout, + joinPathFragments, + names, + Tree, +} from '@nrwl/devkit'; +import { CreatePackageSchema } from '../schema'; + +export interface NormalizedSchema extends CreatePackageSchema { + bundler: 'swc' | 'tsc'; + libsDir: string; + projectName: string; + projectRoot: string; + projectDirectory: string; +} + +export function normalizeSchema( + host: Tree, + schema: CreatePackageSchema +): NormalizedSchema { + const { layoutDirectory, projectDirectory } = extractLayoutDirectory( + schema.directory + ); + const { libsDir: defaultLibsDir } = getWorkspaceLayout(host); + const libsDir = layoutDirectory ?? defaultLibsDir; + const name = names(schema.name).fileName; + const fullProjectDirectory = projectDirectory + ? `${names(projectDirectory).fileName}/${name}` + : name; + const projectName = fullProjectDirectory.replace(new RegExp('/', 'g'), '-'); + const projectRoot = joinPathFragments(libsDir, fullProjectDirectory); + const importPath = schema.importPath ?? name; + return { + ...schema, + bundler: schema.compiler ?? 'tsc', + libsDir, + projectName, + projectRoot, + name, + projectDirectory: fullProjectDirectory, + importPath, + }; +} diff --git a/packages/nx-plugin/src/generators/e2e-project/e2e.ts b/packages/nx-plugin/src/generators/e2e-project/e2e.ts index 63784a4b3c6f0..c2bea829b5de3 100644 --- a/packages/nx-plugin/src/generators/e2e-project/e2e.ts +++ b/packages/nx-plugin/src/generators/e2e-project/e2e.ts @@ -74,7 +74,7 @@ function updateWorkspaceConfiguration(host: Tree, options: NormalizedSchema) { addProjectConfiguration(host, options.projectName, { root: options.projectRoot, projectType: 'application', - sourceRoot: `${options.projectRoot}/src`, + sourceRoot: `${options.projectRoot}/tests`, targets: { e2e: { executor: '@nx/nx-plugin:e2e', diff --git a/packages/nx-plugin/src/generators/generator/files/generator/__fileName__/generator.ts__tmpl__ b/packages/nx-plugin/src/generators/generator/files/generator/__fileName__/generator.ts__tmpl__ index ed05aae07e2f4..f7a2c889f173c 100644 --- a/packages/nx-plugin/src/generators/generator/files/generator/__fileName__/generator.ts__tmpl__ +++ b/packages/nx-plugin/src/generators/generator/files/generator/__fileName__/generator.ts__tmpl__ @@ -23,7 +23,10 @@ function normalizeOptions(tree: Tree, options: <%= className %>GeneratorSchema): ? `${names(options.directory).fileName}/${name}` : name; const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-'); - const projectRoot = `${getWorkspaceLayout(tree).libsDir}/${projectDirectory}`; + const projectRoot = + getWorkspaceLayout(tree).libsDir === '.' + ? '.' + : `${getWorkspaceLayout(tree).libsDir}/${projectDirectory}`; const parsedTags = options.tags ? options.tags.split(',').map((s) => s.trim()) : []; diff --git a/packages/nx-plugin/src/generators/plugin/plugin.ts b/packages/nx-plugin/src/generators/plugin/plugin.ts index fcb2bde66ee55..5c566e67bc97a 100644 --- a/packages/nx-plugin/src/generators/plugin/plugin.ts +++ b/packages/nx-plugin/src/generators/plugin/plugin.ts @@ -3,9 +3,10 @@ import { convertNxGenerator, formatFiles, generateFiles, - installPackagesTask, + GeneratorCallback, normalizePath, readProjectConfiguration, + runTasksInSerial, Tree, updateProjectConfiguration, } from '@nx/devkit'; @@ -73,55 +74,66 @@ function updatePluginConfig(host: Tree, options: NormalizedSchema) { export async function pluginGenerator(host: Tree, schema: Schema) { const options = normalizeOptions(host, schema); + const tasks: GeneratorCallback[] = []; + + tasks.push( + await jsLibraryGenerator(host, { + ...schema, + config: 'project', + bundler: options.bundler, + buildable: true, + publishable: true, + importPath: options.npmPackageName, + skipFormat: true, + }) + ); - await jsLibraryGenerator(host, { - ...schema, - config: 'project', - bundler: options.bundler, - importPath: options.npmPackageName, - skipFormat: true, - }); - - addTsLibDependencies(host); - - addDependenciesToPackageJson( - host, - { - '@nx/devkit': nxVersion, - }, - { - '@nx/jest': nxVersion, - '@nx/js': nxVersion, - '@nx/nx-plugin': nxVersion, - } + tasks.push(addTsLibDependencies(host)); + + tasks.push( + addDependenciesToPackageJson( + host, + { + '@nx/devkit': nxVersion, + }, + { + '@nx/jest': nxVersion, + '@nx/js': nxVersion, + '@nx/nx-plugin': nxVersion, + } + ) ); // Ensures Swc Deps are installed to handle running // local plugin generators and executors - addSwcDependencies(host); - addSwcRegisterDependencies(host); + tasks.push(addSwcDependencies(host)); + tasks.push(addSwcRegisterDependencies(host)); await addFiles(host, options); updatePluginConfig(host, options); if (options.e2eTestRunner !== 'none') { - await e2eProjectGenerator(host, { - pluginName: options.name, - projectDirectory: options.projectDirectory, - pluginOutputPath: `dist/${options.libsDir}/${options.projectDirectory}`, - npmPackageName: options.npmPackageName, - skipFormat: true, - rootProject: options.rootProject, - }); + tasks.push( + await e2eProjectGenerator(host, { + pluginName: options.name, + projectDirectory: options.projectDirectory, + pluginOutputPath: `dist/${options.libsDir}/${options.projectDirectory}`, + npmPackageName: options.npmPackageName, + skipFormat: true, + rootProject: options.rootProject, + }) + ); } if (options.linter === Linter.EsLint && !options.skipLintChecks) { await pluginLintCheckGenerator(host, { projectName: options.name }); } - await formatFiles(host); + if (!options.skipFormat) { + await formatFiles(host); + } - return () => installPackagesTask(host); + return runTasksInSerial(...tasks); } export default pluginGenerator; diff --git a/packages/nx-plugin/src/generators/preset/generator.ts b/packages/nx-plugin/src/generators/preset/generator.ts index b374968a45f17..d4a99112b543d 100644 --- a/packages/nx-plugin/src/generators/preset/generator.ts +++ b/packages/nx-plugin/src/generators/preset/generator.ts @@ -1,17 +1,25 @@ -import { Tree, updateJson, updateNxJson, readNxJson } from '@nx/devkit'; +import { + Tree, + updateJson, + updateNxJson, + readNxJson, + formatFiles, + runTasksInSerial, +} from '@nx/devkit'; import { Linter } from '@nx/linter'; import { PackageJson } from 'nx/src/utils/package-json'; import { pluginGenerator } from '../plugin/plugin'; import { PresetGeneratorSchema } from './schema'; +import createPackageGenerator from '../create-package/create-package'; export default async function (tree: Tree, options: PresetGeneratorSchema) { - const task = await pluginGenerator(tree, { + const pluginTask = await pluginGenerator(tree, { compiler: 'tsc', linter: Linter.EsLint, name: options.pluginName.includes('/') ? options.pluginName.split('/')[1] : options.pluginName, - skipFormat: false, + skipFormat: true, skipLintChecks: false, skipTsConfig: false, unitTestRunner: 'jest', @@ -23,12 +31,27 @@ export default async function (tree: Tree, options: PresetGeneratorSchema) { removeNpmScope(tree); moveNxPluginToDevDeps(tree); - return task; + const cliTask = await createPackageGenerator(tree, { + name: options.cliName ?? `create-${options.pluginName}-package`, + project: options.pluginName, + skipFormat: true, + skipTsConfig: false, + unitTestRunner: 'jest', + linter: Linter.EsLint, + setParserOptionsProject: false, + compiler: 'tsc', + rootProject: true, + }); + + await formatFiles(tree); + + return runTasksInSerial(pluginTask, cliTask); } function removeNpmScope(tree: Tree) { updateNxJson(tree, { ...readNxJson(tree), npmScope: undefined }); } + function moveNxPluginToDevDeps(tree: Tree) { updateJson(tree, 'package.json', (json) => { const nxPluginEntry = json.dependencies['@nx/nx-plugin']; diff --git a/packages/nx-plugin/src/generators/preset/schema.d.ts b/packages/nx-plugin/src/generators/preset/schema.d.ts index bff8df3c05dfb..897d0b7e10c5a 100644 --- a/packages/nx-plugin/src/generators/preset/schema.d.ts +++ b/packages/nx-plugin/src/generators/preset/schema.d.ts @@ -1,3 +1,4 @@ export interface PresetGeneratorSchema { pluginName: string; + cliName?: string; } diff --git a/packages/nx-plugin/src/generators/preset/schema.json b/packages/nx-plugin/src/generators/preset/schema.json index bc224d8091d57..edb0cdf69a84b 100644 --- a/packages/nx-plugin/src/generators/preset/schema.json +++ b/packages/nx-plugin/src/generators/preset/schema.json @@ -10,6 +10,11 @@ "type": "string", "description": "Plugin name", "aliases": ["name"] + }, + "cliName": { + "type": "string", + "description": "Name of cli command to create workspace with plugin", + "aliases": ["name"] } }, "required": ["pluginName"] diff --git a/packages/nx-plugin/src/utils/testing-utils/async-commands.ts b/packages/nx-plugin/src/utils/testing-utils/async-commands.ts index 2eaa0977fe850..08785b3240fdd 100644 --- a/packages/nx-plugin/src/utils/testing-utils/async-commands.ts +++ b/packages/nx-plugin/src/utils/testing-utils/async-commands.ts @@ -11,15 +11,16 @@ import { fileExists } from './utils'; */ export function runCommandAsync( command: string, - opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv } = { + opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv; cwd?: string } = { silenceError: false, + cwd: tmpProjPath(), } ): Promise<{ stdout: string; stderr: string }> { return new Promise((resolve, reject) => { exec( command, { - cwd: tmpProjPath(), + cwd: opts.cwd, env: { ...process.env, ...opts.env }, }, (err, stdout, stderr) => { @@ -39,8 +40,9 @@ export function runCommandAsync( */ export function runNxCommandAsync( command: string, - opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv } = { + opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv; cwd?: string } = { silenceError: false, + cwd: tmpProjPath(), } ): Promise<{ stdout: string; stderr: string }> { if (fileExists(tmpProjPath('package.json'))) { diff --git a/packages/nx-plugin/src/utils/testing-utils/commands.ts b/packages/nx-plugin/src/utils/testing-utils/commands.ts index 62602a4221524..7fc27d1ad9e43 100644 --- a/packages/nx-plugin/src/utils/testing-utils/commands.ts +++ b/packages/nx-plugin/src/utils/testing-utils/commands.ts @@ -12,13 +12,14 @@ import { fileExists } from './utils'; */ export function runNxCommand( command?: string, - opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv } = { + opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv; cwd?: string } = { silenceError: false, + cwd: tmpProjPath(), } ): string { function _runNxCommand(c) { const execSyncOptions: ExecOptions = { - cwd: tmpProjPath(), + cwd: opts.cwd, env: { ...process.env, ...opts.env }, }; if (fileExists(tmpProjPath('package.json'))) { @@ -50,11 +51,11 @@ export function runNxCommand( export function runCommand( command: string, - opts?: { env?: NodeJS.ProcessEnv } + opts: { env?: NodeJS.ProcessEnv; cwd?: string } = { cwd: tmpProjPath() } ): string { try { return execSync(command, { - cwd: tmpProjPath(), + cwd: opts.cwd, stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env, ...opts?.env }, }).toString(); diff --git a/packages/nx-plugin/src/utils/testing-utils/create-package-cli.ts b/packages/nx-plugin/src/utils/testing-utils/create-package-cli.ts new file mode 100644 index 0000000000000..fc4c660e9586f --- /dev/null +++ b/packages/nx-plugin/src/utils/testing-utils/create-package-cli.ts @@ -0,0 +1,39 @@ +import { workspaceRoot } from '@nrwl/devkit'; +import { runCommand, runNxCommand } from './commands'; +import { tmpProjPath } from './paths'; + +/** + * This function is used to run the create package CLI command. + * It builds the plugin library and the create package library and run the create package command with for the plugin library. + * It needs to be ran inside an Nx project. It would assume that an Nx project already exists. + * @param pluginLibraryName e.g. my-plugin + * @param pluginLibraryBuildPath e.g. dist/packages/my-plugin + * @param createPackageLibraryName e.g. create-my-plugin-package + * @param createPackageLibraryBuildPath e.g. dist/packages/create-my-plugin-package + * @param projectToBeCreated project name to be created using the cli + * @returns results for the create package command + */ +export function runCreatePackageCli( + pluginLibraryName: string, + pluginLibraryBuildPath: string, + createPackageLibraryName: string, + createPackageLibraryBuildPath: string, + projectToBeCreated: string +) { + runNxCommand(`build ${createPackageLibraryName}`, { + cwd: process.cwd(), + }); + return runCommand( + `node ${workspaceRoot}/${createPackageLibraryBuildPath}/bin/index.js ${projectToBeCreated} --verbose`, + { + env: { + [pluginLibraryName]: `file:${workspaceRoot}/${pluginLibraryBuildPath}`, + }, + cwd: tmpProjPath(), + } + ); +} + +export function generatedPackagePath(projectToBeCreated: string) { + return `${tmpProjPath}/${projectToBeCreated}`; +} diff --git a/packages/nx-plugin/src/utils/testing-utils/index.ts b/packages/nx-plugin/src/utils/testing-utils/index.ts index 81414ad685bfb..2541b07012ee3 100644 --- a/packages/nx-plugin/src/utils/testing-utils/index.ts +++ b/packages/nx-plugin/src/utils/testing-utils/index.ts @@ -1,5 +1,6 @@ export * from './async-commands'; export * from './commands'; +export * from './create-package-cli'; export * from './paths'; export * from './nx-project'; export * from './utils'; diff --git a/packages/nx-plugin/src/utils/testing-utils/nx-project.ts b/packages/nx-plugin/src/utils/testing-utils/nx-project.ts index 706d7289b8628..06a252f06e9ae 100644 --- a/packages/nx-plugin/src/utils/testing-utils/nx-project.ts +++ b/packages/nx-plugin/src/utils/testing-utils/nx-project.ts @@ -8,7 +8,7 @@ import { execSync } from 'child_process'; import { dirname } from 'path'; import { ensureDirSync } from 'fs-extra'; import { tmpProjPath } from './paths'; -import { cleanup } from './utils'; +import { cleanup, directoryExists } from './utils'; function runNxNewCommand(args?: string, silent?: boolean) { const localTmpDir = dirname(tmpProjPath()); @@ -69,7 +69,9 @@ export function newNxProject( pluginDistPath: string ): void { cleanup(); - runNxNewCommand('', true); + if (!directoryExists(tmpProjPath())) { + runNxNewCommand('', true); + } patchPackageJsonForPlugin(npmPackageName, pluginDistPath); runPackageManagerInstall(); } diff --git a/packages/nx-plugin/src/utils/testing-utils/utils.ts b/packages/nx-plugin/src/utils/testing-utils/utils.ts index f6a9b5741c49b..efb9502082085 100644 --- a/packages/nx-plugin/src/utils/testing-utils/utils.ts +++ b/packages/nx-plugin/src/utils/testing-utils/utils.ts @@ -125,7 +125,9 @@ export function readFile(path: string): string { * Deletes the e2e directory */ export function cleanup(): void { - removeSync(tmpProjPath()); + try { + removeSync(tmpProjPath()); + } catch (e) {} } /** diff --git a/packages/react/src/module-federation/with-module-federation.ts b/packages/react/src/module-federation/with-module-federation.ts index 28a341d4f8598..f1c1e185a6155 100644 --- a/packages/react/src/module-federation/with-module-federation.ts +++ b/packages/react/src/module-federation/with-module-federation.ts @@ -2,7 +2,7 @@ import { ModuleFederationConfig } from '@nx/devkit'; import { readCachedProjectConfiguration } from 'nx/src/project-graph/project-graph'; import { getModuleFederationConfig } from './utils'; import ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); -import type { AsyncNxWebpackPlugin, NxWebpackPlugin } from '@nx/webpack'; +import type { AsyncNxWebpackPlugin } from '@nx/webpack'; function determineRemoteUrl(remote: string) { const remoteConfiguration = readCachedProjectConfiguration(remote); diff --git a/packages/workspace/src/generators/new/generate-preset.ts b/packages/workspace/src/generators/new/generate-preset.ts index 83e6670c15ed3..a52f2a9dc5b46 100644 --- a/packages/workspace/src/generators/new/generate-preset.ts +++ b/packages/workspace/src/generators/new/generate-preset.ts @@ -149,12 +149,12 @@ function getPresetDependencies({ return { dependencies: {}, dev: { '@nx/node': nxVersion } }; default: { + presetVersion = + presetVersion ?? getNpmPackageVersion(preset) ?? process.env?.[preset]; // read from env variable for e2e testing return { dev: {}, dependencies: { - [preset]: - process.env['NX_E2E_PRESET_VERSION'] ?? - getNpmPackageVersion(preset, presetVersion), + [preset]: presetVersion, }, }; } diff --git a/packages/workspace/src/generators/preset/schema.json b/packages/workspace/src/generators/preset/schema.json index 5fce098d0bf71..1c6a73534ed96 100644 --- a/packages/workspace/src/generators/preset/schema.json +++ b/packages/workspace/src/generators/preset/schema.json @@ -89,5 +89,6 @@ "type": "boolean", "default": false } - } + }, + "required": ["preset", "name"] } From 934847ba330e18ccb50802727faa5ca9eacea2b2 Mon Sep 17 00:00:00 2001 From: Emily Xiong Date: Wed, 12 Apr 2023 14:33:59 -0400 Subject: [PATCH 2/3] feat(misc): update pr with comments --- docs/generated/manifests/packages.json | 2 +- docs/generated/packages-metadata.json | 2 +- .../nx-plugin/generators/create-package.json | 8 +- .../packages/nx-plugin/generators/preset.json | 5 +- .../src/create-nx-plugin.test.ts | 2 + .../create-nx-plugin/bin/create-nx-plugin.ts | 23 ++++- .../create-nx-workspace/src/create-preset.ts | 4 +- .../src/create-workspace-options.ts | 1 + packages/nx-plugin/generators.json | 4 +- .../nx-plugin/src/executors/e2e/e2e.impl.ts | 2 +- .../create-package/create-package.spec.ts | 1 + .../create-package/create-package.ts | 93 ++++++++++++------- .../bin/index.ts__tmpl__ | 7 ++ .../files/e2e/__name__.spec.ts__tmpl__ | 39 ++++---- .../src/generators/create-package/schema.d.ts | 6 +- .../src/generators/create-package/schema.json | 6 ++ .../nx-plugin/src/generators/plugin/plugin.ts | 1 - .../src/generators/preset/generator.ts | 29 +++--- .../src/generators/preset/schema.d.ts | 2 +- .../src/generators/preset/schema.json | 5 +- .../src/utils/testing-utils/async-commands.ts | 4 +- .../src/utils/testing-utils/commands.ts | 5 +- .../utils/testing-utils/create-package-cli.ts | 61 ++++++++---- .../src/utils/testing-utils/nx-project.ts | 4 +- .../src/utils/testing-utils/paths.ts | 8 +- .../src/utils/testing-utils/utils.ts | 10 +- .../src/generators/new/generate-preset.ts | 5 +- packages/workspace/src/generators/new/new.ts | 1 + 28 files changed, 220 insertions(+), 120 deletions(-) diff --git a/docs/generated/manifests/packages.json b/docs/generated/manifests/packages.json index 8d547cf0ecd2e..1cfe447e55c0c 100644 --- a/docs/generated/manifests/packages.json +++ b/docs/generated/manifests/packages.json @@ -1833,7 +1833,7 @@ "type": "generator" }, "/packages/nx-plugin/generators/create-package": { - "description": "Create a framework package that uses Nx CLI", + "description": "Create a package which can be used by npx to create a new workspace", "file": "generated/packages/nx-plugin/generators/create-package.json", "hidden": false, "name": "create-package", diff --git a/docs/generated/packages-metadata.json b/docs/generated/packages-metadata.json index 81e87d4cf8bd5..d7c210a9b1933 100644 --- a/docs/generated/packages-metadata.json +++ b/docs/generated/packages-metadata.json @@ -1811,7 +1811,7 @@ "type": "generator" }, { - "description": "Create a framework package that uses Nx CLI", + "description": "Create a package which can be used by npx to create a new workspace", "file": "generated/packages/nx-plugin/generators/create-package.json", "hidden": false, "name": "create-package", diff --git a/docs/generated/packages/nx-plugin/generators/create-package.json b/docs/generated/packages/nx-plugin/generators/create-package.json index eee1fea878be0..720abcaa8a2bf 100644 --- a/docs/generated/packages/nx-plugin/generators/create-package.json +++ b/docs/generated/packages/nx-plugin/generators/create-package.json @@ -70,12 +70,18 @@ "importPath": { "type": "string", "description": "How the plugin will be published, like `create-framework-app`. Note this must be a valid NPM name. Will use name if not provided." + }, + "e2eTestRunner": { + "type": "string", + "enum": ["jest", "none"], + "description": "Test runner to use for end to end (E2E) tests.", + "default": "jest" } }, "required": ["name", "project"], "presets": [] }, - "description": "Create a framework package that uses Nx CLI", + "description": "Create a package which can be used by npx to create a new workspace", "implementation": "/packages/nx-plugin/src/generators/create-package/create-package.ts", "aliases": [], "hidden": false, diff --git a/docs/generated/packages/nx-plugin/generators/preset.json b/docs/generated/packages/nx-plugin/generators/preset.json index bf7c16ce8c2ba..082117d91b888 100644 --- a/docs/generated/packages/nx-plugin/generators/preset.json +++ b/docs/generated/packages/nx-plugin/generators/preset.json @@ -14,10 +14,9 @@ "description": "Plugin name", "aliases": ["name"] }, - "cliName": { + "createPackageName": { "type": "string", - "description": "Name of cli command to create workspace with plugin", - "aliases": ["name"] + "description": "Name of package which creates a workspace" } }, "required": ["pluginName"], diff --git a/e2e/workspace-create/src/create-nx-plugin.test.ts b/e2e/workspace-create/src/create-nx-plugin.test.ts index 312606ba4fe37..ab825957c285e 100644 --- a/e2e/workspace-create/src/create-nx-plugin.test.ts +++ b/e2e/workspace-create/src/create-nx-plugin.test.ts @@ -21,6 +21,7 @@ describe('create-nx-plugin', () => { runCreatePlugin(pluginName, { packageManager, + extraArgs: `--createPackageName=create-${wsName}-package`, }); checkFilesExist( @@ -53,5 +54,6 @@ describe('create-nx-plugin', () => { checkFilesExist(`dist/create-${pluginName}-package/bin/index.js`); expect(() => runCLI(`e2e e2e`)).not.toThrow(); + expect(() => runCLI(`e2e create-${wsName}-package-e2e`)).not.toThrow(); }); }); diff --git a/packages/create-nx-plugin/bin/create-nx-plugin.ts b/packages/create-nx-plugin/bin/create-nx-plugin.ts index 2114aa52f36ed..5dc3121b6c1ae 100644 --- a/packages/create-nx-plugin/bin/create-nx-plugin.ts +++ b/packages/create-nx-plugin/bin/create-nx-plugin.ts @@ -68,9 +68,26 @@ async function determinePluginName( return results.pluginName; } +async function determineCreatePackageName( + parsedArgs: CreateNxPluginArguments +): Promise { + if (parsedArgs.createPackageName) { + return Promise.resolve(parsedArgs.createPackageName); + } + + const results = await enquirer.prompt<{ createPackageName: string }>([ + { + name: 'createPackageName', + message: `Create package name (optional) `, + type: 'input', + }, + ]); + return results.createPackageName; +} + interface CreateNxPluginArguments { pluginName: string; - cliName?: string; + createPackageName?: string; packageManager: PackageManager; ci: CI; allPrompts: boolean; @@ -95,7 +112,7 @@ export const commandsObject: yargs.Argv = yargs type: 'string', alias: ['name'], }) - .option('cliName', { + .option('createPackageName', { describe: 'Name of the CLI package to create workspace with plugin', type: 'string', }), @@ -170,6 +187,7 @@ async function normalizeArgsMiddleware( ): Promise { try { const pluginName = await determinePluginName(argv); + const createPackageName = await determineCreatePackageName(argv); const packageManager = await determinePackageManager(argv); const defaultBase = await determineDefaultBase(argv); const nxCloud = await determineNxCloud(argv); @@ -177,6 +195,7 @@ async function normalizeArgsMiddleware( Object.assign(argv, { pluginName, + createPackageName, nxCloud, packageManager, defaultBase, diff --git a/packages/create-nx-workspace/src/create-preset.ts b/packages/create-nx-workspace/src/create-preset.ts index fa108393f7193..8d9722b864322 100644 --- a/packages/create-nx-workspace/src/create-preset.ts +++ b/packages/create-nx-workspace/src/create-preset.ts @@ -39,7 +39,9 @@ export async function createPreset( } } - if (process.env.NX_VERBOSE_LOGGING !== 'true') { + if ( + !(process.env.NX_VERBOSE_LOGGING === 'true' || args.includes('--verbose')) + ) { args = '--quiet ' + args; } const command = `g ${preset}:preset ${args}`; diff --git a/packages/create-nx-workspace/src/create-workspace-options.ts b/packages/create-nx-workspace/src/create-workspace-options.ts index 3ada0b0678176..54284061d7f5d 100644 --- a/packages/create-nx-workspace/src/create-workspace-options.ts +++ b/packages/create-nx-workspace/src/create-workspace-options.ts @@ -5,6 +5,7 @@ export interface CreateWorkspaceOptions { name: string; // Workspace name (e.g. org name) packageManager: PackageManager; // Package manager to use nxCloud: boolean; // Enable Nx Cloud + presetVersion?: string; // Version of the preset to use /** * @description Enable interactive mode with presets * @default true diff --git a/packages/nx-plugin/generators.json b/packages/nx-plugin/generators.json index ca43c9bbb4b0d..365be5458f412 100644 --- a/packages/nx-plugin/generators.json +++ b/packages/nx-plugin/generators.json @@ -11,7 +11,7 @@ "create-package": { "factory": "./src/generators/create-package/create-package", "schema": "./src/generators/create-package/schema.json", - "description": "Create a framework package that uses Nx CLI" + "description": "Create a package which can be used by npx to create a new workspace" }, "e2e-project": { "factory": "./src/generators/e2e-project/e2e", @@ -55,7 +55,7 @@ "create-package": { "factory": "./src/generators/create-package/create-package#createPackageSchematic", "schema": "./src/generators/create-package/schema.json", - "description": "Create a framework package that uses Nx CLI" + "description": "Create a package which can be used by npx to create a new workspace" }, "e2e-project": { "factory": "./src/generators/e2e-project/e2e#e2eProjectSchematic", diff --git a/packages/nx-plugin/src/executors/e2e/e2e.impl.ts b/packages/nx-plugin/src/executors/e2e/e2e.impl.ts index 9d0f5bae29060..d3f2c82eb699f 100644 --- a/packages/nx-plugin/src/executors/e2e/e2e.impl.ts +++ b/packages/nx-plugin/src/executors/e2e/e2e.impl.ts @@ -59,7 +59,7 @@ async function runTests( context: ExecutorContext ): Promise { const { success } = await jestExecutor( - { ...jestOptions, watch: false, runInBand: true }, + { runInBand: true, ...jestOptions, watch: false }, context ); diff --git a/packages/nx-plugin/src/generators/create-package/create-package.spec.ts b/packages/nx-plugin/src/generators/create-package/create-package.spec.ts index ca8cdb5ecb619..5e51ddda15ed1 100644 --- a/packages/nx-plugin/src/generators/create-package/create-package.spec.ts +++ b/packages/nx-plugin/src/generators/create-package/create-package.spec.ts @@ -56,6 +56,7 @@ describe('NxPlugin Create Package Generator', () => { assets: [], buildableProjectDepsInPackageJsonType: 'dependencies', }, + dependsOn: ['^build'], }); }); diff --git a/packages/nx-plugin/src/generators/create-package/create-package.ts b/packages/nx-plugin/src/generators/create-package/create-package.ts index 298e06df69acf..16023e4f245b0 100644 --- a/packages/nx-plugin/src/generators/create-package/create-package.ts +++ b/packages/nx-plugin/src/generators/create-package/create-package.ts @@ -7,6 +7,9 @@ import { convertNxGenerator, formatFiles, updateProjectConfiguration, + updateJson, + GeneratorCallback, + runTasksInSerial, } from '@nrwl/devkit'; import { libraryGenerator as jsLibraryGenerator } from '@nrwl/js'; import { join } from 'path'; @@ -14,11 +17,14 @@ import { nxVersion } from '../../utils/versions'; import generatorGenerator from '../generator/generator'; import { CreatePackageSchema } from './schema'; import { NormalizedSchema, normalizeSchema } from './utils/normalize-schema'; +import e2eProjectGenerator from '../e2e-project/e2e'; export async function createPackageGenerator( host: Tree, schema: CreatePackageSchema ) { + const tasks: GeneratorCallback[] = []; + const options = normalizeSchema(host, schema); const pluginPackageName = await addPresetGenerator(host, { ...options, @@ -27,20 +33,23 @@ export async function createPackageGenerator( const installTask = addDependenciesToPackageJson( host, - {}, { 'create-nx-workspace': nxVersion, - } + }, + {} ); + tasks.push(installTask); await createCliPackage(host, options, pluginPackageName); - addTestsToE2eProject(host, options, pluginPackageName); + if (options.e2eTestRunner !== 'none') { + tasks.push(await addE2eProject(host, options, pluginPackageName)); + } if (!options.skipFormat) { await formatFiles(host); } - return installTask; + return runTasksInSerial(...tasks); } /** @@ -74,24 +83,24 @@ async function createCliPackage( ...options, rootProject: false, config: 'project', - buildable: true, publishable: true, bundler: options.bundler, importPath: options.importPath, + skipTsConfig: true, }); host.delete(join(options.projectRoot, 'src')); // Add the bin entry to the package.json - const packageJsonPath = join(options.projectRoot, 'package.json'); - const packageJson = readJson(host, packageJsonPath); - packageJson.bin = { - [options.name]: './bin/index.js', - }; - packageJson.dependencies = { - 'create-nx-workspace': nxVersion, - }; - host.write(packageJsonPath, JSON.stringify(packageJson)); + updateJson(host, join(options.projectRoot, 'package.json'), (packageJson) => { + packageJson.bin = { + [options.name]: './bin/index.js', + }; + packageJson.dependencies = { + 'create-nx-workspace': nxVersion, + }; + return packageJson; + }); // update project build target to use the bin entry const projectConfiguration = readProjectConfiguration( @@ -105,13 +114,19 @@ async function createCliPackage( ); projectConfiguration.targets.build.options.buildableProjectDepsInPackageJsonType = 'dependencies'; + projectConfiguration.targets.build.dependsOn = ['^build']; + projectConfiguration.implicitDependencies = [options.project]; updateProjectConfiguration(host, options.projectName, projectConfiguration); // Add bin files to tsconfg.lib.json - const tsConfigPath = join(options.projectRoot, 'tsconfig.lib.json'); - const tsConfig = readJson(host, tsConfigPath); - tsConfig.include.push('bin/**/*.ts'); - host.write(tsConfigPath, JSON.stringify(tsConfig)); + updateJson( + host, + join(options.projectRoot, 'tsconfig.lib.json'), + (tsConfig) => { + tsConfig.include.push('bin/**/*.ts'); + return tsConfig; + } + ); generateFiles( host, @@ -125,21 +140,13 @@ async function createCliPackage( ); } -function getE2eProjectConfiguration(host: Tree, e2eProjectName: string) { - try { - return readProjectConfiguration(host, e2eProjectName); - } catch (e) { - return; - } -} - /** * Add a test file to plugin e2e project * @param host * @param options * @returns */ -function addTestsToE2eProject( +async function addE2eProject( host: Tree, options: NormalizedSchema, pluginPackageName: string @@ -158,12 +165,30 @@ function addTestsToE2eProject( const cliOutputPath = cliProjectConfiguration.targets.build.options.outputPath; - const e2eProjectConfiguration = - getE2eProjectConfiguration(host, 'e2e') ?? - getE2eProjectConfiguration(host, `${options.project}-e2e`); - if (!e2eProjectConfiguration) { - return; // e2e project does not exist, do not add tests - } + const e2eTask = await e2eProjectGenerator(host, { + pluginName: options.projectName, + projectDirectory: options.projectDirectory, + pluginOutputPath, + npmPackageName: options.name, + minimal: false, + skipFormat: true, + rootProject: false, + }); + + const e2eProjectConfiguration = readProjectConfiguration( + host, + `${options.projectName}-e2e` + ); + e2eProjectConfiguration.targets.e2e.dependsOn = ['^build']; + updateProjectConfiguration( + host, + e2eProjectConfiguration.name, + e2eProjectConfiguration + ); + + // delete the default e2e test file + host.delete(e2eProjectConfiguration.sourceRoot); + generateFiles( host, join(__dirname, './files/e2e'), @@ -176,6 +201,8 @@ function addTestsToE2eProject( tmpl: '', } ); + + return e2eTask; } export default createPackageGenerator; diff --git a/packages/nx-plugin/src/generators/create-package/files/create-framework-package/bin/index.ts__tmpl__ b/packages/nx-plugin/src/generators/create-package/files/create-framework-package/bin/index.ts__tmpl__ index 06b25a34bf3a0..6d03412ec1bc6 100644 --- a/packages/nx-plugin/src/generators/create-package/files/create-framework-package/bin/index.ts__tmpl__ +++ b/packages/nx-plugin/src/generators/create-package/files/create-framework-package/bin/index.ts__tmpl__ @@ -4,11 +4,18 @@ import { createWorkspace } from 'create-nx-workspace'; async function main() { const name = process.argv[2]; // TODO: use libraries like yargs or enquirer to set your workspace name + if (!name) { + throw new Error('Please provide a name for the workspace'); + } + // TODO: update below to customize the workspace await createWorkspace('<%= preset %>', { name, nxCloud: false, packageManager: 'npm', + // This assumes "<%= preset %>" and "<%= projectName %>" are at the same version + // eslint-disable-next-line @typescript-eslint/no-var-requires + presetVersion: require('../package.json').version, }); console.log(`Successfully created the workspace: ${name}.`); diff --git a/packages/nx-plugin/src/generators/create-package/files/e2e/__name__.spec.ts__tmpl__ b/packages/nx-plugin/src/generators/create-package/files/e2e/__name__.spec.ts__tmpl__ index e73b45d135b4a..fe6751532999b 100644 --- a/packages/nx-plugin/src/generators/create-package/files/e2e/__name__.spec.ts__tmpl__ +++ b/packages/nx-plugin/src/generators/create-package/files/e2e/__name__.spec.ts__tmpl__ @@ -1,36 +1,29 @@ import { - ensureNxProject, uniq, runCreatePackageCli, - runNxCommandAsync + removeTmpProject, } from '@nrwl/nx-plugin/testing'; describe('<%= name %> e2e', () => { - // Setting up individual workspaces per - // test can cause e2e runs to take a long time. - // For this reason, we recommend each suite only - // consumes 1 workspace. The tests should each operate - // on a unique project in the workspace, such that they - // are not dependant on one another. - beforeAll(() => { - ensureNxProject('<%= pluginPackageName %>', '<%= pluginOutputPath %>'); - }); + const project = uniq('<%= name %>'); + let createPackageResult; - afterAll(() => { - // `nx reset` kills the daemon, and performs - // some work which can help clean up e2e leftovers - runNxCommandAsync('reset'); - }); - - it('should run <%= name %>', () => { - const project = uniq('<%= name %>'); - const result = runCreatePackageCli( + beforeAll(async () => { + // Create project using CLI command + createPackageResult = await runCreatePackageCli( '<%= pluginPackageName %>', '<%= pluginOutputPath %>', - '<%= name %>', '<%= cliOutputPath %>', project ); - expect(result).toContain('Successfully created'); - }, 120000); + }, 240_000); + + afterAll(() => { + // Remove the generated project from the file system + removeTmpProject(project); + }); + + it('should create project using <%= name %>', () => { + expect(createPackageResult).toContain('Successfully created'); + }); }); diff --git a/packages/nx-plugin/src/generators/create-package/schema.d.ts b/packages/nx-plugin/src/generators/create-package/schema.d.ts index b1c97caf33079..10cfc1e904186 100644 --- a/packages/nx-plugin/src/generators/create-package/schema.d.ts +++ b/packages/nx-plugin/src/generators/create-package/schema.d.ts @@ -1,3 +1,5 @@ +import type { Linter } from '@nrwl/linter'; + export interface CreatePackageSchema { name: string; project: string; @@ -12,5 +14,7 @@ export interface CreatePackageSchema { setParserOptionsProject?: boolean; compiler: 'swc' | 'tsc'; importPath?: string; - rootProject?: boolean; + + // options to create e2e project, passed to e2e project generator + e2eTestRunner?: 'jest' | 'none'; } diff --git a/packages/nx-plugin/src/generators/create-package/schema.json b/packages/nx-plugin/src/generators/create-package/schema.json index 1ee36f38b6d69..682ea3459c436 100644 --- a/packages/nx-plugin/src/generators/create-package/schema.json +++ b/packages/nx-plugin/src/generators/create-package/schema.json @@ -72,6 +72,12 @@ "importPath": { "type": "string", "description": "How the plugin will be published, like `create-framework-app`. Note this must be a valid NPM name. Will use name if not provided." + }, + "e2eTestRunner": { + "type": "string", + "enum": ["jest", "none"], + "description": "Test runner to use for end to end (E2E) tests.", + "default": "jest" } }, "required": ["name", "project"] diff --git a/packages/nx-plugin/src/generators/plugin/plugin.ts b/packages/nx-plugin/src/generators/plugin/plugin.ts index 5c566e67bc97a..318f9835acc75 100644 --- a/packages/nx-plugin/src/generators/plugin/plugin.ts +++ b/packages/nx-plugin/src/generators/plugin/plugin.ts @@ -81,7 +81,6 @@ export async function pluginGenerator(host: Tree, schema: Schema) { ...schema, config: 'project', bundler: options.bundler, - buildable: true, publishable: true, importPath: options.npmPackageName, skipFormat: true, diff --git a/packages/nx-plugin/src/generators/preset/generator.ts b/packages/nx-plugin/src/generators/preset/generator.ts index d4a99112b543d..db52f95d30e77 100644 --- a/packages/nx-plugin/src/generators/preset/generator.ts +++ b/packages/nx-plugin/src/generators/preset/generator.ts @@ -5,6 +5,7 @@ import { readNxJson, formatFiles, runTasksInSerial, + GeneratorCallback, } from '@nx/devkit'; import { Linter } from '@nx/linter'; import { PackageJson } from 'nx/src/utils/package-json'; @@ -13,6 +14,7 @@ import { PresetGeneratorSchema } from './schema'; import createPackageGenerator from '../create-package/create-package'; export default async function (tree: Tree, options: PresetGeneratorSchema) { + const tasks: GeneratorCallback[] = []; const pluginTask = await pluginGenerator(tree, { compiler: 'tsc', linter: Linter.EsLint, @@ -27,25 +29,28 @@ export default async function (tree: Tree, options: PresetGeneratorSchema) { rootProject: true, e2eTestRunner: 'jest', }); + tasks.push(pluginTask); removeNpmScope(tree); moveNxPluginToDevDeps(tree); - const cliTask = await createPackageGenerator(tree, { - name: options.cliName ?? `create-${options.pluginName}-package`, - project: options.pluginName, - skipFormat: true, - skipTsConfig: false, - unitTestRunner: 'jest', - linter: Linter.EsLint, - setParserOptionsProject: false, - compiler: 'tsc', - rootProject: true, - }); + if (options.createPackageName) { + const cliTask = await createPackageGenerator(tree, { + name: options.createPackageName, + project: options.pluginName, + skipFormat: true, + skipTsConfig: false, + unitTestRunner: 'jest', + linter: Linter.EsLint, + setParserOptionsProject: false, + compiler: 'tsc', + }); + tasks.push(cliTask); + } await formatFiles(tree); - return runTasksInSerial(pluginTask, cliTask); + return runTasksInSerial(...tasks); } function removeNpmScope(tree: Tree) { diff --git a/packages/nx-plugin/src/generators/preset/schema.d.ts b/packages/nx-plugin/src/generators/preset/schema.d.ts index 897d0b7e10c5a..b7ed9dfbb5367 100644 --- a/packages/nx-plugin/src/generators/preset/schema.d.ts +++ b/packages/nx-plugin/src/generators/preset/schema.d.ts @@ -1,4 +1,4 @@ export interface PresetGeneratorSchema { pluginName: string; - cliName?: string; + createPackageName?: string; } diff --git a/packages/nx-plugin/src/generators/preset/schema.json b/packages/nx-plugin/src/generators/preset/schema.json index edb0cdf69a84b..b59a3f317c6e7 100644 --- a/packages/nx-plugin/src/generators/preset/schema.json +++ b/packages/nx-plugin/src/generators/preset/schema.json @@ -11,10 +11,9 @@ "description": "Plugin name", "aliases": ["name"] }, - "cliName": { + "createPackageName": { "type": "string", - "description": "Name of cli command to create workspace with plugin", - "aliases": ["name"] + "description": "Name of package which creates a workspace" } }, "required": ["pluginName"] diff --git a/packages/nx-plugin/src/utils/testing-utils/async-commands.ts b/packages/nx-plugin/src/utils/testing-utils/async-commands.ts index 08785b3240fdd..718b061df54ec 100644 --- a/packages/nx-plugin/src/utils/testing-utils/async-commands.ts +++ b/packages/nx-plugin/src/utils/testing-utils/async-commands.ts @@ -13,14 +13,13 @@ export function runCommandAsync( command: string, opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv; cwd?: string } = { silenceError: false, - cwd: tmpProjPath(), } ): Promise<{ stdout: string; stderr: string }> { return new Promise((resolve, reject) => { exec( command, { - cwd: opts.cwd, + cwd: opts.cwd ?? tmpProjPath(), env: { ...process.env, ...opts.env }, }, (err, stdout, stderr) => { @@ -42,7 +41,6 @@ export function runNxCommandAsync( command: string, opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv; cwd?: string } = { silenceError: false, - cwd: tmpProjPath(), } ): Promise<{ stdout: string; stderr: string }> { if (fileExists(tmpProjPath('package.json'))) { diff --git a/packages/nx-plugin/src/utils/testing-utils/commands.ts b/packages/nx-plugin/src/utils/testing-utils/commands.ts index 7fc27d1ad9e43..1cbbee3b9755a 100644 --- a/packages/nx-plugin/src/utils/testing-utils/commands.ts +++ b/packages/nx-plugin/src/utils/testing-utils/commands.ts @@ -14,7 +14,6 @@ export function runNxCommand( command?: string, opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv; cwd?: string } = { silenceError: false, - cwd: tmpProjPath(), } ): string { function _runNxCommand(c) { @@ -51,11 +50,11 @@ export function runNxCommand( export function runCommand( command: string, - opts: { env?: NodeJS.ProcessEnv; cwd?: string } = { cwd: tmpProjPath() } + opts: { env?: NodeJS.ProcessEnv; cwd?: string } ): string { try { return execSync(command, { - cwd: opts.cwd, + cwd: opts.cwd ?? tmpProjPath(), stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env, ...opts?.env }, }).toString(); diff --git a/packages/nx-plugin/src/utils/testing-utils/create-package-cli.ts b/packages/nx-plugin/src/utils/testing-utils/create-package-cli.ts index fc4c660e9586f..4efff9a20b0b1 100644 --- a/packages/nx-plugin/src/utils/testing-utils/create-package-cli.ts +++ b/packages/nx-plugin/src/utils/testing-utils/create-package-cli.ts @@ -1,6 +1,6 @@ -import { workspaceRoot } from '@nrwl/devkit'; -import { runCommand, runNxCommand } from './commands'; -import { tmpProjPath } from './paths'; +import { names, workspaceRoot } from '@nrwl/devkit'; +import { tmpFolder } from './paths'; +import { fork } from 'child_process'; /** * This function is used to run the create package CLI command. @@ -8,7 +8,6 @@ import { tmpProjPath } from './paths'; * It needs to be ran inside an Nx project. It would assume that an Nx project already exists. * @param pluginLibraryName e.g. my-plugin * @param pluginLibraryBuildPath e.g. dist/packages/my-plugin - * @param createPackageLibraryName e.g. create-my-plugin-package * @param createPackageLibraryBuildPath e.g. dist/packages/create-my-plugin-package * @param projectToBeCreated project name to be created using the cli * @returns results for the create package command @@ -16,24 +15,50 @@ import { tmpProjPath } from './paths'; export function runCreatePackageCli( pluginLibraryName: string, pluginLibraryBuildPath: string, - createPackageLibraryName: string, createPackageLibraryBuildPath: string, projectToBeCreated: string -) { - runNxCommand(`build ${createPackageLibraryName}`, { - cwd: process.cwd(), +): Promise { + return new Promise((resolve, reject) => { + const childProcess = fork( + `${workspaceRoot}/${createPackageLibraryBuildPath}/bin/index.js`, + [projectToBeCreated, '--verbose'], + { + stdio: ['pipe', 'pipe', 'pipe', 'ipc'], + env: { + ...process.env, + [`NX_E2E_${ + names(pluginLibraryName).constantName + }_VERSION`]: `file:${workspaceRoot}/${pluginLibraryBuildPath}`, + NX_VERBOSE_LOGGING: 'true', + }, + cwd: tmpFolder(), + } + ); + + // Ensure the child process is killed when the parent exits + process.on('exit', () => childProcess.kill()); + process.on('SIGTERM', () => childProcess.kill()); + + let allMessages = ''; + childProcess.on('message', (message) => { + allMessages += message; + }); + childProcess.stdout.on('data', (data) => { + allMessages += data; + }); + childProcess.on('error', (error) => { + reject(error); + }); + childProcess.on('exit', (code) => { + if (code === 0) { + resolve(allMessages); + } else { + reject(allMessages); + } + }); }); - return runCommand( - `node ${workspaceRoot}/${createPackageLibraryBuildPath}/bin/index.js ${projectToBeCreated} --verbose`, - { - env: { - [pluginLibraryName]: `file:${workspaceRoot}/${pluginLibraryBuildPath}`, - }, - cwd: tmpProjPath(), - } - ); } export function generatedPackagePath(projectToBeCreated: string) { - return `${tmpProjPath}/${projectToBeCreated}`; + return `${tmpFolder()}/${projectToBeCreated}`; } diff --git a/packages/nx-plugin/src/utils/testing-utils/nx-project.ts b/packages/nx-plugin/src/utils/testing-utils/nx-project.ts index 06a252f06e9ae..9e58900297788 100644 --- a/packages/nx-plugin/src/utils/testing-utils/nx-project.ts +++ b/packages/nx-plugin/src/utils/testing-utils/nx-project.ts @@ -69,9 +69,7 @@ export function newNxProject( pluginDistPath: string ): void { cleanup(); - if (!directoryExists(tmpProjPath())) { - runNxNewCommand('', true); - } + runNxNewCommand('', true); patchPackageJsonForPlugin(npmPackageName, pluginDistPath); runPackageManagerInstall(); } diff --git a/packages/nx-plugin/src/utils/testing-utils/paths.ts b/packages/nx-plugin/src/utils/testing-utils/paths.ts index a743052272173..8defb9e6e0b3e 100644 --- a/packages/nx-plugin/src/utils/testing-utils/paths.ts +++ b/packages/nx-plugin/src/utils/testing-utils/paths.ts @@ -1,3 +1,7 @@ +export function tmpFolder() { + return `${process.cwd()}/tmp`; +} + /** * The directory where the e2e workspace resides in. * @@ -6,8 +10,8 @@ */ export function tmpProjPath(path?: string) { return path - ? `${process.cwd()}/tmp/nx-e2e/proj/${path}` - : `${process.cwd()}/tmp/nx-e2e/proj`; + ? `${tmpFolder()}/nx-e2e/proj/${path}` + : `${tmpFolder()}/nx-e2e/proj`; } /** diff --git a/packages/nx-plugin/src/utils/testing-utils/utils.ts b/packages/nx-plugin/src/utils/testing-utils/utils.ts index efb9502082085..33e1c1a341d5a 100644 --- a/packages/nx-plugin/src/utils/testing-utils/utils.ts +++ b/packages/nx-plugin/src/utils/testing-utils/utils.ts @@ -9,7 +9,7 @@ import { writeFileSync, } from 'fs-extra'; import { dirname, isAbsolute } from 'path'; -import { tmpProjPath } from './paths'; +import { tmpFolder, tmpProjPath } from './paths'; import { parseJson } from '@nx/devkit'; import type { JsonParseOptions } from '@nx/devkit'; import { directoryExists, fileExists } from 'nx/src/utils/fileutils'; @@ -125,9 +125,7 @@ export function readFile(path: string): string { * Deletes the e2e directory */ export function cleanup(): void { - try { - removeSync(tmpProjPath()); - } catch (e) {} + removeSync(tmpProjPath()); } /** @@ -137,6 +135,10 @@ export function rmDist(): void { removeSync(`${tmpProjPath()}/dist`); } +export function removeTmpProject(project: string): void { + removeSync(`${tmpFolder()}/${project}`); +} + /** * Get the currend `cwd` in the process */ diff --git a/packages/workspace/src/generators/new/generate-preset.ts b/packages/workspace/src/generators/new/generate-preset.ts index a52f2a9dc5b46..6ea3b6752260a 100644 --- a/packages/workspace/src/generators/new/generate-preset.ts +++ b/packages/workspace/src/generators/new/generate-preset.ts @@ -2,6 +2,7 @@ import { addDependenciesToPackageJson, getPackageManagerCommand, Tree, + names, } from '@nx/devkit'; import { Preset } from '../utils/presets'; import { @@ -150,7 +151,9 @@ function getPresetDependencies({ default: { presetVersion = - presetVersion ?? getNpmPackageVersion(preset) ?? process.env?.[preset]; // read from env variable for e2e testing + process.env?.[`NX_E2E_${names(preset).constantName}_VERSION`] ?? // read from env variable for e2e testing + presetVersion ?? + getNpmPackageVersion(preset); return { dev: {}, dependencies: { diff --git a/packages/workspace/src/generators/new/new.ts b/packages/workspace/src/generators/new/new.ts index bb9e7b1397826..006245e161e52 100644 --- a/packages/workspace/src/generators/new/new.ts +++ b/packages/workspace/src/generators/new/new.ts @@ -30,6 +30,7 @@ interface Schema { standaloneApi?: boolean; routing?: boolean; packageManager?: PackageManager; + presetVersion?: string; } export interface NormalizedSchema extends Schema { From 8cd1dc4303651a8cc4932158d7166b2f329ed8b1 Mon Sep 17 00:00:00 2001 From: Emily Xiong Date: Mon, 17 Apr 2023 11:44:21 -0400 Subject: [PATCH 3/3] feat(misc): update pr with comments --- .../packages/nx-plugin/executors/e2e.json | 3 +- .../nx-plugin/generators/create-package.json | 15 ---- .../nx-plugin/generators/executor.json | 6 ++ .../src/create-nx-plugin.test.ts | 19 ++++- .../create-nx-plugin/bin/create-nx-plugin.ts | 15 +--- packages/nx-plugin/index.ts | 0 .../nx-plugin/src/executors/e2e/e2e.impl.ts | 2 +- .../nx-plugin/src/executors/e2e/schema.json | 3 +- .../create-package/create-package.spec.ts | 71 ++++++++---------- .../create-package/create-package.ts | 74 +++++++++---------- .../bin/index.ts__tmpl__ | 6 +- .../files/e2e/__name__.spec.ts__tmpl__ | 11 +-- .../src/generators/create-package/schema.d.ts | 5 +- .../src/generators/create-package/schema.json | 15 ---- .../create-package/utils/normalize-schema.ts | 4 +- .../tests/__pluginName__.spec.ts__tmpl__ | 2 +- .../src/generators/executor/executor.ts | 5 ++ .../src/generators/executor/schema.d.ts | 1 + .../src/generators/executor/schema.json | 6 ++ .../src/generators/generator/generator.ts | 2 - .../src/generators/plugin/plugin.spec.ts | 7 +- .../nx-plugin/src/generators/plugin/plugin.ts | 2 +- .../src/generators/plugin/schema.d.ts | 6 +- .../src/generators/preset/generator.ts | 4 - .../utils/testing-utils/create-package-cli.ts | 32 +++++--- .../src/utils/testing-utils/nx-project.ts | 2 +- .../src/utils/testing-utils/paths.ts | 8 +- .../src/generators/new/generate-preset.ts | 9 +-- packages/workspace/src/generators/new/new.ts | 1 - 29 files changed, 161 insertions(+), 175 deletions(-) create mode 100644 packages/nx-plugin/index.ts diff --git a/docs/generated/packages/nx-plugin/executors/e2e.json b/docs/generated/packages/nx-plugin/executors/e2e.json index 4edf67f6d562d..8924234821712 100644 --- a/docs/generated/packages/nx-plugin/executors/e2e.json +++ b/docs/generated/packages/nx-plugin/executors/e2e.json @@ -117,7 +117,8 @@ "runInBand": { "alias": "i", "description": "Run all tests serially in the current process (rather than creating a worker pool of child processes that run tests). This is sometimes useful for debugging, but such use cases are pretty rare. Useful for CI. (https://jestjs.io/docs/cli#--runinband)", - "type": "boolean" + "type": "boolean", + "default": true }, "showConfig": { "description": "Print your Jest config and then exits. (https://jestjs.io/docs/en/cli#--showconfig)", diff --git a/docs/generated/packages/nx-plugin/generators/create-package.json b/docs/generated/packages/nx-plugin/generators/create-package.json index 720abcaa8a2bf..bd20a069a297a 100644 --- a/docs/generated/packages/nx-plugin/generators/create-package.json +++ b/docs/generated/packages/nx-plugin/generators/create-package.json @@ -50,27 +50,12 @@ "default": false, "x-priority": "internal" }, - "skipTsConfig": { - "type": "boolean", - "default": false, - "description": "Do not update tsconfig.json for development experience.", - "x-priority": "internal" - }, - "setParserOptionsProject": { - "type": "boolean", - "description": "Whether or not to configure the ESLint `parserOptions.project` option. We do not do this by default for lint performance reasons.", - "default": false - }, "compiler": { "type": "string", "enum": ["tsc", "swc"], "default": "tsc", "description": "The compiler used by the build and test targets." }, - "importPath": { - "type": "string", - "description": "How the plugin will be published, like `create-framework-app`. Note this must be a valid NPM name. Will use name if not provided." - }, "e2eTestRunner": { "type": "string", "enum": ["jest", "none"], diff --git a/docs/generated/packages/nx-plugin/generators/executor.json b/docs/generated/packages/nx-plugin/generators/executor.json index bf88b95a5ab94..65b68e9538d00 100644 --- a/docs/generated/packages/nx-plugin/generators/executor.json +++ b/docs/generated/packages/nx-plugin/generators/executor.json @@ -49,6 +49,12 @@ "type": "boolean", "default": false, "description": "Do not add an eslint configuration for plugin json files." + }, + "skipFormat": { + "type": "boolean", + "description": "Skip formatting files.", + "default": false, + "x-priority": "internal" } }, "required": ["project", "name"], diff --git a/e2e/workspace-create/src/create-nx-plugin.test.ts b/e2e/workspace-create/src/create-nx-plugin.test.ts index ab825957c285e..e3758b65c155d 100644 --- a/e2e/workspace-create/src/create-nx-plugin.test.ts +++ b/e2e/workspace-create/src/create-nx-plugin.test.ts @@ -21,7 +21,7 @@ describe('create-nx-plugin', () => { runCreatePlugin(pluginName, { packageManager, - extraArgs: `--createPackageName=create-${wsName}-package`, + extraArgs: `--createPackageName='false'`, }); checkFilesExist( @@ -46,14 +46,25 @@ describe('create-nx-plugin', () => { checkFilesExist( `dist/package.json`, `dist/generators.json`, - `dist/executors.json`, - `dist/src/index.js` + `dist/executors.json` ); + }); + + it('should be able to create a repo with create workspace cli', () => { + const pluginName = uniq('plugin'); + + runCreatePlugin(pluginName, { + packageManager, + extraArgs: `--createPackageName=create-${pluginName}-package`, + }); + + runCLI(`build ${pluginName}`); + checkFilesExist(`dist/package.json`, `dist/generators.json`); runCLI(`build create-${pluginName}-package`); checkFilesExist(`dist/create-${pluginName}-package/bin/index.js`); expect(() => runCLI(`e2e e2e`)).not.toThrow(); - expect(() => runCLI(`e2e create-${wsName}-package-e2e`)).not.toThrow(); + expect(() => runCLI(`e2e create-${pluginName}-package-e2e`)).not.toThrow(); }); }); diff --git a/packages/create-nx-plugin/bin/create-nx-plugin.ts b/packages/create-nx-plugin/bin/create-nx-plugin.ts index 5dc3121b6c1ae..4638b8ab98c4b 100644 --- a/packages/create-nx-plugin/bin/create-nx-plugin.ts +++ b/packages/create-nx-plugin/bin/create-nx-plugin.ts @@ -47,7 +47,7 @@ async function determinePluginName( parsedArgs: CreateNxPluginArguments ): Promise { if (parsedArgs.pluginName) { - return Promise.resolve(parsedArgs.pluginName); + return parsedArgs.pluginName; } const results = await enquirer.prompt<{ pluginName: string }>([ @@ -55,16 +55,9 @@ async function determinePluginName( name: 'pluginName', message: `Plugin name `, type: 'input', - validate: (s_1) => (s_1.length ? true : 'Name cannot be empty'), + validate: (s_1) => (s_1.length ? true : 'Plugin name cannot be empty'), }, ]); - if (!results.pluginName) { - output.error({ - title: 'Invalid name', - bodyLines: [`Name cannot be empty`], - }); - process.exit(1); - } return results.pluginName; } @@ -72,13 +65,13 @@ async function determineCreatePackageName( parsedArgs: CreateNxPluginArguments ): Promise { if (parsedArgs.createPackageName) { - return Promise.resolve(parsedArgs.createPackageName); + return parsedArgs.createPackageName; } const results = await enquirer.prompt<{ createPackageName: string }>([ { name: 'createPackageName', - message: `Create package name (optional) `, + message: `Create a package which can be used by npx to create a new workspace (Leave blank to not create this package)`, type: 'input', }, ]); diff --git a/packages/nx-plugin/index.ts b/packages/nx-plugin/index.ts new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/nx-plugin/src/executors/e2e/e2e.impl.ts b/packages/nx-plugin/src/executors/e2e/e2e.impl.ts index d3f2c82eb699f..75678f9f00b7c 100644 --- a/packages/nx-plugin/src/executors/e2e/e2e.impl.ts +++ b/packages/nx-plugin/src/executors/e2e/e2e.impl.ts @@ -59,7 +59,7 @@ async function runTests( context: ExecutorContext ): Promise { const { success } = await jestExecutor( - { runInBand: true, ...jestOptions, watch: false }, + { ...jestOptions, watch: false }, context ); diff --git a/packages/nx-plugin/src/executors/e2e/schema.json b/packages/nx-plugin/src/executors/e2e/schema.json index 78581cc6723e9..d830e71d9d1a0 100644 --- a/packages/nx-plugin/src/executors/e2e/schema.json +++ b/packages/nx-plugin/src/executors/e2e/schema.json @@ -128,7 +128,8 @@ "runInBand": { "alias": "i", "description": "Run all tests serially in the current process (rather than creating a worker pool of child processes that run tests). This is sometimes useful for debugging, but such use cases are pretty rare. Useful for CI. (https://jestjs.io/docs/cli#--runinband)", - "type": "boolean" + "type": "boolean", + "default": true }, "showConfig": { "description": "Print your Jest config and then exits. (https://jestjs.io/docs/en/cli#--showconfig)", diff --git a/packages/nx-plugin/src/generators/create-package/create-package.spec.ts b/packages/nx-plugin/src/generators/create-package/create-package.spec.ts index 5e51ddda15ed1..0b8a1f36c6175 100644 --- a/packages/nx-plugin/src/generators/create-package/create-package.spec.ts +++ b/packages/nx-plugin/src/generators/create-package/create-package.spec.ts @@ -3,9 +3,10 @@ import { readJson, readProjectConfiguration, Tree, -} from '@nrwl/devkit'; -import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; -import { Linter } from '@nrwl/linter'; +} from '@nx/devkit'; +import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; +import { Linter } from '@nx/linter'; +import { PackageJson } from 'nx/src/utils/package-json'; import pluginGenerator from '../plugin/plugin'; import { createPackageGenerator } from './create-package'; import { CreatePackageSchema } from './schema'; @@ -13,7 +14,7 @@ import { CreatePackageSchema } from './schema'; const getSchema: ( overrides?: Partial ) => CreatePackageSchema = (overrides = {}) => ({ - name: 'create-package', + name: 'create-a-workspace', project: 'my-plugin', compiler: 'tsc', skipTsConfig: false, @@ -21,7 +22,6 @@ const getSchema: ( skipLintChecks: false, linter: Linter.EsLint, unitTestRunner: 'jest', - minimal: true, ...overrides, }); @@ -43,20 +43,19 @@ describe('NxPlugin Create Package Generator', () => { it('should update the project.json file', async () => { await createPackageGenerator(tree, getSchema()); - const project = readProjectConfiguration(tree, 'create-package'); - expect(project.root).toEqual('libs/create-package'); - expect(project.sourceRoot).toEqual('libs/create-package/bin'); + const project = readProjectConfiguration(tree, 'create-a-workspace'); + expect(project.root).toEqual('libs/create-a-workspace'); + expect(project.sourceRoot).toEqual('libs/create-a-workspace/bin'); expect(project.targets.build).toEqual({ - executor: '@nrwl/js:tsc', + executor: '@nx/js:tsc', outputs: ['{options.outputPath}'], options: { - outputPath: 'dist/libs/create-package', - tsConfig: 'libs/create-package/tsconfig.lib.json', - main: 'libs/create-package/bin/index.ts', - assets: [], - buildableProjectDepsInPackageJsonType: 'dependencies', + outputPath: 'dist/libs/create-a-workspace', + tsConfig: 'libs/create-a-workspace/tsconfig.lib.json', + main: 'libs/create-a-workspace/bin/index.ts', + assets: ['libs/create-a-workspace/*.md'], + updateBuildableProjectDepsInPackageJson: false, }, - dependsOn: ['^build'], }); }); @@ -67,8 +66,11 @@ describe('NxPlugin Create Package Generator', () => { directory: 'plugins', } as Partial) ); - const project = readProjectConfiguration(tree, 'plugins-create-package'); - expect(project.root).toEqual('libs/plugins/create-package'); + const project = readProjectConfiguration( + tree, + 'plugins-create-a-workspace' + ); + expect(project.root).toEqual('libs/plugins/create-a-workspace'); }); it('should specify tsc as compiler', async () => { @@ -79,9 +81,12 @@ describe('NxPlugin Create Package Generator', () => { }) ); - const { build } = readProjectConfiguration(tree, 'create-package').targets; + const { build } = readProjectConfiguration( + tree, + 'create-a-workspace' + ).targets; - expect(build.executor).toEqual('@nrwl/js:tsc'); + expect(build.executor).toEqual('@nx/js:tsc'); }); it('should specify swc as compiler', async () => { @@ -92,35 +97,23 @@ describe('NxPlugin Create Package Generator', () => { }) ); - const { build } = readProjectConfiguration(tree, 'create-package').targets; + const { build } = readProjectConfiguration( + tree, + 'create-a-workspace' + ).targets; - expect(build.executor).toEqual('@nrwl/js:swc'); + expect(build.executor).toEqual('@nx/js:swc'); }); it("should use name as default for the package.json's name", async () => { await createPackageGenerator(tree, getSchema()); - const { root } = readProjectConfiguration(tree, 'create-package'); - const { name } = readJson<{ name: string }>( - tree, - joinPathFragments(root, 'package.json') - ); - - expect(name).toEqual('create-package'); - }); - - it('should use importPath as the package.json name', async () => { - await createPackageGenerator( - tree, - getSchema({ importPath: '@my-company/create-package' }) - ); - - const { root } = readProjectConfiguration(tree, 'create-package'); - const { name } = readJson<{ name: string }>( + const { root } = readProjectConfiguration(tree, 'create-a-workspace'); + const { name } = readJson( tree, joinPathFragments(root, 'package.json') ); - expect(name).toEqual('@my-company/create-package'); + expect(name).toEqual('create-a-workspace'); }); }); diff --git a/packages/nx-plugin/src/generators/create-package/create-package.ts b/packages/nx-plugin/src/generators/create-package/create-package.ts index 16023e4f245b0..0163b4e0c757d 100644 --- a/packages/nx-plugin/src/generators/create-package/create-package.ts +++ b/packages/nx-plugin/src/generators/create-package/create-package.ts @@ -10,14 +10,15 @@ import { updateJson, GeneratorCallback, runTasksInSerial, -} from '@nrwl/devkit'; -import { libraryGenerator as jsLibraryGenerator } from '@nrwl/js'; -import { join } from 'path'; -import { nxVersion } from '../../utils/versions'; + joinPathFragments, +} from '@nx/devkit'; +import { libraryGenerator as jsLibraryGenerator } from '@nx/js'; +import { nxVersion } from 'nx/src/utils/versions'; import generatorGenerator from '../generator/generator'; import { CreatePackageSchema } from './schema'; import { NormalizedSchema, normalizeSchema } from './utils/normalize-schema'; import e2eProjectGenerator from '../e2e-project/e2e'; +import { hasGenerator } from '../../utils/has-generator'; export async function createPackageGenerator( host: Tree, @@ -26,10 +27,7 @@ export async function createPackageGenerator( const tasks: GeneratorCallback[] = []; const options = normalizeSchema(host, schema); - const pluginPackageName = await addPresetGenerator(host, { - ...options, - skipFormat: true, - }); + const pluginPackageName = await addPresetGenerator(host, options); const installTask = addDependenciesToPackageJson( host, @@ -42,7 +40,7 @@ export async function createPackageGenerator( await createCliPackage(host, options, pluginPackageName); if (options.e2eTestRunner !== 'none') { - tasks.push(await addE2eProject(host, options, pluginPackageName)); + tasks.push(await addE2eProject(host, options)); } if (!options.skipFormat) { @@ -63,15 +61,16 @@ async function addPresetGenerator( schema: NormalizedSchema ): Promise { const { root: projectRoot } = readProjectConfiguration(host, schema.project); - if (!host.exists(`${projectRoot}/src/generators/preset`)) { + if (!hasGenerator(host, schema.project, 'preset')) { await generatorGenerator(host, { name: 'preset', project: schema.project, unitTestRunner: schema.unitTestRunner, + skipFormat: true, }); } - return readJson(host, join(projectRoot, 'package.json'))?.name; + return readJson(host, joinPathFragments(projectRoot, 'package.json'))?.name; } async function createCliPackage( @@ -85,43 +84,50 @@ async function createCliPackage( config: 'project', publishable: true, bundler: options.bundler, - importPath: options.importPath, + importPath: options.name, + skipFormat: true, skipTsConfig: true, }); - host.delete(join(options.projectRoot, 'src')); + host.delete(joinPathFragments(options.projectRoot, 'src')); // Add the bin entry to the package.json - updateJson(host, join(options.projectRoot, 'package.json'), (packageJson) => { - packageJson.bin = { - [options.name]: './bin/index.js', - }; - packageJson.dependencies = { - 'create-nx-workspace': nxVersion, - }; - return packageJson; - }); + updateJson( + host, + joinPathFragments(options.projectRoot, 'package.json'), + (packageJson) => { + packageJson.bin = { + [options.name]: './bin/index.js', + }; + packageJson.dependencies = { + 'create-nx-workspace': nxVersion, + }; + return packageJson; + } + ); // update project build target to use the bin entry const projectConfiguration = readProjectConfiguration( host, options.projectName ); - projectConfiguration.sourceRoot = join(options.projectRoot, 'bin'); - projectConfiguration.targets.build.options.main = join( + projectConfiguration.sourceRoot = joinPathFragments( + options.projectRoot, + 'bin' + ); + projectConfiguration.targets.build.options.main = joinPathFragments( options.projectRoot, 'bin/index.ts' ); - projectConfiguration.targets.build.options.buildableProjectDepsInPackageJsonType = - 'dependencies'; - projectConfiguration.targets.build.dependsOn = ['^build']; + projectConfiguration.targets.build.options.updateBuildableProjectDepsInPackageJson = + false; projectConfiguration.implicitDependencies = [options.project]; updateProjectConfiguration(host, options.projectName, projectConfiguration); // Add bin files to tsconfg.lib.json updateJson( host, - join(options.projectRoot, 'tsconfig.lib.json'), + joinPathFragments(options.projectRoot, 'tsconfig.lib.json'), (tsConfig) => { tsConfig.include.push('bin/**/*.ts'); return tsConfig; @@ -130,7 +136,7 @@ async function createCliPackage( generateFiles( host, - join(__dirname, './files/create-framework-package'), + joinPathFragments(__dirname, './files/create-framework-package'), options.projectRoot, { ...options, @@ -146,11 +152,7 @@ async function createCliPackage( * @param options * @returns */ -async function addE2eProject( - host: Tree, - options: NormalizedSchema, - pluginPackageName: string -) { +async function addE2eProject(host: Tree, options: NormalizedSchema) { const pluginProjectConfiguration = readProjectConfiguration( host, options.project @@ -170,7 +172,6 @@ async function addE2eProject( projectDirectory: options.projectDirectory, pluginOutputPath, npmPackageName: options.name, - minimal: false, skipFormat: true, rootProject: false, }); @@ -191,11 +192,10 @@ async function addE2eProject( generateFiles( host, - join(__dirname, './files/e2e'), + joinPathFragments(__dirname, './files/e2e'), e2eProjectConfiguration.sourceRoot, { ...options, - pluginPackageName, pluginOutputPath, cliOutputPath, tmpl: '', diff --git a/packages/nx-plugin/src/generators/create-package/files/create-framework-package/bin/index.ts__tmpl__ b/packages/nx-plugin/src/generators/create-package/files/create-framework-package/bin/index.ts__tmpl__ index 6d03412ec1bc6..e76aec671a10d 100644 --- a/packages/nx-plugin/src/generators/create-package/files/create-framework-package/bin/index.ts__tmpl__ +++ b/packages/nx-plugin/src/generators/create-package/files/create-framework-package/bin/index.ts__tmpl__ @@ -8,8 +8,10 @@ async function main() { throw new Error('Please provide a name for the workspace'); } + console.log(`Creating the workspace: ${name}`); + // TODO: update below to customize the workspace - await createWorkspace('<%= preset %>', { + const { directory } = await createWorkspace('<%= preset %>', { name, nxCloud: false, packageManager: 'npm', @@ -18,7 +20,7 @@ async function main() { presetVersion: require('../package.json').version, }); - console.log(`Successfully created the workspace: ${name}.`); + console.log(`Successfully created the workspace: ${directory}.`); } main(); \ No newline at end of file diff --git a/packages/nx-plugin/src/generators/create-package/files/e2e/__name__.spec.ts__tmpl__ b/packages/nx-plugin/src/generators/create-package/files/e2e/__name__.spec.ts__tmpl__ index fe6751532999b..e0e0f6adda52e 100644 --- a/packages/nx-plugin/src/generators/create-package/files/e2e/__name__.spec.ts__tmpl__ +++ b/packages/nx-plugin/src/generators/create-package/files/e2e/__name__.spec.ts__tmpl__ @@ -2,7 +2,7 @@ import { uniq, runCreatePackageCli, removeTmpProject, -} from '@nrwl/nx-plugin/testing'; +} from '@nx/nx-plugin/testing'; describe('<%= name %> e2e', () => { const project = uniq('<%= name %>'); @@ -11,10 +11,11 @@ describe('<%= name %> e2e', () => { beforeAll(async () => { // Create project using CLI command createPackageResult = await runCreatePackageCli( - '<%= pluginPackageName %>', - '<%= pluginOutputPath %>', - '<%= cliOutputPath %>', - project + project, + { + pluginLibraryBuildPath: '<%= pluginOutputPath %>', + createPackageLibraryBuildPath: '<%= cliOutputPath %>', + } ); }, 240_000); diff --git a/packages/nx-plugin/src/generators/create-package/schema.d.ts b/packages/nx-plugin/src/generators/create-package/schema.d.ts index 10cfc1e904186..6acf4c1f775f9 100644 --- a/packages/nx-plugin/src/generators/create-package/schema.d.ts +++ b/packages/nx-plugin/src/generators/create-package/schema.d.ts @@ -1,4 +1,4 @@ -import type { Linter } from '@nrwl/linter'; +import type { Linter } from '@nx/linter'; export interface CreatePackageSchema { name: string; @@ -6,14 +6,11 @@ export interface CreatePackageSchema { // options to create cli package, passed to js library generator directory?: string; - skipTsConfig: boolean; skipFormat: boolean; tags?: string; unitTestRunner: 'jest' | 'none'; linter: Linter; - setParserOptionsProject?: boolean; compiler: 'swc' | 'tsc'; - importPath?: string; // options to create e2e project, passed to e2e project generator e2eTestRunner?: 'jest' | 'none'; diff --git a/packages/nx-plugin/src/generators/create-package/schema.json b/packages/nx-plugin/src/generators/create-package/schema.json index 682ea3459c436..3892775419354 100644 --- a/packages/nx-plugin/src/generators/create-package/schema.json +++ b/packages/nx-plugin/src/generators/create-package/schema.json @@ -52,27 +52,12 @@ "default": false, "x-priority": "internal" }, - "skipTsConfig": { - "type": "boolean", - "default": false, - "description": "Do not update tsconfig.json for development experience.", - "x-priority": "internal" - }, - "setParserOptionsProject": { - "type": "boolean", - "description": "Whether or not to configure the ESLint `parserOptions.project` option. We do not do this by default for lint performance reasons.", - "default": false - }, "compiler": { "type": "string", "enum": ["tsc", "swc"], "default": "tsc", "description": "The compiler used by the build and test targets." }, - "importPath": { - "type": "string", - "description": "How the plugin will be published, like `create-framework-app`. Note this must be a valid NPM name. Will use name if not provided." - }, "e2eTestRunner": { "type": "string", "enum": ["jest", "none"], diff --git a/packages/nx-plugin/src/generators/create-package/utils/normalize-schema.ts b/packages/nx-plugin/src/generators/create-package/utils/normalize-schema.ts index 67f4febc15024..cb85d7f0f8d10 100644 --- a/packages/nx-plugin/src/generators/create-package/utils/normalize-schema.ts +++ b/packages/nx-plugin/src/generators/create-package/utils/normalize-schema.ts @@ -4,7 +4,7 @@ import { joinPathFragments, names, Tree, -} from '@nrwl/devkit'; +} from '@nx/devkit'; import { CreatePackageSchema } from '../schema'; export interface NormalizedSchema extends CreatePackageSchema { @@ -30,7 +30,6 @@ export function normalizeSchema( : name; const projectName = fullProjectDirectory.replace(new RegExp('/', 'g'), '-'); const projectRoot = joinPathFragments(libsDir, fullProjectDirectory); - const importPath = schema.importPath ?? name; return { ...schema, bundler: schema.compiler ?? 'tsc', @@ -39,6 +38,5 @@ export function normalizeSchema( projectRoot, name, projectDirectory: fullProjectDirectory, - importPath, }; } diff --git a/packages/nx-plugin/src/generators/e2e-project/files/tests/__pluginName__.spec.ts__tmpl__ b/packages/nx-plugin/src/generators/e2e-project/files/tests/__pluginName__.spec.ts__tmpl__ index cd101be787714..8f5570f4e07ff 100644 --- a/packages/nx-plugin/src/generators/e2e-project/files/tests/__pluginName__.spec.ts__tmpl__ +++ b/packages/nx-plugin/src/generators/e2e-project/files/tests/__pluginName__.spec.ts__tmpl__ @@ -32,6 +32,6 @@ describe('<%= pluginName %> e2e', () => { const generator = 'PLACEHOLDER'; await runNxCommandAsync(`generate <%= npmPackageName %>:${generator} --name ${name}`); expect(() => runNxCommand('build ${proj}')).not.toThrow(); - expect(() => checkFilesExist([`dist/${name}/index.js`])).not.toThrow(); + expect(() => checkFilesExist(`dist/${name}/index.js`)).not.toThrow(); }); }); diff --git a/packages/nx-plugin/src/generators/executor/executor.ts b/packages/nx-plugin/src/generators/executor/executor.ts index f24c6ece4b61c..d461931b3ac2a 100644 --- a/packages/nx-plugin/src/generators/executor/executor.ts +++ b/packages/nx-plugin/src/generators/executor/executor.ts @@ -9,6 +9,7 @@ import { writeJson, readJson, ExecutorsJson, + formatFiles, } from '@nx/devkit'; import type { Tree } from '@nx/devkit'; import type { Schema } from './schema'; @@ -176,6 +177,10 @@ export async function executorGenerator(host: Tree, schema: Schema) { } await updateExecutorJson(host, options); + + if (!schema.skipFormat) { + await formatFiles(host); + } } export default executorGenerator; diff --git a/packages/nx-plugin/src/generators/executor/schema.d.ts b/packages/nx-plugin/src/generators/executor/schema.d.ts index 6946c85d5bbba..4e896a3f909f6 100644 --- a/packages/nx-plugin/src/generators/executor/schema.d.ts +++ b/packages/nx-plugin/src/generators/executor/schema.d.ts @@ -5,4 +5,5 @@ export interface Schema { unitTestRunner: 'jest' | 'none'; includeHasher: boolean; skipLintChecks?: boolean; + skipFormat?: boolean; } diff --git a/packages/nx-plugin/src/generators/executor/schema.json b/packages/nx-plugin/src/generators/executor/schema.json index e7d3f1b9467a2..4337938fa6654 100644 --- a/packages/nx-plugin/src/generators/executor/schema.json +++ b/packages/nx-plugin/src/generators/executor/schema.json @@ -51,6 +51,12 @@ "type": "boolean", "default": false, "description": "Do not add an eslint configuration for plugin json files." + }, + "skipFormat": { + "type": "boolean", + "description": "Skip formatting files.", + "default": false, + "x-priority": "internal" } }, "required": ["project", "name"], diff --git a/packages/nx-plugin/src/generators/generator/generator.ts b/packages/nx-plugin/src/generators/generator/generator.ts index a54670b6d1794..23936b80dd9d1 100644 --- a/packages/nx-plugin/src/generators/generator/generator.ts +++ b/packages/nx-plugin/src/generators/generator/generator.ts @@ -4,8 +4,6 @@ import { joinPathFragments, Tree, writeJson, -} from '@nx/devkit'; -import { convertNxGenerator, generateFiles, getWorkspaceLayout, diff --git a/packages/nx-plugin/src/generators/plugin/plugin.spec.ts b/packages/nx-plugin/src/generators/plugin/plugin.spec.ts index 6abb31d39c392..92f9a67866d0a 100644 --- a/packages/nx-plugin/src/generators/plugin/plugin.spec.ts +++ b/packages/nx-plugin/src/generators/plugin/plugin.spec.ts @@ -7,6 +7,7 @@ import { } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Linter } from '@nx/linter'; +import { PackageJson } from 'nx/src/utils/package-json'; import { pluginGenerator } from './plugin'; import { Schema } from './schema'; @@ -161,7 +162,7 @@ describe('NxPlugin Plugin Generator', () => { await pluginGenerator(tree, getSchema()); const { root } = readProjectConfiguration(tree, 'my-plugin'); - const { name } = readJson<{ name: string }>( + const { name } = readJson( tree, joinPathFragments(root, 'package.json') ); @@ -178,7 +179,7 @@ describe('NxPlugin Plugin Generator', () => { await pluginGenerator(tree, getSchema()); const { root } = readProjectConfiguration(tree, 'my-plugin'); - const { name } = readJson<{ name: string }>( + const { name } = readJson( tree, joinPathFragments(root, 'package.json') ); @@ -193,7 +194,7 @@ describe('NxPlugin Plugin Generator', () => { ); const { root } = readProjectConfiguration(tree, 'my-plugin'); - const { name } = readJson<{ name: string }>( + const { name } = readJson( tree, joinPathFragments(root, 'package.json') ); diff --git a/packages/nx-plugin/src/generators/plugin/plugin.ts b/packages/nx-plugin/src/generators/plugin/plugin.ts index 318f9835acc75..765ee97fd0e7a 100644 --- a/packages/nx-plugin/src/generators/plugin/plugin.ts +++ b/packages/nx-plugin/src/generators/plugin/plugin.ts @@ -88,7 +88,7 @@ export async function pluginGenerator(host: Tree, schema: Schema) { ); tasks.push(addTsLibDependencies(host)); - + tasks.push( addDependenciesToPackageJson( host, diff --git a/packages/nx-plugin/src/generators/plugin/schema.d.ts b/packages/nx-plugin/src/generators/plugin/schema.d.ts index 5de5ce4613354..294249c817f5b 100644 --- a/packages/nx-plugin/src/generators/plugin/schema.d.ts +++ b/packages/nx-plugin/src/generators/plugin/schema.d.ts @@ -4,9 +4,9 @@ export interface Schema { name: string; directory?: string; importPath?: string; - skipTsConfig: boolean; - skipFormat: boolean; - skipLintChecks: boolean; + skipTsConfig?: boolean; // default is false + skipFormat?: boolean; // default is false + skipLintChecks?: boolean; // default is false e2eTestRunner?: 'jest' | 'none'; tags?: string; unitTestRunner: 'jest' | 'none'; diff --git a/packages/nx-plugin/src/generators/preset/generator.ts b/packages/nx-plugin/src/generators/preset/generator.ts index db52f95d30e77..533cc9c86cc28 100644 --- a/packages/nx-plugin/src/generators/preset/generator.ts +++ b/packages/nx-plugin/src/generators/preset/generator.ts @@ -22,8 +22,6 @@ export default async function (tree: Tree, options: PresetGeneratorSchema) { ? options.pluginName.split('/')[1] : options.pluginName, skipFormat: true, - skipLintChecks: false, - skipTsConfig: false, unitTestRunner: 'jest', importPath: options.pluginName, rootProject: true, @@ -39,10 +37,8 @@ export default async function (tree: Tree, options: PresetGeneratorSchema) { name: options.createPackageName, project: options.pluginName, skipFormat: true, - skipTsConfig: false, unitTestRunner: 'jest', linter: Linter.EsLint, - setParserOptionsProject: false, compiler: 'tsc', }); tasks.push(cliTask); diff --git a/packages/nx-plugin/src/utils/testing-utils/create-package-cli.ts b/packages/nx-plugin/src/utils/testing-utils/create-package-cli.ts index 4efff9a20b0b1..b983fe590f68b 100644 --- a/packages/nx-plugin/src/utils/testing-utils/create-package-cli.ts +++ b/packages/nx-plugin/src/utils/testing-utils/create-package-cli.ts @@ -1,4 +1,4 @@ -import { names, workspaceRoot } from '@nrwl/devkit'; +import { workspaceRoot } from '@nx/devkit'; import { tmpFolder } from './paths'; import { fork } from 'child_process'; @@ -6,30 +6,38 @@ import { fork } from 'child_process'; * This function is used to run the create package CLI command. * It builds the plugin library and the create package library and run the create package command with for the plugin library. * It needs to be ran inside an Nx project. It would assume that an Nx project already exists. - * @param pluginLibraryName e.g. my-plugin + * @param projectToBeCreated project name to be created using the cli * @param pluginLibraryBuildPath e.g. dist/packages/my-plugin * @param createPackageLibraryBuildPath e.g. dist/packages/create-my-plugin-package - * @param projectToBeCreated project name to be created using the cli + * @param extraArguments extra arguments to be passed to the create package command + * @param verbose if true, NX_VERBOSE_LOGGING will be set to true * @returns results for the create package command */ export function runCreatePackageCli( - pluginLibraryName: string, - pluginLibraryBuildPath: string, - createPackageLibraryBuildPath: string, - projectToBeCreated: string + projectToBeCreated: string, + { + pluginLibraryBuildPath, + createPackageLibraryBuildPath, + extraArguments, + verbose, + }: { + pluginLibraryBuildPath: string; + createPackageLibraryBuildPath: string; + extraArguments?: string[]; + verbose?: boolean; + } ): Promise { return new Promise((resolve, reject) => { const childProcess = fork( `${workspaceRoot}/${createPackageLibraryBuildPath}/bin/index.js`, - [projectToBeCreated, '--verbose'], + [projectToBeCreated, ...(extraArguments || [])], { stdio: ['pipe', 'pipe', 'pipe', 'ipc'], env: { ...process.env, - [`NX_E2E_${ - names(pluginLibraryName).constantName - }_VERSION`]: `file:${workspaceRoot}/${pluginLibraryBuildPath}`, - NX_VERBOSE_LOGGING: 'true', + [`NX_E2E_PRESET_VERSION`]: `file:${workspaceRoot}/${pluginLibraryBuildPath}`, + // only add NX_VERBOSE_LOGGING if verbose is true + ...(verbose && { NX_VERBOSE_LOGGING: 'true' }), }, cwd: tmpFolder(), } diff --git a/packages/nx-plugin/src/utils/testing-utils/nx-project.ts b/packages/nx-plugin/src/utils/testing-utils/nx-project.ts index 9e58900297788..706d7289b8628 100644 --- a/packages/nx-plugin/src/utils/testing-utils/nx-project.ts +++ b/packages/nx-plugin/src/utils/testing-utils/nx-project.ts @@ -8,7 +8,7 @@ import { execSync } from 'child_process'; import { dirname } from 'path'; import { ensureDirSync } from 'fs-extra'; import { tmpProjPath } from './paths'; -import { cleanup, directoryExists } from './utils'; +import { cleanup } from './utils'; function runNxNewCommand(args?: string, silent?: boolean) { const localTmpDir = dirname(tmpProjPath()); diff --git a/packages/nx-plugin/src/utils/testing-utils/paths.ts b/packages/nx-plugin/src/utils/testing-utils/paths.ts index 8defb9e6e0b3e..0cd239f9ac53a 100644 --- a/packages/nx-plugin/src/utils/testing-utils/paths.ts +++ b/packages/nx-plugin/src/utils/testing-utils/paths.ts @@ -1,5 +1,7 @@ +import { workspaceRoot } from '@nx/devkit'; + export function tmpFolder() { - return `${process.cwd()}/tmp`; + return `${workspaceRoot}/tmp`; } /** @@ -22,6 +24,6 @@ export function tmpProjPath(path?: string) { */ export function tmpBackupProjPath(path?: string) { return path - ? `${process.cwd()}/tmp/nx-e2e/proj-backup/${path}` - : `${process.cwd()}/tmp/nx-e2e/proj-backup`; + ? `${workspaceRoot}/tmp/nx-e2e/proj-backup/${path}` + : `${workspaceRoot}/tmp/nx-e2e/proj-backup`; } diff --git a/packages/workspace/src/generators/new/generate-preset.ts b/packages/workspace/src/generators/new/generate-preset.ts index 6ea3b6752260a..83e6670c15ed3 100644 --- a/packages/workspace/src/generators/new/generate-preset.ts +++ b/packages/workspace/src/generators/new/generate-preset.ts @@ -2,7 +2,6 @@ import { addDependenciesToPackageJson, getPackageManagerCommand, Tree, - names, } from '@nx/devkit'; import { Preset } from '../utils/presets'; import { @@ -150,14 +149,12 @@ function getPresetDependencies({ return { dependencies: {}, dev: { '@nx/node': nxVersion } }; default: { - presetVersion = - process.env?.[`NX_E2E_${names(preset).constantName}_VERSION`] ?? // read from env variable for e2e testing - presetVersion ?? - getNpmPackageVersion(preset); return { dev: {}, dependencies: { - [preset]: presetVersion, + [preset]: + process.env['NX_E2E_PRESET_VERSION'] ?? + getNpmPackageVersion(preset, presetVersion), }, }; } diff --git a/packages/workspace/src/generators/new/new.ts b/packages/workspace/src/generators/new/new.ts index 006245e161e52..bb9e7b1397826 100644 --- a/packages/workspace/src/generators/new/new.ts +++ b/packages/workspace/src/generators/new/new.ts @@ -30,7 +30,6 @@ interface Schema { standaloneApi?: boolean; routing?: boolean; packageManager?: PackageManager; - presetVersion?: string; } export interface NormalizedSchema extends Schema {