From 1207152cd975a95258777e51f807558df7353e11 Mon Sep 17 00:00:00 2001
From: Richard <richardcornelissen@users.noreply.github.com>
Date: Wed, 17 Jul 2019 14:48:08 +0200
Subject: [PATCH] feat: add pruneStaleBranches config option (#4107)

Closes #4106
---
 docs/local-development.md                     |  2 +-
 lib/config/definitions.js                     |  6 ++++++
 lib/workers/repository/finalise/prune.js      | 21 ++++++++++++++-----
 renovate-schema.json                          |  5 +++++
 .../workers/repository/finalise/prune.spec.js | 13 ++++++++++++
 website/docs/configuration-options.md         |  5 +++++
 6 files changed, 46 insertions(+), 6 deletions(-)

diff --git a/docs/local-development.md b/docs/local-development.md
index 2a97a8a49a..1727e0124f 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 909f67ccf5..92e9422c9c 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 bb858fb72e..da3bd78ff3 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 52868c23f5..cd33efaf81 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 f0a9d31532..2acbfa565d 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 b5cacfa049..1118460650 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
-- 
GitLab