From 1ff51b689949902368a6e8b20b41e683c08cf6e8 Mon Sep 17 00:00:00 2001 From: Tine Kondo Date: Sat, 23 Nov 2024 11:18:23 +0000 Subject: [PATCH] chore: update e2e tasks, to only populate local registry once for all tests --- .github/workflows/ci.yml | 4 +- .verdaccio/config.yml | 3 +- .../tests/create-nx-flutter.spec.ts | 3 +- e2e/nx-ktor-e2e/tests/create-nx-ktor.spec.ts | 3 +- e2e/nx-ktor-e2e/tests/nx-ktor.spec.ts | 16 ++-- e2e/nx-melos-e2e/tests/nx-melos.spec.ts | 31 ++++--- e2e/nx-micronaut-e2e/project.json | 24 +---- .../tests/create-nx-micronaut.spec.ts | 3 +- .../tests/nx-micronaut.spec.ts | 16 ++-- .../tests/create-nx-quarkus.spec.ts | 7 +- e2e/nx-quarkus-e2e/tests/nx-quarkus.spec.ts | 17 ++-- .../tests/create-nx-spring-boot.spec.ts | 3 +- .../tests/nx-spring-boot.spec.ts | 17 ++-- e2e/smoke/project.json | 5 +- nx.json | 14 +-- packages/common/testing/e2e/index.ts | 89 +++++++++++++------ project.json | 8 ++ tools/scripts/populate-local-registry.ts | 45 ++++++++++ tools/scripts/run-all-e2e-tests.ts | 7 +- tools/scripts/start-local-registry.ts | 60 ++++++++++--- tools/scripts/stop-local-registry.ts | 6 +- 21 files changed, 252 insertions(+), 129 deletions(-) create mode 100644 tools/scripts/populate-local-registry.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 234a4948..4ddbe250 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: # Connect your workspace on nx.app and uncomment this to enable task distribution. # The "--stop-agents-after" is optional, but allows idle agents to shut down once the "e2e" targets have been requested - - run: pnpm exec nx-cloud start-ci-run --distribute-on=".nx/workflows/dynamic-changesets.yaml" --stop-agents-after="e2e" --with-env-vars="ANDROID_SDK_VERSION,FLUTTER_VERSION,JDK_VERSION" + - run: pnpm exec nx-cloud start-ci-run --distribute-on=".nx/workflows/dynamic-changesets.yaml" --stop-agents-after="e2e-ci" --with-env-vars="ANDROID_SDK_VERSION,FLUTTER_VERSION,JDK_VERSION" # This line is needed for nx affected to work when CI is running on a PR - run: git branch --track develop origin/develop || exit 0 @@ -46,4 +46,4 @@ jobs: main-branch-name: 'develop' - run: pnpm exec nx-cloud record -- nx format:check - - run: pnpm exec nx affected -t lint test-ci build e2e --parallel=5 --exclude=smoke + - run: NX_VERBOSE_LOGGING=true pnpm exec nx affected -t lint test build e2e-ci --parallel=5 --exclude=smoke diff --git a/.verdaccio/config.yml b/.verdaccio/config.yml index e9cdce7d..88d75029 100644 --- a/.verdaccio/config.yml +++ b/.verdaccio/config.yml @@ -23,7 +23,7 @@ packages: proxy: npmjs # log settings -logs: +log: type: stdout format: pretty level: warn @@ -31,4 +31,3 @@ logs: publish: allow_offline: true # set offline to true to allow publish offline -listen: 0.0.0.0:4873 # listen on all addresses (INADDR_ANY) diff --git a/e2e/nx-flutter-e2e/tests/create-nx-flutter.spec.ts b/e2e/nx-flutter-e2e/tests/create-nx-flutter.spec.ts index d0614438..b020b97b 100644 --- a/e2e/nx-flutter-e2e/tests/create-nx-flutter.spec.ts +++ b/e2e/nx-flutter-e2e/tests/create-nx-flutter.spec.ts @@ -1,3 +1,4 @@ +import { getPackageManagerCommand } from '@nx/devkit'; import { hasNxWrapper, isNxWrapperInstalled } from '@nxrocks/common-cli'; import { createCLITestProject } from '@nxrocks/common/testing'; import { execSync } from 'child_process'; @@ -27,7 +28,7 @@ describe('create-nx-flutter', () => { ); // npm ls will fail if the package is not installed properly - execSync('npm ls @nxrocks/nx-flutter', { + execSync(`${getPackageManagerCommand().list} @nxrocks/nx-flutter`, { cwd: useNxWrapper ? join(projectDirectory, '/.nx/installation') : projectDirectory, diff --git a/e2e/nx-ktor-e2e/tests/create-nx-ktor.spec.ts b/e2e/nx-ktor-e2e/tests/create-nx-ktor.spec.ts index 738bf85f..38d62f6c 100644 --- a/e2e/nx-ktor-e2e/tests/create-nx-ktor.spec.ts +++ b/e2e/nx-ktor-e2e/tests/create-nx-ktor.spec.ts @@ -1,3 +1,4 @@ +import { getPackageManagerCommand } from '@nx/devkit'; import { hasNxWrapper, isNxWrapperInstalled } from '@nxrocks/common-cli'; import { createCLITestProject } from '@nxrocks/common-jvm/testing'; import { execSync } from 'child_process'; @@ -27,7 +28,7 @@ describe('create-nx-ktor', () => { ); // npm ls will fail if the package is not installed properly - execSync('npm ls @nxrocks/nx-ktor', { + execSync(`${getPackageManagerCommand().list} @nxrocks/nx-ktor`, { cwd: useNxWrapper ? join(projectDirectory, '/.nx/installation') : projectDirectory, diff --git a/e2e/nx-ktor-e2e/tests/nx-ktor.spec.ts b/e2e/nx-ktor-e2e/tests/nx-ktor.spec.ts index b6037c9b..7eb7a4fd 100644 --- a/e2e/nx-ktor-e2e/tests/nx-ktor.spec.ts +++ b/e2e/nx-ktor-e2e/tests/nx-ktor.spec.ts @@ -1,3 +1,4 @@ +import { getPackageManagerCommand } from '@nx/devkit'; import { uniq } from '@nx/plugin/testing'; import { createTestProject, @@ -19,11 +20,14 @@ describe('nx-ktor e2e', () => { // The plugin has been built and published to a local registry in the jest globalSetup // Install the plugin built with the latest source code into the test repo - execSync(`npm install @nxrocks/nx-ktor@0.0.0-e2e`, { - cwd: projectDirectory, - stdio: 'inherit', - env: process.env, - }); + execSync( + `${getPackageManagerCommand().install} @nxrocks/nx-ktor@0.0.0-e2e`, + { + cwd: projectDirectory, + stdio: 'inherit', + env: process.env, + } + ); }); afterAll(() => { @@ -37,7 +41,7 @@ describe('nx-ktor e2e', () => { it('should be installed', () => { // npm ls will fail if the package is not installed properly - execSync('npm ls @nxrocks/nx-ktor', { + execSync(`${getPackageManagerCommand().list} @nxrocks/nx-ktor`, { cwd: projectDirectory, stdio: 'inherit', }); diff --git a/e2e/nx-melos-e2e/tests/nx-melos.spec.ts b/e2e/nx-melos-e2e/tests/nx-melos.spec.ts index 119e07a3..8e27cd86 100644 --- a/e2e/nx-melos-e2e/tests/nx-melos.spec.ts +++ b/e2e/nx-melos-e2e/tests/nx-melos.spec.ts @@ -1,4 +1,9 @@ -import { checkFilesExist, createTestProject, runNxCommandAsync } from '@nxrocks/common/testing'; +import { getPackageManagerCommand } from '@nx/devkit'; +import { + checkFilesExist, + createTestProject, + runNxCommandAsync, +} from '@nxrocks/common/testing'; import { execSync } from 'child_process'; import { rmSync } from 'fs-extra'; @@ -10,24 +15,28 @@ describe('nx-melos e2e', () => { // The plugin has been built and published to a local registry in the jest globalSetup // Install the plugin built with the latest source code into the test repo - execSync(`npm install @nxrocks/nx-melos@0.0.0-e2e`, { - cwd: projectDirectory, - stdio: 'inherit', - env: process.env, - }); + execSync( + `${getPackageManagerCommand().install} @nxrocks/nx-melos@0.0.0-e2e`, + { + cwd: projectDirectory, + stdio: 'inherit', + env: process.env, + } + ); }); afterAll(() => { // Cleanup the test project - projectDirectory && rmSync(projectDirectory, { - recursive: true, - force: true, - }); + projectDirectory && + rmSync(projectDirectory, { + recursive: true, + force: true, + }); }); it('should be installed', () => { // npm ls will fail if the package is not installed properly - execSync('npm ls @nxrocks/nx-melos', { + execSync(`${getPackageManagerCommand().list} @nxrocks/nx-melos`, { cwd: projectDirectory, stdio: 'inherit', }); diff --git a/e2e/nx-micronaut-e2e/project.json b/e2e/nx-micronaut-e2e/project.json index edd07eed..0dbaecab 100644 --- a/e2e/nx-micronaut-e2e/project.json +++ b/e2e/nx-micronaut-e2e/project.json @@ -5,27 +5,5 @@ "sourceRoot": "e2e/nx-micronaut-e2e/tests", "tags": ["e2e"], "implicitDependencies": ["nx-micronaut"], - "targets": { - "e2e": { - "inputs": [ - "default", - "^default", - "{workspaceRoot}/jest.preset.js", - { - "externalDependencies": ["jest"] - } - ], - "options": { - "passWithNoTests": true, - "runInBand": true - }, - "dependsOn": ["^build"], - "configurations": { - "ci": { - "ci": true, - "coverage": true - } - } - } - } + "targets": {} } diff --git a/e2e/nx-micronaut-e2e/tests/create-nx-micronaut.spec.ts b/e2e/nx-micronaut-e2e/tests/create-nx-micronaut.spec.ts index 3c1efa1b..1458c93a 100644 --- a/e2e/nx-micronaut-e2e/tests/create-nx-micronaut.spec.ts +++ b/e2e/nx-micronaut-e2e/tests/create-nx-micronaut.spec.ts @@ -1,3 +1,4 @@ +import { getPackageManagerCommand } from '@nx/devkit'; import { hasNxWrapper, isNxWrapperInstalled } from '@nxrocks/common-cli'; import { createCLITestProject } from '@nxrocks/common-jvm/testing'; import { execSync } from 'child_process'; @@ -27,7 +28,7 @@ describe('create-nx-micronaut', () => { ); // npm ls will fail if the package is not installed properly - execSync('npm ls @nxrocks/nx-micronaut', { + execSync(`${getPackageManagerCommand().list} @nxrocks/nx-micronaut`, { cwd: useNxWrapper ? join(projectDirectory, '/.nx/installation') : projectDirectory, diff --git a/e2e/nx-micronaut-e2e/tests/nx-micronaut.spec.ts b/e2e/nx-micronaut-e2e/tests/nx-micronaut.spec.ts index 3473465f..d930efd5 100644 --- a/e2e/nx-micronaut-e2e/tests/nx-micronaut.spec.ts +++ b/e2e/nx-micronaut-e2e/tests/nx-micronaut.spec.ts @@ -1,3 +1,4 @@ +import { getPackageManagerCommand } from '@nx/devkit'; import { uniq } from '@nx/plugin/testing'; import { createTestProject, @@ -20,11 +21,14 @@ describe('nx-micronaut e2e', () => { // The plugin has been built and published to a local registry in the jest globalSetup // Install the plugin built with the latest source code into the test repo - execSync(`npm install @nxrocks/nx-micronaut@0.0.0-e2e`, { - cwd: projectDirectory, - stdio: 'inherit', - env: process.env, - }); + execSync( + `${getPackageManagerCommand().install} @nxrocks/nx-micronaut@0.0.0-e2e`, + { + cwd: projectDirectory, + stdio: 'inherit', + env: process.env, + } + ); }); afterAll(() => { @@ -38,7 +42,7 @@ describe('nx-micronaut e2e', () => { it('should be installed', () => { // npm ls will fail if the package is not installed properly - execSync('npm ls @nxrocks/nx-micronaut', { + execSync(`${getPackageManagerCommand().list} @nxrocks/nx-micronaut`, { cwd: projectDirectory, stdio: 'inherit', }); diff --git a/e2e/nx-quarkus-e2e/tests/create-nx-quarkus.spec.ts b/e2e/nx-quarkus-e2e/tests/create-nx-quarkus.spec.ts index 27b2e5b3..8744e1dc 100644 --- a/e2e/nx-quarkus-e2e/tests/create-nx-quarkus.spec.ts +++ b/e2e/nx-quarkus-e2e/tests/create-nx-quarkus.spec.ts @@ -1,10 +1,11 @@ +import { getPackageManagerCommand } from '@nx/devkit'; import { hasNxWrapper, isNxWrapperInstalled } from '@nxrocks/common-cli'; import { createCLITestProject } from '@nxrocks/common-jvm/testing'; import { execSync } from 'child_process'; import { rmSync } from 'fs'; import { join } from 'path'; -describe('create-nx-spring-boot', () => { +describe('create-nx-quarkus', () => { let projectDirectory: string; beforeAll(() => { @@ -22,12 +23,12 @@ describe('create-nx-spring-boot', () => { ${false} `('should be installed with Nx Wrapper=$useNxWrapper', ({ useNxWrapper }) => { projectDirectory = createCLITestProject( - 'create-nx-spring-boot', + 'create-nx-quarkus', `--prjName=bootapp --useNxWrapper=${useNxWrapper} --nxCloud=skip --no-interactive` ); // npm ls will fail if the package is not installed properly - execSync('npm ls @nxrocks/nx-spring-boot', { + execSync(`${getPackageManagerCommand().list} @nxrocks/nx-quarkus`, { cwd: useNxWrapper ? join(projectDirectory, '/.nx/installation') : projectDirectory, diff --git a/e2e/nx-quarkus-e2e/tests/nx-quarkus.spec.ts b/e2e/nx-quarkus-e2e/tests/nx-quarkus.spec.ts index 5a121b90..62affc0f 100644 --- a/e2e/nx-quarkus-e2e/tests/nx-quarkus.spec.ts +++ b/e2e/nx-quarkus-e2e/tests/nx-quarkus.spec.ts @@ -1,3 +1,4 @@ +import { getPackageManagerCommand } from '@nx/devkit'; import { uniq } from '@nx/plugin/testing'; import { createTestProject, @@ -21,11 +22,14 @@ describe('nx-quarkus e2e', () => { // The plugin has been built and published to a local registry in the jest globalSetup // Install the plugin built with the latest source code into the test repo - execSync(`npm install @nxrocks/nx-quarkus@0.0.0-e2e`, { - cwd: projectDirectory, - stdio: 'inherit', - env: process.env, - }); + execSync( + `${getPackageManagerCommand().add} @nxrocks/nx-quarkus@0.0.0-e2e`, + { + cwd: projectDirectory, + stdio: 'inherit', + env: process.env, + } + ); }); afterAll(() => { @@ -39,7 +43,7 @@ describe('nx-quarkus e2e', () => { it('should be installed', () => { // npm ls will fail if the package is not installed properly - execSync('npm ls @nxrocks/nx-quarkus', { + execSync(`${getPackageManagerCommand().list} @nxrocks/nx-quarkus`, { cwd: projectDirectory, stdio: 'inherit', }); @@ -83,7 +87,6 @@ describe('nx-quarkus e2e', () => { `should create a quarkus '$projectType' with given options`, async ({ projectType }) => { const prjName = uniq('nx-quarkus'); - const prjDir = projectType === 'application' ? 'apps' : 'libs'; const buildSystem = 'MAVEN'; const groupId = 'com.tinesoft'; const artifactId = 'api'; diff --git a/e2e/nx-spring-boot-e2e/tests/create-nx-spring-boot.spec.ts b/e2e/nx-spring-boot-e2e/tests/create-nx-spring-boot.spec.ts index 27b2e5b3..38dce64c 100644 --- a/e2e/nx-spring-boot-e2e/tests/create-nx-spring-boot.spec.ts +++ b/e2e/nx-spring-boot-e2e/tests/create-nx-spring-boot.spec.ts @@ -1,3 +1,4 @@ +import { getPackageManagerCommand } from '@nx/devkit'; import { hasNxWrapper, isNxWrapperInstalled } from '@nxrocks/common-cli'; import { createCLITestProject } from '@nxrocks/common-jvm/testing'; import { execSync } from 'child_process'; @@ -27,7 +28,7 @@ describe('create-nx-spring-boot', () => { ); // npm ls will fail if the package is not installed properly - execSync('npm ls @nxrocks/nx-spring-boot', { + execSync(`${getPackageManagerCommand().list} @nxrocks/nx-spring-boot`, { cwd: useNxWrapper ? join(projectDirectory, '/.nx/installation') : projectDirectory, diff --git a/e2e/nx-spring-boot-e2e/tests/nx-spring-boot.spec.ts b/e2e/nx-spring-boot-e2e/tests/nx-spring-boot.spec.ts index 3e31c01b..5d1b9623 100644 --- a/e2e/nx-spring-boot-e2e/tests/nx-spring-boot.spec.ts +++ b/e2e/nx-spring-boot-e2e/tests/nx-spring-boot.spec.ts @@ -9,7 +9,7 @@ import { runNxCommandAsync, tmpProjPath, } from '@nxrocks/common-jvm/testing'; -import { names } from '@nx/devkit'; +import { getPackageManagerCommand, names } from '@nx/devkit'; import { lstatSync, rmSync } from 'fs'; import { execSync } from 'child_process'; @@ -22,11 +22,14 @@ describe('nx-spring-boot e2e', () => { // The plugin has been built and published to a local registry in the jest globalSetup // Install the plugin built with the latest source code into the test repo - execSync(`npm install @nxrocks/nx-spring-boot@0.0.0-e2e`, { - cwd: projectDirectory, - stdio: 'inherit', - env: process.env, - }); + execSync( + `${getPackageManagerCommand().install} @nxrocks/nx-spring-boot@0.0.0-e2e`, + { + cwd: projectDirectory, + stdio: 'inherit', + env: process.env, + } + ); }); afterAll(() => { @@ -39,7 +42,7 @@ describe('nx-spring-boot e2e', () => { it('should be installed', () => { // npm ls will fail if the package is not installed properly - execSync('npm ls @nxrocks/nx-spring-boot', { + execSync(`${getPackageManagerCommand().list} @nxrocks/nx-spring-boot`, { cwd: projectDirectory, stdio: 'inherit', }); diff --git a/e2e/smoke/project.json b/e2e/smoke/project.json index 731047ab..0c9e12c9 100644 --- a/e2e/smoke/project.json +++ b/e2e/smoke/project.json @@ -3,14 +3,13 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/smoke/src", "projectType": "application", - "tags": [], + "tags": ["e2e"], "implicitDependencies": [ "nx-spring-boot", "nx-quarkus", "nx-micronaut", "nx-flutter", - "nx-ktor", - "nx-melos" + "nx-ktor" ], "targets": {} } diff --git a/nx.json b/nx.json index ad22e95f..c2adeffc 100644 --- a/nx.json +++ b/nx.json @@ -17,11 +17,12 @@ } }, "version": { - "preVersionCommand": "pnpm dlx nx run-many -t build", + "preVersionCommand": "pnpm nx run-many -t build", "generatorOptions": { "packageRoot": "dist/packages/{projectName}", "currentVersionResolver": "git-tag", - "specifierSource": "conventional-commits" + "specifierSource": "conventional-commits", + "updateDependents": "auto" } } }, @@ -56,7 +57,7 @@ "passWithNoTests": true, "runInBand": true }, - "dependsOn": ["^build"], + "dependsOn": ["nxrocks:populate-local-registry"], "configurations": { "ci": { "ci": true, @@ -69,7 +70,7 @@ "passWithNoTests": true, "runInBand": true }, - "dependsOn": ["^build"], + "dependsOn": ["nxrocks:populate-local-registry"], "configurations": { "ci": { "ci": true, @@ -162,5 +163,8 @@ "sharedGlobals": ["{workspaceRoot}/.nx/workflows/**/**"] }, "defaultBase": "develop", - "useLegacyCache": true + "useLegacyCache": true, + "cli": { + "packageManager": "pnpm" + } } diff --git a/packages/common/testing/e2e/index.ts b/packages/common/testing/e2e/index.ts index ebf9c983..359c6112 100644 --- a/packages/common/testing/e2e/index.ts +++ b/packages/common/testing/e2e/index.ts @@ -1,17 +1,35 @@ -import { JsonParseOptions, PackageManager, detectPackageManager, getPackageManagerCommand, joinPathFragments, parseJson, readJsonFile, workspaceRoot } from '@nx/devkit'; +import { + JsonParseOptions, + PackageManager, + detectPackageManager, + getPackageManagerCommand, + joinPathFragments, + parseJson, + readJsonFile, + workspaceRoot, +} from '@nx/devkit'; import { getPackageLatestNpmVersion } from '../../src/'; import { exec, execSync } from 'child_process'; -import { rmSync, mkdirSync, statSync, readFileSync, existsSync } from 'fs-extra'; +import { + rmSync, + mkdirSync, + statSync, + readFileSync, + existsSync, +} from 'fs-extra'; import { join, dirname, isAbsolute } from 'path'; - export const isWin = process.platform === 'win32'; /** * Creates a test project with create-nx-workspace and installs the plugin * @returns The directory where the test project was created */ -export function createTestProject(pkgManager: PackageManager = 'npm', projectName = 'test-project', workspaceVersion: 'latest' | 'local' = 'local') { +export function createTestProject( + pkgManager: PackageManager = detectPackageManager(), + projectName = 'test-project', + workspaceVersion: 'latest' | 'local' = 'local' +) { const projectDirectory = join(process.cwd(), 'tmp', projectName); // Ensure projectDirectory is empty @@ -23,11 +41,13 @@ export function createTestProject(pkgManager: PackageManager = 'npm', projectNam recursive: true, }); - const nxVersion = workspaceVersion === 'local' ? readLocalNxWorkspaceVersion() : 'latest'; - + const nxVersion = + workspaceVersion === 'local' ? readLocalNxWorkspaceVersion() : 'latest'; const confirm = pkgManager === 'npm' ? ' --yes' : ''; execSync( - `${getPackageManagerCommand(pkgManager).dlx}${confirm} create-nx-workspace@${nxVersion} ${projectName} --preset apps --nxCloud=skip --no-interactive --pm ${pkgManager}`, + `${ + getPackageManagerCommand(pkgManager).dlx + }${confirm} create-nx-workspace@${nxVersion} ${projectName} --preset apps --nxCloud=skip --no-interactive --pm ${pkgManager}`, { cwd: dirname(projectDirectory), stdio: 'inherit', @@ -44,9 +64,15 @@ export function createTestProject(pkgManager: PackageManager = 'npm', projectNam * Creates a test project with create-nx-workspace and installs the plugin * @returns The directory where the test project was created */ -export function createCLITestProject(createPkgName: string, extraArgs = '', createPkgVersion = '0.0.0-e2e', pkgManager: PackageManager = 'npm', projectName = 'test-project') { - +export function createCLITestProject( + createPkgName: string, + extraArgs = '', + createPkgVersion = '0.0.0-e2e', + pkgManager: PackageManager = detectPackageManager(), + projectName = 'test-project' +) { const projectDirectory = join(process.cwd(), 'tmp', projectName); + const confirm = pkgManager === 'npm' ? ' --yes' : ''; // Ensure projectDirectory is empty rmSync(projectDirectory, { @@ -57,17 +83,21 @@ export function createCLITestProject(createPkgName: string, extraArgs = '', crea recursive: true, }); - execSync(`${getPackageManagerCommand(pkgManager).dlx} --yes ${createPkgName}@${createPkgVersion} ${projectName} ${extraArgs}`, { - cwd: dirname(projectDirectory), - stdio: 'inherit', - env: process.env, - }); + execSync( + `${ + getPackageManagerCommand(pkgManager).dlx + }${confirm} ${createPkgName}@${createPkgVersion} ${projectName} ${extraArgs}`, + { + cwd: dirname(projectDirectory), + stdio: 'inherit', + env: process.env, + } + ); console.log(`Created test project in "${projectDirectory}"`); return projectDirectory; } - // Temporary utilities from @nx/plugin/testing package, like `runNxCommandAsync`, `readJson`, etc // Adapted to support the new 'test-project' folder, instead of the default 'nx-e2e' used internally by those methods // (until properly updated/published By Nx ?) @@ -104,7 +134,6 @@ function exists(filePath: string): boolean { return directoryExists(filePath) || fileExists(filePath); } - //https://github.com/nrwl/nx/blob/master/e2e/utils/create-project-utils.ts#L628 /** @@ -150,8 +179,10 @@ export function runNxCommandAsync( ): Promise<{ stdout: string; stderr: string }> { const cwd = opts.cwd ?? tmpProjPath(); if (fileExists(tmpProjPath('package.json'))) { - const pmc = getPackageManagerCommand(pkgManager || detectPackageManager(cwd)); - return runCommandAsync(`${pmc.exec} nx ${command}`, opts); + const pmc = getPackageManagerCommand( + pkgManager || detectPackageManager(cwd) + ); + return runCommandAsync(`${pmc.dlx} nx ${command}`, opts); } else if (process.platform === 'win32') { return runCommandAsync(`./nx.bat %${command}`, opts); } else { @@ -170,13 +201,14 @@ export async function runNxCommand( opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv; cwd?: string } = { silenceError: false, } -): Promise<{ stdout: string; stderr: string; }> { - - return await runNxCommandAsync(command,pkgManager, opts); - +): Promise<{ stdout: string; stderr: string }> { + return await runNxCommandAsync(command, pkgManager, opts); } -export function readJson(path: string, options?: JsonParseOptions): T { +export function readJson( + path: string, + options?: JsonParseOptions +): T { return parseJson(readFile(path), options); } @@ -186,7 +218,7 @@ export function readFile(path: string): string { } export function getLatestNxWorkspaceVersion(): string { - return getPackageLatestNpmVersion("nx"); + return getPackageLatestNpmVersion('nx'); } export function readLocalNxWorkspaceVersion(): string { @@ -197,7 +229,7 @@ export function readLocalNxWorkspaceVersion(): string { ); } - return readJsonFile(pkgJsonPath).devDependencies["nx"]; + return readJsonFile(pkgJsonPath).devDependencies['nx']; } /** @@ -208,5 +240,8 @@ export function isLocalNxMatchingLatestFeatureVersion() { const localNxVersion = readLocalNxWorkspaceVersion().split('.'); const latestNxVersion = getLatestNxWorkspaceVersion().split('.'); - return localNxVersion[0] === latestNxVersion[0] && localNxVersion[1] === latestNxVersion?.[1]; -} \ No newline at end of file + return ( + localNxVersion[0] === latestNxVersion[0] && + localNxVersion[1] === latestNxVersion?.[1] + ); +} diff --git a/project.json b/project.json index 1888954a..d604cd22 100644 --- a/project.json +++ b/project.json @@ -5,9 +5,17 @@ "local-registry": { "executor": "@nx/js:verdaccio", "options": { + "port": 4873, + "listenAddress": "0.0.0.0", "config": ".verdaccio/config.yml", "storage": "tmp/local-registry/storage" } + }, + "populate-local-registry": { + "cache": true, + "inputs": ["production"], + "command": "ts-node -P ./tools/tsconfig.tools.json ./tools/scripts/populate-local-registry.ts", + "outputs": ["{workspaceRoot}/tmp/local-registry/storage"] } } } diff --git a/tools/scripts/populate-local-registry.ts b/tools/scripts/populate-local-registry.ts new file mode 100644 index 00000000..0705d071 --- /dev/null +++ b/tools/scripts/populate-local-registry.ts @@ -0,0 +1,45 @@ +/** + * This script starts a local registry, populates it by installing packages,then stop the registry. + * It is meant to allows reusing that storage when running e2e tasks later on. + */ +import { startLocalRegistry } from '@nx/js/plugins/jest/local-registry'; +import { startLocalRelease } from './start-local-registry'; + +(async () => { + + // local registry target to run + const localRegistryTarget = 'nxrocks:local-registry'; + // storage folder for the local registry + const storage = './tmp/local-registry/storage'; + + const isVerbose = process.env.NX_VERBOSE_LOGGING === 'true'; + + let stopLocalRegistry; + + try { + stopLocalRegistry = await startLocalRegistry({ + localRegistryTarget, + storage, + verbose: isVerbose, + listenAddress: '0.0.0.0', + }); + + console.log('Publishing packages to local registry to populate storage...'); + + await startLocalRelease(isVerbose); + + stopLocalRegistry(); + + console.log('Killed local registry process'); + process.exit(); + } catch (err) { + // Clean up registry if possible after setup related errors + if (typeof stopLocalRegistry === 'function') { + stopLocalRegistry(); + console.log('Killed local registry process due to an error during setup'); + } + + console.error('Error:', err); + process.exit(1); + } +})(); diff --git a/tools/scripts/run-all-e2e-tests.ts b/tools/scripts/run-all-e2e-tests.ts index 2bd6fa33..950abfe5 100644 --- a/tools/scripts/run-all-e2e-tests.ts +++ b/tools/scripts/run-all-e2e-tests.ts @@ -4,17 +4,14 @@ import stopRegistry from './stop-local-registry'; (async () => { - + await startLocalRegistry(); const nx = require.resolve('nx'); execFileSync( nx, ['affected', '-t', 'e2e', '--runInBand', '--exclude', 'smoke'], { - env: { - ...process.env, - 'SKIP_LOCAL_REGISTRY_GLOBAL_SETUP': 'true', - }, stdio: 'inherit' + stdio: 'inherit' } ); diff --git a/tools/scripts/start-local-registry.ts b/tools/scripts/start-local-registry.ts index 7a5a3b75..99f00942 100644 --- a/tools/scripts/start-local-registry.ts +++ b/tools/scripts/start-local-registry.ts @@ -4,29 +4,58 @@ */ import { startLocalRegistry } from '@nx/js/plugins/jest/local-registry'; import { releasePublish, releaseVersion } from 'nx/release'; +import { readdirSync } from 'fs'; +import { joinPathFragments, workspaceRoot } from '@nx/devkit'; + +function isFolderEmptySync(folderPath: string): boolean { + try { + const files = readdirSync(folderPath); + const relevantFiles = files.filter(file => file !== '.verdaccio-db.json'); + return relevantFiles.length === 0; + } catch (error) { + console.error('Error checking folder:', error); + throw error; + } +} export default async () => { - if ( - process.env.SKIP_LOCAL_REGISTRY_GLOBAL_SETUP && - process.env.SKIP_LOCAL_REGISTRY_GLOBAL_SETUP !== 'false' - ) { - console.log( - "Environment variable 'SKIP_LOCAL_REGISTRY_GLOBAL_SETUP' is set. Skipping global setup of Verdaccio's Local Registry..." - ); - return; - } // local registry target to run const localRegistryTarget = 'nxrocks:local-registry'; // storage folder for the local registry - const storage = './tmp/local-registry/storage'; + const storage = joinPathFragments( + workspaceRoot, + 'tmp/local-registry/storage', + ); + + const isVerbose = process.env.NX_VERBOSE_LOGGING === 'true'; + + /** + * We populate the verdaccio storage up front, so we only need to start the local registry and serves that storage. + * Otherwise, if the storage is empty, we do a full release to populate it again. This allows speeding up e2e tests + */ + const requiresLocalRelease = isFolderEmptySync(storage); global.stopLocalRegistry = await startLocalRegistry({ localRegistryTarget, storage, - verbose: false, + verbose: isVerbose, + clearStorage: requiresLocalRelease, + listenAddress: '0.0.0.0', }); + if (requiresLocalRelease) { + console.log('>>> Started the local registry, with local release'); + + await startLocalRelease(isVerbose); + } + else { + console.log('>>> Started the local registry, but no local release was perfomed') + } +}; + +export async function startLocalRelease(isVerbose=false) { + await releaseVersion({ specifier: '0.0.0-e2e', stageChanges: false, @@ -34,11 +63,16 @@ export default async () => { gitTag: false, firstRelease: true, generatorOptionsOverrides: { - skipLockFileUpdate: true, + "packageRoot": "{workspaceRoot}/dist/packages/{projectName}", + "currentVersionResolver": "git-tag", + "fallbackCurrentVersionResolver": "registry", + "specifierSource": "conventional-commits", }, + verbose: isVerbose, }); await releasePublish({ tag: 'e2e', firstRelease: true, + verbose: isVerbose, }); -}; +} \ No newline at end of file diff --git a/tools/scripts/stop-local-registry.ts b/tools/scripts/stop-local-registry.ts index 7df2ae80..a2fa0da1 100644 --- a/tools/scripts/stop-local-registry.ts +++ b/tools/scripts/stop-local-registry.ts @@ -4,11 +4,7 @@ */ export default () => { - if(process.env.SKIP_LOCAL_REGISTRY_GLOBAL_SETUP && process.env.SKIP_LOCAL_REGISTRY_GLOBAL_SETUP !== 'false') { - console.log("\nEnvironment variable 'SKIP_LOCAL_REGISTRY_GLOBAL_SETUP' is set. Skipping global teardown of Verdaccio's Local Registry..."); - return; - } - + if (global.stopLocalRegistry) { global.stopLocalRegistry(); }