Skip to content

Commit

Permalink
Support fallback syntax in .npmrc file (#5030)
Browse files Browse the repository at this point in the history
* Support fallback syntax in .npmrc file

* Simplify diff.

* Simplify tests.

* More minor cleanup.

* fixup! More minor cleanup.

* Add isPnpm property.

* Only support fallback for pnpm.

* Rush change.

---------

Co-authored-by: Ian Clanton-Thuon <[email protected]>
  • Loading branch information
fzxen and iclanton authored Dec 10, 2024
1 parent 3f9aa73 commit ae62698
Show file tree
Hide file tree
Showing 26 changed files with 481 additions and 78 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@microsoft/rush",
"comment": "Support fallback syntax in `.npmrc` files if the package manager is PNPM. See https://pnpm.io/npmrc",
"type": "none"
}
],
"packageName": "@microsoft/rush"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@microsoft/rush",
"comment": "Add an `.isPnpm` property to `RushConfiguration` that is set to true if the package manager for the Rush repo is PNPM.",
"type": "none"
}
],
"packageName": "@microsoft/rush"
}
1 change: 1 addition & 0 deletions common/reviews/api/rush-lib.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1222,6 +1222,7 @@ export class RushConfiguration {
readonly gitTagSeparator: string | undefined;
readonly gitVersionBumpCommitMessage: string | undefined;
readonly hotfixChangeEnabled: boolean;
readonly isPnpm: boolean;
static loadFromConfigurationFile(rushJsonFilename: string): RushConfiguration;
// (undocumented)
static loadFromDefaultLocation(options?: ITryFindRushJsonLocationOptions): RushConfiguration;
Expand Down
9 changes: 9 additions & 0 deletions libraries/rush-lib/src/api/RushConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,11 @@ export class RushConfiguration {
*/
public readonly packageManager!: PackageManagerName;

/**
* If true, the repository is using PNPM as its package manager.
*/
public readonly isPnpm!: boolean;

/**
* {@inheritdoc PackageManager}
*
Expand Down Expand Up @@ -698,16 +703,20 @@ export class RushConfiguration {
// TODO: Add an actual "packageManager" field in rush.json
const packageManagerFields: string[] = [];

this.isPnpm = false;
if (rushConfigurationJson.npmVersion) {
this.packageManager = 'npm';
this.packageManagerOptions = this.npmOptions;
packageManagerFields.push('npmVersion');
}

if (rushConfigurationJson.pnpmVersion) {
this.packageManager = 'pnpm';
this.isPnpm = true;
this.packageManagerOptions = this.pnpmOptions;
packageManagerFields.push('pnpmVersion');
}

if (rushConfigurationJson.yarnVersion) {
this.packageManager = 'yarn';
this.packageManagerOptions = this.yarnOptions;
Expand Down
2 changes: 1 addition & 1 deletion libraries/rush-lib/src/cli/RushXCommandLine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export class RushXCommandLine {
});
const terminal: ITerminal = new Terminal(terminalProvider);

if (rushConfiguration?.packageManager === 'pnpm' && rushConfiguration?.experimentsConfiguration) {
if (rushConfiguration?.isPnpm && rushConfiguration?.experimentsConfiguration) {
const { configuration: experiments } = rushConfiguration?.experimentsConfiguration;

if (experiments?.usePnpmSyncForInjectedDependencies) {
Expand Down
2 changes: 1 addition & 1 deletion libraries/rush-lib/src/cli/actions/DeployAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ export class DeployAction extends BaseRushAction {
}

const projects: RushConfigurationProject[] = this.rushConfiguration.projects;
if (this.rushConfiguration.packageManager === 'pnpm') {
if (this.rushConfiguration.isPnpm) {
const currentlyInstalledVariant: string | undefined =
await this.rushConfiguration.getCurrentlyInstalledVariantAsync();
for (const project of projects) {
Expand Down
2 changes: 1 addition & 1 deletion libraries/rush-lib/src/cli/actions/InstallAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class InstallAction extends BaseInstallAction {
description: `Only check the validity of the shrinkwrap file without performing an install.`
});

if (this.rushConfiguration?.packageManager === 'pnpm') {
if (this.rushConfiguration?.isPnpm) {
this._resolutionOnlyParameter = this.defineFlagParameter({
parameterLongName: '--resolution-only',
description: `Only perform dependency resolution, useful for ensuring peer dependendencies are up to date. Note that this flag is only supported when using the pnpm package manager.`
Expand Down
9 changes: 5 additions & 4 deletions libraries/rush-lib/src/cli/actions/PublishAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ export class PublishAction extends BaseRushAction {

this._validate();

this._addNpmPublishHome();
this._addNpmPublishHome(this.rushConfiguration.isPnpm);

const git: Git = new Git(this.rushConfiguration);
const publishGit: PublishGit = new PublishGit(git, this._targetBranch.value);
Expand Down Expand Up @@ -455,7 +455,7 @@ export class PublishAction extends BaseRushAction {
args.push(`--access`, this._npmAccessLevel.value);
}

if (this.rushConfiguration.packageManager === 'pnpm') {
if (this.rushConfiguration.isPnpm) {
// PNPM 4.11.0 introduced a feature that may interrupt publishing and prompt the user for input.
// See this issue for details: https://github.com/microsoft/rushstack/issues/1940
args.push('--no-git-checks');
Expand Down Expand Up @@ -582,15 +582,16 @@ export class PublishAction extends BaseRushAction {
}
}

private _addNpmPublishHome(): void {
private _addNpmPublishHome(supportEnvVarFallbackSyntax: boolean): void {
// Create "common\temp\publish-home" folder, if it doesn't exist
Utilities.createFolderWithRetry(this._targetNpmrcPublishFolder);

// Copy down the committed "common\config\rush\.npmrc-publish" file, if there is one
Utilities.syncNpmrc({
sourceNpmrcFolder: this.rushConfiguration.commonRushConfigFolder,
targetNpmrcFolder: this._targetNpmrcPublishFolder,
useNpmrcPublish: true
useNpmrcPublish: true,
supportEnvVarFallbackSyntax
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -466,10 +466,7 @@ export class PhasedScriptAction extends BaseScriptAction<IPhasedCommandConfig> {
}

const { configuration: experiments } = this.rushConfiguration.experimentsConfiguration;
if (
this.rushConfiguration?.packageManager === 'pnpm' &&
experiments?.usePnpmSyncForInjectedDependencies
) {
if (this.rushConfiguration?.isPnpm && experiments?.usePnpmSyncForInjectedDependencies) {
const { PnpmSyncCopyOperationPlugin } = await import(
'../../logic/operations/PnpmSyncCopyOperationPlugin'
);
Expand Down
8 changes: 5 additions & 3 deletions libraries/rush-lib/src/logic/Autoinstaller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ export class Autoinstaller {
// Copy: .../common/autoinstallers/my-task/.npmrc
Utilities.syncNpmrc({
sourceNpmrcFolder: this._rushConfiguration.commonRushConfigFolder,
targetNpmrcFolder: autoinstallerFullPath
targetNpmrcFolder: autoinstallerFullPath,
supportEnvVarFallbackSyntax: this._rushConfiguration.isPnpm
});

this._logIfConsoleOutputIsNotRestricted(
Expand Down Expand Up @@ -193,7 +194,7 @@ export class Autoinstaller {
oldFileContents = FileSystem.readFile(this.shrinkwrapFilePath, { convertLineEndings: NewlineKind.Lf });
this._logIfConsoleOutputIsNotRestricted('Deleting ' + this.shrinkwrapFilePath);
await FileSystem.deleteFileAsync(this.shrinkwrapFilePath);
if (this._rushConfiguration.packageManager === 'pnpm') {
if (this._rushConfiguration.isPnpm) {
// Workaround for https://github.com/pnpm/pnpm/issues/1890
//
// When "rush update-autoinstaller" is run, Rush deletes "common/autoinstallers/my-task/pnpm-lock.yaml"
Expand Down Expand Up @@ -222,7 +223,8 @@ export class Autoinstaller {

Utilities.syncNpmrc({
sourceNpmrcFolder: this._rushConfiguration.commonRushConfigFolder,
targetNpmrcFolder: this.folderFullPath
targetNpmrcFolder: this.folderFullPath,
supportEnvVarFallbackSyntax: this._rushConfiguration.isPnpm
});

await Utilities.executeCommandAsync({
Expand Down
2 changes: 1 addition & 1 deletion libraries/rush-lib/src/logic/InstallManagerFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class InstallManagerFactory {
options: IInstallManagerOptions
): Promise<BaseInstallManager> {
if (
rushConfiguration.packageManager === 'pnpm' &&
rushConfiguration.isPnpm &&
rushConfiguration.pnpmOptions &&
rushConfiguration.pnpmOptions.useWorkspaces
) {
Expand Down
6 changes: 2 additions & 4 deletions libraries/rush-lib/src/logic/ProjectChangeAnalyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,7 @@ export class ProjectChangeAnalyzer {
return new Set(rushConfiguration.projects);
}

const { packageManager } = rushConfiguration;

if (packageManager === 'pnpm') {
if (rushConfiguration.isPnpm) {
const currentShrinkwrap: PnpmShrinkwrapFile | undefined =
PnpmShrinkwrapFile.loadFromFile(fullShrinkwrapPath);

Expand Down Expand Up @@ -256,7 +254,7 @@ export class ProjectChangeAnalyzer {
// Include project shrinkwrap files as part of the computation
const additionalRelativePathsToHash: string[] = [];
const globalAdditionalFiles: string[] = [];
if (rushConfiguration.packageManager === 'pnpm') {
if (rushConfiguration.isPnpm) {
await Async.forEachAsync(rushConfiguration.projects, async (project: RushConfigurationProject) => {
const projectShrinkwrapFilePath: string = BaseProjectShrinkwrapFile.getFilePathForProject(project);
if (!(await FileSystem.existsAsync(projectShrinkwrapFilePath))) {
Expand Down
2 changes: 1 addition & 1 deletion libraries/rush-lib/src/logic/PurgeManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export class PurgeManager {
);

if (
this._rushConfiguration.packageManager === 'pnpm' &&
this._rushConfiguration.isPnpm &&
this._rushConfiguration.pnpmOptions.pnpmStore === 'global' &&
this._rushConfiguration.pnpmOptions.pnpmStorePath
) {
Expand Down
4 changes: 2 additions & 2 deletions libraries/rush-lib/src/logic/RepoStateFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export class RepoStateFile {

// Only support saving the pnpm shrinkwrap hash if it was enabled
const preventShrinkwrapChanges: boolean =
rushConfiguration.packageManager === 'pnpm' &&
rushConfiguration.isPnpm &&
rushConfiguration.pnpmOptions &&
rushConfiguration.pnpmOptions.preventManualShrinkwrapChanges;
if (preventShrinkwrapChanges) {
Expand Down Expand Up @@ -200,7 +200,7 @@ export class RepoStateFile {
this._modified = true;
}

if (rushConfiguration.packageManager === 'pnpm' && rushConfiguration.subspacesFeatureEnabled) {
if (rushConfiguration.isPnpm && rushConfiguration.subspacesFeatureEnabled) {
const packageJsonInjectedDependenciesHash: string | undefined =
subspace.getPackageJsonInjectedDependenciesHash(variant);

Expand Down
2 changes: 1 addition & 1 deletion libraries/rush-lib/src/logic/SetupChecks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class SetupChecks {

private static _validate(rushConfiguration: RushConfiguration): string | undefined {
// Check for outdated tools
if (rushConfiguration.packageManager === 'pnpm') {
if (rushConfiguration.isPnpm) {
if (semver.lt(rushConfiguration.packageManagerToolVersion, MINIMUM_SUPPORTED_PNPM_VERSION)) {
return (
`The ${RushConstants.rushJsonFilename} file requests PNPM version ` +
Expand Down
2 changes: 1 addition & 1 deletion libraries/rush-lib/src/logic/StandardScriptUpdater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const _pnpmOnlyScripts: IScriptSpecifier[] = [
];

const getScripts = (rushConfiguration: RushConfiguration): IScriptSpecifier[] => {
if (rushConfiguration.packageManager === 'pnpm') {
if (rushConfiguration.isPnpm) {
return _scripts.concat(_pnpmOnlyScripts);
}

Expand Down
21 changes: 12 additions & 9 deletions libraries/rush-lib/src/logic/base/BaseInstallManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ export abstract class BaseInstallManager {
const { configuration: experiments } = this.rushConfiguration.experimentsConfiguration;
// if usePnpmSyncForInjectedDependencies is true
// the pnpm-sync will generate the pnpm-sync.json based on lockfile
if (this.rushConfiguration.packageManager === 'pnpm' && experiments?.usePnpmSyncForInjectedDependencies) {
if (this.rushConfiguration.isPnpm && experiments?.usePnpmSyncForInjectedDependencies) {
const pnpmLockfilePath: string = subspace.getTempShrinkwrapFilename();
const dotPnpmFolder: string = `${subspace.getSubspaceTempFolderPath()}/node_modules/.pnpm`;

Expand Down Expand Up @@ -400,7 +400,7 @@ export abstract class BaseInstallManager {
// Add pnpm-config.json file to the potentially changed files list.
potentiallyChangedFiles.push(subspace.getPnpmConfigFilePath());

if (this.rushConfiguration.packageManager === 'pnpm') {
if (this.rushConfiguration.isPnpm) {
// If the repo is using pnpmfile.js, consider that also
const pnpmFileFilePath: string = subspace.getPnpmfilePath(variant);
const pnpmFileExists: boolean = await FileSystem.existsAsync(pnpmFileFilePath);
Expand Down Expand Up @@ -535,15 +535,16 @@ export abstract class BaseInstallManager {
sourceNpmrcFolder: subspace.getSubspaceConfigFolderPath(),
targetNpmrcFolder: subspace.getSubspaceTempFolderPath(),
linesToPrepend: extraNpmrcLines,
createIfMissing: this.rushConfiguration.subspacesFeatureEnabled
createIfMissing: this.rushConfiguration.subspacesFeatureEnabled,
supportEnvVarFallbackSyntax: this.rushConfiguration.isPnpm
});
this._syncNpmrcAlreadyCalled = true;

const npmrcHash: string | undefined = npmrcText
? crypto.createHash('sha1').update(npmrcText).digest('hex')
: undefined;

if (this.rushConfiguration.packageManager === 'pnpm') {
if (this.rushConfiguration.isPnpm) {
// Copy the committed patches folder if using pnpm
const commonTempPnpmPatchesFolder: string = `${subspace.getSubspaceTempFolderPath()}/${
RushConstants.pnpmPatchesFolderName
Expand Down Expand Up @@ -598,7 +599,7 @@ export abstract class BaseInstallManager {

// Shim support for pnpmfile in.
// Additionally when in workspaces, the shim implements support for common versions.
if (this.rushConfiguration.packageManager === 'pnpm') {
if (this.rushConfiguration.isPnpm) {
await PnpmfileConfiguration.writeCommonTempPnpmfileShimAsync(
this.rushConfiguration,
subspace.getSubspaceTempFolderPath(),
Expand Down Expand Up @@ -836,7 +837,7 @@ ${gitLfsHookHandling}
if (collectLogFile) {
args.push('--verbose');
}
} else if (this.rushConfiguration.packageManager === 'pnpm') {
} else if (this.rushConfiguration.isPnpm) {
// Only explicitly define the store path if `pnpmStore` is using the default, or has been set to
// 'local'. If `pnpmStore` = 'global', then allow PNPM to use the system's default
// path. In all cases, this will be overridden by RUSH_PNPM_STORE_PATH
Expand Down Expand Up @@ -911,7 +912,8 @@ ${gitLfsHookHandling}
*/
const isAutoInstallPeersInNpmrc: boolean = isVariableSetInNpmrcFile(
subspace.getSubspaceConfigFolderPath(),
'auto-install-peers'
'auto-install-peers',
this.rushConfiguration.isPnpm
);

let autoInstallPeers: boolean | undefined = this.rushConfiguration.pnpmOptions.autoInstallPeers;
Expand Down Expand Up @@ -939,7 +941,8 @@ ${gitLfsHookHandling}
*/
const isResolutionModeInNpmrc: boolean = isVariableSetInNpmrcFile(
subspace.getSubspaceConfigFolderPath(),
'resolution-mode'
'resolution-mode',
this.rushConfiguration.isPnpm
);

let resolutionMode: PnpmResolutionMode | undefined = this.rushConfiguration.pnpmOptions.resolutionMode;
Expand Down Expand Up @@ -1116,7 +1119,7 @@ ${gitLfsHookHandling}
// Otherwise delete the temporary file
FileSystem.deleteFile(subspace.getTempShrinkwrapFilename());

if (this.rushConfiguration.packageManager === 'pnpm') {
if (this.rushConfiguration.isPnpm) {
// Workaround for https://github.com/pnpm/pnpm/issues/1890
//
// When "rush update --full" is run, Rush deletes "common/temp/pnpm-lock.yaml"
Expand Down
4 changes: 2 additions & 2 deletions libraries/rush-lib/src/logic/installManager/InstallHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export class InstallHelpers {
version: '0.0.0'
};

if (rushConfiguration.packageManager === 'pnpm') {
if (rushConfiguration.isPnpm) {
const pnpmOptions: PnpmOptionsConfiguration =
subspace.getPnpmOptions() || rushConfiguration.pnpmOptions;
if (!commonPackageJson.pnpm) {
Expand Down Expand Up @@ -132,7 +132,7 @@ export class InstallHelpers {
if (rushConfiguration.npmOptions && rushConfiguration.npmOptions.environmentVariables) {
configurationEnvironment = rushConfiguration.npmOptions.environmentVariables;
}
} else if (rushConfiguration.packageManager === 'pnpm') {
} else if (rushConfiguration.isPnpm) {
if (rushConfiguration.pnpmOptions && rushConfiguration.pnpmOptions.environmentVariables) {
configurationEnvironment = rushConfiguration.pnpmOptions.environmentVariables;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ export class RushInstallManager extends BaseInstallManager {
// with the shrinkwrap file, since these will cause install to fail.
if (
shrinkwrapFile &&
this.rushConfiguration.packageManager === 'pnpm' &&
this.rushConfiguration.isPnpm &&
this.rushConfiguration.experimentsConfiguration.configuration.usePnpmFrozenLockfileForRushInstall
) {
const pnpmShrinkwrapFile: PnpmShrinkwrapFile = shrinkwrapFile as PnpmShrinkwrapFile;
Expand Down Expand Up @@ -361,7 +361,7 @@ export class RushInstallManager extends BaseInstallManager {
}

// Remove the workspace file if it exists
if (this.rushConfiguration.packageManager === 'pnpm') {
if (this.rushConfiguration.isPnpm) {
const workspaceFilePath: string = path.join(
this.rushConfiguration.commonTempFolder,
'pnpm-workspace.yaml'
Expand Down Expand Up @@ -622,7 +622,7 @@ export class RushInstallManager extends BaseInstallManager {
},
this.options.maxInstallAttempts,
() => {
if (this.rushConfiguration.packageManager === 'pnpm') {
if (this.rushConfiguration.isPnpm) {
// eslint-disable-next-line no-console
console.log(Colorize.yellow(`Deleting the "node_modules" folder`));
this.installRecycler.moveFolder(commonNodeModulesFolder);
Expand Down
Loading

0 comments on commit ae62698

Please sign in to comment.