diff --git a/docs/local-development.md b/docs/local-development.md index 2a97a8a49ad0551134e09047c5327366fae64020..1727e0124f3450cb3ed769fca7e2d168cae0aff2 100644 --- a/docs/local-development.md +++ b/docs/local-development.md @@ -117,7 +117,7 @@ We wish to keep backwards-compatibility as often as possible, as well as make the code configurable, so most new functionality should be controllable via configuration options. -If you wish to add one, add it to `lib/config/definitions.js` and then add documentation to `website/docs/_posts/2017-10-05-configuration-options.md`. +If you wish to add one, add it to `lib/config/definitions.js` and then add documentation to `website/docs/configuration-options.md`. ## Debugging diff --git a/lib/config/definitions.js b/lib/config/definitions.js index 909f67ccf56cdbce1728ea08f33efb2d85f74105..92e9422c9c6360a32bdc3395ac663516a6c1141c 100644 --- a/lib/config/definitions.js +++ b/lib/config/definitions.js @@ -1847,6 +1847,12 @@ const options = [ mergeable: true, cli: false, }, + { + name: 'pruneStaleBranches', + description: `Enable or disable pruning of stale branches`, + type: 'boolean', + default: true, + }, ]; function getOptions() { diff --git a/lib/workers/repository/finalise/prune.js b/lib/workers/repository/finalise/prune.js index bb858fb72e4836996cbd65309cad43672ceb4b48..da3bd78ff310ea8aa8eeadd83db91b9b3f7d66ae 100644 --- a/lib/workers/repository/finalise/prune.js +++ b/lib/workers/repository/finalise/prune.js @@ -4,24 +4,35 @@ module.exports = { pruneStaleBranches, }; -async function cleanUpBranches({ dryRun }, remainingBranches) { +async function cleanUpBranches( + { dryRun, pruneStaleBranches: enabled }, + remainingBranches +) { for (const branchName of remainingBranches) { try { const pr = await platform.findPr(branchName, null, 'open'); if (pr) { if (!pr.title.endsWith('- autoclosed')) { - if (dryRun) + if (dryRun) { logger.info( `DRY-RUN: Would update pr ${pr.number} to ${pr.title} - autoclosed` ); - else await platform.updatePr(pr.number, `${pr.title} - autoclosed`); + } else if (enabled === false) { + logger.info( + `PRUNING-DISABLED: Would update pr ${pr.number} to ${pr.title} - autoclosed` + ); + } else await platform.updatePr(pr.number, `${pr.title} - autoclosed`); } } const closePr = true; logger.info({ branch: branchName }, `Deleting orphan branch`); - if (dryRun) + if (dryRun) { logger.info(`DRY-RUN: Would deleting orphan branch ${branchName}`); - else await platform.deleteBranch(branchName, closePr); + } else if (enabled === false) { + logger.info( + `PRUNING-DISABLED: Would deleting orphan branch ${branchName}` + ); + } else await platform.deleteBranch(branchName, closePr); if (pr) { logger.info({ prNo: pr.number, prTitle: pr.title }, 'PR autoclosed'); } diff --git a/renovate-schema.json b/renovate-schema.json index 52868c23f5e4a226f32fd71dc834d3380cc423d2..cd33efaf8114c4a3e7ea77fa81b61ef3f081b801 100644 --- a/renovate-schema.json +++ b/renovate-schema.json @@ -1265,6 +1265,11 @@ "rangeStrategy": "bump" }, "$ref": "#" + }, + "pruneStaleBranches": { + "description": "Enable or disable pruning of stale branches", + "type": "boolean", + "default": true } } } diff --git a/test/workers/repository/finalise/prune.spec.js b/test/workers/repository/finalise/prune.spec.js index f0a9d3153226ce004f656ea6573f3cf187c28caa..2acbfa565d56281363694c25628202a6e1c15329 100644 --- a/test/workers/repository/finalise/prune.spec.js +++ b/test/workers/repository/finalise/prune.spec.js @@ -55,5 +55,18 @@ describe('workers/repository/finalise/prune', () => { expect(platform.deleteBranch).toHaveBeenCalledTimes(0); expect(platform.updatePr).toHaveBeenCalledTimes(0); }); + it('does nothing on prune stale branches disabled', async () => { + config.branchList = ['renovate/a', 'renovate/b']; + config.dryRun = false; + config.pruneStaleBranches = false; + platform.getAllRenovateBranches.mockReturnValueOnce( + config.branchList.concat(['renovate/c']) + ); + platform.findPr.mockReturnValueOnce({ title: 'foo' }); + await cleanup.pruneStaleBranches(config, config.branchList); + expect(platform.getAllRenovateBranches).toHaveBeenCalledTimes(1); + expect(platform.deleteBranch).toHaveBeenCalledTimes(0); + expect(platform.updatePr).toHaveBeenCalledTimes(0); + }); }); }); diff --git a/website/docs/configuration-options.md b/website/docs/configuration-options.md index b5cacfa049ec8185b647e3d8ec87c694347920de..11184606502c5dbb0becfd30c5e590413cb411aa 100644 --- a/website/docs/configuration-options.md +++ b/website/docs/configuration-options.md @@ -911,6 +911,11 @@ If you set `prCreation=not-pending`, then Renovate will wait until tests are non The PR title is important for some of Renovate's matching algorithms (e.g. determining whether to recreate a PR or not) so ideally don't modify it much. +## pruneStaleBranches + +Set to `false` to disable deleting orphan branches and autoclosing PRs. +Defaults to `true`. + ## pub ## python