diff --git a/e2e/nx-misc/src/misc.test.ts b/e2e/nx-misc/src/misc.test.ts index ab6869c97e..46e8a843f5 100644 --- a/e2e/nx-misc/src/misc.test.ts +++ b/e2e/nx-misc/src/misc.test.ts @@ -1,6 +1,7 @@ import type { NxJsonConfiguration } from '@nx/devkit'; import { cleanupProject, + createNonNxProjectDirectory, e2eCwd, getPackageManagerCommand, getPublishedVersion, @@ -588,8 +589,6 @@ describe('global installation', () => { let oldPath: string; beforeAll(() => { - newProject(); - ensureDirSync(globalsPath); writeFileSync( path.join(path.dirname(path.dirname(globalsPath)), 'package.json'), @@ -618,66 +617,95 @@ describe('global installation', () => { process.env.PATH = oldPath; }); - it('should invoke Nx commands from local repo', () => { - const nxJsContents = readFile('node_modules/nx/bin/nx.js'); - updateFile('node_modules/nx/bin/nx.js', `console.log('local install');`); - let output: string; - expect(() => { - output = runCommand(`nx show projects`); - }).not.toThrow(); - expect(output).toContain('local install'); - updateFile('node_modules/nx/bin/nx.js', nxJsContents); + describe('inside nx directory', () => { + beforeAll(() => { + newProject(); + }); + + it('should invoke Nx commands from local repo', () => { + const nxJsContents = readFile('node_modules/nx/bin/nx.js'); + updateFile('node_modules/nx/bin/nx.js', `console.log('local install');`); + let output: string; + expect(() => { + output = runCommand(`nx show projects`); + }).not.toThrow(); + expect(output).toContain('local install'); + updateFile('node_modules/nx/bin/nx.js', nxJsContents); + }); + + it('should warn if local Nx has higher major version', () => { + const packageJsonContents = readFile('node_modules/nx/package.json'); + updateJson('node_modules/nx/package.json', (json) => { + json.version = `${major(getPublishedVersion()) + 2}.0.0`; + return json; + }); + let output: string; + expect(() => { + output = runCommand(`nx show projects`); + }).not.toThrow(); + expect(output).toContain('Its time to update Nx'); + updateFile('node_modules/nx/package.json', packageJsonContents); + }); + + it('--version should display global installs version', () => { + const packageJsonContents = readFile('node_modules/nx/package.json'); + const localVersion = `${major(getPublishedVersion()) + 2}.0.0`; + updateJson('node_modules/nx/package.json', (json) => { + json.version = localVersion; + return json; + }); + let output: string; + expect(() => { + output = runCommand(`nx --version`); + }).not.toThrow(); + expect(output).toContain(`- Local: v${localVersion}`); + expect(output).toContain(`- Global: v${getPublishedVersion()}`); + updateFile('node_modules/nx/package.json', packageJsonContents); + }); + + it('report should display global installs version', () => { + const packageJsonContents = readFile('node_modules/nx/package.json'); + const localVersion = `${major(getPublishedVersion()) + 2}.0.0`; + updateJson('node_modules/nx/package.json', (json) => { + json.version = localVersion; + return json; + }); + let output: string; + expect(() => { + output = runCommand(`nx report`); + }).not.toThrow(); + expect(output).toEqual( + expect.stringMatching(new RegExp(`nx.*:.*${localVersion}`)) + ); + expect(output).toEqual( + expect.stringMatching( + new RegExp(`nx \\(global\\).*:.*${getPublishedVersion()}`) + ) + ); + updateFile('node_modules/nx/package.json', packageJsonContents); + }); }); - it('should warn if local Nx has higher major version', () => { - const packageJsonContents = readFile('node_modules/nx/package.json'); - updateJson('node_modules/nx/package.json', (json) => { - json.version = `${major(getPublishedVersion()) + 2}.0.0`; - return json; + describe('non-nx directory', () => { + beforeAll(() => { + createNonNxProjectDirectory(); }); - let output: string; - expect(() => { - output = runCommand(`nx show projects`); - }).not.toThrow(); - expect(output).toContain('Its time to update Nx'); - updateFile('node_modules/nx/package.json', packageJsonContents); - }); - it('--version should display global installs version', () => { - const packageJsonContents = readFile('node_modules/nx/package.json'); - const localVersion = `${major(getPublishedVersion()) + 2}.0.0`; - updateJson('node_modules/nx/package.json', (json) => { - json.version = localVersion; - return json; + it('--version should report global version and local not found', () => { + let output: string; + expect(() => { + output = runCommand(`nx --version`); + }).not.toThrow(); + expect(output).toContain(`- Local: Not found`); + expect(output).toContain(`- Global: v${getPublishedVersion()}`); }); - let output: string; - expect(() => { - output = runCommand(`nx --version`); - }).not.toThrow(); - expect(output).toContain(`- Local: v${localVersion}`); - expect(output).toContain(`- Global: v${getPublishedVersion()}`); - updateFile('node_modules/nx/package.json', packageJsonContents); - }); - it('report should display global installs version', () => { - const packageJsonContents = readFile('node_modules/nx/package.json'); - const localVersion = `${major(getPublishedVersion()) + 2}.0.0`; - updateJson('node_modules/nx/package.json', (json) => { - json.version = localVersion; - return json; + it('graph should work in npm workspaces repo', () => { + expect(() => { + runCommand(`nx graph --file graph.json`); + }).not.toThrow(); + const { graph } = readJson('graph.json'); + expect(graph).toHaveProperty('nodes'); }); - let output: string; - expect(() => { - output = runCommand(`nx report`); - }).not.toThrow(); - expect(output).toEqual( - expect.stringMatching(new RegExp(`nx.*:.*${localVersion}`)) - ); - expect(output).toEqual( - expect.stringMatching( - new RegExp(`nx \\(global\\).*:.*${getPublishedVersion()}`) - ) - ); - updateFile('node_modules/nx/package.json', packageJsonContents); }); }); diff --git a/packages/nx/bin/nx.ts b/packages/nx/bin/nx.ts index 0e58cf4cba..47ff78c576 100644 --- a/packages/nx/bin/nx.ts +++ b/packages/nx/bin/nx.ts @@ -35,47 +35,27 @@ function main() { if (!(Symbol as any).observable) (Symbol as any).observable = Symbol('observable polyfill'); - if (!workspace) { - output.log({ - title: `The current directory isn't part of an Nx workspace.`, - bodyLines: [ - `To create a workspace run:`, - chalk.bold.white(`npx create-nx-workspace@latest `), - '', - `To add Nx to an existing workspace with a workspace-specific nx.json, run:`, - chalk.bold.white(`npx nx@latest init`), - ], - }); - - output.note({ - title: `For more information please visit https://nx.dev/`, - }); - process.exit(1); - } - // Make sure that a local copy of Nx exists in workspace let localNx: string; try { - localNx = resolveNx(workspace); + localNx = workspace && resolveNx(workspace); } catch { localNx = null; } const isLocalInstall = localNx === resolveNx(null); - const LOCAL_NX_VERSION: string | null = localNx - ? getLocalNxVersion(workspace) - : null; - const GLOBAL_NX_VERSION: string | null = isLocalInstall - ? null - : require('../package.json').version; - - globalThis.GLOBAL_NX_VERSION ??= GLOBAL_NX_VERSION; + const { LOCAL_NX_VERSION, GLOBAL_NX_VERSION } = determineNxVersions( + localNx, + workspace, + isLocalInstall + ); if (process.argv[2] === '--version') { - console.log(stripIndents`Nx Version: - - Local: ${LOCAL_NX_VERSION ? 'v' + LOCAL_NX_VERSION : 'Not found'} - - Global: ${GLOBAL_NX_VERSION ? 'v' + GLOBAL_NX_VERSION : 'Not found'}`); - process.exit(0); + handleNxVersionCommand(LOCAL_NX_VERSION, GLOBAL_NX_VERSION); + } + + if (!workspace) { + handleNoWorkspace(); } if (!localNx) { @@ -98,6 +78,50 @@ function main() { } } +function handleNoWorkspace() { + output.log({ + title: `The current directory isn't part of an Nx workspace.`, + bodyLines: [ + `To create a workspace run:`, + chalk.bold.white(`npx create-nx-workspace@latest `), + '', + `To add Nx to an existing workspace with a workspace-specific nx.json, run:`, + chalk.bold.white(`npx nx@latest init`), + ], + }); + + output.note({ + title: `For more information please visit https://nx.dev/`, + }); + process.exit(1); +} + +function handleNxVersionCommand( + LOCAL_NX_VERSION: string, + GLOBAL_NX_VERSION: string +) { + console.log(stripIndents`Nx Version: + - Local: ${LOCAL_NX_VERSION ? 'v' + LOCAL_NX_VERSION : 'Not found'} + - Global: ${GLOBAL_NX_VERSION ? 'v' + GLOBAL_NX_VERSION : 'Not found'}`); + process.exit(0); +} + +function determineNxVersions( + localNx: string, + workspace: WorkspaceTypeAndRoot, + isLocalInstall: boolean +) { + const LOCAL_NX_VERSION: string | null = localNx + ? getLocalNxVersion(workspace) + : null; + const GLOBAL_NX_VERSION: string | null = isLocalInstall + ? null + : require('../package.json').version; + + globalThis.GLOBAL_NX_VERSION ??= GLOBAL_NX_VERSION; + return { LOCAL_NX_VERSION, GLOBAL_NX_VERSION }; +} + function resolveNx(workspace: WorkspaceTypeAndRoot | null) { // prefer Nx installed in .nx/installation try { @@ -167,17 +191,13 @@ function warnIfUsingOutdatedGlobalInstall( } function getLocalNxVersion(workspace: WorkspaceTypeAndRoot): string | null { - // TODO(v17): Remove @nrwl/cli from this list - const localNxPackages = ['nx', '@nrwl/tao', '@nrwl/cli']; - for (const pkg of localNxPackages) { - try { - const { packageJson } = readModulePackageJson( - 'nx', - getNxRequirePaths(workspace.dir) - ); - return packageJson.version; - } catch {} - } + try { + const { packageJson } = readModulePackageJson( + 'nx', + getNxRequirePaths(workspace.dir) + ); + return packageJson.version; + } catch {} } function _getLatestVersionOfNx(): string { diff --git a/packages/nx/src/utils/package-json.ts b/packages/nx/src/utils/package-json.ts index 93e217290f..b99e9de9f6 100644 --- a/packages/nx/src/utils/package-json.ts +++ b/packages/nx/src/utils/package-json.ts @@ -6,7 +6,6 @@ import { } from '../config/workspace-json-project-json'; import { readJsonFile } from './fileutils'; import { getNxRequirePaths } from './installation-directory'; -import { workspaceRoot } from './workspace-root'; export type PackageJsonTargetConfiguration = Omit< TargetConfiguration,