diff --git a/e2e-examples/cli-e2e-env/setup/global-setup.ts b/e2e-examples/cli-e2e-env/setup/global-setup.ts index 53704a07..3b13a26d 100644 --- a/e2e-examples/cli-e2e-env/setup/global-setup.ts +++ b/e2e-examples/cli-e2e-env/setup/global-setup.ts @@ -1,5 +1,5 @@ import { executeProcess, objectToCliArgs } from '@org/test-utils'; -import { NpmTestEnvResult, VerdaccioExecuterOptions } from '@org/tools-utils'; +import { NpmTestEnvResult } from '@org/tools-utils'; import { join } from 'node:path'; import { rm } from 'node:fs/promises'; import { readJsonFile } from '@nx/devkit'; @@ -21,13 +21,7 @@ export async function setup() { // start registry await executeProcess({ command: 'nx', - args: objectToCliArgs< - Partial< - VerdaccioExecuterOptions & { - _: string[]; - } - > - >({ + args: objectToCliArgs({ _: ['env-setup-npm-env', projectName ?? ''], verbose: isVerbose, clear: true, @@ -37,12 +31,12 @@ export async function setup() { shell: true, }); - const workspaceRoot = join('tmp', 'npm-env', projectName); + const workspaceRoot = join('tmp', 'environments', projectName); activeRegistry = await readJsonFile( join(workspaceRoot, 'verdaccio-registry.json') ); const { registry } = activeRegistry; - stopRegistry = () => process.kill(Number(registry.pid)); + stopRegistry = () => process.kill(Number(registry?.pid)); // package publish all projects await executeProcess({ diff --git a/e2e-examples/cli-e2e-env/tooling/bin/setup-npm-env.ts b/e2e-examples/cli-e2e-env/tooling/bin/setup-npm-env.ts new file mode 100644 index 00000000..b8c37c7c --- /dev/null +++ b/e2e-examples/cli-e2e-env/tooling/bin/setup-npm-env.ts @@ -0,0 +1,47 @@ +import yargs, { Options } from 'yargs'; +import { + setupNpmEnv, + StartVerdaccioAndSetupEnvOptions, +} from '@org/tools-utils'; + +const isVerbose: boolean = + process.env['NX_VERBOSE_LOGGING'] === 'true' ?? false; + +const args = yargs(process.argv.slice(2)) + .version(false) + .options({ + projectName: { + type: 'string', + description: 'Project name', + demandOption: true, + }, + workspaceRoot: { + type: 'string', + description: 'Location of test environment', + }, + verbose: { + type: 'boolean', + description: 'Verbose logging', + default: isVerbose, + }, + targetName: { + type: 'string', + description: 'Verbose logging', + default: isVerbose, + }, + port: { + type: 'number', + }, + } satisfies Partial>) + .parse() as StartVerdaccioAndSetupEnvOptions; + +(async () => { + const workspaceRoot = args.workspaceRoot; + if (workspaceRoot == null) { + throw new Error('Workspace root required.'); + } + await setupNpmEnv({ + ...args, + workspaceRoot, + }); +})(); diff --git a/e2e-examples/cli-e2e-env/tooling/env.plugin.ts b/e2e-examples/cli-e2e-env/tooling/env.plugin.ts index eaf65190..afa87f26 100644 --- a/e2e-examples/cli-e2e-env/tooling/env.plugin.ts +++ b/e2e-examples/cli-e2e-env/tooling/env.plugin.ts @@ -7,7 +7,7 @@ import { dirname, join, relative } from 'node:path'; import type { ProjectConfiguration } from 'nx/src/config/workspace-json-project-json'; import { getBuildOutputPathFromBuildTarget } from '@org/tools-utils'; -const tmpNpmEnv = join('tmp', 'npm-env'); +const tmpEnv = join('tmp', 'environments'); export const createNodes: CreateNodes = [ '**/project.json', @@ -22,15 +22,6 @@ export const createNodes: CreateNodes = [ throw new Error('Project name required'); } - // only execute for the -env example projects e.g. `cli-e2e-env`, `e2e-models-env` - if (!projectName.endsWith('-env')) { - return { - projects: { - [root]: {}, - }, - }; - } - const tags = projectConfiguration?.tags ?? []; const isPublishable = tags.some((target) => target === 'publishable'); const isNpmEnv = tags.some((target) => target === 'npm-env'); @@ -67,11 +58,11 @@ function verdaccioTargets( }, 'env-setup-npm-env': { command: - 'tsx --tsconfig=tools/tsconfig.tools.json tools/tools-utils/src/bin/setup-npm-env.ts', + 'tsx --tsconfig=e2e-examples/cli-e2e-env/tsconfig.tools.json e2e-examples/cli-e2e-env/tooling/bin/setup-npm-env.ts', options: { projectName, targetName: 'env-start-verdaccio', - workspaceRoot: join(tmpNpmEnv, projectName), + workspaceRoot: join(tmpEnv, projectName), location: 'none', }, }, @@ -95,16 +86,16 @@ function npmTargets( 'env-npm-publish': { command: `npm publish --userconfig=${relativeFromPath( outputPath - )}/${tmpNpmEnv}/{args.envProjectName}/.npmrc`, + )}/${tmpEnv}/{args.envProjectName}/.npmrc`, options: { cwd: outputPath, envProjectName: `${projectName}-npm-env`, }, }, 'env-npm-install': { - command: `npm install --no-fund --no-shrinkwrap --save ${packageName}@{args.pkgVersion} --prefix=${tmpNpmEnv}/{args.envProjectName} --userconfig=${relativeFromPath( + command: `npm install --no-fund --no-shrinkwrap --save ${packageName}@{args.pkgVersion} --prefix=${tmpEnv}/{args.envProjectName} --userconfig=${relativeFromPath( outputPath - )}/${tmpNpmEnv}/{args.envProjectName}/.npmrc`, + )}/${tmpEnv}/{args.envProjectName}/.npmrc`, options: { pkgVersion, envProjectName: `${projectName}-npm-env`, diff --git a/e2e-examples/cli-e2e-graph/tooling/graph.plugin.ts b/e2e-examples/cli-e2e-graph/tooling/graph.plugin.ts index fc01ad80..581bc1bb 100644 --- a/e2e-examples/cli-e2e-graph/tooling/graph.plugin.ts +++ b/e2e-examples/cli-e2e-graph/tooling/graph.plugin.ts @@ -22,15 +22,6 @@ export const createNodes: CreateNodes = [ throw new Error('Project name required'); } - // only execute for the -graph example projects e.g. `cli-e2e-graph`, `e2e-models-graph` - if (!projectName.endsWith('-graph')) { - return { - projects: { - [root]: {}, - }, - }; - } - const tags = projectConfiguration?.tags ?? []; const isPublishable = tags.some((target) => target === 'publishable'); const isNpmEnv = tags.some((target) => target === 'npm-env'); @@ -87,6 +78,7 @@ function verdaccioTargets( }, ], command: 'echo Dependencies installed!', + options: {}, }, }; } diff --git a/e2e-examples/cli-e2e-original/setup/global-setup.ts b/e2e-examples/cli-e2e-original/setup/global-setup.ts index 7b380d6e..5f1d2417 100644 --- a/e2e-examples/cli-e2e-original/setup/global-setup.ts +++ b/e2e-examples/cli-e2e-original/setup/global-setup.ts @@ -1,32 +1,27 @@ +import { rm } from 'node:fs/promises'; import { executeProcess, objectToCliArgs } from '@org/test-utils'; import { configureRegistry, + RegistryResult, startVerdaccioServer, unconfigureRegistry, - VercaddioServerResult, } from '@org/tools-utils'; -import { rm } from 'node:fs/promises'; const isVerbose = true; // process.env.NX_VERBOSE_LOGGING === 'true' ?? false; - -let activeRegistry: VercaddioServerResult; -let stopRegistry: () => void; +const projectName = process.env['NX_TASK_TARGET_PROJECT']; export async function setup() { - // start Verdaccio server and setup local registry storage - const { stop, registry } = await startVerdaccioServer({ + if (projectName == null) { + throw new Error('Project name required.'); + } + + const registryResult = await startVerdaccioServer({ targetName: 'original-local-registry', verbose: isVerbose, clear: true, }); - activeRegistry = registry; - stopRegistry = stop; - // configure env with verdaccio registry as default - // exec commands: - // - `npm config set registry "${url}"` - // - `npm config set //${host}:${port}/:_authToken "secretVerdaccioToken"` - configureRegistry(registry, isVerbose); + configureRegistry(registryResult.registry, isVerbose); // package publish all projects await executeProcess({ @@ -52,9 +47,13 @@ export async function setup() { }), verbose: isVerbose, }); + + // @TODO figure out why named exports don't work https://vitest.dev/config/#globalsetup + return () => teardownSetup(registryResult); } -export async function teardown() { +export async function teardownSetup({ registry, stop }: RegistryResult) { + console.info(`Teardown ${projectName}`); // uninstall all projects await executeProcess({ command: 'nx', @@ -64,11 +63,9 @@ export async function teardown() { }), verbose: isVerbose, }); - stopRegistry(); - // exec commands: - // - `npm config delete //${host}:${port}/:_authToken` - // - `npm config delete registry` - unconfigureRegistry(activeRegistry, isVerbose); - await rm(activeRegistry.storage, { recursive: true, force: true }); + + stop(); + unconfigureRegistry(registry, isVerbose); + await rm(registry.storage, { recursive: true, force: true }); await rm('local-registry', { recursive: true, force: true }); } diff --git a/e2e-examples/cli-e2e-original/tooling/original.plugin.ts b/e2e-examples/cli-e2e-original/tooling/original.plugin.ts index 46d301c6..bdcb41f6 100644 --- a/e2e-examples/cli-e2e-original/tooling/original.plugin.ts +++ b/e2e-examples/cli-e2e-original/tooling/original.plugin.ts @@ -24,13 +24,13 @@ export const createNodes: CreateNodes = [ (tag) => tag === 'publishable' ); - return { projects: { [root]: { targets: { ...(isRoot && verdaccioTargets()), - ...(isPublishable && npmTargets({ ...projectConfiguration, root, name: projectName })), + ...(isPublishable && + npmTargets({ ...projectConfiguration, root, name: projectName })), }, }, }, @@ -45,7 +45,7 @@ function verdaccioTargets(): Record { options: { config: '.verdaccio/config.yml', storage: `tmp/local-registry/storage`, - port: 4200 + port: 4200, }, }, }; @@ -68,7 +68,7 @@ function npmTargets( }, }, 'original-npm-install': { - command: `npm install -D ${packageName}@{args.pkgVersion}`, + command: `npm install -D --no-fund --no-package-lock ${packageName}@{args.pkgVersion}`, options: { pkgVersion, }, diff --git a/nx.json b/nx.json index 5e13e2e6..fcf5efdd 100644 --- a/nx.json +++ b/nx.json @@ -79,8 +79,9 @@ } }, "plugins": [ - "./tooling/build-env/src/plugin/verdaccio-env.plugin.ts", - "./e2e-examples/cli-e2e-original/tooling/original.plugin.ts" + "./e2e-examples/cli-e2e-original/tooling/original.plugin.ts", + "./e2e-examples/cli-e2e-env/tooling/env.plugin.ts", + "./tooling/build-env/src/plugin/verdaccio-env.plugin.ts" ], "release": { "version": { diff --git a/package-lock.json b/package-lock.json index e7a9a6f0..ee625f5b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,11 +9,12 @@ "version": "0.0.0", "license": "MIT", "dependencies": { + "memfs": "^4.11.1", "tslib": "^2.3.0", "yargs": "^17.7.2" }, "devDependencies": { - "@nx/devkit": "^19.6.4", + "@nx/devkit": "^19.6.5", "@nx/esbuild": "18.2.4", "@nx/eslint": "18.2.4", "@nx/eslint-plugin": "18.2.4", @@ -2675,6 +2676,57 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.0.tgz", + "integrity": "sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==", + "dependencies": { + "@jsonjoy.com/base64": "^1.1.1", + "@jsonjoy.com/util": "^1.1.2", + "hyperdyperid": "^1.2.0", + "thingies": "^1.20.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.3.0.tgz", + "integrity": "sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, "node_modules/@mole-inc/bin-wrapper": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/@mole-inc/bin-wrapper/-/bin-wrapper-8.0.1.tgz", @@ -2741,12 +2793,12 @@ } }, "node_modules/@nrwl/devkit": { - "version": "19.6.4", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.6.4.tgz", - "integrity": "sha512-jpr+T5/+21W/fwAMB6zDLZKO+ReYAfOOMIeM8CpeBi/r9nWmjGXaXN9YKwEOYS1fath62Y5ldGK4yZUttv1tkw==", + "version": "19.6.5", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.6.5.tgz", + "integrity": "sha512-KaQeVyYaWBQwQSITtumPvx+P7IpKFReETx4gLTcOpQ/a3QD/AZFGbNjiG+xDLbgo1FDh9dRt9k7eWhGk6oPWKQ==", "dev": true, "dependencies": { - "@nx/devkit": "19.6.4" + "@nx/devkit": "19.6.5" } }, "node_modules/@nrwl/esbuild": { @@ -2835,12 +2887,12 @@ } }, "node_modules/@nx/devkit": { - "version": "19.6.4", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.6.4.tgz", - "integrity": "sha512-mBitFwb/gcz8MR7STt7KQG0vf+QcsasDXiSYcf3OWpc6lGE5wn1q5jg6Iabp49Bd/mdHXVLQnP1aV5A+QqFIOQ==", + "version": "19.6.5", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.6.5.tgz", + "integrity": "sha512-AEaMSr55Ar48QHU8TBi/gzLtjeT100zdyfLmk0RoiLzjjC8pWmm3Xfvqxyt1WsUUf4oQhlHlolJuoM41qKsdZw==", "dev": true, "dependencies": { - "@nrwl/devkit": "19.6.4", + "@nrwl/devkit": "19.6.5", "ejs": "^3.1.7", "enquirer": "~2.3.6", "ignore": "^5.0.4", @@ -3200,6 +3252,35 @@ "yargs-parser": "21.1.1" } }, + "node_modules/@nx/jest/node_modules/@nrwl/devkit": { + "version": "19.6.4", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.6.4.tgz", + "integrity": "sha512-jpr+T5/+21W/fwAMB6zDLZKO+ReYAfOOMIeM8CpeBi/r9nWmjGXaXN9YKwEOYS1fath62Y5ldGK4yZUttv1tkw==", + "dev": true, + "dependencies": { + "@nx/devkit": "19.6.4" + } + }, + "node_modules/@nx/jest/node_modules/@nx/devkit": { + "version": "19.6.4", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.6.4.tgz", + "integrity": "sha512-mBitFwb/gcz8MR7STt7KQG0vf+QcsasDXiSYcf3OWpc6lGE5wn1q5jg6Iabp49Bd/mdHXVLQnP1aV5A+QqFIOQ==", + "dev": true, + "dependencies": { + "@nrwl/devkit": "19.6.4", + "ejs": "^3.1.7", + "enquirer": "~2.3.6", + "ignore": "^5.0.4", + "minimatch": "9.0.3", + "semver": "^7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 17 <= 20" + } + }, "node_modules/@nx/js": { "version": "19.6.4", "resolved": "https://registry.npmjs.org/@nx/js/-/js-19.6.4.tgz", @@ -3246,6 +3327,15 @@ } } }, + "node_modules/@nx/js/node_modules/@nrwl/devkit": { + "version": "19.6.4", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.6.4.tgz", + "integrity": "sha512-jpr+T5/+21W/fwAMB6zDLZKO+ReYAfOOMIeM8CpeBi/r9nWmjGXaXN9YKwEOYS1fath62Y5ldGK4yZUttv1tkw==", + "dev": true, + "dependencies": { + "@nx/devkit": "19.6.4" + } + }, "node_modules/@nx/js/node_modules/@nrwl/tao": { "version": "19.6.4", "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-19.6.4.tgz", @@ -3268,6 +3358,26 @@ "@nx/workspace": "19.6.4" } }, + "node_modules/@nx/js/node_modules/@nx/devkit": { + "version": "19.6.4", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.6.4.tgz", + "integrity": "sha512-mBitFwb/gcz8MR7STt7KQG0vf+QcsasDXiSYcf3OWpc6lGE5wn1q5jg6Iabp49Bd/mdHXVLQnP1aV5A+QqFIOQ==", + "dev": true, + "dependencies": { + "@nrwl/devkit": "19.6.4", + "ejs": "^3.1.7", + "enquirer": "~2.3.6", + "ignore": "^5.0.4", + "minimatch": "9.0.3", + "semver": "^7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 17 <= 20" + } + }, "node_modules/@nx/js/node_modules/@nx/nx-darwin-arm64": { "version": "19.6.4", "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-19.6.4.tgz", @@ -3450,6 +3560,35 @@ "tslib": "^2.3.0" } }, + "node_modules/@nx/plugin/node_modules/@nrwl/devkit": { + "version": "19.6.4", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.6.4.tgz", + "integrity": "sha512-jpr+T5/+21W/fwAMB6zDLZKO+ReYAfOOMIeM8CpeBi/r9nWmjGXaXN9YKwEOYS1fath62Y5ldGK4yZUttv1tkw==", + "dev": true, + "dependencies": { + "@nx/devkit": "19.6.4" + } + }, + "node_modules/@nx/plugin/node_modules/@nx/devkit": { + "version": "19.6.4", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.6.4.tgz", + "integrity": "sha512-mBitFwb/gcz8MR7STt7KQG0vf+QcsasDXiSYcf3OWpc6lGE5wn1q5jg6Iabp49Bd/mdHXVLQnP1aV5A+QqFIOQ==", + "dev": true, + "dependencies": { + "@nrwl/devkit": "19.6.4", + "ejs": "^3.1.7", + "enquirer": "~2.3.6", + "ignore": "^5.0.4", + "minimatch": "9.0.3", + "semver": "^7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 17 <= 20" + } + }, "node_modules/@nx/plugin/node_modules/@nx/eslint": { "version": "19.6.4", "resolved": "https://registry.npmjs.org/@nx/eslint/-/eslint-19.6.4.tgz", @@ -8880,6 +9019,14 @@ "node": ">=16.17.0" } }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "engines": { + "node": ">=10.18" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -10555,6 +10702,24 @@ "node": ">= 0.6" } }, + "node_modules/memfs": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.11.1.tgz", + "integrity": "sha512-LZcMTBAgqUUKNXZagcZxvXXfgF1bHX7Y7nQ0QyEiNbRJgE29GhgPd8Yna1VQcLlPiHt/5RFJMWYN9Uv/VPNvjQ==", + "dependencies": { + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.3.0", + "tree-dump": "^1.0.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">= 4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + } + }, "node_modules/merge-descriptors": { "version": "1.0.1", "dev": true, @@ -12836,6 +13001,17 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/thingies": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", + "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "tslib": "^2" + } + }, "node_modules/thread-stream": { "version": "2.7.0", "dev": true, @@ -13008,6 +13184,21 @@ "dev": true, "license": "MIT" }, + "node_modules/tree-dump": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", + "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, "node_modules/trim-repeated": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-2.0.0.tgz", diff --git a/package.json b/package.json index 02daa51d..5f4acf5e 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,12 @@ "scripts": {}, "private": true, "dependencies": { + "memfs": "^4.11.1", "tslib": "^2.3.0", "yargs": "^17.7.2" }, "devDependencies": { - "@nx/devkit": "^19.6.4", + "@nx/devkit": "^19.6.5", "@nx/esbuild": "18.2.4", "@nx/eslint": "18.2.4", "@nx/eslint-plugin": "18.2.4", diff --git a/projects/cli/src/lib/cli.spec.ts b/projects/cli/src/lib/cli.spec.ts index 44dbaf96..99b8baab 100644 --- a/projects/cli/src/lib/cli.spec.ts +++ b/projects/cli/src/lib/cli.spec.ts @@ -1,7 +1,7 @@ -import {join} from 'node:path'; -import {sortCommandHandle} from './cli'; -import {afterEach, beforeEach, type MockInstance, vi} from "vitest"; -import {vol} from "memfs"; +import { join } from 'node:path'; +import { sortCommandHandle } from './cli'; +import { afterEach, beforeEach, type MockInstance, vi } from 'vitest'; +import { vol } from 'memfs'; vi.mock('fs', async () => { const memfs: typeof import('memfs') = await vi.importActual('memfs'); @@ -26,19 +26,21 @@ describe('sortCommandHandle', () => { it('should sort file of users', async () => { const testPath = join(MEMFS_VOLUME, 'sort', 'users.json'); - vol.fromJSON({ - [testPath]: JSON.stringify([ - {name: 'Michael'}, - {name: 'Alice'}, - ]), - }, MEMFS_VOLUME); + vol.fromJSON( + { + [testPath]: JSON.stringify([{ name: 'Michael' }, { name: 'Alice' }]), + }, + MEMFS_VOLUME + ); - await expect(sortCommandHandle({file: testPath})).resolves.not.toThrow(); + await expect( + sortCommandHandle({ filePath: testPath }) + ).resolves.not.toThrow(); const content = vol.readFileSync(testPath).toString(); expect(JSON.parse(content)).toEqual([ - {name: 'Alice'}, - {name: 'Michael'}, + { name: 'Alice' }, + { name: 'Michael' }, ]); }); }); diff --git a/projects/cli/src/lib/cli.ts b/projects/cli/src/lib/cli.ts index 15c6c031..07692397 100644 --- a/projects/cli/src/lib/cli.ts +++ b/projects/cli/src/lib/cli.ts @@ -1,4 +1,4 @@ -import yargs, { ArgumentsCamelCase, Options } from 'yargs'; +import yargs, { Options } from 'yargs'; import { sortUserFile } from '@org/core'; export type CliArgs = { @@ -7,24 +7,22 @@ export type CliArgs = { const NOOP_BUILDER = undefined; export function cli(args: string[]) { - return ( - yargs(args) - .version(false) - .help(true) - .alias('help', 'h') - .options({ - filePath: { - type: 'string', - description: 'Path to the user file', - demandOption: true, - }, - } satisfies Record) - //.command('*', 'Sort users', sortCommandHandle) - .command('sort', 'Sort users', NOOP_BUILDER, sortCommandHandle) - ); + return yargs(args) + .version(false) + .help(true) + .alias('help', 'h') + .options({ + filePath: { + type: 'string', + description: 'Path to the user file', + demandOption: true, + }, + } satisfies Record) + .command('*', 'Sort users', NOOP_BUILDER, sortCommandHandle) + .command('sort', 'Sort users', NOOP_BUILDER, sortCommandHandle); } -export async function sortCommandHandle(args: ArgumentsCamelCase) { +export async function sortCommandHandle(args: CliArgs) { const { filePath } = args; await sortUserFile(filePath); console.log(`Sorted users in ${filePath}`); diff --git a/tooling/build-env/project.json b/tooling/build-env/project.json index ee8a4208..5863a823 100644 --- a/tooling/build-env/project.json +++ b/tooling/build-env/project.json @@ -24,11 +24,6 @@ "glob": "**/*.d.ts", "output": "./src" }, - { - "input": "./tooling/build-env", - "glob": "generators.json", - "output": "." - }, { "input": "./tooling/build-env", "glob": "executors.json", @@ -51,12 +46,6 @@ "options": { "configFile": "tooling/build-env/vite.config.ts" } - }, - "integration-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "tooling/build-env/vite.config.ts" - } } }, "tags": ["scope:tooling"] diff --git a/tooling/build-env/src/index.ts b/tooling/build-env/src/index.ts index 01c3ec6d..86310c16 100644 --- a/tooling/build-env/src/index.ts +++ b/tooling/build-env/src/index.ts @@ -1,2 +1,2 @@ -export { getEnvironmentsRoot, getEnvironmentRoot } from './utils/setup'; +export { getEnvironmentsRoot, getEnvironmentRoot } from './shared/setup'; export { createNodes } from './plugin/verdaccio-env.plugin'; diff --git a/tooling/build-env/src/internal/verdaccio/verdaccio-registry.ts b/tooling/build-env/src/internal/verdaccio/verdaccio-registry.ts index b5cddc01..ff1ab4ed 100644 --- a/tooling/build-env/src/internal/verdaccio/verdaccio-registry.ts +++ b/tooling/build-env/src/internal/verdaccio/verdaccio-registry.ts @@ -5,7 +5,7 @@ import { logger } from '@nx/devkit'; import { objectToCliArgs } from '../utils/terminal-command'; import { executeProcess } from '../utils/execute-process'; import { uniquePort } from '../utils/utils'; -import {getEnvironmentsRoot} from "@org/build-env"; +import { getEnvironmentsRoot } from '../../shared/setup'; export function logInfo(msg: string) { info(msg, 'Verdaccio: '); @@ -88,12 +88,12 @@ export type StarVerdaccioOptions = VerdaccioExecuterOptions & export async function startVerdaccioServer({ targetName = 'start-verdaccio', - projectName, - port = String(uniquePort()), - storage = join(getEnvironmentsRoot(projectName), targetName, 'storage'), - location = 'none', - clear = true, - verbose = true, + projectName, + port = String(uniquePort()), + storage = join(getEnvironmentsRoot(projectName), targetName, 'storage'), + location = 'none', + clear = true, + verbose = true, ...opt }: StarVerdaccioOptions): Promise { let startDetected = false; diff --git a/tooling/build-env/src/utils/setup.ts b/tooling/build-env/src/shared/setup.ts similarity index 95% rename from tooling/build-env/src/utils/setup.ts rename to tooling/build-env/src/shared/setup.ts index 0f2ee10d..6360d7f3 100644 --- a/tooling/build-env/src/utils/setup.ts +++ b/tooling/build-env/src/shared/setup.ts @@ -4,7 +4,7 @@ import { DEFAULT_ENVIRONMENTS_OUTPUT_DIR } from '../internal/constants'; export function getEnvironmentsRoot( environmentsDir: string = DEFAULT_ENVIRONMENTS_OUTPUT_DIR ) { - return environmentsDir; + return environmentsDir; } /** diff --git a/tooling/tools-utils/project.json b/tooling/tools-utils/project.json index 6b77e3f8..fc225436 100644 --- a/tooling/tools-utils/project.json +++ b/tooling/tools-utils/project.json @@ -18,11 +18,11 @@ "executor": "@nx/esbuild:esbuild", "outputs": ["{options.outputPath}"], "options": { - "outputPath": "dist/projects/tools-utils", - "main": "projects/tools-utils/src/index.ts", - "tsConfig": "projects/tools-utils/tsconfig.lib.json", - "assets": ["projects/tools-utils/*.md"], - "generatePackageJson": true, + "outputPath": "dist/tooling/tools-utils", + "main": "tooling/tools-utils/src/index.ts", + "tsConfig": "tooling/tools-utils/tsconfig.lib.json", + "assets": ["tooling/tools-utils/*.md"], + "format": ["esm"] } }, diff --git a/tooling/tools-utils/src/index.ts b/tooling/tools-utils/src/index.ts index 5e0fce4f..61d1b8c2 100644 --- a/tooling/tools-utils/src/index.ts +++ b/tooling/tools-utils/src/index.ts @@ -1,5 +1,6 @@ export * from './lib/utils/logging'; export * from './lib/utils/utils'; +export * from './lib/utils/build-target-helper'; export { setupNpmWorkspace } from './lib/utils/npm'; export { diff --git a/tooling/tools-utils/src/lib/utils/build-target-helper.ts b/tooling/tools-utils/src/lib/utils/build-target-helper.ts new file mode 100644 index 00000000..4c9658eb --- /dev/null +++ b/tooling/tools-utils/src/lib/utils/build-target-helper.ts @@ -0,0 +1,14 @@ +import { ProjectConfiguration } from 'nx/src/config/workspace-json-project-json'; + +export function getBuildOutputPathFromBuildTarget( + projectConfiguration: ProjectConfiguration +) { + const { targets } = projectConfiguration; + const { build } = targets ?? {}; + const { options } = build ?? {}; + const { outputPath } = options ?? {}; + if (outputPath == null) { + throw new Error('outputPath is required'); + } + return outputPath; +} diff --git a/tooling/tools-utils/src/lib/utils/execute-process.ts b/tooling/tools-utils/src/lib/utils/execute-process.ts deleted file mode 100644 index 02d974a5..00000000 --- a/tooling/tools-utils/src/lib/utils/execute-process.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { - type ChildProcess, - type ChildProcessByStdio, - type SpawnOptionsWithStdioTuple, - type StdioPipe, - spawn, -} from 'node:child_process'; -import type { Readable, Writable } from 'node:stream'; - -export type ProcessResult = { - stdout: string; - stderr: string; - code: number | null; - date: string; - duration: number; -}; - -export class ProcessError extends Error { - code: number | null; - stderr: string; - stdout: string; - - constructor(result: ProcessResult) { - super(result.stderr); - this.code = result.code; - this.stderr = result.stderr; - this.stdout = result.stdout; - } -} - -export type ProcessConfig = Omit< - SpawnOptionsWithStdioTuple, - 'stdio' -> & { - command: string; - args?: string[]; - verbose?: boolean; - observer?: ProcessObserver; - ignoreExitCode?: boolean; -}; - -export type ProcessObserver = { - onStdout?: (stdout: string, sourceProcess?: ChildProcess) => void; - onStderr?: (stderr: string, sourceProcess?: ChildProcess) => void; - onError?: (error: ProcessError) => void; - onComplete?: () => void; -}; - -export function executeProcess(cfg: ProcessConfig): Promise { - const { - command, - args, - observer, - verbose = false, - ignoreExitCode = false, - ...options - } = cfg; - const { onStdout, onStderr, onError, onComplete } = observer ?? {}; - const date = new Date().toISOString(); - const start = performance.now(); - - return new Promise((resolve, reject) => { - // shell:true tells Windows to use shell command for spawning a child process - const spawnedProcess = spawn(command, args ?? [], { - shell: true, - ...options, - }) as ChildProcessByStdio; - - let stdout = ''; - let stderr = ''; - - spawnedProcess.stdout.on('data', (data) => { - stdout += String(data); - if (verbose) { - console.info(String(data)); - } - onStdout?.(String(data), spawnedProcess); - }); - - spawnedProcess.stderr.on('data', (data) => { - stderr += String(data); - if (verbose) { - console.error(String(data)); - } - onStderr?.(String(data), spawnedProcess); - }); - - spawnedProcess.on('error', (err) => { - stderr += err.toString(); - }); - - spawnedProcess.on('close', (code) => { - const timings = { date, duration: performance.now() - start }; - if (code === 0 || ignoreExitCode) { - onComplete?.(); - resolve({ code, stdout, stderr, ...timings }); - } else { - const errorMsg = new ProcessError({ code, stdout, stderr, ...timings }); - onError?.(errorMsg); - reject(errorMsg); - } - }); - }); -} diff --git a/tooling/tools-utils/src/lib/utils/terminal-command.ts b/tooling/tools-utils/src/lib/utils/terminal-command.ts deleted file mode 100644 index ae836be9..00000000 --- a/tooling/tools-utils/src/lib/utils/terminal-command.ts +++ /dev/null @@ -1,52 +0,0 @@ -type ArgumentValue = number | string | boolean | string[]; -export type CliArgsObject> = - T extends never - ? Record | { _: string } - : T; - -export function objectToCliArgs< - T extends object = Record ->(params?: CliArgsObject): string[] { - if (!params) { - return []; - } - - return Object.entries(params).flatMap(([key, value]) => { - // process/file/script - if (key === '_') { - return Array.isArray(value) ? value : [`${value}`]; - } - - const prefix = key.length === 1 ? '-' : '--'; - // "-*" arguments (shorthands) - if (Array.isArray(value)) { - return value.map((v) => `${prefix}${key}="${v}"`); - } - - if (typeof value === 'object') { - return Object.entries(value as Record).flatMap( - // transform nested objects to the dot notation `key.subkey` - ([k, v]) => objectToCliArgs({ [`${key}.${k}`]: v }) - ); - } - - if (typeof value === 'string') { - return [`${prefix}${key}="${value}"`]; - } - - if (typeof value === 'number') { - return [`${prefix}${key}=${value}`]; - } - - if (typeof value === 'boolean') { - return [`${prefix}${value ? '' : 'no-'}${key}`]; - } - - // empty property gets removed - if (value === undefined) { - return []; - } - - throw new Error(`Unsupported type ${typeof value} for key ${key}`); - }); -} diff --git a/tooling/tools-utils/src/lib/utils/utils.ts b/tooling/tools-utils/src/lib/utils/utils.ts index 69ee0425..63f3175b 100644 --- a/tooling/tools-utils/src/lib/utils/utils.ts +++ b/tooling/tools-utils/src/lib/utils/utils.ts @@ -1,18 +1,4 @@ import { mkdir } from 'node:fs/promises'; -import { ProjectConfiguration } from 'nx/src/config/workspace-json-project-json'; - -export function getBuildOutputPathFromBuildTarget( - projectConfiguration: ProjectConfiguration -) { - const { targets } = projectConfiguration; - const { build } = targets ?? {}; - const { options } = build ?? {}; - const { outputPath } = options ?? {}; - if (outputPath == null) { - throw new Error('outputPath is required'); - } - return outputPath; -} export async function ensureDirectoryExists(baseDir: string) { try { diff --git a/tooling/tools-utils/tsconfig.lib.json b/tooling/tools-utils/tsconfig.lib.json index ce3b531c..3a557089 100644 --- a/tooling/tools-utils/tsconfig.lib.json +++ b/tooling/tools-utils/tsconfig.lib.json @@ -5,6 +5,6 @@ "declaration": true, "types": ["node"] }, - "include": ["src/**/*.ts"], + "include": ["src/**/*.ts", "bin/**/*.ts"], "exclude": ["vite.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] } diff --git a/tooling/tools-utils/tsconfig.spec.json b/tooling/tools-utils/tsconfig.spec.json index 3c002c21..6680b091 100644 --- a/tooling/tools-utils/tsconfig.spec.json +++ b/tooling/tools-utils/tsconfig.spec.json @@ -7,6 +7,7 @@ "vitest/importMeta", "vite/client", "node", + "tslib", "vitest" ] }, diff --git a/tooling/tsconfig.json b/tooling/tsconfig.json deleted file mode 100644 index 212767e1..00000000 --- a/tooling/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "extends": "../tsconfig.base.json", - "compilerOptions": { - "module": "esnext", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.tools.json" - } - ] -} diff --git a/tooling/tsconfig.tools.json b/tooling/tsconfig.tools.json deleted file mode 100644 index 4b80da18..00000000 --- a/tooling/tsconfig.tools.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "types": ["node"] - }, - "include": ["src/**/*.ts", "src/**/*.d.ts"] -}