diff --git a/apps/rush-lib/src/cli/RushPnpmCommandLine.ts b/apps/rush-lib/src/cli/RushPnpmCommandLine.ts new file mode 100644 index 00000000000..5b5de1365ce --- /dev/null +++ b/apps/rush-lib/src/cli/RushPnpmCommandLine.ts @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import colors from 'colors/safe'; + +import { RushConfiguration } from '../api/RushConfiguration'; +import { NodeJsCompatibility } from '../logic/NodeJsCompatibility'; + +export interface ILaunchRushPnpmInternalOptions { + isManaged: boolean; + alreadyReportedNodeTooNewError?: boolean; +} + +export class RushPnpmCommandLine { + public static launch(launcherVersion: string, options: ILaunchRushPnpmInternalOptions): void { + // Node.js can sometimes accidentally terminate with a zero exit code (e.g. for an uncaught + // promise exception), so we start with the assumption that the exit code is 1 + // and set it to 0 only on success. + process.exitCode = 1; + + try { + // Are we in a Rush repo? + let rushConfiguration: RushConfiguration | undefined = undefined; + if (RushConfiguration.tryFindRushJsonLocation()) { + rushConfiguration = RushConfiguration.loadFromDefaultLocation({ showVerbose: true }); + } + + NodeJsCompatibility.warnAboutCompatibilityIssues({ + isRushLib: true, + alreadyReportedNodeTooNewError: !!options.alreadyReportedNodeTooNewError, + rushConfiguration + }); + + console.log('Success'); + process.exitCode = 0; + + } catch (error) { + console.log(colors.red('Error: ' + error.message)); + } + } +} diff --git a/apps/rush-lib/src/start-pnpm.ts b/apps/rush-lib/src/start-pnpm.ts new file mode 100644 index 00000000000..12e8fb46bb7 --- /dev/null +++ b/apps/rush-lib/src/start-pnpm.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Rush } from './api/Rush'; + +Rush.launchRushPnpm(Rush.version, { isManaged: false }); diff --git a/apps/rush/bin/rush-pnpm b/apps/rush/bin/rush-pnpm new file mode 100644 index 00000000000..783bb806fce --- /dev/null +++ b/apps/rush/bin/rush-pnpm @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../lib/start.js') diff --git a/apps/rush/package.json b/apps/rush/package.json index b0464ef7296..2b6c2d93eaa 100644 --- a/apps/rush/package.json +++ b/apps/rush/package.json @@ -31,6 +31,7 @@ }, "bin": { "rush": "./bin/rush", + "rush-pnpm": "./bin/rush-pnpm", "rushx": "./bin/rushx" }, "license": "MIT", diff --git a/apps/rush/src/RushCommandSelector.ts b/apps/rush/src/RushCommandSelector.ts index 1509a04cec5..8264b060f21 100644 --- a/apps/rush/src/RushCommandSelector.ts +++ b/apps/rush/src/RushCommandSelector.ts @@ -5,7 +5,7 @@ import colors from 'colors/safe'; import * as path from 'path'; import * as rushLib from '@microsoft/rush-lib'; -type CommandName = 'rush' | 'rushx' | undefined; +type CommandName = 'rush' | 'rush-pnpm' | 'rushx' | undefined; /** * Both "rush" and "rushx" share the same src/start.ts entry point. This makes it @@ -16,9 +16,10 @@ type CommandName = 'rush' | 'rushx' | undefined; */ export class RushCommandSelector { public static failIfNotInvokedAsRush(version: string): void { - if (RushCommandSelector._getCommandName() === 'rushx') { + const commandName: CommandName = RushCommandSelector._getCommandName(); + if (commandName !== 'rush' && commandName !== undefined) { RushCommandSelector._failWithError( - `This repository is using Rush version ${version} which does not support the "rushx" command` + `This repository is using Rush version ${version} which does not support the ${commandName} command` ); } } @@ -36,7 +37,20 @@ export class RushCommandSelector { RushCommandSelector._failWithError(`Unable to find the "Rush" entry point in @microsoft/rush-lib`); } - if (RushCommandSelector._getCommandName() === 'rushx') { + const commandName: CommandName = RushCommandSelector._getCommandName(); + + if (commandName === 'rush-pnpm') { + if (!Rush.launchRushPnpm) { + RushCommandSelector._failWithError( + `This repository is using Rush version ${Rush.version}` + + ` which does not support the "rush-pnpm" command` + ); + } + Rush.launchRushPnpm(launcherVersion, { + isManaged: options.isManaged, + alreadyReportedNodeTooNewError: options.alreadyReportedNodeTooNewError + }); + } else if (commandName === 'rushx') { if (!Rush.launchRushX) { RushCommandSelector._failWithError( `This repository is using Rush version ${Rush.version}` + @@ -60,12 +74,15 @@ export class RushCommandSelector { // argv[0]: "C:\\Program Files\\nodejs\\node.exe" // argv[1]: "C:\\Program Files\\nodejs\\node_modules\\@microsoft\\rush\\bin\\rushx" const basename: string = path.basename(process.argv[1]).toUpperCase(); - if (basename === 'RUSHX') { - return 'rushx'; - } if (basename === 'RUSH') { return 'rush'; } + if (basename === 'RUSH-PNPM') { + return 'rush-pnpm'; + } + if (basename === 'RUSHX') { + return 'rushx'; + } } return undefined; } diff --git a/apps/rush/src/RushVersionSelector.ts b/apps/rush/src/RushVersionSelector.ts index 2f3308ecda4..7f00b5a0b57 100644 --- a/apps/rush/src/RushVersionSelector.ts +++ b/apps/rush/src/RushVersionSelector.ts @@ -73,12 +73,12 @@ export class RushVersionSelector { if (semver.lt(version, '3.0.20')) { // In old versions, requiring the entry point invoked the command-line parser immediately, - // so fail if "rushx" was used + // so fail if "rushx" or "rush-pnpm" was used RushCommandSelector.failIfNotInvokedAsRush(version); require(path.join(expectedRushPath, 'node_modules', '@microsoft', 'rush', 'lib', 'rush')); } else if (semver.lt(version, '4.0.0')) { // In old versions, requiring the entry point invoked the command-line parser immediately, - // so fail if "rushx" was used + // so fail if "rushx" or "rush-pnpm" was used RushCommandSelector.failIfNotInvokedAsRush(version); require(path.join(expectedRushPath, 'node_modules', '@microsoft', 'rush', 'lib', 'start')); } else { diff --git a/common/reviews/api/rush-lib.api.md b/common/reviews/api/rush-lib.api.md index 5048ffdca8b..cd3675a1051 100644 --- a/common/reviews/api/rush-lib.api.md +++ b/common/reviews/api/rush-lib.api.md @@ -671,6 +671,7 @@ export class RepoStateFile { // @public export class Rush { static launch(launcherVersion: string, arg: ILaunchOptions): void; + static launchRushPnpm(launcherVersion: string, options: ILaunchOptions): void; static launchRushX(launcherVersion: string, options: ILaunchOptions): void; static get version(): string; } diff --git a/libraries/rush-lib/src/api/Rush.ts b/libraries/rush-lib/src/api/Rush.ts index 9b680cb7a05..9acbd98cc53 100644 --- a/libraries/rush-lib/src/api/Rush.ts +++ b/libraries/rush-lib/src/api/Rush.ts @@ -9,6 +9,7 @@ import { RushXCommandLine } from '../cli/RushXCommandLine'; import { CommandLineMigrationAdvisor } from '../cli/CommandLineMigrationAdvisor'; import { EnvironmentVariableNames } from './EnvironmentConfiguration'; import { IBuiltInPluginConfiguration } from '../pluginFramework/PluginLoader/BuiltInPluginLoader'; +import { RushPnpmCommandLine } from '../cli/RushPnpmCommandLine'; /** * Options to pass to the rush "launch" functions. @@ -50,8 +51,6 @@ export class Rush { * Third-party tools should not use this API. Instead, they should execute the "rush" binary * and start a new Node.js process. * - * @param launcherVersion - The version of the `@microsoft/rush` wrapper used to call invoke the CLI. - * * @remarks * Earlier versions of the rush frontend used a different API contract. In the old contract, * the second argument was the `isManaged` value of the {@link ILaunchOptions} object. @@ -83,8 +82,6 @@ export class Rush { * This API is used by the `@microsoft/rush` front end to launch the "rushx" command-line. * Third-party tools should not use this API. Instead, they should execute the "rushx" binary * and start a new Node.js process. - * - * @param launcherVersion - The version of the `@microsoft/rush` wrapper used to call invoke the CLI. */ public static launchRushX(launcherVersion: string, options: ILaunchOptions): void { options = Rush._normalizeLaunchOptions(options); @@ -93,6 +90,16 @@ export class Rush { RushXCommandLine._launchRushXInternal(launcherVersion, { ...options }); } + /** + * This API is used by the `@microsoft/rush` front end to launch the "rush-pnpm" command-line. + * Third-party tools should not use this API. Instead, they should execute the "rush-pnpm" binary + * and start a new Node.js process. + */ + public static launchRushPnpm(launcherVersion: string, options: ILaunchOptions): void { + Rush._assignRushInvokedFolder(); + RushPnpmCommandLine.launch(launcherVersion, { ...options }); + } + /** * The currently executing version of the "rush-lib" library. * This is the same as the Rush tool version for that release.