diff --git a/common/changes/@microsoft/rush/chao-rush-alert-cmd_2024-07-22-19-34.json b/common/changes/@microsoft/rush/chao-rush-alert-cmd_2024-07-22-19-34.json new file mode 100644 index 00000000000..d39389ccfe0 --- /dev/null +++ b/common/changes/@microsoft/rush/chao-rush-alert-cmd_2024-07-22-19-34.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/rush", + "comment": "Add rush alert CLI", + "type": "none" + } + ], + "packageName": "@microsoft/rush" +} \ No newline at end of file diff --git a/libraries/rush-lib/src/cli/RushCommandLineParser.ts b/libraries/rush-lib/src/cli/RushCommandLineParser.ts index 80009e6d883..3fa3792c4b0 100644 --- a/libraries/rush-lib/src/cli/RushCommandLineParser.ts +++ b/libraries/rush-lib/src/cli/RushCommandLineParser.ts @@ -60,6 +60,7 @@ import { PhasedScriptAction } from './scriptActions/PhasedScriptAction'; import type { IBuiltInPluginConfiguration } from '../pluginFramework/PluginLoader/BuiltInPluginLoader'; import { InitSubspaceAction } from './actions/InitSubspaceAction'; import { RushAlerts } from '../utilities/RushAlerts'; +import { AlertAction } from './actions/AlertAction'; /** * Options for `RushCommandLineParser`. @@ -236,7 +237,9 @@ export class RushCommandLineParser extends CommandLineParser { terminal: this._terminal }); if (await rushAlerts.isAlertsStateUpToDateAsync()) { - await rushAlerts.printAlertsAsync(); + if (!(await rushAlerts.isSnoozeAsync())) { + await rushAlerts.printAlertsAsync(); + } } else { await rushAlerts.retrieveAlertsAsync(); } @@ -289,6 +292,7 @@ export class RushCommandLineParser extends CommandLineParser { try { // Alphabetical order this.addAction(new AddAction(this)); + this.addAction(new AlertAction(this)); this.addAction(new ChangeAction(this)); this.addAction(new CheckAction(this)); this.addAction(new DeployAction(this)); diff --git a/libraries/rush-lib/src/cli/actions/AlertAction.ts b/libraries/rush-lib/src/cli/actions/AlertAction.ts new file mode 100644 index 00000000000..35899eee2a7 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/AlertAction.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 { CommandLineFlagParameter } from '@rushstack/ts-command-line'; + +import { BaseRushAction } from './BaseRushAction'; +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import { ConsoleTerminalProvider, Terminal } from '@rushstack/terminal'; +import { RushAlerts } from '../../utilities/RushAlerts'; +export class AlertAction extends BaseRushAction { + private readonly _snoozeParameter: CommandLineFlagParameter; + private readonly _rushAlerts: RushAlerts; + + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'alert', + summary: 'Use this command to interact with Rush alert feature', + documentation: + 'The "rush alert" command is used to interact with Rush alert feature. For example,' + + ' you can mute the alerts if you think they are annoying', + parser + }); + + this._snoozeParameter = this.defineFlagParameter({ + parameterLongName: '--snooze', + description: + 'Snooze the alerts for today.' + + ' Please note, if you delete the `common/temp` folder, the snooze state will be reset. ' + }); + + const terminal: Terminal = new Terminal(new ConsoleTerminalProvider()); + this._rushAlerts = new RushAlerts({ + rushConfiguration: this.rushConfiguration, + terminal + }); + } + + protected async runAsync(): Promise { + if (this._snoozeParameter.value!) { + await this._rushAlerts.snoozeAlertsAsync(); + } + } +} diff --git a/libraries/rush-lib/src/utilities/RushAlerts.ts b/libraries/rush-lib/src/utilities/RushAlerts.ts index ac47145f59f..30f1e0344ad 100644 --- a/libraries/rush-lib/src/utilities/RushAlerts.ts +++ b/libraries/rush-lib/src/utilities/RushAlerts.ts @@ -25,6 +25,8 @@ interface IRushAlertsConfigEntry { } interface IRushAlertsState { lastUpdateTime: string; + snooze: boolean; + rushVersion: string; alerts: Array; } interface IRushAlertStateEntry { @@ -60,7 +62,16 @@ export class RushAlerts { public async isAlertsStateUpToDateAsync(): Promise { const rushAlertsState: IRushAlertsState | undefined = await this._loadRushAlertsStateAsync(); - if (rushAlertsState === undefined || !rushAlertsState.lastUpdateTime) { + if ( + rushAlertsState === undefined || + !rushAlertsState.lastUpdateTime || + rushAlertsState.rushVersion === undefined + ) { + return false; + } + + // if the state file is generated by another Rush version, also return false + if (rushAlertsState.rushVersion !== this._rushConfiguration.rushConfigurationJson.rushVersion) { return false; } @@ -262,6 +273,8 @@ export class RushAlerts { if (validAlerts.length > 0) { const rushAlertsState: IRushAlertsState = { lastUpdateTime: new Date().toISOString(), + snooze: false, + rushVersion: this._rushConfiguration.rushConfigurationJson.rushVersion, alerts: validAlerts }; @@ -276,4 +289,32 @@ export class RushAlerts { await FileSystem.deleteFileAsync(this.rushAlertsStateFilePath); } } + + public async snoozeAlertsAsync(): Promise { + const rushAlertsState: IRushAlertsState | undefined = await this._loadRushAlertsStateAsync(); + + if (!rushAlertsState) { + return; + } + + rushAlertsState.snooze = true; + + await JsonFile.saveAsync(rushAlertsState, this.rushAlertsStateFilePath, { + ignoreUndefinedValues: true, + headerComment: '// THIS FILE IS MACHINE-GENERATED -- DO NOT MODIFY', + jsonSyntax: JsonSyntax.JsonWithComments + }); + + this._terminal.writeLine('Snoozing the rush alerts for today!'); + } + + public async isSnoozeAsync(): Promise { + const rushAlertsState: IRushAlertsState | undefined = await this._loadRushAlertsStateAsync(); + + if (rushAlertsState === undefined || !rushAlertsState.snooze) { + return false; + } + + return true; + } }