diff --git a/common/changes/@microsoft/rush/feat-install-autoinstaller_2024-07-04-13-25.json b/common/changes/@microsoft/rush/feat-install-autoinstaller_2024-07-04-13-25.json new file mode 100644 index 00000000000..fa463bed98d --- /dev/null +++ b/common/changes/@microsoft/rush/feat-install-autoinstaller_2024-07-04-13-25.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/rush", + "comment": "Add a new `rush install-autoinstaller` command that ensures that the specified autoinstaller is installed.", + "type": "none" + } + ], + "packageName": "@microsoft/rush" +} \ No newline at end of file diff --git a/libraries/rush-lib/src/api/test/__snapshots__/RushCommandLine.test.ts.snap b/libraries/rush-lib/src/api/test/__snapshots__/RushCommandLine.test.ts.snap index 1176f03cc55..fde44db0060 100644 --- a/libraries/rush-lib/src/api/test/__snapshots__/RushCommandLine.test.ts.snap +++ b/libraries/rush-lib/src/api/test/__snapshots__/RushCommandLine.test.ts.snap @@ -907,11 +907,24 @@ Object { }, ], }, + Object { + "actionName": "install-autoinstaller", + "parameters": Array [ + Object { + "description": "The name of the autoinstaller, which must be one of the folders under common/autoinstallers.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--name", + "required": true, + "shortName": undefined, + }, + ], + }, Object { "actionName": "update-autoinstaller", "parameters": Array [ Object { - "description": "Specifies the name of the autoinstaller, which must be one of the folders under common/autoinstallers.", + "description": "The name of the autoinstaller, which must be one of the folders under common/autoinstallers.", "environmentVariable": undefined, "kind": "String", "longName": "--name", diff --git a/libraries/rush-lib/src/cli/RushCommandLineParser.ts b/libraries/rush-lib/src/cli/RushCommandLineParser.ts index 26bf565a927..9c5b37e5d83 100644 --- a/libraries/rush-lib/src/cli/RushCommandLineParser.ts +++ b/libraries/rush-lib/src/cli/RushCommandLineParser.ts @@ -61,6 +61,7 @@ import { PhasedScriptAction } from './scriptActions/PhasedScriptAction'; import type { IBuiltInPluginConfiguration } from '../pluginFramework/PluginLoader/BuiltInPluginLoader'; import { InitSubspaceAction } from './actions/InitSubspaceAction'; import { RushAlerts } from '../utilities/RushAlerts'; +import { InstallAutoinstallerAction } from './actions/InstallAutoinstallerAction'; /** * Options for `RushCommandLineParser`. @@ -313,6 +314,7 @@ export class RushCommandLineParser extends CommandLineParser { this.addAction(new SetupAction(this)); this.addAction(new UnlinkAction(this)); this.addAction(new UpdateAction(this)); + this.addAction(new InstallAutoinstallerAction(this)); this.addAction(new UpdateAutoinstallerAction(this)); this.addAction(new UpdateCloudCredentialsAction(this)); this.addAction(new UpgradeInteractiveAction(this)); diff --git a/libraries/rush-lib/src/cli/actions/BaseAutoinstallerAction.ts b/libraries/rush-lib/src/cli/actions/BaseAutoinstallerAction.ts new file mode 100644 index 00000000000..5a1c6770e38 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/BaseAutoinstallerAction.ts @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IRequiredCommandLineStringParameter } from '@rushstack/ts-command-line'; +import type { ITerminal } from '@rushstack/terminal'; + +import { BaseRushAction, type IBaseRushActionOptions } from './BaseRushAction'; +import { Autoinstaller } from '../../logic/Autoinstaller'; + +export abstract class BaseAutoinstallerAction extends BaseRushAction { + protected readonly _name: IRequiredCommandLineStringParameter; + protected readonly _terminal: ITerminal; + + public constructor(options: IBaseRushActionOptions) { + super(options); + + this._name = this.defineStringParameter({ + parameterLongName: '--name', + argumentName: 'AUTOINSTALLER_NAME', + required: true, + description: + 'The name of the autoinstaller, which must be one of the folders under common/autoinstallers.' + }); + + this._terminal = this.parser.terminal; + } + + protected abstract prepareAsync(autoinstaller: Autoinstaller): Promise; + + protected async runAsync(): Promise { + const autoinstallerName: string = this._name.value; + const autoinstaller: Autoinstaller = new Autoinstaller({ + autoinstallerName, + rushConfiguration: this.rushConfiguration, + rushGlobalFolder: this.rushGlobalFolder + }); + + await this.prepareAsync(autoinstaller); + + this._terminal.writeLine(); + this._terminal.writeLine('Success.'); + } +} diff --git a/libraries/rush-lib/src/cli/actions/InstallAutoinstallerAction.ts b/libraries/rush-lib/src/cli/actions/InstallAutoinstallerAction.ts new file mode 100644 index 00000000000..b8445383d75 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/InstallAutoinstallerAction.ts @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { Autoinstaller } from '../../logic/Autoinstaller'; +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import { BaseAutoinstallerAction } from './BaseAutoinstallerAction'; + +export class InstallAutoinstallerAction extends BaseAutoinstallerAction { + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'install-autoinstaller', + summary: 'Install autoinstaller package dependencies', + documentation: 'Use this command to install dependencies for an autoinstaller folder.', + parser + }); + } + + protected async prepareAsync(autoinstaller: Autoinstaller): Promise { + await autoinstaller.prepareAsync(); + } +} diff --git a/libraries/rush-lib/src/cli/actions/UpdateAutoinstallerAction.ts b/libraries/rush-lib/src/cli/actions/UpdateAutoinstallerAction.ts index 29dbb898e26..e8e2f7085b2 100644 --- a/libraries/rush-lib/src/cli/actions/UpdateAutoinstallerAction.ts +++ b/libraries/rush-lib/src/cli/actions/UpdateAutoinstallerAction.ts @@ -1,15 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { IRequiredCommandLineStringParameter } from '@rushstack/ts-command-line'; - -import { BaseRushAction } from './BaseRushAction'; import type { RushCommandLineParser } from '../RushCommandLineParser'; -import { Autoinstaller } from '../../logic/Autoinstaller'; - -export class UpdateAutoinstallerAction extends BaseRushAction { - private readonly _name: IRequiredCommandLineStringParameter; +import type { Autoinstaller } from '../../logic/Autoinstaller'; +import { BaseAutoinstallerAction } from './BaseAutoinstallerAction'; +export class UpdateAutoinstallerAction extends BaseAutoinstallerAction { public constructor(parser: RushCommandLineParser) { super({ actionName: 'update-autoinstaller', @@ -17,31 +13,12 @@ export class UpdateAutoinstallerAction extends BaseRushAction { documentation: 'Use this command to regenerate the shrinkwrap file for an autoinstaller folder.', parser }); - - this._name = this.defineStringParameter({ - parameterLongName: '--name', - argumentName: 'AUTOINSTALLER_NAME', - required: true, - description: - 'Specifies the name of the autoinstaller, which must be one of the folders under common/autoinstallers.' - }); } - protected async runAsync(): Promise { - const autoinstallerName: string = this._name.value; - const autoinstaller: Autoinstaller = new Autoinstaller({ - autoinstallerName, - rushConfiguration: this.rushConfiguration, - rushGlobalFolder: this.rushGlobalFolder - }); - + protected async prepareAsync(autoinstaller: Autoinstaller): Promise { // Do not run `autoinstaller.prepareAsync` here. It tries to install the autoinstaller with // --frozen-lockfile or equivalent, which will fail if the autoinstaller's dependencies // have been changed. - await autoinstaller.updateAsync(); - - // eslint-disable-next-line no-console - console.log('\nSuccess.'); } } diff --git a/libraries/rush-lib/src/cli/test/__snapshots__/CommandLineHelp.test.ts.snap b/libraries/rush-lib/src/cli/test/__snapshots__/CommandLineHelp.test.ts.snap index 6d7ef926f75..c85c1b11bf2 100644 --- a/libraries/rush-lib/src/cli/test/__snapshots__/CommandLineHelp.test.ts.snap +++ b/libraries/rush-lib/src/cli/test/__snapshots__/CommandLineHelp.test.ts.snap @@ -51,6 +51,8 @@ Positional arguments: update Install package dependencies for all projects in the repo, and create or update the shrinkwrap file as needed + install-autoinstaller + Install autoinstaller package dependencies update-autoinstaller Updates autoinstaller package dependencies update-cloud-credentials @@ -758,6 +760,19 @@ Optional arguments: " `; +exports[`CommandLineHelp prints the help for each action: install-autoinstaller 1`] = ` +"usage: rush install-autoinstaller [-h] --name AUTOINSTALLER_NAME + +Use this command to install dependencies for an autoinstaller folder. + +Optional arguments: + -h, --help Show this help message and exit. + --name AUTOINSTALLER_NAME + The name of the autoinstaller, which must be one of + the folders under common/autoinstallers. +" +`; + exports[`CommandLineHelp prints the help for each action: link 1`] = ` "usage: rush link [-h] [-f] @@ -1279,8 +1294,8 @@ folder. Optional arguments: -h, --help Show this help message and exit. --name AUTOINSTALLER_NAME - Specifies the name of the autoinstaller, which must - be one of the folders under common/autoinstallers. + The name of the autoinstaller, which must be one of + the folders under common/autoinstallers. " `; diff --git a/libraries/rush-lib/src/logic/Autoinstaller.ts b/libraries/rush-lib/src/logic/Autoinstaller.ts index 91d7218f33c..b136a554d3f 100644 --- a/libraries/rush-lib/src/logic/Autoinstaller.ts +++ b/libraries/rush-lib/src/logic/Autoinstaller.ts @@ -24,7 +24,7 @@ import { LastInstallFlag } from '../api/LastInstallFlag'; import { RushCommandLineParser } from '../cli/RushCommandLineParser'; import type { PnpmPackageManager } from '../api/packageManager/PnpmPackageManager'; -interface IAutoinstallerOptions { +export interface IAutoinstallerOptions { autoinstallerName: string; rushConfiguration: RushConfiguration; rushGlobalFolder: RushGlobalFolder;