Skip to content

Commit

Permalink
feat: separateMultipleMinor (#24538)
Browse files Browse the repository at this point in the history
Co-authored-by: Rhys Arkins <rhys@arkins.net>
Co-authored-by: Jan Philipp Gölz <32487587+jpgoelz@users.noreply.github.com>
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com>
  • Loading branch information
5 people committed Mar 24, 2024
1 parent 58bf6e3 commit e8493c5
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 6 deletions.
9 changes: 9 additions & 0 deletions docs/usage/configuration-options.md
Expand Up @@ -3773,6 +3773,15 @@ Configure this to `true` if you wish to get one PR for every separate major vers
e.g. if you are on webpack@v1 currently then default behavior is a PR for upgrading to webpack@v3 and not for webpack@v2.
If this setting is true then you would get one PR for webpack@v2 and one for webpack@v3.

## separateMultipleMinor

Enable this for dependencies when it is important to split updates into separate PRs per minor release stream (e.g. `python`).

For example, if you are on `python@v3.9.0` currently, then by default Renovate creates a PR to upgrade you to the latest version such as `python@v3.12.x`.
By default, Renovate skips versions in between, like `python@v3.10.x`.

But if you set `separateMultipleMinor=true` then you get separate PRs for each minor stream, like `python@3.9.x`, `python@v3.10.x` and `python@v3.11.x`, etc.

## skipInstalls

By default, Renovate will use the most efficient approach to updating package files and lock files, which in most cases skips the need to perform a full module install by the bot.
Expand Down
9 changes: 9 additions & 0 deletions lib/config/options/index.ts
Expand Up @@ -1620,6 +1620,15 @@ const options: RenovateOptions[] = [
type: 'boolean',
default: false,
},
{
name: 'separateMultipleMinor',
description:
'If set to `true`, Renovate creates separate PRs for each `minor` stream.',
stage: 'package',
type: 'boolean',
default: false,
experimental: true,
},
{
name: 'separateMinorPatch',
description:
Expand Down
5 changes: 5 additions & 0 deletions lib/config/presets/internal/default.ts
Expand Up @@ -574,6 +574,11 @@ export const presets: Record<string, Preset> = {
separateMajorMinor: true,
separateMultipleMajor: true,
},
separateMultipleMinorReleases: {
description:
'Separate each `minor` version of dependencies into individual branches/PRs.',
separateMultipleMinor: true,
},
separatePatchReleases: {
description:
'Separate `patch` and `minor` releases of dependencies into separate PRs.',
Expand Down
1 change: 1 addition & 0 deletions lib/config/validation.ts
Expand Up @@ -464,6 +464,7 @@ export async function validateConfig(
'separateMajorMinor',
'separateMinorPatch',
'separateMultipleMajor',
'separateMultipleMinor',
'versioning',
];
if (is.nonEmptyArray(resolvedRule.matchUpdateTypes)) {
Expand Down
11 changes: 7 additions & 4 deletions lib/workers/repository/process/lookup/bucket.ts
Expand Up @@ -3,6 +3,7 @@ import type { VersioningApi } from '../../../../modules/versioning/types';
export interface BucketConfig {
separateMajorMinor?: boolean;
separateMultipleMajor?: boolean;
separateMultipleMinor?: boolean;
separateMinorPatch?: boolean;
}

Expand All @@ -12,8 +13,12 @@ export function getBucket(
newVersion: string,
versioning: VersioningApi,
): string | null {
const { separateMajorMinor, separateMultipleMajor, separateMinorPatch } =
config;
const {
separateMajorMinor,
separateMultipleMajor,
separateMultipleMinor,
separateMinorPatch,
} = config;
if (!separateMajorMinor) {
return 'latest';
}
Expand Down Expand Up @@ -46,11 +51,9 @@ export function getBucket(

// Check the minor update type first
if (fromMinor !== toMinor) {
/* future option
if (separateMultipleMinor) {
return `v${toMajor}.${toMinor}`;
}
*/

if (separateMinorPatch) {
return 'minor';
Expand Down
15 changes: 15 additions & 0 deletions lib/workers/repository/process/lookup/index.spec.ts
Expand Up @@ -2785,6 +2785,21 @@ describe('workers/repository/process/lookup/index', () => {
]);
});

it('should upgrade to 16 minors', async () => {
config.currentValue = '1.0.0';
config.separateMultipleMinor = true;
config.packageName = 'webpack';
config.datasource = NpmDatasource.id;
httpMock
.scope('https://registry.npmjs.org')
.get('/webpack')
.reply(200, webpackJson);
const { updates } = await Result.wrap(
lookup.lookupUpdates(config),
).unwrapOrThrow();
expect(updates).toHaveLength(16);
});

it('does not jump major unstable', async () => {
config.currentValue = '^4.4.0-canary.3';
config.rangeStrategy = 'replace';
Expand Down
1 change: 1 addition & 0 deletions lib/workers/repository/process/lookup/types.ts
Expand Up @@ -41,6 +41,7 @@ export interface LookupUpdateConfig
isVulnerabilityAlert?: boolean;
separateMajorMinor?: boolean;
separateMultipleMajor?: boolean;
separateMultipleMinor?: boolean;
datasource: string;
packageName: string;
minimumConfidence?: MergeConfidence | undefined;
Expand Down
1 change: 1 addition & 0 deletions lib/workers/repository/process/lookup/update-type.ts
Expand Up @@ -4,6 +4,7 @@ import type * as allVersioning from '../../../../modules/versioning';
export interface UpdateTypeConfig {
separateMajorMinor?: boolean;
separateMultipleMajor?: boolean;
separateMultipleMinor?: boolean;
separateMinorPatch?: boolean;
}

Expand Down
37 changes: 37 additions & 0 deletions lib/workers/repository/updates/branch-name.spec.ts
Expand Up @@ -59,6 +59,43 @@ describe('workers/repository/updates/branch-name', () => {
expect(upgrade.branchName).toBe('major-2-some-group-slug-grouptopic');
});

it('separates minor with groups', () => {
const upgrade: RenovateConfig = {
groupName: 'some group name',
groupSlug: 'some group slug',
updateType: 'minor',
separateMultipleMinor: true,
newMinor: 1,
newMajor: 2,
group: {
branchName: '{{groupSlug}}-{{branchTopic}}',
branchTopic: 'grouptopic',
},
};
generateBranchName(upgrade);
expect(upgrade.branchName).toBe('minor-2.1-some-group-slug-grouptopic');
});

it('separates minor when separateMultipleMinor=true', () => {
const upgrade: RenovateConfig = {
branchName:
'{{{branchPrefix}}}{{{additionalBranchPrefix}}}{{{branchTopic}}}',
branchPrefix: 'renovate/',
additionalBranchPrefix: '',
depNameSanitized: 'lodash',
newMajor: 4,
separateMinorPatch: true,
isPatch: true,
newMinor: 17,
branchTopic:
'{{{depNameSanitized}}}-{{{newMajor}}}{{#if separateMinorPatch}}{{#if isPatch}}.{{{newMinor}}}{{/if}}{{/if}}.x{{#if isLockfileUpdate}}-lockfile{{/if}}',
depName: 'dep',
group: {},
};
generateBranchName(upgrade);
expect(upgrade.branchName).toBe('renovate/lodash-4.17.x');
});

it('uses single major with groups', () => {
const upgrade: RenovateConfig = {
groupName: 'some group name',
Expand Down
10 changes: 8 additions & 2 deletions lib/workers/repository/updates/branch-name.ts
Expand Up @@ -47,6 +47,8 @@ function cleanBranchName(

export function generateBranchName(update: RenovateConfig): void {
// Check whether to use a group name
const newMajor = String(update.newMajor);
const newMinor = String(update.newMinor);
if (update.groupName) {
update.groupName = template.compile(update.groupName, update);
logger.trace('Using group branchName template');
Expand All @@ -64,12 +66,14 @@ export function generateBranchName(update: RenovateConfig): void {
});
if (update.updateType === 'major' && update.separateMajorMinor) {
if (update.separateMultipleMajor) {
const newMajor = String(update.newMajor);
update.groupSlug = `major-${newMajor}-${update.groupSlug}`;
} else {
update.groupSlug = `major-${update.groupSlug}`;
}
}
if (update.updateType === 'minor' && update.separateMultipleMinor) {
update.groupSlug = `minor-${newMajor}.${newMinor}-${update.groupSlug}`;
}
if (update.updateType === 'patch' && update.separateMinorPatch) {
update.groupSlug = `patch-${update.groupSlug}`;
}
Expand Down Expand Up @@ -116,7 +120,9 @@ export function generateBranchName(update: RenovateConfig): void {
update.branchName = template.compile(update.branchName, update);
update.branchName = template.compile(update.branchName, update);
}

if (update.updateType === 'minor' && update.separateMultipleMinor) {
update.branchName = update.branchName.replace('.x', `.${newMinor}.x`);
}
update.branchName = cleanBranchName(
update.branchName,
update.branchNameStrict,
Expand Down

0 comments on commit e8493c5

Please sign in to comment.