Skip to content

Commit f0f99f7

Browse files
committed
Fix scoped npmMinimalAgeGate fallback
1 parent fe04180 commit f0f99f7

5 files changed

Lines changed: 99 additions & 8 deletions

File tree

.yarn/versions/56c1f837.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
releases:
2+
"@yarnpkg/core": patch
3+
"@yarnpkg/plugin-npm": patch
4+
5+
declined:
6+
- "@yarnpkg/plugin-catalog"
7+
- "@yarnpkg/plugin-compat"
8+
- "@yarnpkg/plugin-constraints"
9+
- "@yarnpkg/plugin-dlx"
10+
- "@yarnpkg/plugin-essentials"
11+
- "@yarnpkg/plugin-exec"
12+
- "@yarnpkg/plugin-file"
13+
- "@yarnpkg/plugin-git"
14+
- "@yarnpkg/plugin-github"
15+
- "@yarnpkg/plugin-http"
16+
- "@yarnpkg/plugin-init"
17+
- "@yarnpkg/plugin-interactive-tools"
18+
- "@yarnpkg/plugin-jsr"
19+
- "@yarnpkg/plugin-link"
20+
- "@yarnpkg/plugin-nm"
21+
- "@yarnpkg/plugin-npm-cli"
22+
- "@yarnpkg/plugin-pack"
23+
- "@yarnpkg/plugin-patch"
24+
- "@yarnpkg/plugin-pnp"
25+
- "@yarnpkg/plugin-pnpm"
26+
- "@yarnpkg/plugin-stage"
27+
- "@yarnpkg/plugin-typescript"
28+
- "@yarnpkg/plugin-version"
29+
- "@yarnpkg/plugin-workspace-tools"
30+
- "@yarnpkg/builder"
31+
- "@yarnpkg/cli"
32+
- "@yarnpkg/doctor"
33+
- "@yarnpkg/extensions"
34+
- "@yarnpkg/nm"
35+
- "@yarnpkg/pnpify"
36+
- "@yarnpkg/sdks"

packages/acceptance-tests/pkg-tests-specs/sources/features/npmMinimalAgeGate.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,28 @@ describe(`Features`, () => {
472472
}),
473473
);
474474

475+
test(
476+
`unset scope gate inherits from the disabled global gate`,
477+
makeTemporaryEnv({}, async ({path, run, source}) => {
478+
const registryUrl = await startPackageServer();
479+
await xfs.writeJsonPromise(`${path}/.yarnrc.yml` as PortablePath, {
480+
npmMinimalAgeGate: 0,
481+
npmScopes: {
482+
scoped: {
483+
npmRegistryServer: registryUrl,
484+
},
485+
},
486+
});
487+
488+
await run(`add`, `@scoped/release-date@1.1.1`);
489+
490+
await expect(source(`require('@scoped/release-date/package.json')`)).resolves.toMatchObject({
491+
name: `@scoped/release-date`,
492+
version: `1.1.1`,
493+
});
494+
}),
495+
);
496+
475497
test(
476498
`--no-time-gate bypasses scope override`,
477499
makeTemporaryEnv({}, async ({path, run, source}) => {

packages/plugin-npm/sources/index.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ const scopablePackageGateSettings = {
7777
},
7878
} satisfies Record<string, SettingsDefinition>;
7979

80+
const scopedPackageGateSettings = {
81+
npmMinimalAgeGate: {
82+
...scopablePackageGateSettings.npmMinimalAgeGate,
83+
fallback: `npmMinimalAgeGate`,
84+
default: undefined,
85+
},
86+
} satisfies Record<string, SettingsDefinition>;
87+
8088
const globalOnlyPackageGateSettings = {
8189
npmPreapprovedPackages: {
8290
description: `Array of package descriptors or package name glob patterns to exclude from the minimum release age check`,
@@ -107,7 +115,7 @@ declare module '@yarnpkg/core' {
107115
npmPublishRegistry: string | null;
108116
npmRegistryServer: string;
109117

110-
npmMinimalAgeGate: number;
118+
npmMinimalAgeGate: number | undefined;
111119
}>>;
112120
npmRegistries: Map<string, miscUtils.ToMapValue<{
113121
npmAlwaysAuth: boolean;
@@ -133,7 +141,7 @@ const plugin: Plugin = {
133141
properties: {
134142
...authSettings,
135143
...registrySettings,
136-
...scopablePackageGateSettings,
144+
...scopedPackageGateSettings,
137145
},
138146
},
139147
},

packages/yarnpkg-core/sources/Configuration.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ export const FormatType = formatUtils.Type;
157157
export type BaseSettingsDefinition<T extends SettingsType = SettingsType> = {
158158
description: string;
159159
type: T;
160+
fallback?: string;
160161
} & ({isArray?: false} | {isArray: true, concatenateValues?: boolean});
161162

162163
export enum DurationUnit {
@@ -168,7 +169,7 @@ export enum DurationUnit {
168169
WEEKS = `w`,
169170
}
170171
export type DurationSettingsDefinition = BaseSettingsDefinition<SettingsType.DURATION> & {
171-
default: string;
172+
default: string | undefined;
172173
unit: DurationUnit;
173174
isNullable?: boolean;
174175
};
@@ -953,6 +954,9 @@ function getDefaultValue(configuration: Configuration, definition: SettingsDefin
953954
}
954955
}
955956
case SettingsType.DURATION: {
957+
if (typeof definition.default === `undefined`)
958+
return undefined;
959+
956960
return miscUtils.parseDuration(definition.default, definition.unit);
957961
}
958962
default: {
@@ -966,7 +970,10 @@ type SettingTransforms = {
966970
getNativePaths: boolean;
967971
};
968972

969-
function transformConfiguration(rawValue: unknown, definition: SettingsDefinitionNoDefault, transforms: SettingTransforms) {
973+
function transformConfiguration(configuration: Configuration, rawValue: unknown, definition: SettingsDefinitionNoDefault, transforms: SettingTransforms) {
974+
if (typeof rawValue === `undefined` && typeof definition.fallback !== `undefined`)
975+
return configuration.get(definition.fallback);
976+
970977
if (definition.type === SettingsType.SECRET && typeof rawValue === `string` && transforms.hideSecrets)
971978
return SECRET;
972979
if (definition.type === SettingsType.ABSOLUTE_PATH && typeof rawValue === `string` && transforms.getNativePaths)
@@ -976,7 +983,7 @@ function transformConfiguration(rawValue: unknown, definition: SettingsDefinitio
976983
const newValue: Array<unknown> = [];
977984

978985
for (const value of rawValue)
979-
newValue.push(transformConfiguration(value, definition, transforms));
986+
newValue.push(transformConfiguration(configuration, value, definition, transforms));
980987

981988
return newValue;
982989
}
@@ -988,7 +995,7 @@ function transformConfiguration(rawValue: unknown, definition: SettingsDefinitio
988995
const newValue: Map<string, unknown> = new Map();
989996

990997
for (const [key, value] of rawValue.entries()) {
991-
const transformedValue = transformConfiguration(value, definition.valueDefinition, transforms);
998+
const transformedValue = transformConfiguration(configuration, value, definition.valueDefinition, transforms);
992999
if (typeof transformedValue !== `undefined`) {
9931000
newValue.set(key, transformedValue);
9941001
}
@@ -1006,7 +1013,7 @@ function transformConfiguration(rawValue: unknown, definition: SettingsDefinitio
10061013
for (const [key, value] of rawValue.entries()) {
10071014
const propertyDefinition = definition.properties[key];
10081015

1009-
const transformedValue = transformConfiguration(value, propertyDefinition, transforms);
1016+
const transformedValue = transformConfiguration(configuration, value, propertyDefinition, transforms);
10101017
if (typeof transformedValue !== `undefined`) {
10111018
newValue.set(key, transformedValue);
10121019
}
@@ -1733,7 +1740,7 @@ export class Configuration {
17331740
if (typeof definition === `undefined`)
17341741
throw new UsageError(`Couldn't find a configuration settings named "${key}"`);
17351742

1736-
return transformConfiguration(rawValue, definition, {
1743+
return transformConfiguration(this, rawValue, definition, {
17371744
hideSecrets,
17381745
getNativePaths,
17391746
}) as T;

packages/yarnpkg-core/tests/Configuration.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,24 @@ describe(`Configuration`, () => {
323323
});
324324

325325
describe(`Configuration merging`, () => {
326+
it(`should resolve scoped npmMinimalAgeGate from the global value when unset`, async () => {
327+
await initializeConfiguration({
328+
npmMinimalAgeGate: 0,
329+
npmScopes: {
330+
scopeName: {
331+
npmRegistryServer: `https://example.com/npm/registry`,
332+
},
333+
},
334+
}, async dir => {
335+
const configuration = await Configuration.find(dir, {
336+
modules: new Map([[`@yarnpkg/plugin-npm`, NpmPlugin]]),
337+
plugins: new Set([`@yarnpkg/plugin-npm`]),
338+
});
339+
340+
expect(configuration.getSpecial(`npmScopes`, {hideSecrets: false}).get(`scopeName`).get(`npmMinimalAgeGate`)).toBe(0);
341+
});
342+
});
343+
326344
it(`should merge map properties`, async () => {
327345
await initializeConfiguration({
328346
npmRegistryServer: `https://foo.server`,

0 commit comments

Comments
 (0)