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
21 changes: 21 additions & 0 deletions docs/usage/configuration-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -3375,6 +3375,27 @@ For example to replace the npm package `jade` with version `2.0.0` of the packag
}
```

### replacementVersionTemplate

<!-- prettier-ignore -->
!!! note
`replacementVersion` will take precedence if used within the same package rule.

Use the `replacementVersionTemplate` config option to control the replacement version.

For example, the following package rule can be used to replace version with major-only version (17.0.1 -> 17):

```json
{
"packageRules": [
{
"matchPackageNames": ["dummy"],
"replacementVersionTemplate": "{{ lookup (split currentValue '.') 0 }}"
}
]
}
```

### sourceDirectory

Use this field to set the directory in which the package is present at the source of the package.
Expand Down
10 changes: 10 additions & 0 deletions lib/config/options/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1465,6 +1465,16 @@ const options: RenovateOptions[] = [
cli: false,
env: false,
},
{
name: 'replacementVersionTemplate',
description:
'Template field for the version of the new dependency that replaces the old deprecated dependency.',
type: 'string',
stage: 'package',
parents: ['packageRules'],
cli: false,
env: false,
},
{
name: 'replacementApproach',
description:
Expand Down
155 changes: 155 additions & 0 deletions lib/workers/repository/process/lookup/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4910,6 +4910,161 @@ describe('workers/repository/process/lookup/index', () => {
]);
});

it('handles replacements - can template replacement version without a replacement name', async () => {
config.packageName = 'mirror_some_org/library/openjdk';
config.currentValue = '17.0.0';
config.replacementVersionTemplate = `{{ lookup (split currentValue '.') 0 }}`;
config.datasource = DockerDatasource.id;
getDockerReleases.mockResolvedValueOnce({
releases: [
{
version: '17.0.0',
},
{
version: '18.0.0',
},
],
});

const { updates } = await Result.wrap(
lookup.lookupUpdates(config),
).unwrapOrThrow();

expect(updates).toEqual([
{
bucket: 'major',
newMajor: 18,
newMinor: 0,
newPatch: 0,
newValue: '18.0.0',
newVersion: '18.0.0',
updateType: 'major',
},
{
newName: 'mirror_some_org/library/openjdk',
newValue: '17',
updateType: 'replacement',
},
]);
});

it('handles replacements - can template replacement version with a replacement name', async () => {
config.packageName = 'mirror_some_org/library/openjdk';
config.currentValue = '17.0.0';
config.replacementName = 'eclipse-temurin';
config.replacementVersionTemplate = `{{ lookup (split currentValue '.') 0 }}`;
config.datasource = DockerDatasource.id;
getDockerReleases.mockResolvedValueOnce({
releases: [
{
version: '17.0.0',
},
{
version: '18.0.0',
},
],
});

const { updates } = await Result.wrap(
lookup.lookupUpdates(config),
).unwrapOrThrow();

expect(updates).toEqual([
{
bucket: 'major',
newMajor: 18,
newMinor: 0,
newPatch: 0,
newValue: '18.0.0',
newVersion: '18.0.0',
updateType: 'major',
},
{
newName: 'eclipse-temurin',
newValue: '17',
updateType: 'replacement',
},
]);
});

it('handles replacements - can template replacement version with a template replacement name', async () => {
config.packageName = 'mirror_some_org/library/openjdk';
config.currentValue = '17.0.0';
config.replacementNameTemplate = `{{{replace 'mirror_some_org/' 'new.registry.io/' packageName}}}`;
config.replacementVersionTemplate = `{{ lookup (split currentValue '.') 0 }}`;
config.datasource = DockerDatasource.id;
getDockerReleases.mockResolvedValueOnce({
releases: [
{
version: '17.0.0',
},
{
version: '18.0.0',
},
],
});

const { updates } = await Result.wrap(
lookup.lookupUpdates(config),
).unwrapOrThrow();

expect(updates).toEqual([
{
bucket: 'major',
newMajor: 18,
newMinor: 0,
newPatch: 0,
newValue: '18.0.0',
newVersion: '18.0.0',
updateType: 'major',
},
{
newName: 'new.registry.io/library/openjdk',
newValue: '17',
updateType: 'replacement',
},
]);
});

it('handles replacements - replacementVersion takes precedence over replacementVersionTemplate', async () => {
config.packageName = 'mirror_some_org/library/openjdk';
config.currentValue = '17.0.0';
config.replacementVersionTemplate = `{{ lookup (split currentValue '.') 0 }}`;
config.replacementVersion = '18.0.0';
config.datasource = DockerDatasource.id;
getDockerReleases.mockResolvedValueOnce({
releases: [
{
version: '17.0.0',
},
{
version: '18.0.0',
},
],
});

const { updates } = await Result.wrap(
lookup.lookupUpdates(config),
).unwrapOrThrow();

expect(updates).toEqual([
{
bucket: 'major',
newMajor: 18,
newMinor: 0,
newPatch: 0,
newValue: '18.0.0',
newVersion: '18.0.0',
updateType: 'major',
},
{
newName: 'mirror_some_org/library/openjdk',
newValue: '18.0.0',
updateType: 'replacement',
},
]);
});

it('handles replacements - can perform replacement even for invalid versioning', async () => {
config.packageName = 'adoptopenjdk/openjdk11';
config.currentValue = 'alpine-jre';
Expand Down
1 change: 1 addition & 0 deletions lib/workers/repository/process/lookup/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export interface LookupUpdateConfig
replacementName?: string;
replacementNameTemplate?: string;
replacementVersion?: string;
replacementVersionTemplate?: string;
extractVersion?: string;
vulnerabilityFixVersion?: string;
vulnerabilityFixStrategy?: string;
Expand Down
32 changes: 22 additions & 10 deletions lib/workers/repository/process/lookup/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ export function isReplacementRulesConfigured(
return (
is.nonEmptyString(config.replacementName) ||
is.nonEmptyString(config.replacementNameTemplate) ||
is.nonEmptyString(config.replacementVersion)
is.nonEmptyString(config.replacementVersion) ||
is.nonEmptyString(config.replacementVersionTemplate)
);
}

Expand All @@ -50,18 +51,29 @@ export function determineNewReplacementName(
export function determineNewReplacementValue(
config: LookupUpdateConfig,
): string | undefined | null {
const newVersion = getNewVersion(config);
if (!newVersion) {
return config.currentValue;
}

const versioningApi = allVersioning.get(config.versioning);
const rangeStrategy = getRangeStrategy(config);

return versioningApi.getNewValue({
// TODO #22198
currentValue: config.currentValue!,
newVersion,
rangeStrategy: rangeStrategy!,
isReplacement: true,
});
}

function getNewVersion(config: LookupUpdateConfig): string | null {
if (!is.nullOrUndefined(config.replacementVersion)) {
return versioningApi.getNewValue({
// TODO #22198
currentValue: config.currentValue!,
newVersion: config.replacementVersion,
rangeStrategy: rangeStrategy!,
isReplacement: true,
});
return config.replacementVersion;
}

return config.currentValue;
if (!is.nullOrUndefined(config.replacementVersionTemplate)) {
return template.compile(config.replacementVersionTemplate, config, true);
}
return null;
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@
"@smithy/util-stream": "3.3.4",
"@types/auth-header": "1.0.6",
"@types/aws4": "1.11.6",
"@types/better-sqlite3": "7.6.12",
"@types/better-sqlite3": "7.6.13",
"@types/breejs__later": "4.1.5",
"@types/bunyan": "1.8.11",
"@types/cacache": "17.0.2",
Expand Down Expand Up @@ -348,7 +348,7 @@
"vite": "6.2.6",
"vite-tsconfig-paths": "5.1.4",
"vitest": "3.1.1",
"vitest-mock-extended": "3.0.1"
"vitest-mock-extended": "3.1.0"
},
"packageManager": "pnpm@10.7.1",
"files": [
Expand Down
20 changes: 10 additions & 10 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion tools/schemas/replacements-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
"replacementName": { "type": "string" },
"replacementVersion": { "type": "string" },
"description": { "type": "string" },
"replacementNameTemplate": { "type": "string" }
"replacementNameTemplate": { "type": "string" },
"replacementVersionTemplate": { "type": "string" }
},
"required": ["matchDatasources", "matchPackageNames"]
},
Expand Down
1 change: 1 addition & 0 deletions tools/schemas/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const PackageRuleSchema = z.object({
replacementVersion: z.string().optional(),
description: z.string().optional(),
replacementNameTemplate: z.string().optional(),
replacementVersionTemplate: z.string().optional(),
});

const RuleSetSchema = z.object({
Expand Down
Loading