diff --git a/.env b/.env new file mode 100644 index 00000000..e69de29b diff --git a/e2e/nx-verdaccio-e2e/fixtures/basic-nx-workspace.ts b/e2e/nx-verdaccio-e2e/fixtures/basic-nx-workspace.ts new file mode 100644 index 00000000..5b5d71d7 --- /dev/null +++ b/e2e/nx-verdaccio-e2e/fixtures/basic-nx-workspace.ts @@ -0,0 +1,7 @@ +import { join } from 'node:path'; + +export const REPO_NAME = 'nx-ts-repo'; +export const envRoot = `tmp/environments/${process.env['NX_TASK_TARGET_PROJECT']}`; +export const workspaceRoot = join(envRoot, '__test__', REPO_NAME); +export const projectName = 'pkg'; +export const e2eProjectName = 'pkg-e2e'; diff --git a/e2e/nx-verdaccio-e2e/setup/exec-global-setup.ts b/e2e/nx-verdaccio-e2e/setup/exec-global-setup.ts new file mode 100644 index 00000000..e13d9c02 --- /dev/null +++ b/e2e/nx-verdaccio-e2e/setup/exec-global-setup.ts @@ -0,0 +1,18 @@ +import { setup } from './setup.ts'; +import { REPO_NAME } from '../fixtures/basic-nx-workspace'; +import { join } from 'node:path'; +import { + DEFAULT_TEST_FIXTURE_DIST, + getTestEnvironmentRoot, + teardownTestFolder, +} from '@push-based/test-utils'; + +(async () => { + const projectName = process.env['NX_TASK_TARGET_PROJECT']; + const envRoot = getTestEnvironmentRoot(projectName); + const repoPath = join(envRoot, DEFAULT_TEST_FIXTURE_DIST, REPO_NAME); + + // clean up previous runs + await teardownTestFolder(repoPath); + await setup({ envRoot: repoPath, repoName: REPO_NAME, projectName }); +})(); diff --git a/e2e/nx-verdaccio-e2e/setup/setup.ts b/e2e/nx-verdaccio-e2e/setup/setup.ts new file mode 100644 index 00000000..0ce1d53c --- /dev/null +++ b/e2e/nx-verdaccio-e2e/setup/setup.ts @@ -0,0 +1,164 @@ +import { + DEFAULT_TEST_FIXTURE_DIST, + executeProcess, + getTestEnvironmentRoot, + objectToCliArgs, + updateJson, +} from '@push-based/test-utils'; +import { dirname, join } from 'node:path'; +import { copyFile, mkdir } from 'node:fs/promises'; +import { + logger, + NxJsonConfiguration, + PluginConfiguration, + TargetConfiguration, +} from '@nx/devkit'; +import { PackageJson } from 'nx/src/utils/package-json'; + +export async function setup({ + envRoot, + projectName, + repoName, +}: { + envRoot: string; + repoName: string; + projectName: string; +}) { + await mkdir(envRoot, { recursive: true }); + // setup nx environment for e2e tests + logger.info(`Created nx workspace under ${envRoot}`); + await executeProcess({ + command: 'npx', + args: objectToCliArgs({ + _: ['--yes', '--quiet', 'create-nx-workspace'], + name: repoName, + preset: 'ts', + ci: 'skip', + e2eTestRunner: 'none', + interactive: false, + }), + verbose: true, + cwd: dirname(envRoot), + }); + + logger.info(`Add project & target`); + await executeProcess({ + command: 'nx', + args: objectToCliArgs({ + _: ['generate', '@nx/js:library', 'pkg'], + directory: 'packages/pkg', + bundler: 'tsc', + unitTestRunner: 'none', + linter: 'none', + interactive: false, + }), + verbose: true, + cwd: envRoot, + }); + await updateJson( + join(envRoot, 'packages', 'pkg', 'package.json'), + (json) => ({ + ...json, + nx: { + ...json?.nx, + targets: { + ...json?.nx?.targets, + build: { + options: { + outputPath: ['dist/pkg'], + }, + command: 'echo "lib"', + }, + }, + }, + }) + ); + + logger.info(`Add e2e project & target`); + await executeProcess({ + command: 'nx', + args: objectToCliArgs({ + _: ['generate', '@nx/js:library', 'pkg-e2e'], + directory: 'packages/pkg-e2e', + bundler: 'tsc', + unitTestRunner: 'none', + linter: 'none', + interactive: false, + }), + verbose: true, + cwd: envRoot, + }); + await updateJson( + join(envRoot, 'packages', 'pkg-e2e', 'package.json'), + (json) => + updatePackageJsonNxTargets(json, { + ...json?.nx?.targets, + e2e: { + command: 'echo "e2e"', + }, + }) + ); + + logger.info(`Install @push-based/nx-verdaccio`); + await mkdir( + join( + getTestEnvironmentRoot(projectName), + DEFAULT_TEST_FIXTURE_DIST, + repoName + ), + { recursive: true } + ); + await copyFile( + join(getTestEnvironmentRoot(projectName), '.npmrc'), + join(envRoot, '.npmrc') + ); + await executeProcess({ + command: 'npm', + args: objectToCliArgs({ + _: ['install', '@push-based/nx-verdaccio'], + save: true, + }), + cwd: envRoot, + verbose: true, + }); +} + +export async function registerNxVerdaccioPlugin(envRoot: string) { + logger.info(`register nx-verdaccio plugin`); + await updateJson(join(envRoot, 'nx.json'), (json) => + registerPluginInNxJson(json, { + plugin: '@push-based/nx-verdaccio', + options: { + environments: { + targetNames: ['e2e'], + }, + }, + }) + ); +} + +function registerPluginInNxJson( + nxJson: NxJsonConfiguration, + pluginConfig: PluginConfiguration +) { + return { + ...nxJson, + plugins: [...(nxJson?.plugins ?? []), pluginConfig], + }; +} + +function updatePackageJsonNxTargets( + pkgJson: PackageJson, + targets: Record +) { + return { + ...pkgJson, + nx: { + ...pkgJson?.nx, + targets: { + ...pkgJson?.nx?.targets, + ...targets, + }, + }, + }; +} diff --git a/e2e/nx-verdaccio-e2e/test/plugin-create-nodes.e2e.test.ts b/e2e/nx-verdaccio-e2e/test/plugin-create-nodes.e2e.test.ts index 6cd0fab6..2dc3ac38 100644 --- a/e2e/nx-verdaccio-e2e/test/plugin-create-nodes.e2e.test.ts +++ b/e2e/nx-verdaccio-e2e/test/plugin-create-nodes.e2e.test.ts @@ -43,7 +43,7 @@ describe('nx-verdaccio plugin create-nodes-v2', () => { }); afterEach(async () => { - await teardownTestFolder(baseDir); + // await teardownTestFolder(baseDir); }); it('should add package targets to library project', async () => { @@ -274,7 +274,6 @@ describe('nx-verdaccio plugin create-nodes-v2', () => { }), }) ); - }); it('should NOT add environment targets to project without targetName e2e', async () => { diff --git a/e2e/nx-verdaccio-e2e/tsconfig.spec.json b/e2e/nx-verdaccio-e2e/tsconfig.spec.json index f70d5879..e7edf502 100644 --- a/e2e/nx-verdaccio-e2e/tsconfig.spec.json +++ b/e2e/nx-verdaccio-e2e/tsconfig.spec.json @@ -13,6 +13,7 @@ "include": [ "vite.config.ts", "vitest.config.ts", + "setup/**/*.ts", "test/**/*.test.ts", "test/**/*.spec.ts", "test/**/*.test.tsx", diff --git a/examples/e2e/cli-post-script-e2e/.eslintrc.json b/examples/e2e/cli-post-script-e2e/.eslintrc.json new file mode 100644 index 00000000..75d7c5f4 --- /dev/null +++ b/examples/e2e/cli-post-script-e2e/.eslintrc.json @@ -0,0 +1,30 @@ +{ + "extends": ["../../../.eslintrc.base.json", "../../../.eslintrc.base.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.json"], + "parser": "jsonc-eslint-parser", + "rules": { + "@nx/dependency-checks": [ + "error", + { + "ignoredFiles": ["{projectRoot}/vite.config.{js,ts,mjs,mts}"] + } + ] + } + } + ] +} diff --git a/examples/e2e/cli-post-script-e2e/README.md b/examples/e2e/cli-post-script-e2e/README.md new file mode 100644 index 00000000..159fe280 --- /dev/null +++ b/examples/e2e/cli-post-script-e2e/README.md @@ -0,0 +1,89 @@ +# Nx Verdaccio Example - Custom Test Environment Setup 🧪 + +This example demonstrates how to set up a custom test environment for projects with specific tags. +It creates a Nx workspace, installs the package dependencies after the Nx setup is done, and runs the E2E tests for the project. + +## Plugin Configuration + +**nx.json** + +```json +{ + "plugins": [ + { + "plugin": "@push-based/nx-verdaccio", + "options": { + "environments": { + "targetNames": ["e2e"] + } + } + } + ] +} +``` + +## Project Configuration + +**projects/utils/project.json** + +```jsonc +{ + "implicitDependencies": ["cli"], + "targets": { + "nxv-env-setup": { + "options": { + "skipInstall": true, + "postScript": "npx tsx --tsconfig examples/e2e/cli-post-script-e2e/tsconfig.spec.json examples/e2e/cli-post-script-e2e/setup/exec-global-setup.ts" + } + }, + "e2e": { + // test provides data + } + } +} +``` + +**projects/utils/setup/exec-global-setup.ts** + +```ts +export async function setup({ userconfig, envRoot, projectName, repoName }: { envRoot: string; repoName: string; userconfig: string; projectName: string }) { + // setup nx environment for e2e tests + await execSync(`npx --yes create-nx-workspace@latest --preset=ts-standalone --ci=skip --no-interactive --name=${repoName}`, { + cwd: dirname(envRoot), + }); + // install cli + await execSync(`npm install @push-based/cli`, { + cwd: envRoot, + }); + + // update project.json with target + const json = JSON.parse((await readFile(join(envRoot, 'project.json'))).toString()); + await writeFile( + join(envRoot, 'project.json'), + JSON.stringify({ + ...json, + targets: { + ...json.targets, + sort: { + command: 'npx cli sort --filePath=users.json', + }, + }, + }) + ); + + // copy data to test + await cp(join('examples', 'e2e', 'cli-post-scripts', 'fixtures', 'small-data'), envRoot, { recursive: true }); +} +``` + +## Running the Example + +```bash +nx run cli-post-script-e2e:nxv-e2e +``` + +## Inspect the test environment setup + +```bash +nx run cli-post-script-e2e:nxv-env-setup --keepServerRunning --verboes +``` diff --git a/examples/e2e/cli-post-script-e2e/fixtures/small-data/users.json b/examples/e2e/cli-post-script-e2e/fixtures/small-data/users.json new file mode 100644 index 00000000..7d10c530 --- /dev/null +++ b/examples/e2e/cli-post-script-e2e/fixtures/small-data/users.json @@ -0,0 +1,8 @@ +[ + { + "name": "Michael" + }, + { + "name": "Alice" + } +] diff --git a/examples/e2e/cli-post-script-e2e/project.json b/examples/e2e/cli-post-script-e2e/project.json new file mode 100644 index 00000000..94dc2a50 --- /dev/null +++ b/examples/e2e/cli-post-script-e2e/project.json @@ -0,0 +1,20 @@ +{ + "name": "cli-post-script-e2e", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "projects/cli-post-script-e2e/test", + "projectType": "application", + "tags": ["type:e2e", "type:e2e-vi", "type:example"], + "implicitDependencies": ["cli"], + "targets": { + "nxv-env-setup": { + "options": { + "skipInstall": true, + "postScript": "npx tsx --tsconfig examples/e2e/cli-post-script-e2e/tsconfig.spec.json examples/e2e/cli-post-script-e2e/setup/exec-global-setup.ts" + } + }, + "e2e": { + "executor": "@nx/vite:test", + "inputs": ["default", "^production"] + } + } +} diff --git a/examples/e2e/cli-post-script-e2e/setup/config.ts b/examples/e2e/cli-post-script-e2e/setup/config.ts new file mode 100644 index 00000000..3608a89d --- /dev/null +++ b/examples/e2e/cli-post-script-e2e/setup/config.ts @@ -0,0 +1 @@ +export const REPO_NAME = 'nx-ts-repo'; diff --git a/examples/e2e/cli-post-script-e2e/setup/exec-global-setup.ts b/examples/e2e/cli-post-script-e2e/setup/exec-global-setup.ts new file mode 100644 index 00000000..2b9fd08e --- /dev/null +++ b/examples/e2e/cli-post-script-e2e/setup/exec-global-setup.ts @@ -0,0 +1,18 @@ +import { setup } from './setup.ts'; +import { REPO_NAME } from './config.ts'; +import { join } from 'node:path'; +import { + DEFAULT_TEST_FIXTURE_DIST, + getTestEnvironmentRoot, + teardownTestFolder, +} from '@push-based/test-utils'; + +export const projectName = 'cli-post-script-e2e'; +const envRoot = getTestEnvironmentRoot(projectName); +export const repoPath = join(envRoot, DEFAULT_TEST_FIXTURE_DIST, REPO_NAME); + +(async () => { + // clean up previous runs + await teardownTestFolder(repoPath); + await setup({ envRoot: repoPath, repoName: REPO_NAME, projectName }); +})(); diff --git a/examples/e2e/cli-post-script-e2e/setup/setup.ts b/examples/e2e/cli-post-script-e2e/setup/setup.ts new file mode 100644 index 00000000..0cbeee3b --- /dev/null +++ b/examples/e2e/cli-post-script-e2e/setup/setup.ts @@ -0,0 +1,78 @@ +import { + DEFAULT_TEST_FIXTURE_DIST, + executeProcess, + getTestEnvironmentRoot, + objectToCliArgs, +} from '@push-based/test-utils'; +import { dirname, join } from 'node:path'; +import { copyFile, cp, mkdir, readFile, writeFile } from 'node:fs/promises'; + +export async function setup({ + envRoot, + projectName, + repoName, +}: { + envRoot: string; + repoName: string; + projectName: string; +}) { + await mkdir(envRoot, { recursive: true }); + // setup nx environment for e2e tests + await executeProcess({ + command: 'npx', + args: objectToCliArgs({ + _: ['--yes', 'create-nx-workspace'], + name: repoName, + preset: 'ts-standalone', + ci: 'skip', + interactive: false, + }), + verbose: true, + cwd: dirname(envRoot), + }); + await mkdir( + join( + getTestEnvironmentRoot(projectName), + DEFAULT_TEST_FIXTURE_DIST, + repoName + ), + { recursive: true } + ); + await copyFile( + join(getTestEnvironmentRoot(projectName), '.npmrc'), + join(envRoot, '.npmrc') + ); + + await executeProcess({ + command: 'npm', + args: objectToCliArgs({ + _: ['install', '@push-based/cli'], + save: true, + }), + cwd: envRoot, + verbose: true, + }); + + await cp( + join('examples', 'e2e', 'cli-post-script-e2e', 'fixtures', 'small-data'), + envRoot, + { recursive: true } + ); + + const json = JSON.parse( + (await readFile(join(envRoot, 'project.json'))).toString() + ); + + await writeFile( + join(envRoot, 'project.json'), + JSON.stringify({ + ...json, + targets: { + ...json.targets, + sort: { + command: 'npx cli sort --filePath=users.json', + }, + }, + }) + ); +} diff --git a/examples/e2e/cli-post-script-e2e/test/nx-target-sort.spec.ts b/examples/e2e/cli-post-script-e2e/test/nx-target-sort.spec.ts new file mode 100644 index 00000000..54df658c --- /dev/null +++ b/examples/e2e/cli-post-script-e2e/test/nx-target-sort.spec.ts @@ -0,0 +1,36 @@ +import { basename, dirname, join } from 'node:path'; +import { describe, expect, it } from 'vitest'; +import { mkdir, readFile, writeFile } from 'node:fs/promises'; +import { + DEFAULT_TEST_FIXTURE_DIST, + executeProcess, + getTestEnvironmentRoot, + objectToCliArgs, +} from '@push-based/test-utils'; +import { REPO_NAME } from '../setup/config'; + +describe('Nx target - sort', () => { + const projectName = 'cli-post-script-e2e'; + const envRoot = getTestEnvironmentRoot(projectName); + const repoRoot = join(envRoot, DEFAULT_TEST_FIXTURE_DIST, REPO_NAME); + + it('should execute Nx target in nx setup created with postScript', async () => { + const { code, stdout } = await executeProcess({ + command: 'npx', + args: objectToCliArgs({ + _: ['nx', 'run', `${REPO_NAME}:sort`], + }), + cwd: repoRoot, + verbose: true, + }); + + expect(code).toBe(0); + expect(stdout).toContain('Sorted users in users.json'); + + const content = (await readFile(join(repoRoot, 'users.json'))).toString(); + expect(JSON.parse(content)).toStrictEqual([ + { name: 'Alice' }, + { name: 'Michael' }, + ]); + }); +}); diff --git a/examples/e2e/cli-post-script-e2e/tsconfig.json b/examples/e2e/cli-post-script-e2e/tsconfig.json new file mode 100644 index 00000000..2ea3517f --- /dev/null +++ b/examples/e2e/cli-post-script-e2e/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "module": "esnext", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/examples/e2e/cli-post-script-e2e/tsconfig.spec.json b/examples/e2e/cli-post-script-e2e/tsconfig.spec.json new file mode 100644 index 00000000..e7edf502 --- /dev/null +++ b/examples/e2e/cli-post-script-e2e/tsconfig.spec.json @@ -0,0 +1,27 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [ + "vitest/globals", + "vitest/importMeta", + "vite/client", + "node", + "vitest" + ] + }, + "include": [ + "vite.config.ts", + "vitest.config.ts", + "setup/**/*.ts", + "test/**/*.test.ts", + "test/**/*.spec.ts", + "test/**/*.test.tsx", + "test/**/*.spec.tsx", + "test/**/*.test.js", + "test/**/*.spec.js", + "test/**/*.test.jsx", + "test/**/*.spec.jsx", + "test/**/*.d.ts" + ] +} diff --git a/examples/e2e/cli-post-script-e2e/vite.config.ts b/examples/e2e/cli-post-script-e2e/vite.config.ts new file mode 100644 index 00000000..f8a7af01 --- /dev/null +++ b/examples/e2e/cli-post-script-e2e/vite.config.ts @@ -0,0 +1,27 @@ +import { defineConfig } from 'vite'; + +import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin'; + +export default defineConfig({ + root: __dirname, + cacheDir: '../../../node_modules/.vite/projects/cli-post-script-e2e', + + plugins: [nxViteTsPaths()], + + // Uncomment this if you are using workers. + // worker: { + // plugins: [ nxViteTsPaths() ], + // }, + + test: { + globals: true, + cache: { dir: '../../../node_modules/.vitest' }, + environment: 'node', + include: ['test/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + reporters: ['default'], + coverage: { + reportsDirectory: '../../../coverage/projects/cli-post-script-e2e', + provider: 'v8', + }, + }, +}); diff --git a/nx.json b/nx.json index c6b312a1..fb2eb13c 100644 --- a/nx.json +++ b/nx.json @@ -29,8 +29,7 @@ "cache": true, "inputs": ["default", "^production"] }, - "nxv-e2e": {}, - "nxv-env-setup": { + "@push-based/nx-verdaccio:env-setup": { "cache": true, "inputs": [ "{projectRoot}/project.json", @@ -46,6 +45,9 @@ "^production" ] }, + "nxv-env-setup": { + "executor": "@push-based/nx-verdaccio:env-setup" + }, "nx-release-publish": {}, "lint": { "executor": "@nx/linter:eslint", diff --git a/projects/nx-verdaccio/README.md b/projects/nx-verdaccio/README.md index ae99c4f4..88658ac8 100644 --- a/projects/nx-verdaccio/README.md +++ b/projects/nx-verdaccio/README.md @@ -22,16 +22,16 @@ This executor helps to initiate an [environment folder](../../../../../README.md "env-setup": { "executor": "@code-pushup/nx-verdaccio:env-setup", "options": { - "keepServerRunning": false + "skipInstall": true + "keepServerRunning": true "envRoot": "/tmp/test-npm-workspace" - "verbose": true, } } } } ``` -Read more under [setup executor docs](./projects/nx-verdaccio/src/executors/setup/README.md). +Read more under [setup executor docs](./projects/nx-verdaccio/src/executors/env-setup/README.md). ### Bootstrap Environment Executor @@ -54,13 +54,12 @@ This executor helps to initiate [environment](../../../../../README.md#-environm } ``` -Read more under [bootstrap executor docs](./projects/nx-verdaccio/src/executors/bootstrap/README.md). +Read more under [bootstrap executor docs](./projects/nx-verdaccio/src/executors/env-bootstrap/README.md). ### Kill Process Executor This executor helps to kill processes by `ProcessID` or a JSON file containing a property `pid` as number. - ```jsonc // project.json { @@ -102,7 +101,7 @@ This executor helps to install a [`pubishable`](../../../../../README.md#fine-gr } ``` -Read more under [pkg install executor docs](./projects/nx-verdaccio/src/executors/npm-install/README.md). +Read more under [pkg install executor docs](./projects/nx-verdaccio/src/executors/pkg-install/README.md). ### NPM Publish Executor @@ -126,7 +125,7 @@ This executor helps to publish a [`pubishable`](../../../../../README.md#fine-gr } ``` -Read more under [pkg publish executor docs](./projects/nx-verdaccio/src/executors/npm-publish/README.md). +Read more under [pkg publish executor docs](./projects/nx-verdaccio/src/executors/pkg-publish/README.md). ## Debugging e2e environments diff --git a/projects/nx-verdaccio/project.json b/projects/nx-verdaccio/project.json index 7a1a748f..d20244bd 100644 --- a/projects/nx-verdaccio/project.json +++ b/projects/nx-verdaccio/project.json @@ -4,7 +4,7 @@ "sourceRoot": "projects/nx-verdaccio/src", "projectType": "library", "tags": ["publishable"], - "implicitDependencies": [], + "implicitDependencies": ["nx-verdaccio"], "targets": { "build": { "executor": "@nx/js:tsc", diff --git a/projects/nx-verdaccio/src/executors/env-bootstrap/bootstrap-env.ts b/projects/nx-verdaccio/src/executors/env-bootstrap/bootstrap-env.ts index 89ad13b4..de4a0437 100644 --- a/projects/nx-verdaccio/src/executors/env-bootstrap/bootstrap-env.ts +++ b/projects/nx-verdaccio/src/executors/env-bootstrap/bootstrap-env.ts @@ -6,7 +6,6 @@ import { type VercaddioServerResult, } from './verdaccio-registry'; import { writeFile } from 'node:fs/promises'; -import { setupNpmWorkspace } from './npm'; import { formatError, formatInfo } from '../../internal/logging'; import { VERDACCIO_REGISTRY_JSON } from './constants'; import { logger } from '@nx/devkit'; @@ -15,6 +14,7 @@ import { type Environment, VERDACCIO_ENV_TOKEN, } from './npm'; +import { setupNpmWorkspace } from '../env-setup/npm'; export type BootstrapEnvironmentOptions = StartVerdaccioOptions & Environment; @@ -50,7 +50,6 @@ export async function bootstrapEnvironment( try { const { url, port, host } = registry; - await setupNpmWorkspace(environmentRoot, verbose); const userconfig = join(environmentRoot, '.npmrc'); await configureRegistry({ url, port, host, userconfig }, verbose); } catch (error) { diff --git a/projects/nx-verdaccio/src/executors/env-bootstrap/bootstrap-env.unit-test.ts b/projects/nx-verdaccio/src/executors/env-bootstrap/bootstrap-env.unit-test.ts index 9c6c3acc..cb70fc7d 100644 --- a/projects/nx-verdaccio/src/executors/env-bootstrap/bootstrap-env.unit-test.ts +++ b/projects/nx-verdaccio/src/executors/env-bootstrap/bootstrap-env.unit-test.ts @@ -36,9 +36,6 @@ describe('bootstrapEnvironment', () => { }, stop: vi.fn(), }); - const setupNpmWorkspaceSpy = vi - .spyOn(npmModule, 'setupNpmWorkspace') - .mockImplementation(vi.fn()); const configureRegistrySpy = vi .spyOn(npmModule, 'configureRegistry') .mockImplementation(vi.fn()); @@ -73,12 +70,6 @@ describe('bootstrapEnvironment', () => { verbose: undefined, }); - expect(setupNpmWorkspaceSpy).toHaveBeenCalledTimes(1); - expect(setupNpmWorkspaceSpy).toHaveBeenCalledWith( - expect.toMatchPath('tmp/environments/my-lib-e2e'), - undefined - ); - expect(configureRegistrySpy).toHaveBeenCalledTimes(1); expect(configureRegistrySpy).toHaveBeenCalledWith( { diff --git a/projects/nx-verdaccio/src/executors/env-bootstrap/npm.ts b/projects/nx-verdaccio/src/executors/env-bootstrap/npm.ts index 06725f11..91878081 100644 --- a/projects/nx-verdaccio/src/executors/env-bootstrap/npm.ts +++ b/projects/nx-verdaccio/src/executors/env-bootstrap/npm.ts @@ -1,8 +1,6 @@ -import { exec, execFile } from 'node:child_process'; -import { join } from 'node:path'; +import { exec } from 'node:child_process'; import { promisify } from 'node:util'; -import { ensureDirectoryExists } from '../../internal/file-system'; -import { formatError, formatInfo } from '../../internal/logging'; +import { formatInfo } from '../../internal/logging'; import { logger } from '@nx/devkit'; import type { VercaddioServerResult } from './verdaccio-registry'; import { objectToCliArgs } from '../../internal/terminal'; @@ -18,36 +16,6 @@ export function chdir(path: string): void { process.chdir(path); } -export async function setupNpmWorkspace( - environmentRoot: string, - verbose?: boolean -): Promise { - if (verbose) { - logger.info( - formatInfo( - `Execute: npm init in directory ${environmentRoot}`, - NPM_ENV_TOKEN - ) - ); - } - const cwd = process.cwd(); - await ensureDirectoryExists(environmentRoot); - try { - await promisify(execFile)('npm', ['init', '--force'], { - shell: true, - windowsHide: true, - cwd: join(cwd, environmentRoot), - }); - } catch (error) { - logger.error( - formatError( - `Error creating NPM workspace: ${(error as Error).message}`, - NPM_ENV_TOKEN - ) - ); - } -} - export const VERDACCIO_ENV_TOKEN = 'Verdaccio Env: '; export type Environment = { diff --git a/projects/nx-verdaccio/src/executors/env-bootstrap/npm.unit-test.ts b/projects/nx-verdaccio/src/executors/env-bootstrap/npm.unit-test.ts index eed5dcd2..7ae56f31 100644 --- a/projects/nx-verdaccio/src/executors/env-bootstrap/npm.unit-test.ts +++ b/projects/nx-verdaccio/src/executors/env-bootstrap/npm.unit-test.ts @@ -4,12 +4,12 @@ import { MEMFS_VOLUME } from '@push-based/test-utils'; import { configureRegistry, type ConfigureRegistryOptions, - setupNpmWorkspace, unconfigureRegistry, VERDACCIO_ENV_TOKEN, } from './npm'; import { logger } from '@nx/devkit'; import { formatInfo } from '../../internal/logging'; +import { setupNpmWorkspace } from '../env-setup/npm'; const execMock = vi.fn(); vi.mock('util', () => ({ @@ -133,36 +133,3 @@ describe('unconfigureRegistry', () => { ); }); }); - -describe.skip('setupNpmWorkspace', () => { - let cwdSpy; - let chdirSpy; - let consoleInfoSpy; - - beforeEach(() => { - cwdSpy = vi.spyOn(process, 'cwd').mockReturnValue(MEMFS_VOLUME); - chdirSpy = vi.spyOn(process, 'chdir').mockImplementation(vi.fn()); - consoleInfoSpy = vi.spyOn(console, 'info').mockImplementation(vi.fn()); - }); - - afterEach(() => { - cwdSpy.mockRestore(); - chdirSpy.mockRestore(); - consoleInfoSpy.mockRestore(); - }); - - it('should create npm workspace in given folder', async () => { - await setupNpmWorkspace('tmp'); - expect(chdirSpy).toHaveBeenCalledTimes(1); - expect(chdirSpy).toHaveBeenCalledWith('tmp'); - expect(consoleInfoSpy).not.toHaveBeenCalled(); - }); - - it('should call infoLog if verbose is given', async () => { - await setupNpmWorkspace('tmp', true); - expect(consoleInfoSpy).toHaveBeenCalledTimes(1); - expect(consoleInfoSpy).toHaveBeenCalledWith( - `${red('>')} ${red(bold('Npm Env: '))} Execute: npm init in directory tmp` - ); - }); -}); diff --git a/projects/nx-verdaccio/src/executors/env-setup/README.md b/projects/nx-verdaccio/src/executors/env-setup/README.md index e302fc3b..2df4dae7 100644 --- a/projects/nx-verdaccio/src/executors/env-setup/README.md +++ b/projects/nx-verdaccio/src/executors/env-setup/README.md @@ -52,5 +52,94 @@ Show what will be executed without actually executing it: | --------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | **envRoot** | `string` (REQUIRED) | The folder in which the package should get published. This folder is the environment folder and contains a configured `.npmrc` file. | | **keepServerRunning** | `boolean` (DEFAULT false) | keep the Verdaccio server running after bootstraping the environment | +| **skipInstall** | `boolean` (DEFAULT false) | Skip package install during setup | +| **postScript** | `string` | Script executed after packge publish/install is finished but before server teardown | | **printConfig** | `boolean` | Print config without executing | | **verbose** | `boolean` | Show more verbose logs | + +## Examples + +By default, the `env-setup` executor in combination with the `nx-verdaccio` plugin not need any configuration. + +To give some examples, here are some common examples and their configurations: + +### Change the environment root to a custom directory + +By default, the environment root is set to `tmp/environments/` where project name is the current executed task. +That means if you run `nx run my-project:env-setup` the environment root will be `tmp/environments/my-project`. + +```json +{ + "name": "my-project", + "targets": { + "env-setup": { + "options": { + "envRoot": "/tmp/e2e/{projectName}" + } + }, + "e2e": { + // ... + } + } +} +``` + +With the above configuration, the environment root will be `/tmp/e2e/my-project` and all environment files will be stored there. + +### Use a custom script for the environment setup + +If you want to run a custom script after the environment is set up, you can use the `postScript` option. + +The following example assumes that you will install the packages in a separate step and only publish the packages. +After the packages are published, the post script executes, installs the needed dependencies programmatically and then tears down the server. + +```jsonc +// projects/my-project/project.json +{ + "name": "my-project", + "targets": { + "env-setup": { + "options": { + "skipInstall": true, + "postScript": "tsx --tsconfig=tsconfig.e2e.json projects/my-project/setup/global-setup.ts" + } + }, + "e2e": { + // ... + } + } +} +``` + +```ts +// projects/my-project/setup/global-setup.ts + +await copyFile(join(getTestEnvironmentRoot('my-project'), '.npmrc'), join(repoPath, '.npmrc')); +execSync('npm init @org/create-my-project'); +``` + +In the above example, the `postScript` option is used to programmatically install the dependencies while still using the published packages from the Verdaccio registry. +This gives flexibility and control over the environment setup process. See the [cli-post-script-e2e](../../../../../examples/e2e/cli-post-script-e2e/README.md) project for a more real life example. + +### Inspect the environment setup with the Verdaccio registry server running + +If you want to inspect the environment setup with the server running, you can use the `keepServerRunning` option. + +```json +{ + "name": "my-project", + "targets": { + "env-setup": { + "options": { + "keepServerRunning": true + } + }, + "e2e": { + // ... + } + } +} +``` + +Executing the above configuration will keep the Verdaccio server running after the environment setup is finished. +The URL under which the Verdaccio server is running will be printed to the console and is also available in the `verdaccio.regirsty.json` file in the projects environment folder. diff --git a/projects/nx-verdaccio/src/executors/env-setup/executor.ts b/projects/nx-verdaccio/src/executors/env-setup/executor.ts index 10214247..5ea9f39a 100644 --- a/projects/nx-verdaccio/src/executors/env-setup/executor.ts +++ b/projects/nx-verdaccio/src/executors/env-setup/executor.ts @@ -7,15 +7,21 @@ import { stopVerdaccioServer, type VerdaccioProcessResult, } from '../env-bootstrap/verdaccio-registry'; +import { formatError, formatInfo } from '../../internal/logging'; + import type { SetupEnvironmentExecutorOptions } from './schema'; import { VERDACCIO_REGISTRY_JSON } from '../env-bootstrap/constants'; import { TARGET_ENVIRONMENT_BOOTSTRAP, TARGET_ENVIRONMENT_INSTALL, + TARGET_ENVIRONMENT_PUBLISH_ONLY, + TARGET_ENVIRONMENT_SETUP, } from '../../plugin/targets/environment.targets'; import { runSingleExecutor } from '../../internal/run-executor'; import { getEnvironmentRoot } from '../../internal/environment-root'; -import {cleanupEnv} from "../internal/cleanup-env"; +import { cleanupEnv } from '../internal/cleanup-env'; + +import { setupNpmWorkspace } from './npm'; export type ExecutorOutput = { success: boolean; @@ -23,12 +29,15 @@ export type ExecutorOutput = { error?: Error; }; +const INFO_TOKEN = 'ENV SETUP'; + export default async function runSetupEnvironmentExecutor( terminalAndExecutorOptions: SetupEnvironmentExecutorOptions, context: ExecutorContext ) { const { configurationName: configuration, projectName } = context; - const { verbose, keepServerRunning } = terminalAndExecutorOptions; + const { verbose, keepServerRunning, skipInstall, postScript } = + terminalAndExecutorOptions; const environmentRoot = getEnvironmentRoot( context, terminalAndExecutorOptions @@ -57,16 +66,48 @@ export default async function runSetupEnvironmentExecutor( } try { - await executeProcess({ - command: 'npx', - args: objectToCliArgs({ - _: ['nx', TARGET_ENVIRONMENT_INSTALL, projectName], - environmentRoot, + if (skipInstall) { + logger.info( + formatInfo(`Run target: ${TARGET_ENVIRONMENT_PUBLISH_ONLY}`, INFO_TOKEN) + ); + await executeProcess({ + command: 'npx', + args: objectToCliArgs({ + _: ['nx', TARGET_ENVIRONMENT_PUBLISH_ONLY, projectName], + environmentRoot, + ...(verbose ? { verbose } : {}), + }), + cwd: process.cwd(), ...(verbose ? { verbose } : {}), - }), - cwd: process.cwd(), - ...(verbose ? { verbose } : {}), - }); + }); + } else { + logger.info( + formatInfo(`Run target: ${TARGET_ENVIRONMENT_INSTALL}`, INFO_TOKEN) + ); + await setupNpmWorkspace(environmentRoot, verbose); + await executeProcess({ + command: 'npx', + args: objectToCliArgs({ + _: ['nx', TARGET_ENVIRONMENT_INSTALL, projectName], + environmentRoot, + ...(verbose ? { verbose } : {}), + }), + cwd: process.cwd(), + ...(verbose ? { verbose } : {}), + }); + } + if (postScript) { + const [command, ...args] = postScript.split(' '); + logger.info( + formatInfo(`Run postScript: ${command} ${args.join(' ')}`, INFO_TOKEN) + ); + await executeProcess({ + command, + args, + cwd: process.cwd(), + ...(verbose ? { verbose } : {}), + }); + } } catch (error) { logger.error(error.message); await stopVerdaccioServer({ @@ -93,7 +134,7 @@ export default async function runSetupEnvironmentExecutor( environmentRoot, }); // delete storage, .npmrc - await cleanupEnv(environmentRoot) + await cleanupEnv(environmentRoot); } else { const { url } = await readFile( join(environmentRoot, VERDACCIO_REGISTRY_JSON), diff --git a/projects/nx-verdaccio/src/executors/env-setup/executor.unit-test.ts b/projects/nx-verdaccio/src/executors/env-setup/executor.unit-test.ts index 1513f35c..dd5a9cd6 100644 --- a/projects/nx-verdaccio/src/executors/env-setup/executor.unit-test.ts +++ b/projects/nx-verdaccio/src/executors/env-setup/executor.unit-test.ts @@ -7,6 +7,7 @@ import { TARGET_ENVIRONMENT_VERDACCIO_STOP, } from '../../plugin/targets/environment.targets'; import { MockAsyncIterableIterator } from '@push-based/test-utils'; +import * as npmModule from './npm'; vi.mock('@nx/devkit', async () => { const actual = await vi.importActual('@nx/devkit'); @@ -38,6 +39,7 @@ vi.mock('fs/promises', async () => { describe('runSetupEnvironmentExecutor', () => { const runExecutorSpy = vi.spyOn(devkit, 'runExecutor'); const executeProcessSpy = vi.spyOn(executeProcessModule, 'executeProcess'); + const setupNpmWorkspaceSpy = vi.spyOn(npmModule, 'setupNpmWorkspace'); beforeEach(() => { runExecutorSpy.mockReset(); @@ -122,6 +124,12 @@ describe('runSetupEnvironmentExecutor', () => { }, context ); + + expect(setupNpmWorkspaceSpy).toHaveBeenCalledTimes(1); + expect(setupNpmWorkspaceSpy).toHaveBeenCalledWith( + expect.toMatchPath('tmp/environments/my-lib-e2e'), + undefined + ); }); it('should catch error cause by runBootstrapEnvironment', async () => { @@ -238,7 +246,7 @@ describe('runSetupEnvironmentExecutor', () => { context ); - expect(devkit.logger.info).toHaveBeenCalledTimes(1); + expect(devkit.logger.info).toHaveBeenCalledTimes(2); expect(devkit.logger.info).toHaveBeenCalledWith( 'Verdaccio server kept running under : http://localhost:4873' ); diff --git a/projects/nx-verdaccio/src/executors/env-setup/npm.ts b/projects/nx-verdaccio/src/executors/env-setup/npm.ts new file mode 100644 index 00000000..ca33ceac --- /dev/null +++ b/projects/nx-verdaccio/src/executors/env-setup/npm.ts @@ -0,0 +1,37 @@ +import { logger } from '@nx/devkit'; +import { formatError, formatInfo } from '../../internal/logging'; +import { ensureDirectoryExists } from '../../internal/file-system'; +import { promisify } from 'node:util'; +import { execFile } from 'node:child_process'; +import { join } from 'node:path'; +import { NPM_ENV_TOKEN } from '../env-bootstrap/npm'; + +export async function setupNpmWorkspace( + environmentRoot: string, + verbose?: boolean +): Promise { + if (verbose) { + logger.info( + formatInfo( + `Execute: npm init in directory ${environmentRoot}`, + NPM_ENV_TOKEN + ) + ); + } + const cwd = process.cwd(); + await ensureDirectoryExists(environmentRoot); + try { + await promisify(execFile)('npm', ['init', '--force'], { + shell: true, + windowsHide: true, + cwd: join(cwd, environmentRoot), + }); + } catch (error) { + logger.error( + formatError( + `Error creating NPM workspace: ${(error as Error).message}`, + NPM_ENV_TOKEN + ) + ); + } +} diff --git a/projects/nx-verdaccio/src/executors/env-setup/npm.unit-test.ts b/projects/nx-verdaccio/src/executors/env-setup/npm.unit-test.ts new file mode 100644 index 00000000..13b5d4a2 --- /dev/null +++ b/projects/nx-verdaccio/src/executors/env-setup/npm.unit-test.ts @@ -0,0 +1,55 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { bold, red } from 'ansis'; +import { MEMFS_VOLUME } from '@push-based/test-utils'; +import { + configureRegistry, + type ConfigureRegistryOptions, + unconfigureRegistry, + VERDACCIO_ENV_TOKEN, +} from './npm'; +import { logger } from '@nx/devkit'; +import { formatInfo } from '../../internal/logging'; +import { setupNpmWorkspace } from '../env-setup/npm'; + +vi.mock('@nx/devkit', async () => { + const actual = await vi.importActual('@nx/devkit'); + return { + ...actual, + logger: { + info: vi.fn(), + }, + }; +}); + +describe.skip('setupNpmWorkspace', () => { + let cwdSpy; + let chdirSpy; + let consoleInfoSpy; + + beforeEach(() => { + cwdSpy = vi.spyOn(process, 'cwd').mockReturnValue(MEMFS_VOLUME); + chdirSpy = vi.spyOn(process, 'chdir').mockImplementation(vi.fn()); + consoleInfoSpy = vi.spyOn(console, 'info').mockImplementation(vi.fn()); + }); + + afterEach(() => { + cwdSpy.mockRestore(); + chdirSpy.mockRestore(); + consoleInfoSpy.mockRestore(); + }); + + it('should create npm workspace in given folder', async () => { + await setupNpmWorkspace('tmp'); + expect(chdirSpy).toHaveBeenCalledTimes(1); + expect(chdirSpy).toHaveBeenCalledWith('tmp'); + expect(consoleInfoSpy).not.toHaveBeenCalled(); + }); + + it('should call infoLog if verbose is given', async () => { + await setupNpmWorkspace('tmp', true); + expect(consoleInfoSpy).toHaveBeenCalledTimes(1); + expect(consoleInfoSpy).toHaveBeenCalledWith( + `${red('>')} ${red(bold('Npm Env: '))} Execute: npm init in directory tmp` + ); + }); +}); diff --git a/projects/nx-verdaccio/src/executors/env-setup/schema.json b/projects/nx-verdaccio/src/executors/env-setup/schema.json index 7c56ad90..eb0694cd 100644 --- a/projects/nx-verdaccio/src/executors/env-setup/schema.json +++ b/projects/nx-verdaccio/src/executors/env-setup/schema.json @@ -15,6 +15,16 @@ "default": false, "aliases": ["k"] }, + "skipInstall": { + "type": "boolean", + "description": "Skip installing dependencies", + "default": false, + "aliases": ["i"] + }, + "postScript": { + "type": "string", + "description": "The script to run after the setup task have been executed" + }, "dryRun": { "type": "boolean", "description": "Print the commands that would be run, but don't actually run them" @@ -22,10 +32,6 @@ "verbose": { "type": "boolean", "description": "Print additional logs" - }, - "progress": { - "type": "boolean", - "description": "Print additional logs" } }, "additionalProperties": true, diff --git a/projects/nx-verdaccio/src/executors/env-setup/schema.ts b/projects/nx-verdaccio/src/executors/env-setup/schema.ts index 672a8c7a..7ea926e4 100644 --- a/projects/nx-verdaccio/src/executors/env-setup/schema.ts +++ b/projects/nx-verdaccio/src/executors/env-setup/schema.ts @@ -3,7 +3,8 @@ import { type Environment } from '../env-bootstrap/npm'; export type SetupEnvironmentExecutorOptions = Partial< Environment & { keepServerRunning: boolean; - progress: boolean; + skipInstall: boolean; + postScript: string; verbose: boolean; } >; diff --git a/projects/nx-verdaccio/src/executors/pkg-publish/executor.ts b/projects/nx-verdaccio/src/executors/pkg-publish/executor.ts index a121d968..0ea2665d 100644 --- a/projects/nx-verdaccio/src/executors/pkg-publish/executor.ts +++ b/projects/nx-verdaccio/src/executors/pkg-publish/executor.ts @@ -1,13 +1,13 @@ -import {type ExecutorContext, logger} from '@nx/devkit'; +import { type ExecutorContext, logger } from '@nx/devkit'; -import type {NpmPublishExecutorOptions} from './schema'; -import {join, relative} from 'node:path'; -import {executeProcess} from '../../internal/execute-process'; -import {objectToCliArgs} from '../../internal/terminal'; -import {getTargetOutputPath} from '../../internal/target'; -import {NPMRC_FILENAME} from './constants'; +import type { NpmPublishExecutorOptions } from './schema'; +import { join, relative } from 'node:path'; +import { executeProcess } from '../../internal/execute-process'; +import { objectToCliArgs } from '../../internal/terminal'; +import { getTargetOutputPath } from '../../internal/target'; +import { NPMRC_FILENAME } from './constants'; import * as process from 'process'; -import {markPackageJson} from './pkg-version'; +import { markPackageJson } from './pkg-version'; export type NpmPublishExecutorOutput = { success: boolean; @@ -28,6 +28,7 @@ export default async function runNpmPublishExecutor( const { projectName } = context; const { targets } = projectsConfigurations.projects[projectName]; const packageDistPath = getTargetOutputPath(targets['build']); + logger.info(`Publishing package from ${environmentRoot}`); const userconfig = join( relativeFromDist(packageDistPath), join(environmentRoot, NPMRC_FILENAME) @@ -53,7 +54,7 @@ export default async function runNpmPublishExecutor( } catch (error) { // if package already exists, log and go on if (error.message.includes('EPUBLISHCONFLICT')) { - logger.warn(`Package for ${projectName} already published. Proceeding.`); + logger.warn(`Package for ${projectName} already published.`); return { success: false, command: error, diff --git a/projects/nx-verdaccio/src/executors/pkg-publish/executor.unit-test.ts b/projects/nx-verdaccio/src/executors/pkg-publish/executor.unit-test.ts index 558fb2f9..9c2303be 100644 --- a/projects/nx-verdaccio/src/executors/pkg-publish/executor.unit-test.ts +++ b/projects/nx-verdaccio/src/executors/pkg-publish/executor.unit-test.ts @@ -61,7 +61,7 @@ describe('runNpmPublishExecutor', () => { success: true, }); - expect(logger.info).toHaveBeenCalledTimes(1); + expect(logger.info).toHaveBeenCalledTimes(2); // const userconfigRelative = '../../../tmp/environments/my-lib-e2e/.npmrc'; const pkgDist = 'dist/projects/my-lib'; const envRoot = 'tmp/environments/my-lib-e2e'; diff --git a/projects/nx-verdaccio/src/plugin/caching.ts b/projects/nx-verdaccio/src/plugin/caching.ts index bef0bb18..d1d4079a 100644 --- a/projects/nx-verdaccio/src/plugin/caching.ts +++ b/projects/nx-verdaccio/src/plugin/caching.ts @@ -46,5 +46,6 @@ export function writeTargetsToCache( cachePath: string, results: Record> ) { - writeJsonFile(cachePath, results); + process.env.NX_CACHE_PROJECT_GRAPH !== 'false' && + writeJsonFile(cachePath, results); } diff --git a/projects/nx-verdaccio/src/plugin/project-config.ts b/projects/nx-verdaccio/src/plugin/project-config.ts new file mode 100644 index 00000000..2ca8f2d8 --- /dev/null +++ b/projects/nx-verdaccio/src/plugin/project-config.ts @@ -0,0 +1,22 @@ +import type { ProjectConfiguration } from '@nx/devkit'; +import { readFile } from 'node:fs/promises'; +import { dirname, join } from 'node:path'; + +export async function getProjectConfig(packageJsonFile: string) { + const { nx: pkgNxConfig = {} } = await readFile( + join(process.cwd(), packageJsonFile), + 'utf8' + ).then(JSON.parse); + if (!('name' in pkgNxConfig) || typeof pkgNxConfig?.name !== 'string') { + // fallback to project.json + const projectConfig: ProjectConfiguration = await readFile( + join(process.cwd(), dirname(packageJsonFile), 'project.json'), + 'utf8' + ).then(JSON.parse); + if (!('name' in projectConfig) || typeof projectConfig.name !== 'string') { + throw new Error('Project name is required'); + } + return projectConfig; + } + return pkgNxConfig; +} diff --git a/projects/nx-verdaccio/src/plugin/targets/environment.targets.ts b/projects/nx-verdaccio/src/plugin/targets/environment.targets.ts index c656e57b..b9e889a6 100644 --- a/projects/nx-verdaccio/src/plugin/targets/environment.targets.ts +++ b/projects/nx-verdaccio/src/plugin/targets/environment.targets.ts @@ -1,7 +1,10 @@ import type { ProjectConfiguration, TargetConfiguration } from '@nx/devkit'; import type { NormalizedCreateNodeOptions } from '../normalize-create-nodes-options'; import { join } from 'node:path'; -import { TARGET_PACKAGE_INSTALL } from './package.targets'; +import { + TARGET_PACKAGE_INSTALL, + TARGET_PACKAGE_PUBLISH, +} from './package.targets'; import type { NxVerdaccioEnvironmentsOptions } from '../schema'; import type { StartVerdaccioOptions } from '../../executors/env-bootstrap/verdaccio-registry'; import { uniquePort } from '../../executors/env-bootstrap/unique-port'; @@ -17,6 +20,7 @@ import { EXECUTOR_ENVIRONMENT_TEARDOWN } from '../../executors/env-teardown/cons export const TARGET_ENVIRONMENT_BOOTSTRAP = 'nxv-env-bootstrap'; export const TARGET_ENVIRONMENT_INSTALL = 'nxv-env-install'; +export const TARGET_ENVIRONMENT_PUBLISH_ONLY = 'nxv-env-publish-only'; export const TARGET_ENVIRONMENT_SETUP = 'nxv-env-setup'; export const TARGET_ENVIRONMENT_TEARDOWN = 'nxv-env-teardown'; export const TARGET_ENVIRONMENT_E2E = 'nxv-e2e'; @@ -125,6 +129,19 @@ export function getEnvTargets( // This is here to make it appear in the graph in older nx versions (otherwise it is filtered out) command: `echo "dependencies installed for ${environmentRoot}"`, }, + // intermediate task just here to execute dependent pkg-publish tasks with the correct environmentProject + [TARGET_ENVIRONMENT_PUBLISH_ONLY]: { + dependsOn: [ + { + projects: 'dependencies', + target: TARGET_PACKAGE_PUBLISH, + params: 'forward', + }, + ], + options: { environmentRoot }, + // This is here to make it appear in the graph in older nx versions (otherwise it is filtered out) + command: `echo "dependencies published for ${environmentRoot}"`, + }, // runs env-bootstrap-env, install-env and stop-verdaccio [TARGET_ENVIRONMENT_SETUP]: { // list of inputs that all subsequent tasks depend on diff --git a/projects/nx-verdaccio/src/plugin/targets/package.targets.ts b/projects/nx-verdaccio/src/plugin/targets/package.targets.ts index 6afe8b64..dc6047cd 100644 --- a/projects/nx-verdaccio/src/plugin/targets/package.targets.ts +++ b/projects/nx-verdaccio/src/plugin/targets/package.targets.ts @@ -41,6 +41,7 @@ export function getPkgTargets(): Record { }, ], executor: `${PACKAGE_NAME}:${EXECUTOR_PACKAGE_NPM_PUBLISH}`, + options: {}, }, [TARGET_PACKAGE_INSTALL]: { dependsOn: [ @@ -55,6 +56,7 @@ export function getPkgTargets(): Record { }, ], executor: `${PACKAGE_NAME}:${EXECUTOR_PACKAGE_NPM_INSTALL}`, + options: {}, }, }; } diff --git a/static-environments/user-lists/package.json b/static-environments/user-lists/package.json index 962db80d..572e633f 100644 --- a/static-environments/user-lists/package.json +++ b/static-environments/user-lists/package.json @@ -7,11 +7,11 @@ "keywords": [], "author": "", "license": "ISC", - "description": "", "dependencies": { "@push-based/cli": "^0.0.1", "@push-based/core": "^0.0.1", "@push-based/models": "^0.0.1", "@push-based/utils": "^0.0.1" - } + }, + "description": "" } diff --git a/testing/test-utils/src/lib/file-system.ts b/testing/test-utils/src/lib/file-system.ts index 63f3175b..dba7303e 100644 --- a/testing/test-utils/src/lib/file-system.ts +++ b/testing/test-utils/src/lib/file-system.ts @@ -1,4 +1,5 @@ -import { mkdir } from 'node:fs/promises'; +import { mkdir, readFile, writeFile } from 'node:fs/promises'; +import { join } from 'node:path'; export async function ensureDirectoryExists(baseDir: string) { try { @@ -11,3 +12,11 @@ export async function ensureDirectoryExists(baseDir: string) { } } } + +export async function updateJson>( + target: string, + transformFn: (i: T) => O +): Promise { + const json = JSON.parse((await readFile(target)).toString()); + await writeFile(target, JSON.stringify(transformFn(json), null, 2)); +} diff --git a/testing/test-utils/src/lib/setup.ts b/testing/test-utils/src/lib/setup.ts index e531a31d..d8a60bdc 100644 --- a/testing/test-utils/src/lib/setup.ts +++ b/testing/test-utils/src/lib/setup.ts @@ -1,6 +1,6 @@ import { join } from 'node:path'; -export const DEFAULT_TEST_FIXTURE_DIST = '__test_env__'; +export const DEFAULT_TEST_FIXTURE_DIST = '__test__'; export function getTestFixturesDist( groupName: string,