Skip to content

Commit

Permalink
fix(misc): nx version should report global version outside of an nx r…
Browse files Browse the repository at this point in the history
…epo (nrwl#16918)
  • Loading branch information
AgentEnder authored May 10, 2023
1 parent 548f8d7 commit 09525e8
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 99 deletions.
140 changes: 84 additions & 56 deletions e2e/nx-misc/src/misc.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { NxJsonConfiguration } from '@nx/devkit';
import {
cleanupProject,
createNonNxProjectDirectory,
e2eCwd,
getPackageManagerCommand,
getPublishedVersion,
Expand Down Expand Up @@ -588,8 +589,6 @@ describe('global installation', () => {
let oldPath: string;

beforeAll(() => {
newProject();

ensureDirSync(globalsPath);
writeFileSync(
path.join(path.dirname(path.dirname(globalsPath)), 'package.json'),
Expand Down Expand Up @@ -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 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;
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);
});
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('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);
});
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;
describe('non-nx directory', () => {
beforeAll(() => {
createNonNxProjectDirectory();
});

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()}`);
});

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);
});
});
104 changes: 62 additions & 42 deletions packages/nx/bin/nx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 <workspace name>`),
'',
`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) {
Expand All @@ -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 <workspace name>`),
'',
`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 {
Expand Down Expand Up @@ -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 {
Expand Down
1 change: 0 additions & 1 deletion packages/nx/src/utils/package-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 09525e8

Please sign in to comment.