From 2c264af8d2e2169676debeb6fe8d772ed9141a16 Mon Sep 17 00:00:00 2001 From: RahulGautamSingh <rahultesnik@gmail.com> Date: Mon, 12 Jun 2023 21:33:40 +0545 Subject: [PATCH] feat: migrate`recreateClosed` to `recreateWhen` (#21039) Co-authored-by: Rhys Arkins <rhys@arkins.net> Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Co-authored-by: Michael Kriese <michael.kriese@visualon.de> --- docs/usage/configuration-options.md | 21 ++++++++---- docs/usage/key-concepts/pull-requests.md | 1 + lib/config/__snapshots__/index.spec.ts.snap | 2 +- .../custom/recreate-closed-migration.spec.ts | 25 ++++++++++++++ .../custom/recreate-closed-migration.ts | 13 ++++++++ lib/config/migrations/migrations-service.ts | 2 ++ lib/config/options/index.ts | 9 ++--- lib/config/types.ts | 2 ++ lib/workers/global/config/parse/cli.spec.ts | 28 +++++++++------- lib/workers/global/config/parse/cli.ts | 3 ++ lib/workers/global/config/parse/env.spec.ts | 25 ++++++++++---- lib/workers/global/config/parse/env.ts | 31 +++++++++++++++++ .../update/branch/check-existing.spec.ts | 4 +-- .../update/branch/check-existing.ts | 8 +++-- .../repository/update/branch/index.spec.ts | 2 +- .../update/pr/body/config-description.spec.ts | 15 ++++++++- .../repository/update/pr/pr-fingerprint.ts | 10 ++++-- .../__snapshots__/generate.spec.ts.snap | 2 ++ .../repository/updates/generate.spec.ts | 33 ++++++++++++++++--- lib/workers/repository/updates/generate.ts | 8 +++-- 20 files changed, 200 insertions(+), 44 deletions(-) create mode 100644 lib/config/migrations/custom/recreate-closed-migration.spec.ts create mode 100644 lib/config/migrations/custom/recreate-closed-migration.ts diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 5283cde172..53232f4c4b 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -2889,18 +2889,27 @@ It is also recommended to avoid `rebaseWhen=never` as it can result in conflicte Avoid setting `rebaseWhen=never` and then also setting `prCreation=not-pending` as this can prevent creation of PRs. -## recreateClosed +## recreateWhen -By default, Renovate will detect if it has proposed an update to a project before and not propose the same one again. -For example the Webpack 3.x case described above. -This field lets you customize this behavior down to a per-package level. -For example we override it to `true` in the following cases where branch names and PR titles need to be reused: +This feature used to be called `recreateClosed`. + +By default, Renovate detects if it proposed an update to a project before, and will not propose the same update again. +For example the Webpack 3.x case described in the [`separateMajorMinor`](#separatemajorminor) documentation. +You can use `recreateWhen` to customize this behavior down to a per-package level. +For example we override it to `always` in the following cases where branch names and PR titles must be reused: - Package groups - When pinning versions - Lock file maintenance -Typically you shouldn't need to modify this setting. +You can select which behavior you want from Renovate: + +- `always`: Recreates all closed or blocking PRs +- `auto`: The default option. Recreates only immortal PRs (default) +- `never`: No PR is recreated, doesn't matter if it is immortal or not + +We recommend that you stick with the default setting for this option. +Only change this setting if you really need to. ## regexManagers diff --git a/docs/usage/key-concepts/pull-requests.md b/docs/usage/key-concepts/pull-requests.md index 4f63045a5f..7e2af2e96a 100644 --- a/docs/usage/key-concepts/pull-requests.md +++ b/docs/usage/key-concepts/pull-requests.md @@ -76,6 +76,7 @@ If you regularly wish to close immortal PRs, it's an indication that you may be ### How to fix immortal PRs Avoid grouping dependencies together which have different versions, or which you have a high chance of wanting to ignore. +If you have immortal PRs which you want to keep closed, then set `"recreateWhen": "never"`. #### Major updates require Dependency Dashboard approval diff --git a/lib/config/__snapshots__/index.spec.ts.snap b/lib/config/__snapshots__/index.spec.ts.snap index 83825d9ee3..e8b55b377a 100644 --- a/lib/config/__snapshots__/index.spec.ts.snap +++ b/lib/config/__snapshots__/index.spec.ts.snap @@ -12,7 +12,7 @@ exports[`config/index mergeChildConfig(parentConfig, childConfig) merges 1`] = ` "Change": "All locks refreshed", }, "rebaseStalePrs": true, - "recreateClosed": true, + "recreateWhen": "always", "schedule": [ "on monday", ], diff --git a/lib/config/migrations/custom/recreate-closed-migration.spec.ts b/lib/config/migrations/custom/recreate-closed-migration.spec.ts new file mode 100644 index 0000000000..38628ca6c4 --- /dev/null +++ b/lib/config/migrations/custom/recreate-closed-migration.spec.ts @@ -0,0 +1,25 @@ +import { RecreateClosedMigration } from './recreate-closed-migration'; + +describe('config/migrations/custom/recreate-closed-migration', () => { + it('should migrate true', () => { + expect(RecreateClosedMigration).toMigrate( + { + recreateClosed: true, + }, + { + recreateWhen: 'always', + } + ); + }); + + it('should migrate false', () => { + expect(RecreateClosedMigration).toMigrate( + { + recreateClosed: false, + }, + { + recreateWhen: 'auto', + } + ); + }); +}); diff --git a/lib/config/migrations/custom/recreate-closed-migration.ts b/lib/config/migrations/custom/recreate-closed-migration.ts new file mode 100644 index 0000000000..81cd106f4e --- /dev/null +++ b/lib/config/migrations/custom/recreate-closed-migration.ts @@ -0,0 +1,13 @@ +import is from '@sindresorhus/is'; +import { AbstractMigration } from '../base/abstract-migration'; + +export class RecreateClosedMigration extends AbstractMigration { + override readonly deprecated = true; + override readonly propertyName = 'recreateClosed'; + + override run(value: unknown): void { + if (is.boolean(value)) { + this.setSafely('recreateWhen', value ? 'always' : 'auto'); + } + } +} diff --git a/lib/config/migrations/migrations-service.ts b/lib/config/migrations/migrations-service.ts index 1b6c0d357d..e7e3b314bb 100644 --- a/lib/config/migrations/migrations-service.ts +++ b/lib/config/migrations/migrations-service.ts @@ -39,6 +39,7 @@ import { PostUpdateOptionsMigration } from './custom/post-update-options-migrati import { RaiseDeprecationWarningsMigration } from './custom/raise-deprecation-warnings-migration'; import { RebaseConflictedPrs } from './custom/rebase-conflicted-prs-migration'; import { RebaseStalePrsMigration } from './custom/rebase-stale-prs-migration'; +import { RecreateClosedMigration } from './custom/recreate-closed-migration'; import { RenovateForkMigration } from './custom/renovate-fork-migration'; import { RequireConfigMigration } from './custom/require-config-migration'; import { RequiredStatusChecksMigration } from './custom/required-status-checks-migration'; @@ -145,6 +146,7 @@ export class MigrationsService { SemanticPrefixMigration, MatchDatasourcesMigration, DatasourceMigration, + RecreateClosedMigration, StabilityDaysMigration, ]; diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index f71066be46..f539bbf96b 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -1574,10 +1574,11 @@ const options: RenovateOptions[] = [ default: false, }, { - name: 'recreateClosed', + name: 'recreateWhen', description: 'Recreate PRs even if same ones were closed previously.', - type: 'boolean', - default: false, + type: 'string', + default: 'auto', + allowedValues: ['auto', 'always', 'never'], }, { name: 'rebaseWhen', @@ -1899,7 +1900,7 @@ const options: RenovateOptions[] = [ type: 'object', default: { enabled: false, - recreateClosed: true, + recreateWhen: 'always', rebaseStalePrs: true, branchTopic: 'lock-file-maintenance', commitMessageAction: 'Lock file maintenance', diff --git a/lib/config/types.ts b/lib/config/types.ts index 5c390b09c8..ac915cd803 100644 --- a/lib/config/types.ts +++ b/lib/config/types.ts @@ -21,6 +21,7 @@ export interface GroupConfig extends Record<string, unknown> { branchTopic?: string; } +export type RecreateWhen = 'auto' | 'never' | 'always'; // TODO: Proper typings export interface RenovateSharedConfig { $schema?: string; @@ -70,6 +71,7 @@ export interface RenovateSharedConfig { respectLatest?: boolean; stopUpdatingLabel?: string; rebaseWhen?: string; + recreateWhen?: RecreateWhen; recreateClosed?: boolean; repository?: string; repositoryCache?: RepositoryCacheConfig; diff --git a/lib/workers/global/config/parse/cli.spec.ts b/lib/workers/global/config/parse/cli.spec.ts index a98b4f8939..8cb7a3d785 100644 --- a/lib/workers/global/config/parse/cli.spec.ts +++ b/lib/workers/global/config/parse/cli.spec.ts @@ -33,19 +33,19 @@ describe('workers/global/config/parse/cli', () => { }); it('supports boolean no value', () => { - argv.push('--recreate-closed'); - expect(cli.getConfig(argv)).toEqual({ recreateClosed: true }); + argv.push('--config-migration'); + expect(cli.getConfig(argv)).toEqual({ configMigration: true }); argv = argv.slice(0, -1); }); it('supports boolean space true', () => { - argv.push('--recreate-closed'); + argv.push('--config-migration'); argv.push('true'); - expect(cli.getConfig(argv)).toEqual({ recreateClosed: true }); + expect(cli.getConfig(argv)).toEqual({ configMigration: true }); }); it('throws exception for invalid boolean value', () => { - argv.push('--recreate-closed'); + argv.push('--config-migration'); argv.push('badvalue'); expect(() => cli.getConfig(argv)).toThrow( Error( @@ -55,19 +55,19 @@ describe('workers/global/config/parse/cli', () => { }); it('supports boolean space false', () => { - argv.push('--recreate-closed'); + argv.push('--config-migration'); argv.push('false'); - expect(cli.getConfig(argv)).toEqual({ recreateClosed: false }); + expect(cli.getConfig(argv)).toEqual({ configMigration: false }); }); it('supports boolean equals true', () => { - argv.push('--recreate-closed=true'); - expect(cli.getConfig(argv)).toEqual({ recreateClosed: true }); + argv.push('--config-migration=true'); + expect(cli.getConfig(argv)).toEqual({ configMigration: true }); }); it('supports boolean equals false', () => { - argv.push('--recreate-closed=false'); - expect(cli.getConfig(argv)).toEqual({ recreateClosed: false }); + argv.push('--config-migration=false'); + expect(cli.getConfig(argv)).toEqual({ configMigration: false }); }); it('supports list single', () => { @@ -130,6 +130,12 @@ describe('workers/global/config/parse/cli', () => { ${'--git-lab-automerge=false'} | ${{ platformAutomerge: false }} ${'--git-lab-automerge=true'} | ${{ platformAutomerge: true }} ${'--git-lab-automerge'} | ${{ platformAutomerge: true }} + ${'--recreate-closed=false'} | ${{ recreateWhen: 'auto' }} + ${'--recreate-closed=true'} | ${{ recreateWhen: 'always' }} + ${'--recreate-closed'} | ${{ recreateWhen: 'always' }} + ${'--recreate-when=auto'} | ${{ recreateWhen: 'auto' }} + ${'--recreate-when=always'} | ${{ recreateWhen: 'always' }} + ${'--recreate-when=never'} | ${{ recreateWhen: 'never' }} `('"$arg" -> $config', ({ arg, config }) => { argv.push(arg); expect(cli.getConfig(argv)).toMatchObject(config); diff --git a/lib/workers/global/config/parse/cli.ts b/lib/workers/global/config/parse/cli.ts index f12305fa3e..37c8d37cac 100644 --- a/lib/workers/global/config/parse/cli.ts +++ b/lib/workers/global/config/parse/cli.ts @@ -34,6 +34,9 @@ export function getConfig(input: string[]): AllConfig { .replace('--aliases', '--registry-aliases') .replace('--include-forks=true', '--fork-processing=enabled') .replace('--include-forks', '--fork-processing=enabled') + .replace('--recreate-closed=false', '--recreate-when=auto') + .replace('--recreate-closed=true', '--recreate-when=always') + .replace('--recreate-closed', '--recreate-when=always') ) .filter((a) => !a.startsWith('--git-fs')); const options = getOptions(); diff --git a/lib/workers/global/config/parse/env.spec.ts b/lib/workers/global/config/parse/env.spec.ts index ff963b7658..672839f1c3 100644 --- a/lib/workers/global/config/parse/env.spec.ts +++ b/lib/workers/global/config/parse/env.spec.ts @@ -10,18 +10,20 @@ describe('workers/global/config/parse/env', () => { }); it('supports boolean true', () => { - const envParam: NodeJS.ProcessEnv = { RENOVATE_RECREATE_CLOSED: 'true' }; - expect(env.getConfig(envParam).recreateClosed).toBeTrue(); + const envParam: NodeJS.ProcessEnv = { RENOVATE_CONFIG_MIGRATION: 'true' }; + expect(env.getConfig(envParam).configMigration).toBeTrue(); }); it('supports boolean false', () => { - const envParam: NodeJS.ProcessEnv = { RENOVATE_RECREATE_CLOSED: 'false' }; - expect(env.getConfig(envParam).recreateClosed).toBeFalse(); + const envParam: NodeJS.ProcessEnv = { + RENOVATE_CONFIG_MIGRATION: 'false', + }; + expect(env.getConfig(envParam).configMigration).toBeFalse(); }); it('throws exception for invalid boolean value', () => { const envParam: NodeJS.ProcessEnv = { - RENOVATE_RECREATE_CLOSED: 'badvalue', + RENOVATE_CONFIG_MIGRATION: 'badvalue', }; expect(() => env.getConfig(envParam)).toThrow( Error( @@ -30,7 +32,7 @@ describe('workers/global/config/parse/env', () => { ); }); - delete process.env.RENOVATE_RECREATE_CLOSED; + delete process.env.RENOVATE_CONFIG_MIGRATION; it('supports list single', () => { const envParam: NodeJS.ProcessEnv = { RENOVATE_LABELS: 'a' }; @@ -83,6 +85,17 @@ describe('workers/global/config/parse/env', () => { expect(res).toMatchObject({ hostRules: [{ foo: 'bar' }] }); }); + test.each` + envArg | config + ${{ RENOVATE_RECREATE_CLOSED: 'true' }} | ${{ recreateWhen: 'always' }} + ${{ RENOVATE_RECREATE_CLOSED: 'false' }} | ${{ recreateWhen: 'auto' }} + ${{ RENOVATE_RECREATE_WHEN: 'auto' }} | ${{ recreateWhen: 'auto' }} + ${{ RENOVATE_RECREATE_WHEN: 'always' }} | ${{ recreateWhen: 'always' }} + ${{ RENOVATE_RECREATE_WHEN: 'never' }} | ${{ recreateWhen: 'never' }} + `('"$envArg" -> $config', ({ envArg, config }) => { + expect(env.getConfig(envArg)).toMatchObject(config); + }); + it('skips misconfigured arrays', () => { const envName = 'RENOVATE_HOST_RULES'; const val = JSON.stringify('foobar'); diff --git a/lib/workers/global/config/parse/env.ts b/lib/workers/global/config/parse/env.ts index 4c1afc8b7e..f176043f08 100644 --- a/lib/workers/global/config/parse/env.ts +++ b/lib/workers/global/config/parse/env.ts @@ -53,10 +53,41 @@ function renameEnvKeys(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv { return result; } +const migratedKeysWithValues = [ + { + oldName: 'recreateClosed', + newName: 'recreateWhen', + from: 'true', + to: 'always', + }, + { + oldName: 'recreateClosed', + newName: 'recreateWhen', + from: 'false', + to: 'auto', + }, +]; + +function massageEnvKeyValues(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv { + const result = { ...env }; + for (const { oldName, newName, from, to } of migratedKeysWithValues) { + const key = getEnvName({ name: oldName }); + if (env[key] !== undefined) { + if (result[key] === from) { + delete result[key]; + result[getEnvName({ name: newName })] = to; + } + } + } + return result; +} + export function getConfig(inputEnv: NodeJS.ProcessEnv): AllConfig { let env = inputEnv; env = normalizePrefixes(inputEnv, inputEnv.ENV_PREFIX); env = renameEnvKeys(env); + // massage the values of migrated configuration keys + env = massageEnvKeyValues(env); const options = getOptions(); diff --git a/lib/workers/repository/update/branch/check-existing.spec.ts b/lib/workers/repository/update/branch/check-existing.spec.ts index ff7c545d85..c1f219f22a 100644 --- a/lib/workers/repository/update/branch/check-existing.spec.ts +++ b/lib/workers/repository/update/branch/check-existing.spec.ts @@ -20,13 +20,13 @@ describe('workers/repository/update/branch/check-existing', () => { }); it('returns false if recreating closed PRs', async () => { - config.recreateClosed = true; + config.recreateWhen = 'always'; expect(await prAlreadyExisted(config)).toBeNull(); expect(platform.findPr).toHaveBeenCalledTimes(0); }); it('returns false if check misses', async () => { - config.recreatedClosed = true; + config.recreateWhen = 'auto'; expect(await prAlreadyExisted(config)).toBeNull(); expect(platform.findPr).toHaveBeenCalledTimes(1); }); diff --git a/lib/workers/repository/update/branch/check-existing.ts b/lib/workers/repository/update/branch/check-existing.ts index 877d28fa0d..c0fdba1154 100644 --- a/lib/workers/repository/update/branch/check-existing.ts +++ b/lib/workers/repository/update/branch/check-existing.ts @@ -8,11 +8,13 @@ export async function prAlreadyExisted( config: BranchConfig ): Promise<Pr | null> { logger.trace({ config }, 'prAlreadyExisted'); - if (config.recreateClosed) { - logger.debug('recreateClosed is true'); + if (config.recreateWhen === 'always') { + logger.debug('recreateWhen is "always". No need to check for closed PR.'); return null; } - logger.debug('recreateClosed is false'); + logger.debug( + 'Check for closed PR because recreating closed PRs is disabled.' + ); // Return if same PR already existed let pr = await platform.findPr({ branchName: config.branchName, diff --git a/lib/workers/repository/update/branch/index.spec.ts b/lib/workers/repository/update/branch/index.spec.ts index 66e276a240..4a438e2544 100644 --- a/lib/workers/repository/update/branch/index.spec.ts +++ b/lib/workers/repository/update/branch/index.spec.ts @@ -1026,7 +1026,7 @@ describe('workers/repository/update/branch/index', () => { artifactErrors: [partial<ArtifactError>()], updatedArtifacts: [partial<FileChange>()], }); - config.recreateClosed = true; + config.recreateWhen = 'always'; scm.branchExists.mockResolvedValue(true); automerge.tryBranchAutomerge.mockResolvedValueOnce('failed'); prWorker.ensurePr.mockResolvedValueOnce({ diff --git a/lib/workers/repository/update/pr/body/config-description.spec.ts b/lib/workers/repository/update/pr/body/config-description.spec.ts index 435c37258c..37bba58b2c 100644 --- a/lib/workers/repository/update/pr/body/config-description.spec.ts +++ b/lib/workers/repository/update/pr/body/config-description.spec.ts @@ -67,7 +67,7 @@ describe('workers/repository/update/pr/body/config-description', () => { expect(res).toContain(`At any time (no schedule defined).`); }); - it('renders recreateClosed', () => { + it('renders recreateClosed=true', () => { const res = getPrConfigDescription({ ...config, recreateClosed: true, @@ -75,6 +75,19 @@ describe('workers/repository/update/pr/body/config-description', () => { expect(res).toContain(`**Immortal**`); }); + it('does not render recreateClosed=false', () => { + const res = getPrConfigDescription({ + ...config, + recreateClosed: false, + }); + expect(res).not.toContain(`**Immortal**`); + }); + + it('does not render recreateClosed=undefined', () => { + const res = getPrConfigDescription(config); + expect(res).not.toContain(`**Immortal**`); + }); + it('renders singular', () => { const res = getPrConfigDescription({ ...config, diff --git a/lib/workers/repository/update/pr/pr-fingerprint.ts b/lib/workers/repository/update/pr/pr-fingerprint.ts index 9558522781..cd91d44069 100644 --- a/lib/workers/repository/update/pr/pr-fingerprint.ts +++ b/lib/workers/repository/update/pr/pr-fingerprint.ts @@ -1,7 +1,11 @@ // fingerprint config is based on the old skip pr update logic // https://github.com/renovatebot/renovate/blob/3d85b6048d6a8c57887b64ed4929e2e02ea41aa0/lib/workers/repository/update/pr/index.ts#L294-L306 -import type { UpdateType, ValidationMessage } from '../../../../config/types'; +import type { + RecreateWhen, + UpdateType, + ValidationMessage, +} from '../../../../config/types'; import { logger } from '../../../../logger'; import type { PrCache } from '../../../../util/cache/repository/types'; import { getElapsedHours } from '../../../../util/date'; @@ -28,7 +32,7 @@ export interface PrBodyFingerprintConfig { prHeader?: string; prTitle?: string; rebaseWhen?: string; - recreateClosed?: boolean; + recreateWhen?: RecreateWhen; schedule?: string[]; stopUpdating?: boolean; timezone?: string; @@ -67,7 +71,7 @@ export function generatePrBodyFingerprintConfig( prHeader: config.prHeader, prTitle: config.prTitle, rebaseWhen: config.rebaseWhen, - recreateClosed: config.recreateClosed, + recreateWhen: config.recreateWhen, schedule: config.schedule, stopUpdating: config.stopUpdating, timezone: config.timezone, diff --git a/lib/workers/repository/updates/__snapshots__/generate.spec.ts.snap b/lib/workers/repository/updates/__snapshots__/generate.spec.ts.snap index 9455b1b87a..693e02a74f 100644 --- a/lib/workers/repository/updates/__snapshots__/generate.spec.ts.snap +++ b/lib/workers/repository/updates/__snapshots__/generate.spec.ts.snap @@ -178,6 +178,7 @@ exports[`workers/repository/updates/generate generateBranchConfig() handles lock "prBodyColumns": [], "prTitle": "some-title", "prettyDepType": "dependency", + "recreateClosed": true, "releaseTimestamp": undefined, "reuseLockFiles": true, "upgrades": [ @@ -191,6 +192,7 @@ exports[`workers/repository/updates/generate generateBranchConfig() handles lock "manager": "some-manager", "prTitle": "some-title", "prettyDepType": "dependency", + "recreateClosed": true, }, ], } diff --git a/lib/workers/repository/updates/generate.spec.ts b/lib/workers/repository/updates/generate.spec.ts index c44d2e74ee..ca0b111abb 100644 --- a/lib/workers/repository/updates/generate.spec.ts +++ b/lib/workers/repository/updates/generate.spec.ts @@ -67,6 +67,7 @@ describe('workers/repository/updates/generate', () => { branchName: 'some-branch', prTitle: 'some-title', isLockFileMaintenance: true, + recreateClosed: true, }, ], }); @@ -216,7 +217,7 @@ describe('workers/repository/updates/generate', () => { }); }); - it('groups major updates with different versions but same newValue, no recreateClosed', () => { + it('groups major updates with different versions but same newValue, no recreateWhen', () => { const branch = [ { manager: 'some-manager', @@ -282,7 +283,7 @@ describe('workers/repository/updates/generate', () => { expect(res.recreateClosed).toBeTrue(); }); - it('Grouped pin & pinDigest can be recreated', () => { + it('recreates grouped pin & pinDigest', () => { const branch = [ { ...requiredDefaultOptions, @@ -304,7 +305,31 @@ describe('workers/repository/updates/generate', () => { expect(res.recreateClosed).toBeTrue(); }); - it('Grouped pin can be recreated', () => { + it('does not recreate grouped pin & pinDigest when closed if recreateWhen=never', () => { + const branch = [ + { + ...requiredDefaultOptions, + isPinDigest: true, + updateType: 'pinDigest', + newValue: 'v2', + newDigest: 'dc323e67f16fb5f7663d20ff7941f27f5809e9b6', + recreateWhen: 'never', + }, + { + ...requiredDefaultOptions, + updateType: 'pin', + isPin: true, + newValue: "'2.2.0'", + newVersion: '2.2.0', + newMajor: 2, + recreateWhen: 'never', + }, + ] as BranchUpgradeConfig[]; + const res = generateBranchConfig(branch); + expect(res.recreateClosed).toBeFalse(); + }); + + it('recreates grouped pin', () => { const branch = [ { ...requiredDefaultOptions, @@ -331,7 +356,7 @@ describe('workers/repository/updates/generate', () => { expect(res.recreateClosed).toBeTrue(); }); - it('grouped pinDigest can be recreated', () => { + it('recreates grouped pinDigest', () => { const branch = [ { ...requiredDefaultOptions, diff --git a/lib/workers/repository/updates/generate.ts b/lib/workers/repository/updates/generate.ts index c56cb14345..c044fb94d1 100644 --- a/lib/workers/repository/updates/generate.ts +++ b/lib/workers/repository/updates/generate.ts @@ -103,6 +103,10 @@ export function generateBranchConfig( upg.displayFrom = upg.currentValue; upg.displayTo = upg.newValue; } + + if (upg.isLockFileMaintenance) { + upg.recreateClosed = upg.recreateWhen !== 'never'; + } upg.displayFrom ??= ''; upg.displayTo ??= ''; if (!depNames.includes(upg.depName!)) { @@ -178,14 +182,14 @@ export function generateBranchConfig( logger.trace({ toVersions }); logger.trace({ toValues }); delete upgrade.commitMessageExtra; - upgrade.recreateClosed = true; + upgrade.recreateClosed = upgrade.recreateWhen !== 'never'; } else if ( newValue.length > 1 && (upgrade.isDigest || upgrade.isPinDigest) ) { logger.trace({ newValue }); delete upgrade.commitMessageExtra; - upgrade.recreateClosed = true; + upgrade.recreateClosed = upgrade.recreateWhen !== 'never'; } else if (semver.valid(toVersions[0])) { upgrade.isRange = false; } -- GitLab