Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): version option should display global and local installation separately #15911

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions e2e/nx-misc/src/misc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,7 @@ describe('global installation', () => {
});

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;
Expand All @@ -632,5 +633,44 @@ describe('global installation', () => {
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);
});
});
56 changes: 41 additions & 15 deletions packages/nx/bin/nx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from '../src/utils/installation-directory';
import { major } from 'semver';
import { readJsonFile } from '../src/utils/fileutils';
import { stripIndents } from '../src/utils/strip-indents';
import { execSync } from 'child_process';

function main() {
Expand Down Expand Up @@ -60,21 +61,36 @@ function main() {
try {
localNx = resolveNx(workspace);
} catch {
// If we can't resolve a local copy of Nx, we must be global.
warnIfUsingOutdatedGlobalInstall();
output.error({
title: `Could not find Nx modules in this workspace.`,
bodyLines: [`Have you run ${chalk.bold.white(`npm/yarn install`)}?`],
});
process.exit(1);
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;

if (process.argv[2] === '--version') {
console.log(stripIndents`Nx Version:
- Local: v${LOCAL_NX_VERSION ?? 'Not found'}
- Global: v${GLOBAL_NX_VERSION ?? 'Not found'}`);
AgentEnder marked this conversation as resolved.
Show resolved Hide resolved
process.exit(0);
}

if (!localNx) {
handleMissingLocalInstallation();
}

// this file is already in the local workspace
if (localNx === resolveNx(null)) {
if (isLocalInstall) {
initLocal(workspace);
} else {
// Nx is being run from globally installed CLI - hand off to the local
warnIfUsingOutdatedGlobalInstall(getLocalNxVersion(workspace));
warnIfUsingOutdatedGlobalInstall(GLOBAL_NX_VERSION, LOCAL_NX_VERSION);
if (localNx.includes('.nx')) {
const nxWrapperPath = localNx.replace(/\.nx.*/, '.nx/') + 'nxw.js';
require(nxWrapperPath);
Expand Down Expand Up @@ -106,24 +122,34 @@ function resolveNx(workspace: WorkspaceTypeAndRoot | null) {
}
}

function handleMissingLocalInstallation() {
output.error({
title: `Could not find Nx modules in this workspace.`,
bodyLines: [`Have you run ${chalk.bold.white(`npm/yarn install`)}?`],
});
process.exit(1);
}

/**
* Assumes currently running Nx is global install.
* Warns if out of date by 1 major version or more.
*/
function warnIfUsingOutdatedGlobalInstall(localNxVersion?: string) {
const globalVersion = require('../package.json').version;
function warnIfUsingOutdatedGlobalInstall(
globalNxVersion: string,
localNxVersion?: string
) {
const isOutdatedGlobalInstall =
globalVersion &&
((localNxVersion && major(globalVersion) < major(localNxVersion)) ||
globalNxVersion &&
((localNxVersion && major(globalNxVersion) < major(localNxVersion)) ||
(!localNxVersion &&
getLatestVersionOfNx() &&
major(globalVersion) < major(getLatestVersionOfNx())));
major(globalNxVersion) < major(getLatestVersionOfNx())));

// Using a global Nx Install
if (isOutdatedGlobalInstall) {
const bodyLines = localNxVersion
? [
`Your repository uses a higher version of Nx (${localNxVersion}) than your global CLI version (${globalVersion})`,
`Your repository uses a higher version of Nx (${localNxVersion}) than your global CLI version (${globalNxVersion})`,
]
: [];

Expand Down
6 changes: 5 additions & 1 deletion packages/nx/src/command-line/nx-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { getPackageManagerCommand } from '../utils/package-manager';
import { writeJsonFile } from '../utils/fileutils';
import { WatchArguments } from './watch';
import { runNxSync } from '../utils/child-process';
import { stripIndents } from '../utils/strip-indents';
AgentEnder marked this conversation as resolved.
Show resolved Hide resolved

// Ensure that the output takes up the available width of the terminal.
yargs.wrap(yargs.terminalWidth());
Expand Down Expand Up @@ -411,7 +412,10 @@ export const commandsObject = yargs
})
.scriptName('nx')
.help()
.version(nxVersion);
// NOTE: we handle --version in nx.ts, this just tells yargs that the option exists
// so that it shows up in help. The default yargs implementation of --version is not
// hit, as the implementation in nx.ts is hit first and calls process.exit(0).
.version();

function withShowOptions(yargs: yargs.Argv): yargs.Argv {
return yargs.positional('object', {
Expand Down
13 changes: 11 additions & 2 deletions packages/nx/src/command-line/report.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as chalk from 'chalk';
import { workspaceRoot } from '../utils/workspace-root';
import { output } from '../utils/output';
import { join } from 'path';
import {
Expand Down Expand Up @@ -27,7 +26,6 @@ const nxPackageJson = readJsonFile<typeof import('../../package.json')>(
);

export const packagesWeCareAbout = [
'nx',
'lerna',
...nxPackageJson['nx-migrations'].packageGroup.map((x) =>
typeof x === 'string' ? x : x.package
Expand Down Expand Up @@ -161,6 +159,16 @@ export async function getReportData(): Promise<ReportData> {
}

const packageVersionsWeCareAbout = findInstalledPackagesWeCareAbout();
packageVersionsWeCareAbout.unshift({
package: 'nx',
version: nxPackageJson.version,
});
if (globalThis.GLOBAL_NX_VERSION) {
packageVersionsWeCareAbout.unshift({
package: 'nx (global)',
version: globalThis.GLOBAL_NX_VERSION,
});
}

const outOfSyncPackageGroup = findMisalignedPackagesForPackage(nxPackageJson);

Expand Down Expand Up @@ -248,6 +256,7 @@ export function findInstalledCommunityPlugins(): PackageJson[] {
const installedPlugins = findInstalledPlugins();
return installedPlugins.filter(
(dep) =>
dep.name !== 'nx' &&
!patternsWeIgnoreInCommunityReport.some((pattern) =>
typeof pattern === 'string'
? pattern === dep.name
Expand Down