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,11 @@
{
"changes": [
{
"comment": "Deprecate `minimumReleaseAge` in `common/config/rush/pnpm-config.json`; use `minimumReleaseAgeMinutes` instead",
"type": "none",
"packageName": "@microsoft/rush"
}
],
"packageName": "@microsoft/rush",
"email": "198982749+Copilot@users.noreply.github.com"
}
6 changes: 3 additions & 3 deletions common/config/rush/pnpm-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,18 @@
*
* For example, the following setting ensures that only packages released at least one day ago can be installed:
*
* "minimumReleaseAge": 1440
* "minimumReleaseAgeMinutes": 1440
*
* (SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER)
*
* PNPM documentation: https://pnpm.io/settings#minimumreleaseage
*
* The default value is 0 (disabled).
*/
// "minimumReleaseAge": 1440,
// "minimumReleaseAgeMinutes": 1440,

/**
* An array of package names or patterns to exclude from the minimumReleaseAge check.
* An array of package names or patterns to exclude from the minimumReleaseAgeMinutes check.
* This allows certain trusted packages to be installed immediately after publication.
* Patterns are supported using glob syntax (e.g., "@myorg/*" to exclude all packages from an organization).
*
Expand Down
6 changes: 5 additions & 1 deletion common/reviews/api/rush-lib.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -760,8 +760,10 @@ export interface _IPnpmOptionsJson extends IPackageManagerOptionsJsonBase {
globalPackageExtensions?: Record<string, IPnpmPackageExtension>;
globalPatchedDependencies?: Record<string, string>;
globalPeerDependencyRules?: IPnpmPeerDependencyRules;
// @deprecated (undocumented)
minimumReleaseAge?: number;
minimumReleaseAgeExclude?: string[];
minimumReleaseAgeMinutes?: number;
pnpmLockfilePolicies?: IPnpmLockfilePolicies;
pnpmStore?: PnpmStoreLocation;
preventManualShrinkwrapChanges?: boolean;
Expand Down Expand Up @@ -1189,8 +1191,10 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration
static loadFromJsonFileOrThrow(jsonFilePath: string, commonTempFolder: string): PnpmOptionsConfiguration;
// @internal (undocumented)
static loadFromJsonObject(json: _IPnpmOptionsJson, commonTempFolder: string): PnpmOptionsConfiguration;
readonly minimumReleaseAge: number | undefined;
// @deprecated (undocumented)
get minimumReleaseAge(): number | undefined;
readonly minimumReleaseAgeExclude: string[] | undefined;
readonly minimumReleaseAgeMinutes: number | undefined;
Comment thread
iclanton marked this conversation as resolved.
readonly pnpmLockfilePolicies: IPnpmLockfilePolicies | undefined;
readonly pnpmStore: PnpmStoreLocation;
readonly pnpmStorePath: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,18 @@
*
* For example, the following setting ensures that only packages released at least one day ago can be installed:
*
* "minimumReleaseAge": 1440
* "minimumReleaseAgeMinutes": 1440
*
* (SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER)
*
* PNPM documentation: https://pnpm.io/settings#minimumreleaseage
*
* The default value is 0 (disabled).
*/
/*[LINE "HYPOTHETICAL"]*/ "minimumReleaseAge": 1440,
/*[LINE "HYPOTHETICAL"]*/ "minimumReleaseAgeMinutes": 1440,

/**
* An array of package names or patterns to exclude from the minimumReleaseAge check.
* An array of package names or patterns to exclude from the minimumReleaseAgeMinutes check.
* This allows certain trusted packages to be installed immediately after publication.
* Patterns are supported using glob syntax (e.g., "@myorg/*" to exclude all packages from an organization).
*
Expand Down
11 changes: 6 additions & 5 deletions libraries/rush-lib/src/logic/installManager/InstallHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ interface ICommonPackageJson extends IPackageJson {
ignoredOptionalDependencies?: typeof PnpmOptionsConfiguration.prototype.globalIgnoredOptionalDependencies;
allowedDeprecatedVersions?: typeof PnpmOptionsConfiguration.prototype.globalAllowedDeprecatedVersions;
patchedDependencies?: typeof PnpmOptionsConfiguration.prototype.globalPatchedDependencies;
minimumReleaseAge?: typeof PnpmOptionsConfiguration.prototype.minimumReleaseAge;
minimumReleaseAge?: typeof PnpmOptionsConfiguration.prototype.minimumReleaseAgeMinutes;
minimumReleaseAgeExclude?: typeof PnpmOptionsConfiguration.prototype.minimumReleaseAgeExclude;
trustPolicy?: typeof PnpmOptionsConfiguration.prototype.trustPolicy;
trustPolicyExclude?: typeof PnpmOptionsConfiguration.prototype.trustPolicyExclude;
Expand Down Expand Up @@ -124,23 +124,24 @@ export class InstallHelpers {
commonPackageJson.pnpm.patchedDependencies = pnpmOptions.globalPatchedDependencies;
}

if (pnpmOptions.minimumReleaseAge !== undefined || pnpmOptions.minimumReleaseAgeExclude) {
if (pnpmOptions.minimumReleaseAgeMinutes !== undefined || pnpmOptions.minimumReleaseAgeExclude) {
if (
rushConfiguration.rushConfigurationJson.pnpmVersion !== undefined &&
semver.lt(rushConfiguration.rushConfigurationJson.pnpmVersion, '10.16.0')
) {
terminal.writeWarningLine(
Colorize.yellow(
`Your version of pnpm (${rushConfiguration.rushConfigurationJson.pnpmVersion}) ` +
`doesn't support the "minimumReleaseAge" or "minimumReleaseAgeExclude" fields in ` +
`doesn't support the "minimumReleaseAgeMinutes" or "minimumReleaseAgeExclude" fields in ` +
`${rushConfiguration.commonRushConfigFolder}/${RushConstants.pnpmConfigFilename}. ` +
'Remove these fields or upgrade to pnpm 10.16.0 or newer.'
)
);
}

if (pnpmOptions.minimumReleaseAge !== undefined) {
commonPackageJson.pnpm.minimumReleaseAge = pnpmOptions.minimumReleaseAge;
if (pnpmOptions.minimumReleaseAgeMinutes !== undefined) {
// NOTE: the pnpm setting is `minimumReleaseAge`, but the Rush setting is `minimumReleaseAgeMinutes`
commonPackageJson.pnpm.minimumReleaseAge = pnpmOptions.minimumReleaseAgeMinutes;
}

if (pnpmOptions.minimumReleaseAgeExclude) {
Expand Down
27 changes: 23 additions & 4 deletions libraries/rush-lib/src/logic/pnpm/PnpmOptionsConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,11 @@ export interface IPnpmOptionsJson extends IPackageManagerOptionsJsonBase {
*/
autoInstallPeers?: boolean;
/**
* {@inheritDoc PnpmOptionsConfiguration.minimumReleaseAge}
* {@inheritDoc PnpmOptionsConfiguration.minimumReleaseAgeMinutes}
*/
minimumReleaseAgeMinutes?: number;
/**
* @deprecated Use `minimumReleaseAgeMinutes` instead.
*/
minimumReleaseAge?: number;
/**
Expand Down Expand Up @@ -308,11 +312,18 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration
*
* The default value is 0 (disabled).
*/
public readonly minimumReleaseAge: number | undefined;
public readonly minimumReleaseAgeMinutes: number | undefined;

/**
* @deprecated Use {@link PnpmOptionsConfiguration.minimumReleaseAgeMinutes} instead.
*/
public get minimumReleaseAge(): number | undefined {
return this.minimumReleaseAgeMinutes;
}

/**
* List of package names or patterns that are excluded from the minimumReleaseAge check.
* These packages will always install the newest version immediately, even if minimumReleaseAge is set.
* These packages will always install the newest version immediately, even if minimumReleaseAgeMinutes is set.
*
* @remarks
* (SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER)
Expand Down Expand Up @@ -551,7 +562,15 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration
this._globalPatchedDependencies = json.globalPatchedDependencies;
this.resolutionMode = json.resolutionMode;
this.autoInstallPeers = json.autoInstallPeers;
this.minimumReleaseAge = json.minimumReleaseAge;

if (json.minimumReleaseAge !== undefined && json.minimumReleaseAgeMinutes !== undefined) {
throw new Error(
'The "minimumReleaseAge" setting is deprecated. Use "minimumReleaseAgeMinutes" instead.' +
' Both settings cannot be specified together in pnpm-config.json.'
);
}
this.minimumReleaseAgeMinutes = json.minimumReleaseAgeMinutes ?? json.minimumReleaseAge;

this.minimumReleaseAgeExclude = json.minimumReleaseAgeExclude;
this.trustPolicy = json.trustPolicy;
this.trustPolicyExclude = json.trustPolicyExclude;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,19 +87,37 @@ describe(PnpmOptionsConfiguration.name, () => {
]);
});

it('loads minimumReleaseAge', () => {
it('loads minimumReleaseAgeMinutes', () => {
const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow(
`${__dirname}/jsonFiles/pnpm-config-minimumReleaseAge.json`,
fakeCommonTempFolder
);

expect(pnpmConfiguration.minimumReleaseAge).toEqual(1440);
expect(pnpmConfiguration.minimumReleaseAgeMinutes).toEqual(1440);
expect(TestUtilities.stripAnnotations(pnpmConfiguration.minimumReleaseAgeExclude)).toEqual([
'webpack',
'@myorg/*'
]);
});

it('loads deprecated minimumReleaseAge as minimumReleaseAgeMinutes', () => {
const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow(
`${__dirname}/jsonFiles/pnpm-config-minimumReleaseAge-deprecated.json`,
fakeCommonTempFolder
);

expect(pnpmConfiguration.minimumReleaseAgeMinutes).toEqual(720);
});

it('throws if both minimumReleaseAge and minimumReleaseAgeMinutes are specified', () => {
expect(() =>
PnpmOptionsConfiguration.loadFromJsonFileOrThrow(
`${__dirname}/jsonFiles/pnpm-config-minimumReleaseAge-both.json`,
fakeCommonTempFolder
)
).toThrow(/Both settings cannot be specified together/);
});

it('loads trustPolicy', () => {
const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow(
`${__dirname}/jsonFiles/pnpm-config-trustPolicy.json`,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"minimumReleaseAge": 720,
"minimumReleaseAgeMinutes": 1440
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"minimumReleaseAge": 720
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"minimumReleaseAge": 1440,
"minimumReleaseAgeMinutes": 1440,
"minimumReleaseAgeExclude": ["webpack", "@myorg/*"]
}
7 changes: 6 additions & 1 deletion libraries/rush-lib/src/schemas/pnpm-config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,16 @@
"type": "boolean"
},

"minimumReleaseAge": {
"minimumReleaseAgeMinutes": {
"description": "The minimum number of minutes that must pass after a version is published before pnpm will install it. This setting helps reduce the risk of installing compromised packages, as malicious releases are typically discovered and removed within a short time frame.\n\n(SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER)\n\nPNPM documentation: https://pnpm.io/settings#minimumreleaseage\n\nThe default value is 0 (disabled).",
"type": "number"
},

"minimumReleaseAge": {
"description": "DEPRECATED - Use \"minimumReleaseAgeMinutes\" instead. Cannot be combined with \"minimumReleaseAgeMinutes\".\n\nThe minimum number of minutes that must pass after a version is published before pnpm will install it. This setting helps reduce the risk of installing compromised packages, as malicious releases are typically discovered and removed within a short time frame.\n\n(SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER)\n\nPNPM documentation: https://pnpm.io/settings#minimumreleaseage\n\nThe default value is 0 (disabled).",
"type": "number"
},

"minimumReleaseAgeExclude": {
"description": "List of package names or patterns that are excluded from the minimumReleaseAge check. These packages will always install the newest version immediately, even if minimumReleaseAge is set. Supports glob patterns (e.g., \"@myorg/*\").\n\n(SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER)\n\nPNPM documentation: https://pnpm.io/settings#minimumreleaseageexclude\n\nExample: [\"webpack\", \"react\", \"@myorg/*\"]",
"type": "array",
Expand Down
Loading