diff --git a/.codex/environments/environment.toml b/.codex/environments/environment.toml new file mode 100644 index 0000000..b0859cd --- /dev/null +++ b/.codex/environments/environment.toml @@ -0,0 +1,6 @@ +# THIS IS AUTOGENERATED. DO NOT EDIT MANUALLY +version = 1 +name = "nx-forge" + +[setup] +script = "npm i" diff --git a/e2e/nx-forge-e2e/project.json b/e2e/nx-forge-e2e/project.json index 64c89b3..3107257 100644 --- a/e2e/nx-forge-e2e/project.json +++ b/e2e/nx-forge-e2e/project.json @@ -7,10 +7,9 @@ "e2e": { "executor": "@nx/jest:jest", "options": { - "jestConfig": "e2e/nx-forge-e2e/jest.config.js", - "runInBand": true + "jestConfig": "e2e/nx-forge-e2e/jest.config.js" }, - "dependsOn": ["nx-forge:build"] + "dependsOn": ["^build"] } }, "tags": [], diff --git a/e2e/nx-forge-e2e/src/application.generator.spec.ts b/e2e/nx-forge-e2e/src/application.generator.spec.ts new file mode 100644 index 0000000..c818c87 --- /dev/null +++ b/e2e/nx-forge-e2e/src/application.generator.spec.ts @@ -0,0 +1,78 @@ +import { existsSync, readFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { generateForgeApp } from './utils/generate-forge-app'; +import { runNxCommandAsync } from './utils/async-commands'; +import { cleanupTestProject, createTestProject } from './utils/test-project'; + +describe('Forge application generator', () => { + let projectDirectory: string; + + beforeAll(() => { + projectDirectory = createTestProject(); + }); + + afterAll(async () => { + try { + if (projectDirectory) { + await runNxCommandAsync('reset', { cwd: projectDirectory }); + } + } finally { + cleanupTestProject(projectDirectory); + } + }); + + it('should generate a Forge app', async () => { + const appName = await generateForgeApp({ + cwd: projectDirectory, + directory: 'apps', + options: '--bundler=webpack', + }); + expect( + existsSync(join(projectDirectory, 'apps', appName, 'manifest.yml')) + ).toBe(true); + expect( + existsSync(join(projectDirectory, 'apps', appName, 'webpack.config.js')) + ).toBe(true); + expect( + existsSync(join(projectDirectory, 'apps', appName, 'src', 'index.ts')) + ).toBe(true); + }); + + describe('--directory', () => { + it('should generate a Forge app in the specified directory', async () => { + const subdir = 'subdir'; + const appName = await generateForgeApp({ + cwd: projectDirectory, + directory: subdir, + options: `--bundler=webpack`, + }); + + expect( + existsSync(join(projectDirectory, subdir, appName, 'manifest.yml')) + ).toBe(true); + expect( + existsSync(join(projectDirectory, subdir, appName, 'webpack.config.js')) + ).toBe(true); + expect( + existsSync(join(projectDirectory, subdir, appName, 'src', 'index.ts')) + ).toBe(true); + }); + }); + + describe('--tags', () => { + it('should generate a Forge app with tags added to the project', async () => { + const appName = await generateForgeApp({ + cwd: projectDirectory, + directory: 'apps', + options: `--tags e2etag,e2ePackage`, + }); + const project = JSON.parse( + readFileSync( + join(projectDirectory, 'apps', appName, 'project.json'), + 'utf8' + ) + ); + expect(project.tags).toEqual(['e2etag', 'e2ePackage']); + }); + }); +}); diff --git a/e2e/nx-forge-e2e/src/basic-setup.spec.ts b/e2e/nx-forge-e2e/src/basic-setup.spec.ts new file mode 100644 index 0000000..26e4960 --- /dev/null +++ b/e2e/nx-forge-e2e/src/basic-setup.spec.ts @@ -0,0 +1,183 @@ +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { GraphQLClient } from 'graphql-request'; +import { generateForgeApp } from './utils/generate-forge-app'; +import { + Credentials, + ForgeInstallationContext, + getCredentials, + getDeveloperSpaceId, + getForgeInstallationContext, +} from './utils/config'; +import { createClient, deleteApp } from './utils/atlassian-graphql-client'; +import { + runCommandAsync, + runForgeCommandAsync, + runNxCommandAsync, +} from './utils/async-commands'; +import { + cleanupTestProject, + createTestProject, +} from './utils/test-project'; +import stripAnsi = require('strip-ansi'); + +describe('Forge lifecycle', () => { + // initialize before all tests + let projectDirectory: string; + let developerCredentials: Credentials; + let apiClient: GraphQLClient; + let installationContext: ForgeInstallationContext; + let developerSpaceId: string; + + beforeAll(async () => { + projectDirectory = createTestProject(); + developerCredentials = getCredentials(); + apiClient = createClient(developerCredentials); + installationContext = getForgeInstallationContext(); + developerSpaceId = getDeveloperSpaceId(); + + // Initialize the Forge CLI, otherwise commands may fail due to expected interactive input + await runCommandAsync(`npx forge settings set usage-analytics false`, { + cwd: projectDirectory, + silenceError: true, + }); + }); + + afterAll(async () => { + try { + if (projectDirectory) { + await runNxCommandAsync('reset', { cwd: projectDirectory }); + } + } finally { + cleanupTestProject(projectDirectory); + } + }); + + it('should generate, build, package, register, deploy and install a Forge app', async () => { + const appName = await generateForgeApp({ + cwd: projectDirectory, + directory: 'apps', + }); + + // Build + + const nxBuildResult = await runNxCommandAsync(`run ${appName}:build`, { + cwd: projectDirectory, + silenceError: true, + }); + expect(nxBuildResult.stderr).toEqual(''); + expect(stripAnsi(nxBuildResult.stdout)).toContain( + 'Successfully ran target build for project' + ); + + // Package + + const nxPackageResult = await runNxCommandAsync(`run ${appName}:package`, { + cwd: projectDirectory, + }); + expect(nxPackageResult.stderr).toEqual(''); + expect(stripAnsi(nxPackageResult.stdout)).toEqual( + expect.stringContaining('Successfully ran target package for project') + ); + + // Register + + const unregisteredOutputManifestContent = readFileSync( + join(projectDirectory, 'dist', 'apps', appName, 'manifest.yml'), + 'utf8' + ); + expect(unregisteredOutputManifestContent).toContain( + 'ari:cloud:ecosystem::app/to-be-generated' + ); + + const nxRegisterResult = await runNxCommandAsync( + `run ${appName}:register --accept-terms --developer-space-id ${developerSpaceId}`, + { + cwd: projectDirectory, + silenceError: true, + } + ); + expect(nxRegisterResult.stderr).toEqual(''); + expect(stripAnsi(nxRegisterResult.stdout)).toContain( + 'Forge app registered' + ); + + // ari:cloud:ecosystem::app/ + const registeredAppIdRegex = + /ari:cloud:ecosystem::app\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/; + + const registeredOutputManifestContent = readFileSync( + join(projectDirectory, 'dist', 'apps', appName, 'manifest.yml'), + 'utf8' + ); + const [registeredAppId] = + registeredOutputManifestContent.match(registeredAppIdRegex) ?? []; + expect(registeredAppId).not.toBeNull(); + expect(registeredAppId).toBeDefined(); + expect(registeredAppId).not.toEqual(''); + + const projectManifestContent = readFileSync( + join(projectDirectory, 'apps', appName, 'manifest.yml'), + 'utf8' + ); + expect(projectManifestContent).toContain(registeredAppId); + + try { + // Deploy + + // Run with `--no-verfiy` because the generated blank app template causes linting errors + const nxDeployResult = await runNxCommandAsync( + `run ${appName}:deploy --no-verify`, + { + cwd: projectDirectory, + silenceError: true, + } + ); + expect(nxDeployResult.stderr).toEqual(''); + expect(stripAnsi(nxDeployResult.stdout)).toContain('Forge app deployed'); + + // Install using Forge CLI + + const installResult = await runForgeCommandAsync( + `install --product=${installationContext.product} --site=${installationContext.siteUrl} --environment ${installationContext.environment} --non-interactive`, + { + cwd: join(projectDirectory, 'dist', 'apps', appName), + silenceError: true, + } + ); + expect(installResult.stderr).toEqual(''); + expect(stripAnsi(installResult.stdout)).toMatch(/Install.*complete/); + } finally { + if (registeredAppId) { + try { + await runForgeCommandAsync( + `uninstall --product=${installationContext.product} --site=${installationContext.siteUrl} --environment ${installationContext.environment} --non-interactive`, + { + cwd: join(projectDirectory, 'dist', 'apps', appName), + silenceError: true, + } + ); + } catch (error) { + console.warn( + `Failed to uninstall Forge app ${registeredAppId}`, + error + ); + } + + try { + const result = await deleteApp(registeredAppId)(apiClient); + if (!result.success) { + console.warn( + `Failed to delete registered app ${registeredAppId}: ${result.errors}` + ); + } + } catch (error) { + console.warn( + `Failed to delete registered app ${registeredAppId}`, + error + ); + } + } + } + }); +}); diff --git a/e2e/nx-forge-e2e/tests/utils/async-commands.ts b/e2e/nx-forge-e2e/src/utils/async-commands.ts similarity index 77% rename from e2e/nx-forge-e2e/tests/utils/async-commands.ts rename to e2e/nx-forge-e2e/src/utils/async-commands.ts index 737c4a6..2827c91 100644 --- a/e2e/nx-forge-e2e/tests/utils/async-commands.ts +++ b/e2e/nx-forge-e2e/src/utils/async-commands.ts @@ -1,9 +1,5 @@ import { exec } from 'child_process'; -import { - detectPackageManager, - getPackageManagerCommand, -} from '@nx/devkit'; -import { tmpProjPath } from '@nx/plugin/testing'; +import { detectPackageManager, getPackageManagerCommand } from '@nx/devkit'; const getCommandEnv = (env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv => { const commandEnv = { ...process.env, ...env }; @@ -17,7 +13,7 @@ const getCommandEnv = (env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv => { }; /** - * Runs the given command asynchronously inside the e2e directory (if cwd is not provided). + * Runs the given command asynchronously inside the provided working directory. * * This is a local re-implementation of the helper from `@nx/plugin/testing` * so the e2e suite can control the child process environment. @@ -32,15 +28,13 @@ const getCommandEnv = (env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv => { */ export const runCommandAsync = ( command: string, - opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv; cwd?: string } = { - silenceError: false, - } + opts: { cwd: string; silenceError?: boolean; env?: NodeJS.ProcessEnv } ): Promise<{ stdout: string; stderr: string }> => { return new Promise((resolve, reject) => { exec( command, { - cwd: opts.cwd ?? tmpProjPath(), + cwd: opts.cwd, env: getCommandEnv(opts.env), windowsHide: true, }, @@ -55,7 +49,7 @@ export const runCommandAsync = ( }; /** - * Runs an Nx command asynchronously inside the e2e directory. + * Runs an Nx command asynchronously inside the provided working directory. * * This mirrors `runNxCommandAsync` from `@nx/plugin/testing`, but delegates to * the local `runCommandAsync` above so the same NO_COLOR cleanup is applied to @@ -65,21 +59,17 @@ export const runCommandAsync = ( */ export const runNxCommandAsync = ( command: string, - opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv; cwd?: string } = { - silenceError: false, - } + opts: { cwd: string; silenceError?: boolean; env?: NodeJS.ProcessEnv } ): Promise<{ stdout: string; stderr: string }> => { - const cwd = opts.cwd ?? tmpProjPath(); - const pmc = getPackageManagerCommand(detectPackageManager(cwd)); + const pmc = getPackageManagerCommand(detectPackageManager(opts.cwd)); return runCommandAsync(`${pmc.exec} nx ${command}`, { ...opts, - cwd, }); }; /** - * Runs the given Forge CLI command asynchronously inside the e2e directory (if cwd is not provided). + * Runs the given Forge CLI command asynchronously inside the provided working directory. * * Note that this implementation is only meant to be used in testing code. It is using `exec` * to run the Forge CLI command. `exec` returns `stdout` and `stderr` as strings which is convenient @@ -93,16 +83,14 @@ export const runNxCommandAsync = ( */ export const runForgeCommandAsync = ( command: string, - opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv; cwd?: string } = { - silenceError: false, - } + opts: { cwd: string; silenceError?: boolean; env?: NodeJS.ProcessEnv } ): Promise<{ stdout: string; stderr: string }> => { const pmc = getPackageManagerCommand(); return new Promise((resolve, reject) => { exec( `${pmc.exec} forge ${command}`, { - cwd: opts.cwd ?? tmpProjPath(), + cwd: opts.cwd, env: getCommandEnv(opts.env), }, (err, stdout, stderr) => { diff --git a/e2e/nx-forge-e2e/tests/utils/atlassian-graphql-client.ts b/e2e/nx-forge-e2e/src/utils/atlassian-graphql-client.ts similarity index 100% rename from e2e/nx-forge-e2e/tests/utils/atlassian-graphql-client.ts rename to e2e/nx-forge-e2e/src/utils/atlassian-graphql-client.ts diff --git a/e2e/nx-forge-e2e/tests/utils/config.ts b/e2e/nx-forge-e2e/src/utils/config.ts similarity index 100% rename from e2e/nx-forge-e2e/tests/utils/config.ts rename to e2e/nx-forge-e2e/src/utils/config.ts diff --git a/e2e/nx-forge-e2e/tests/utils/generate-forge-app.ts b/e2e/nx-forge-e2e/src/utils/generate-forge-app.ts similarity index 79% rename from e2e/nx-forge-e2e/tests/utils/generate-forge-app.ts rename to e2e/nx-forge-e2e/src/utils/generate-forge-app.ts index bb317d0..6d589c5 100644 --- a/e2e/nx-forge-e2e/tests/utils/generate-forge-app.ts +++ b/e2e/nx-forge-e2e/src/utils/generate-forge-app.ts @@ -1,6 +1,8 @@ -import { uniq } from '@nx/plugin/testing'; import { runNxCommandAsync } from './async-commands'; +const uniqueAppName = () => + `nx-forge-test-app-${Date.now()}-${Math.floor(Math.random() * 100000)}`; + /** * Generates a Forge app with a unique name to avoid clashes between tests running in parallel. * @@ -11,17 +13,20 @@ import { runNxCommandAsync } from './async-commands'; * @returns Name of the generated Forge app. */ export const generateForgeApp = async ({ + cwd, directory, options, }: { + cwd: string; directory: string; options?: string; }): Promise => { - const appName = uniq('nx-forge-test-app-'); + const appName = uniqueAppName(); await runNxCommandAsync( `generate @toolsplus/nx-forge:application ${directory}/${appName} ${ options ?? '' - }` + }`, + { cwd } ); return appName; }; diff --git a/e2e/nx-forge-e2e/src/utils/test-project.ts b/e2e/nx-forge-e2e/src/utils/test-project.ts new file mode 100644 index 0000000..793d619 --- /dev/null +++ b/e2e/nx-forge-e2e/src/utils/test-project.ts @@ -0,0 +1,57 @@ +import { execSync } from 'node:child_process'; +import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { dirname, join } from 'node:path'; + +const TEST_PROJECTS_ROOT = join(process.cwd(), 'tmp'); + +const runCommand = (command: string, cwd: string) => { + execSync(command, { + cwd, + stdio: 'inherit', + env: process.env, + windowsHide: true, + }); +}; + +const uniqueProjectName = () => + `test-project-${Date.now()}-${Math.floor(Math.random() * 100000)}`; + +export const createTestProject = (projectName = uniqueProjectName()): string => { + const projectDirectory = join(TEST_PROJECTS_ROOT, projectName); + + rmSync(projectDirectory, { + recursive: true, + force: true, + }); + mkdirSync(dirname(projectDirectory), { + recursive: true, + }); + + runCommand( + `npx -y create-nx-workspace@latest ${projectName} --preset=apps --nxCloud=skip --packageManager=npm --no-interactive`, + TEST_PROJECTS_ROOT + ); + + const nxJsonPath = join(projectDirectory, 'nx.json'); + const nxJson = JSON.parse(readFileSync(nxJsonPath, 'utf8')); + nxJson.analytics = false; + writeFileSync(nxJsonPath, JSON.stringify(nxJson, null, 2) + '\n', 'utf8'); + + runCommand( + 'npx nx add @toolsplus/nx-forge@e2e --interactive=false', + projectDirectory + ); + + return projectDirectory; +}; + +export const cleanupTestProject = (projectDirectory?: string) => { + if (!projectDirectory) { + return; + } + + rmSync(projectDirectory, { + recursive: true, + force: true, + }); +}; diff --git a/e2e/nx-forge-e2e/tests/application.generator.spec.ts b/e2e/nx-forge-e2e/tests/application.generator.spec.ts deleted file mode 100644 index 8365c4d..0000000 --- a/e2e/nx-forge-e2e/tests/application.generator.spec.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { - checkFilesExist, - ensureNxProject, - readJson, -} from '@nx/plugin/testing'; -import { generateForgeApp } from './utils/generate-forge-app'; -import { ensureCorrectWorkspaceRoot } from './utils/e2e-workspace'; -import { runNxCommandAsync } from './utils/async-commands'; - -describe('Forge application generator', () => { - beforeAll(() => { - ensureNxProject('@toolsplus/nx-forge', 'dist/packages/nx-forge'); - ensureCorrectWorkspaceRoot(); - }); - - afterAll(async () => { - // `nx reset` kills the daemon, and performs - // some work which can help clean up e2e leftovers - await runNxCommandAsync('reset'); - }); - - it('should generate a Forge app', async () => { - const appName = await generateForgeApp({ - directory: 'apps', - options: '--bundler=webpack', - }); - expect(() => checkFilesExist(`apps/${appName}/manifest.yml`)).not.toThrow(); - expect(() => - checkFilesExist(`apps/${appName}/webpack.config.js`) - ).not.toThrow(); - expect(() => checkFilesExist(`apps/${appName}/src/index.ts`)).not.toThrow(); - }); - - describe('--directory', () => { - it('should generate a Forge app in the specified directory', async () => { - const subdir = 'subdir'; - const appName = await generateForgeApp({ - directory: subdir, - options: `--bundler=webpack`, - }); - - expect(() => - checkFilesExist(`${subdir}/${appName}/manifest.yml`) - ).not.toThrow(); - expect(() => - checkFilesExist(`${subdir}/${appName}/webpack.config.js`) - ).not.toThrow(); - expect(() => - checkFilesExist(`${subdir}/${appName}/src/index.ts`) - ).not.toThrow(); - }); - }); - - describe('--tags', () => { - it('should generate a Forge app with tags added to the project', async () => { - const appName = await generateForgeApp({ - directory: 'apps', - options: `--tags e2etag,e2ePackage`, - }); - const project = readJson(`apps/${appName}/project.json`); - expect(project.tags).toEqual(['e2etag', 'e2ePackage']); - }); - }); -}); diff --git a/e2e/nx-forge-e2e/tests/basic-setup.spec.ts b/e2e/nx-forge-e2e/tests/basic-setup.spec.ts deleted file mode 100644 index 5a9e24d..0000000 --- a/e2e/nx-forge-e2e/tests/basic-setup.spec.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { - ensureNxProject, - readFile, - tmpProjPath, -} from '@nx/plugin/testing'; -import { GraphQLClient } from 'graphql-request'; -import { ensureCorrectWorkspaceRoot } from './utils/e2e-workspace'; -import { generateForgeApp } from './utils/generate-forge-app'; -import { - Credentials, - ForgeInstallationContext, - getCredentials, - getDeveloperSpaceId, - getForgeInstallationContext, -} from './utils/config'; -import { createClient, deleteApp } from './utils/atlassian-graphql-client'; -import { - runCommandAsync, - runForgeCommandAsync, - runNxCommandAsync, -} from './utils/async-commands'; -import { joinPathFragments } from '@nx/devkit'; -import stripAnsi = require('strip-ansi'); - -describe('basic setup', () => { - // initialize before all tests - let developerCredentials: Credentials; - let apiClient: GraphQLClient; - let installationContext: ForgeInstallationContext; - let developerSpaceId: string; - - beforeAll(async () => { - ensureNxProject('@toolsplus/nx-forge', 'dist/packages/nx-forge'); - ensureCorrectWorkspaceRoot(); - developerCredentials = getCredentials(); - apiClient = createClient(developerCredentials); - installationContext = getForgeInstallationContext(); - developerSpaceId = getDeveloperSpaceId(); - - // Initialize the Forge CLI, otherwise commands may fail due to expected interactive input - await runCommandAsync(`npx forge settings set usage-analytics false`, { - silenceError: true, - }); - }); - - afterAll(async () => { - // `nx reset` kills the daemon, and performs - // some work which can help clean up e2e leftovers - await runNxCommandAsync('reset'); - }); - - it('should generate, build, package, register, deploy and install a Forge app', async () => { - const appName = await generateForgeApp({ directory: 'apps' }); - - // Build - - const nxBuildResult = await runNxCommandAsync(`run ${appName}:build`, { - silenceError: true, - }); - expect(nxBuildResult.stderr).toEqual(''); - expect(stripAnsi(nxBuildResult.stdout)).toContain( - 'Successfully ran target build for project' - ); - - // Package - - const nxPackageResult = await runNxCommandAsync(`run ${appName}:package`); - expect(nxPackageResult.stderr).toEqual(''); - expect(stripAnsi(nxPackageResult.stdout)).toEqual( - expect.stringContaining('Successfully ran target package for project') - ); - - // Register - - const unregisteredOutputManifestContent = readFile( - `dist/apps/${appName}/manifest.yml` - ); - expect(unregisteredOutputManifestContent).toContain( - 'ari:cloud:ecosystem::app/to-be-generated' - ); - - const nxRegisterResult = await runNxCommandAsync( - `run ${appName}:register --accept-terms --developer-space-id ${developerSpaceId}`, - { - silenceError: true, - } - ); - expect(nxRegisterResult.stderr).toEqual(''); - expect(stripAnsi(nxRegisterResult.stdout)).toContain( - 'Forge app registered' - ); - - // ari:cloud:ecosystem::app/ - const registeredAppIdRegex = - /ari:cloud:ecosystem::app\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/; - - const registeredOutputManifestContent = readFile( - `dist/apps/${appName}/manifest.yml` - ); - const [appId] = - registeredOutputManifestContent.match(registeredAppIdRegex) ?? []; - expect(appId).not.toBeNull(); - expect(appId).toBeDefined(); - expect(appId).not.toEqual(''); - - const projectManifestContent = readFile(`apps/${appName}/manifest.yml`); - expect(projectManifestContent).toContain(appId); - - // Deploy - - // Run with `--no-verfiy` because the generated blank app template causes linting errors - const nxDeployResult = await runNxCommandAsync( - `run ${appName}:deploy --no-verify`, - { - silenceError: true, - } - ); - expect(nxDeployResult.stderr).toEqual(''); - expect(stripAnsi(nxDeployResult.stdout)).toContain('Forge app deployed'); - - // Install using Forge CLI - - const installResult = await runForgeCommandAsync( - `install --product=${installationContext.product} --site=${installationContext.siteUrl} --environment ${installationContext.environment} --non-interactive`, - { - cwd: joinPathFragments(tmpProjPath(), 'dist', 'apps', appName), - silenceError: true, - } - ); - expect(installResult.stderr).toEqual(''); - expect(stripAnsi(installResult.stdout)).toMatch(/Install.*complete/); - - // Clean up - const uninstallResult = await runForgeCommandAsync( - `uninstall --product=${installationContext.product} --site=${installationContext.siteUrl} --environment ${installationContext.environment}`, - { - cwd: joinPathFragments(tmpProjPath(), 'dist', 'apps', appName), - silenceError: true, - } - ); - expect(uninstallResult.stderr).toEqual(''); - expect(stripAnsi(uninstallResult.stdout)).toContain('Uninstalled'); - - const result = await deleteApp(appId)(apiClient); - if (!result.success) { - throw new Error( - `Failed to clean up registered app with id ${appId}: ${result.errors}` - ); - } - }); -}); diff --git a/e2e/nx-forge-e2e/tests/utils/e2e-workspace.ts b/e2e/nx-forge-e2e/tests/utils/e2e-workspace.ts deleted file mode 100644 index 48307da..0000000 --- a/e2e/nx-forge-e2e/tests/utils/e2e-workspace.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { writeFileSync } from 'fs'; -import { joinPathFragments } from '@nx/devkit'; -import { tmpProjPath } from '@nx/plugin/testing'; - -/** - * Set Nx workspace root path via environment variable. - * - * This can be removed once the related issue with e2e tests is fixed. - * - * @see https://github.com/nrwl/nx/issues/5065 - * @see https://github.com/nrwl/nx/issues/5065#issuecomment-834367298 - * @see https://nrwlcommunity.slack.com/archives/CMFKWPU6Q/p1648642872807809 - */ -export const ensureCorrectWorkspaceRoot = () => { - writeFileSync( - joinPathFragments(tmpProjPath(), '.local.env'), - `NX_WORKSPACE_ROOT_PATH=${tmpProjPath()}`, - { - encoding: 'utf8', - } - ); -}; diff --git a/packages/nx-forge/project.json b/packages/nx-forge/project.json index 0e8fa53..976ed35 100644 --- a/packages/nx-forge/project.json +++ b/packages/nx-forge/project.json @@ -3,7 +3,21 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/nx-forge/src", "tags": [], + "release": { + "version": { + "manifestRootsToUpdate": ["dist/{projectRoot}"], + "currentVersionResolver": "git-tag", + "fallbackCurrentVersionResolver": "disk" + } + }, "targets": { + "nx-release-publish": { + "executor": "@nx/js:release-publish", + "dependsOn": ["^nx-release-publish"], + "options": { + "packageRoot": "dist/{projectRoot}" + } + }, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"],