Skip to content
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@microsoft/rush",
"comment": "Fix an issue where `rush add --make-consistent ...` may drop the `implicitlyPreferredVersions` and `ensureConsistentVersions` properties from `common/config/rush/common-versions.json`.",
"type": "none"
}
],
"packageName": "@microsoft/rush"
}
2 changes: 1 addition & 1 deletion common/config/rush/version-policies.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
"policyName": "rush",
"definitionName": "lockStepVersion",
"version": "5.160.1",
"nextBump": "patch",
"nextBump": "minor",
"mainProject": "@microsoft/rush"
}
]
28 changes: 21 additions & 7 deletions libraries/rush-lib/src/api/CommonVersionsConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
Sort
} from '@rushstack/node-core-library';

import type { OptionalToUndefined } from '../utilities/Utilities';
import { PackageNameParsers } from './PackageNameParsers';
import { JsonSchemaUrls } from '../logic/JsonSchemaUrls';
import type { RushConfiguration } from './RushConfiguration';
Expand Down Expand Up @@ -67,6 +68,7 @@ export class CommonVersionsConfiguration {
private _preferredVersions: ProtectableMap<string, string>;
private _allowedAlternativeVersions: ProtectableMap<string, string[]>;
private _modified: boolean = false;
private _commonVersionsJsonHasEnsureConsistentVersionsProperty: boolean;

/**
* Get the absolute file path of the common-versions.json file.
Expand Down Expand Up @@ -163,6 +165,8 @@ export class CommonVersionsConfiguration {

this.ensureConsistentVersions =
commonVersionsEnsureConsistentVersions ?? rushJsonEnsureConsistentVersions ?? false;
this._commonVersionsJsonHasEnsureConsistentVersionsProperty =
commonVersionsEnsureConsistentVersions !== undefined;

if (commonVersionsJson) {
try {
Expand Down Expand Up @@ -242,7 +246,10 @@ export class CommonVersionsConfiguration {
*/
public save(): boolean {
if (this._modified) {
JsonFile.save(this._serialize(), this.filePath, { updateExistingFile: true });
JsonFile.save(this._serialize(), this.filePath, {
updateExistingFile: true,
ignoreUndefinedValues: true
});
this._modified = false;
return true;
}
Expand Down Expand Up @@ -284,20 +291,27 @@ export class CommonVersionsConfiguration {
}

private _serialize(): ICommonVersionsJson {
const result: ICommonVersionsJson = {
$schema: JsonSchemaUrls.commonVersions
};

let preferredVersions: ICommonVersionsJsonVersionMap | undefined;
if (this._preferredVersions.size) {
result.preferredVersions = CommonVersionsConfiguration._serializeTable(this.preferredVersions);
preferredVersions = CommonVersionsConfiguration._serializeTable(this.preferredVersions);
}

let allowedAlternativeVersions: ICommonVersionsJsonVersionsMap | undefined;
if (this._allowedAlternativeVersions.size) {
result.allowedAlternativeVersions = CommonVersionsConfiguration._serializeTable(
allowedAlternativeVersions = CommonVersionsConfiguration._serializeTable(
this.allowedAlternativeVersions
) as ICommonVersionsJsonVersionsMap;
}

const result: OptionalToUndefined<ICommonVersionsJson> = {
$schema: JsonSchemaUrls.commonVersions,
preferredVersions,
implicitlyPreferredVersions: this.implicitlyPreferredVersions,
allowedAlternativeVersions,
ensureConsistentVersions: this._commonVersionsJsonHasEnsureConsistentVersionsProperty
? this.ensureConsistentVersions
: undefined
};
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,22 @@ Object {
"required": true,
"shortName": "-p",
},
Object {
"description": "If specified, the dependency will be added to all projects.",
"environmentVariable": undefined,
"kind": "Flag",
"longName": "--all",
"required": false,
"shortName": undefined,
},
Object {
"description": "Run command using a variant installation configuration",
"environmentVariable": "RUSH_VARIANT",
"kind": "String",
"longName": "--variant",
"required": false,
"shortName": undefined,
},
Object {
"description": "If specified, the SemVer specifier added to the package.json will be an exact version (e.g. without tilde or caret).",
"environmentVariable": undefined,
Expand Down Expand Up @@ -62,22 +78,6 @@ Object {
"required": false,
"shortName": "-m",
},
Object {
"description": "If specified, the dependency will be added to all projects.",
"environmentVariable": undefined,
"kind": "Flag",
"longName": "--all",
"required": false,
"shortName": undefined,
},
Object {
"description": "Run command using a variant installation configuration",
"environmentVariable": "RUSH_VARIANT",
"kind": "String",
"longName": "--variant",
"required": false,
"shortName": undefined,
},
],
},
Object {
Expand Down
56 changes: 22 additions & 34 deletions libraries/rush-lib/src/cli/actions/AddAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,9 @@

import * as semver from 'semver';

import type {
CommandLineFlagParameter,
CommandLineStringListParameter,
CommandLineStringParameter
} from '@rushstack/ts-command-line';
import type { CommandLineFlagParameter } from '@rushstack/ts-command-line';

import { BaseAddAndRemoveAction } from './BaseAddAndRemoveAction';
import { BaseAddAndRemoveAction, PACKAGE_PARAMETER_NAME } from './BaseAddAndRemoveAction';
import type { RushCommandLineParser } from '../RushCommandLineParser';
import { DependencySpecifier } from '../../logic/DependencySpecifier';
import type { RushConfigurationProject } from '../../api/RushConfigurationProject';
Expand All @@ -18,55 +14,52 @@ import {
type IPackageJsonUpdaterRushAddOptions,
SemVerStyle
} from '../../logic/PackageJsonUpdaterTypes';
import { getVariantAsync, VARIANT_PARAMETER } from '../../api/Variants';
import { getVariantAsync } from '../../api/Variants';

const ADD_ACTION_NAME: 'add' = 'add';
export const MAKE_CONSISTENT_FLAG_NAME: '--make-consistent' = '--make-consistent';
const EXACT_FLAG_NAME: '--exact' = '--exact';
const CARET_FLAG_NAME: '--caret' = '--caret';

export class AddAction extends BaseAddAndRemoveAction {
protected readonly _allFlag: CommandLineFlagParameter;
protected readonly _packageNameList: CommandLineStringListParameter;
private readonly _exactFlag: CommandLineFlagParameter;
private readonly _caretFlag: CommandLineFlagParameter;
private readonly _devDependencyFlag: CommandLineFlagParameter;
private readonly _peerDependencyFlag: CommandLineFlagParameter;
private readonly _makeConsistentFlag: CommandLineFlagParameter;
private readonly _variantParameter: CommandLineStringParameter;

public constructor(parser: RushCommandLineParser) {
const documentation: string = [
'Adds specified package(s) to the dependencies of the current project (as determined by the current working directory)' +
' and then runs "rush update". If no version is specified, a version will be automatically detected (typically' +
' either the latest version or a version that won\'t break the "ensureConsistentVersions" policy). If a version' +
' range (or a workspace range) is specified, the latest version in the range will be used. The version will be' +
' automatically prepended with a tilde, unless the "--exact" or "--caret" flags are used. The "--make-consistent"' +
' flag can be used to update all packages with the dependency.'
` automatically prepended with a tilde, unless the "${EXACT_FLAG_NAME}" or "${CARET_FLAG_NAME}" flags are used.` +
` The "${MAKE_CONSISTENT_FLAG_NAME}" flag can be used to update all packages with the dependency.`
].join('\n');
super({
actionName: 'add',
actionName: ADD_ACTION_NAME,
summary: 'Adds one or more dependencies to the package.json and runs rush update.',
documentation,
safeForSimultaneousRushProcesses: false,
parser
});

this._packageNameList = this.defineStringListParameter({
parameterLongName: '--package',
parameterShortName: '-p',
required: true,
argumentName: 'PACKAGE',
description:
parser,
allFlagDescription: 'If specified, the dependency will be added to all projects.',
packageNameListParameterDescription:
'The name of the package which should be added as a dependency.' +
' A SemVer version specifier can be appended after an "@" sign. WARNING: Symbol characters' +
" are usually interpreted by your shell, so it's recommended to use quotes." +
' For example, write "rush add --package "example@^1.2.3"" instead of "rush add --package example@^1.2.3".' +
' To add multiple packages, write "rush add --package foo --package bar".'
` For example, write "rush add ${PACKAGE_PARAMETER_NAME} "example@^1.2.3"" instead of "rush add ${PACKAGE_PARAMETER_NAME} example@^1.2.3".` +
` To add multiple packages, write "rush add ${PACKAGE_PARAMETER_NAME} foo ${PACKAGE_PARAMETER_NAME} bar".`
});

this._exactFlag = this.defineFlagParameter({
parameterLongName: '--exact',
parameterLongName: EXACT_FLAG_NAME,
description:
'If specified, the SemVer specifier added to the' +
' package.json will be an exact version (e.g. without tilde or caret).'
});
this._caretFlag = this.defineFlagParameter({
parameterLongName: '--caret',
parameterLongName: CARET_FLAG_NAME,
description:
'If specified, the SemVer specifier added to the' +
' package.json will be a prepended with a "caret" specifier ("^").'
Expand All @@ -82,17 +75,12 @@ export class AddAction extends BaseAddAndRemoveAction {
'If specified, the package will be added to the "peerDependencies" section of the package.json'
});
this._makeConsistentFlag = this.defineFlagParameter({
parameterLongName: '--make-consistent',
parameterLongName: MAKE_CONSISTENT_FLAG_NAME,
parameterShortName: '-m',
description:
'If specified, other packages with this dependency will have their package.json' +
' files updated to use the same version of the dependency.'
});
this._allFlag = this.defineFlagParameter({
parameterLongName: '--all',
description: 'If specified, the dependency will be added to all projects.'
});
this._variantParameter = this.defineStringParameter(VARIANT_PARAMETER);
}

public async getUpdateOptionsAsync(): Promise<IPackageJsonUpdaterRushAddOptions> {
Expand Down Expand Up @@ -142,7 +130,7 @@ export class AddAction extends BaseAddAndRemoveAction {
if (this._exactFlag.value || this._caretFlag.value) {
throw new Error(
`The "${this._caretFlag.longName}" and "${this._exactFlag.longName}" flags may not be specified if a ` +
`version is provided in the ${this._packageNameList.longName} specifier. In this case "${version}" was provided.`
`version is provided in the ${this._packageNameListParameter.longName} specifier. In this case "${version}" was provided.`
);
}

Expand All @@ -165,7 +153,7 @@ export class AddAction extends BaseAddAndRemoveAction {
);

return {
projects: projects,
projects,
packagesToUpdate: packagesToAdd,
devDependency: this._devDependencyFlag.value,
peerDependency: this._peerDependencyFlag.value,
Expand Down
42 changes: 36 additions & 6 deletions libraries/rush-lib/src/cli/actions/BaseAddAndRemoveAction.ts
Original file line number Diff line number Diff line change
@@ -1,7 +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 { CommandLineFlagParameter, CommandLineStringListParameter } from '@rushstack/ts-command-line';
import type {
CommandLineFlagParameter,
CommandLineStringListParameter,
CommandLineStringParameter
} from '@rushstack/ts-command-line';

import { BaseRushAction, type IBaseRushActionOptions } from './BaseRushAction';
import type { RushConfigurationProject } from '../../api/RushConfigurationProject';
Expand All @@ -11,6 +15,9 @@ import type {
IPackageJsonUpdaterRushBaseUpdateOptions
} from '../../logic/PackageJsonUpdaterTypes';
import { RushConstants } from '../../logic/RushConstants';
import { VARIANT_PARAMETER } from '../../api/Variants';

export const PACKAGE_PARAMETER_NAME: '--package' = '--package';

export interface IBasePackageJsonUpdaterRushOptions {
/**
Expand All @@ -31,27 +38,50 @@ export interface IBasePackageJsonUpdaterRushOptions {
debugInstall: boolean;
}

export interface IBaseAddAndRemoveActionOptions extends IBaseRushActionOptions {
allFlagDescription: string;
packageNameListParameterDescription: string;
}

/**
* This is the common base class for AddAction and RemoveAction.
*/
export abstract class BaseAddAndRemoveAction extends BaseRushAction {
protected abstract readonly _allFlag: CommandLineFlagParameter;
protected readonly _skipUpdateFlag!: CommandLineFlagParameter;
protected abstract readonly _packageNameList: CommandLineStringListParameter;
protected readonly _skipUpdateFlag: CommandLineFlagParameter;
protected readonly _packageNameListParameter: CommandLineStringListParameter;
protected readonly _allFlag: CommandLineFlagParameter;
protected readonly _variantParameter: CommandLineStringParameter;

protected get specifiedPackageNameList(): readonly string[] {
return this._packageNameList.values!;
return this._packageNameListParameter.values;
}

public constructor(options: IBaseRushActionOptions) {
public constructor(options: IBaseAddAndRemoveActionOptions) {
super(options);

const { packageNameListParameterDescription, allFlagDescription } = options;

this._skipUpdateFlag = this.defineFlagParameter({
parameterLongName: '--skip-update',
parameterShortName: '-s',
description:
'If specified, the "rush update" command will not be run after updating the package.json files.'
});

this._packageNameListParameter = this.defineStringListParameter({
parameterLongName: PACKAGE_PARAMETER_NAME,
parameterShortName: '-p',
required: true,
argumentName: 'PACKAGE',
description: packageNameListParameterDescription
});

this._allFlag = this.defineFlagParameter({
parameterLongName: '--all',
description: allFlagDescription
});

this._variantParameter = this.defineStringParameter(VARIANT_PARAMETER);
}

protected abstract getUpdateOptionsAsync(): Promise<IPackageJsonUpdaterRushBaseUpdateOptions>;
Expand Down
Loading
Loading