From dc98485834611f14cc8abb2cce6d851e0e27fc4e Mon Sep 17 00:00:00 2001 From: Dmitriy Stepanenko <33101123+dmitry-stepanenko@users.noreply.github.com> Date: Mon, 17 Apr 2023 22:26:12 +0300 Subject: [PATCH] feat(core): add presetVersion flag for the create-nx-workspace (#16303) Co-authored-by: FrozenPandaz --- .../src/generators/new/generate-preset.ts | 4 +- .../workspace/src/generators/new/new.spec.ts | 65 +++++++++++++++++++ packages/workspace/src/generators/new/new.ts | 39 +++++++---- .../utils/get-npm-package-version.ts | 24 +++++-- 4 files changed, 113 insertions(+), 19 deletions(-) diff --git a/packages/workspace/src/generators/new/generate-preset.ts b/packages/workspace/src/generators/new/generate-preset.ts index e79133e6c5731..2929e49fbcd1d 100644 --- a/packages/workspace/src/generators/new/generate-preset.ts +++ b/packages/workspace/src/generators/new/generate-preset.ts @@ -150,7 +150,9 @@ function getPresetDependencies({ return { dev: {}, dependencies: { - [preset]: presetVersion ?? getNpmPackageVersion(preset), + [preset]: + process.env['NX_E2E_PRESET_VERSION'] ?? + getNpmPackageVersion(preset, presetVersion), }, }; } diff --git a/packages/workspace/src/generators/new/new.spec.ts b/packages/workspace/src/generators/new/new.spec.ts index af8dbb3ca2e37..066d99dd7a44c 100644 --- a/packages/workspace/src/generators/new/new.spec.ts +++ b/packages/workspace/src/generators/new/new.spec.ts @@ -9,6 +9,14 @@ import { import { Preset } from '../utils/presets'; import { newGenerator, NormalizedSchema } from './new'; +const DEFAULT_PACKAGE_VERSION = '1.0.0'; +jest.mock('./../utils/get-npm-package-version', () => ({ + ...jest.requireActual('./../utils/get-npm-package-version'), + getNpmPackageVersion: jest + .fn() + .mockImplementation((name, version) => version ?? DEFAULT_PACKAGE_VERSION), +})); + const defaultOptions: Omit< NormalizedSchema, 'name' | 'directory' | 'appName' | 'isCustomPreset' @@ -94,6 +102,63 @@ describe('new', () => { typescript: typescriptVersion, }); }); + + describe('custom presets', () => { + let originalValue; + beforeEach(() => { + originalValue = process.env['NX_E2E_PRESET_VERSION']; + }); + + afterEach(() => { + if (originalValue) { + process.env['NX_E2E_PRESET_VERSION'] = originalValue; + } else { + delete process.env['NX_E2E_PRESET_VERSION']; + } + }); + // the process of actual resolving of a version relies on npm and is mocked here, + // thus "package@2" is expected to be resolved with version "2" instead of "2.0.0" + const versionAsPath = + '/Users/username/3rd-party-pkg/dist/packages/3rd-party-pkg-1.12.5.tgz'; + test.each` + preset | presetVersion | expectedVersion + ${'3rd-party-package'} | ${undefined} | ${DEFAULT_PACKAGE_VERSION} + ${'3rd-party-package@1.1.2'} | ${undefined} | ${'1.1.2'} + ${'3rd-party-package@2'} | ${undefined} | ${'2'} + ${'3rd-party-package'} | ${'latest'} | ${'latest'} + ${'3rd-party-package'} | ${'1.1.1'} | ${'1.1.1'} + ${'3rd-party-package'} | ${versionAsPath} | ${versionAsPath} + ${'3rd-party-package@2.3.4'} | ${'1.1.1'} | ${'1.1.1'} + `( + 'should add custom preset "$preset" with a correct expectedVersion "$expectedVersion" when presetVersion is "$presetVersion"', + async ({ presetVersion, preset, expectedVersion }) => { + if (presetVersion) { + process.env['NX_E2E_PRESET_VERSION'] = presetVersion; + } + + await newGenerator(tree, { + ...defaultOptions, + name: 'my-workspace', + directory: 'my-workspace', + npmScope: 'npmScope', + appName: 'app', + preset, + }); + + const { devDependencies, dependencies } = readJson( + tree, + 'my-workspace/package.json' + ); + expect(dependencies).toStrictEqual({ + '3rd-party-package': expectedVersion, + }); + expect(devDependencies).toStrictEqual({ + '@nrwl/workspace': nxVersion, + nx: nxVersion, + }); + } + ); + }); }); it('should not modify any existing files', async () => { diff --git a/packages/workspace/src/generators/new/new.ts b/packages/workspace/src/generators/new/new.ts index 79cc3816428e1..2f8218413e86a 100644 --- a/packages/workspace/src/generators/new/new.ts +++ b/packages/workspace/src/generators/new/new.ts @@ -92,23 +92,40 @@ function validateOptions(options: Schema, host: Tree) { } } +function parsePresetName(input: string): { package: string; version?: string } { + // If the preset already contains a version in the name + // -- my-package@2.0.1 + // -- @scope/package@version + const atIndex = input.indexOf('@', 1); // Skip the beginning @ because it denotes a scoped package. + + if (atIndex > 0) { + return { + package: input.slice(0, atIndex), + version: input.slice(atIndex + 1), + }; + } else { + if (!input) { + throw new Error(`Invalid package name: ${input}`); + } + return { package: input }; + } +} + function normalizeOptions(options: Schema): NormalizedSchema { - const normalized: Partial = { ...options }; + const normalized: Partial = { + ...options, + }; + normalized.name = names(options.name).fileName; if (!options.directory) { normalized.directory = options.name; } - // If the preset already contains a version in the name - // -- my-package@2.0.1 - // -- @scope/package@version - const match = options.preset.match( - /^(?(@.+\/)?[^@]+)(@(?\d+\.\d+\.\d+))?$/ - ); - if (match) { - normalized.preset = match.groups.package; - normalized.presetVersion = match.groups.version; - } + const parsed = parsePresetName(options.preset); + + normalized.preset = parsed.package; + // explicitly specified "presetVersion" takes priority over the one from the package name + normalized.presetVersion ??= parsed.version; normalized.isCustomPreset = !Object.values(Preset).includes( options.preset as any diff --git a/packages/workspace/src/generators/utils/get-npm-package-version.ts b/packages/workspace/src/generators/utils/get-npm-package-version.ts index f98174cb3330b..1cf17d87a871a 100644 --- a/packages/workspace/src/generators/utils/get-npm-package-version.ts +++ b/packages/workspace/src/generators/utils/get-npm-package-version.ts @@ -1,16 +1,26 @@ -export function getNpmPackageVersion(packageName: string): string | null { +export function getNpmPackageVersion( + packageName: string, + packageVersion?: string +): string | null { try { const version = require('child_process').execSync( - `npm view ${packageName} version`, + `npm view ${packageName}${ + packageVersion ? '@' + packageVersion : '' + } version --json`, { stdio: ['pipe', 'pipe', 'ignore'] } ); if (version) { - return version - .toString() - .trim() - .replace(/^\n*|\n*$/g, ''); + // package@1.12 => ["1.12.0", "1.12.1"] + // package@1.12.1 => "1.12.1" + // package@latest => "1.12.1" + const versionOrArray = JSON.parse(version.toString()); + + if (typeof versionOrArray === 'string') { + return versionOrArray; + } + return versionOrArray.pop(); } } catch (err) {} - return null; + return packageVersion ?? null; }