Skip to content

Commit af265e5

Browse files
authored
Merge pull request #4405 from D4N14L/user/danade/PreventAmbiguousAbbreviations
[ts-command-line] Prevent ambiguous abbreviations of parameters defined on parent tool or action
2 parents c71e641 + 1a385b4 commit af265e5

24 files changed

+784
-122
lines changed

apps/heft/package.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
"@rushstack/rig-package": "workspace:*",
4141
"@rushstack/ts-command-line": "workspace:*",
4242
"@types/tapable": "1.0.6",
43-
"argparse": "~1.0.9",
4443
"chokidar": "~3.4.0",
4544
"fast-glob": "~3.3.1",
4645
"git-repo-info": "~2.1.0",
@@ -54,7 +53,6 @@
5453
"local-eslint-config": "workspace:*",
5554
"@rushstack/heft": "0.62.0",
5655
"@rushstack/heft-node-rig": "2.3.2",
57-
"@types/argparse": "1.0.38",
5856
"@types/heft-jest": "1.0.1",
5957
"@types/node": "18.17.15",
6058
"@types/watchpack": "2.4.0",

apps/heft/src/cli/HeftCommandLineParser.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
22
// See LICENSE in the project root for license information.
33

4-
import { ArgumentParser } from 'argparse';
54
import {
65
CommandLineParser,
76
type AliasCommandLineAction,
@@ -20,12 +19,13 @@ import { MetricsCollector } from '../metrics/MetricsCollector';
2019
import { HeftConfiguration } from '../configuration/HeftConfiguration';
2120
import { InternalHeftSession } from '../pluginFramework/InternalHeftSession';
2221
import { LoggingManager } from '../pluginFramework/logging/LoggingManager';
23-
import { Constants } from '../utilities/Constants';
2422
import { CleanAction } from './actions/CleanAction';
2523
import { PhaseAction } from './actions/PhaseAction';
2624
import { RunAction } from './actions/RunAction';
2725
import type { IHeftActionOptions } from './actions/IHeftAction';
2826
import { AliasAction } from './actions/AliasAction';
27+
import { getToolParameterNamesFromArgs } from '../utilities/CliUtilities';
28+
import { Constants } from '../utilities/Constants';
2929

3030
/**
3131
* This interfaces specifies values for parameters that must be parsed before the CLI
@@ -233,13 +233,11 @@ export class HeftCommandLineParser extends CommandLineParser {
233233
throw new InternalError('onDefineParameters() has not yet been called.');
234234
}
235235

236-
// This is a rough parsing of the --debug parameter
237-
const parser: ArgumentParser = new ArgumentParser({ addHelp: false });
238-
parser.addArgument(this._debugFlag.longName, { dest: 'debug', action: 'storeTrue' });
239-
parser.addArgument(this._unmanagedFlag.longName, { dest: 'unmanaged', action: 'storeTrue' });
240-
241-
const [result]: IPreInitializationArgumentValues[] = parser.parseKnownArgs(args);
242-
return result;
236+
const toolParameters: Set<string> = getToolParameterNamesFromArgs(args);
237+
return {
238+
debug: toolParameters.has(this._debugFlag.longName),
239+
unmanaged: toolParameters.has(this._unmanagedFlag.longName)
240+
};
243241
}
244242

245243
private async _reportErrorAndSetExitCode(error: Error): Promise<void> {

apps/heft/src/cli/actions/RunAction.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,21 +78,18 @@ export function definePhaseScopingParameters(action: IHeftAction): IScopingParam
7878
return {
7979
toParameter: action.defineStringListParameter({
8080
parameterLongName: Constants.toParameterLongName,
81-
parameterShortName: Constants.toParameterShortName,
8281
description: `The phase to ${action.actionName} to, including all transitive dependencies.`,
8382
argumentName: 'PHASE',
8483
parameterGroup: ScopedCommandLineAction.ScopingParameterGroup
8584
}),
8685
toExceptParameter: action.defineStringListParameter({
8786
parameterLongName: Constants.toExceptParameterLongName,
88-
parameterShortName: Constants.toExceptParameterShortName,
8987
description: `The phase to ${action.actionName} to (but not include), including all transitive dependencies.`,
9088
argumentName: 'PHASE',
9189
parameterGroup: ScopedCommandLineAction.ScopingParameterGroup
9290
}),
9391
onlyParameter: action.defineStringListParameter({
9492
parameterLongName: Constants.onlyParameterLongName,
95-
parameterShortName: Constants.onlyParameterShortName,
9693
description: `The phase to ${action.actionName}.`,
9794
argumentName: 'PHASE',
9895
parameterGroup: ScopedCommandLineAction.ScopingParameterGroup

apps/heft/src/startWithVersionSelector.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import * as path from 'path';
99
import * as fs from 'fs';
1010
import type { IPackageJson } from '@rushstack/node-core-library';
11+
import { getToolParameterNamesFromArgs } from './utilities/CliUtilities';
1112
import { Constants } from './utilities/Constants';
1213

1314
const HEFT_PACKAGE_NAME: string = '@rushstack/heft';
@@ -49,14 +50,15 @@ function tryGetPackageFolderFor(resolvedFileOrFolderPath: string): string | unde
4950
* Use "heft --unmanaged" to bypass this feature.
5051
*/
5152
function tryStartLocalHeft(): boolean {
52-
if (process.argv.indexOf(Constants.unmanagedParameterLongName) >= 0) {
53+
const toolParameters: Set<string> = getToolParameterNamesFromArgs();
54+
if (toolParameters.has(Constants.unmanagedParameterLongName)) {
5355
console.log(
5456
`Bypassing the Heft version selector because ${JSON.stringify(Constants.unmanagedParameterLongName)} ` +
5557
'was specified.'
5658
);
5759
console.log();
5860
return false;
59-
} else if (process.argv.indexOf(Constants.debugParameterLongName) >= 0) {
61+
} else if (toolParameters.has(Constants.debugParameterLongName)) {
6062
// The unmanaged flag could be undiscoverable if it's not in their locally installed version
6163
console.log(
6264
'Searching for a locally installed version of Heft. Use the ' +
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2+
// See LICENSE in the project root for license information.
3+
4+
/**
5+
* Parse the arguments to the tool being executed and return the tool argument names.
6+
*
7+
* @param argv - The arguments to parse. Defaults to `process.argv`.
8+
*/
9+
export function getToolParameterNamesFromArgs(argv: string[] = process.argv): Set<string> {
10+
const toolParameters: Set<string> = new Set();
11+
// Skip the first two arguments, which are the path to the Node executable and the path to the Heft
12+
// entrypoint. The remaining arguments are the tool arguments. Grab them until we reach a non-"-"-prefixed
13+
// argument. We can do this simple parsing because the Heft tool only has simple optional flags.
14+
for (let i: number = 2; i < argv.length; ++i) {
15+
const arg: string = argv[i];
16+
if (!arg.startsWith('-')) {
17+
break;
18+
}
19+
toolParameters.add(arg);
20+
}
21+
return toolParameters;
22+
}

apps/heft/src/utilities/Constants.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,12 @@ export class Constants {
2020

2121
public static onlyParameterLongName: string = '--only';
2222

23-
public static onlyParameterShortName: string = '-o';
24-
2523
public static productionParameterLongName: string = '--production';
2624

2725
public static toParameterLongName: string = '--to';
2826

29-
public static toParameterShortName: string = '-t';
30-
3127
public static toExceptParameterLongName: string = '--to-except';
3228

33-
public static toExceptParameterShortName: string = '-T';
34-
3529
public static unmanagedParameterLongName: string = '--unmanaged';
3630

3731
public static verboseParameterLongName: string = '--verbose';
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@rushstack/heft",
5+
"comment": "Fix an issue with parsing of the \"--debug\" and \"--unmanaged\" flags for Heft",
6+
"type": "patch"
7+
}
8+
],
9+
"packageName": "@rushstack/heft"
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@rushstack/heft",
5+
"comment": "[BREAKING CHANGE] Remove \"heft run\" short-parameters for \"--to\" (\"-t\"), \"--to-except\" (\"-T\"), and \"--only\" (\"-o\").",
6+
"type": "minor"
7+
}
8+
],
9+
"packageName": "@rushstack/heft"
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@rushstack/ts-command-line",
5+
"comment": "Consider parent tool and action parameters when determining ambiguous abbreviations. For example, if a CLI tool `mytool` has a parameter `--myparam` and an action `myaction`, then `myaction` would not accept a parameter named `--myparam` (i.e. - `mytool --myparam myaction` is valid, `mytool myaction --myparam` is not). Additionally, any parameter that can be abbreviated to `--myparam` must be uniquely provided (i.e. - `--myparam-2` can only be abbreviated to `--myparam-`, since any shorter abbreviation would be ambiguous with the original `--myparam` on the tool).",
6+
"type": "minor"
7+
}
8+
],
9+
"packageName": "@rushstack/ts-command-line"
10+
}

common/config/rush/pnpm-lock.yaml

Lines changed: 0 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)