From 2555339552ab9b58307704426602eb8ab3535c60 Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@arkins.net>
Date: Thu, 27 Sep 2018 15:34:13 +0200
Subject: [PATCH] feat: rebase using PR title
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

If PR title starts with “rebase!” then PR will be rebased.
---
 lib/workers/branch/index.js                      |  4 +---
 lib/workers/branch/parent.js                     | 14 ++++++++++----
 lib/workers/pr/pr-body.js                        |  6 ++----
 test/workers/branch/parent.spec.js               |  9 ++++++++-
 test/workers/pr/__snapshots__/index.spec.js.snap | 12 ++++++------
 5 files changed, 27 insertions(+), 18 deletions(-)

diff --git a/lib/workers/branch/index.js b/lib/workers/branch/index.js
index 60bfebf0fd..a084742893 100644
--- a/lib/workers/branch/index.js
+++ b/lib/workers/branch/index.js
@@ -287,9 +287,7 @@ async function processBranch(branchConfig, packageFiles) {
           content +=
             'you rename then delete this PR unmerged, so that it can be regenerated.';
         }
-        content += `\n\n**To trigger a manual retry of this branch, add the label \`${
-          config.rebaseLabel
-        }\` to this PR.**\n\n`;
+        content += `\n\n**To trigger a manual retry of this PR, rename its title to start with "rebase!".**\n\n`;
         content += '\n\nThe lock file failure details are included below:\n\n';
         config.lockFileErrors.forEach(error => {
           content += `##### ${error.lockFile}\n\n`;
diff --git a/lib/workers/branch/parent.js b/lib/workers/branch/parent.js
index acde9ae779..40f71b618d 100644
--- a/lib/workers/branch/parent.js
+++ b/lib/workers/branch/parent.js
@@ -15,10 +15,16 @@ async function getParentBranch(config) {
   // Check for existing PR
   const pr = await platform.getBranchPr(branchName);
 
-  if (pr && pr.labels && pr.labels.includes(config.rebaseLabel)) {
-    logger.info({ prNo: pr.number }, 'Manual rebase requested for PR');
-    await platform.deleteLabel(pr.number, config.rebaseLabel);
-    return { parentBranch: undefined };
+  if (pr) {
+    if (pr.title && pr.title.startsWith('rebase!')) {
+      logger.info('Manual rebase requested via PR title for #' + pr.number);
+      return { parentBranch: undefined };
+    }
+    if (pr.labels && pr.labels.includes(config.rebaseLabel)) {
+      logger.info('Manual rebase requested via PR labels for #' + pr.number);
+      await platform.deleteLabel(pr.number, config.rebaseLabel);
+      return { parentBranch: undefined };
+    }
   }
 
   if (
diff --git a/lib/workers/pr/pr-body.js b/lib/workers/pr/pr-body.js
index 4728dffbf9..312ecdc8c3 100644
--- a/lib/workers/pr/pr-body.js
+++ b/lib/workers/pr/pr-body.js
@@ -209,12 +209,10 @@ async function getPrBody(config) {
   if (config.rebaseStalePrs) {
     prBody += 'Whenever PR is stale';
   } else {
-    prBody += 'Whenever PR is conflicted';
+    prBody += 'Whenever PR becomes conflicted';
   }
   if (config.platform === 'github') {
-    prBody += `, or if you add the label \`${
-      config.rebaseLabel
-    }\` to trigger it manually.\n\n`;
+    prBody += `, or if you modify the PR title to begin with "\`rebase!\`".\n\n`;
   } else {
     prBody += '.\n\n';
   }
diff --git a/test/workers/branch/parent.spec.js b/test/workers/branch/parent.spec.js
index 5ab57d862a..da5e5551cd 100644
--- a/test/workers/branch/parent.spec.js
+++ b/test/workers/branch/parent.spec.js
@@ -40,10 +40,17 @@ describe('workers/branch/parent', () => {
       const res = await getParentBranch(config);
       expect(res.parentBranch).toBe(config.branchName);
     });
+    it('returns undefined if PR title rebase!', async () => {
+      platform.branchExists.mockReturnValue(true);
+      platform.getBranchPr.mockReturnValue({
+        title: 'rebase!Update foo to v4',
+      });
+      const res = await getParentBranch(config);
+      expect(res.parentBranch).toBe(undefined);
+    });
     it('returns undefined if manual rebase by label', async () => {
       platform.branchExists.mockReturnValue(true);
       platform.getBranchPr.mockReturnValue({
-        isConflicted: true,
         canRebase: false,
         labels: ['rebase'],
       });
diff --git a/test/workers/pr/__snapshots__/index.spec.js.snap b/test/workers/pr/__snapshots__/index.spec.js.snap
index 37de0daf71..978cd323ea 100644
--- a/test/workers/pr/__snapshots__/index.spec.js.snap
+++ b/test/workers/pr/__snapshots__/index.spec.js.snap
@@ -57,7 +57,7 @@ Array [
 
 :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied.
 
-:recycle: **Rebasing**: Whenever PR is stale, or if you add the label \`rebase\` to trigger it manually.
+:recycle: **Rebasing**: Whenever PR is stale, or if you modify the PR title to begin with \\"\`rebase!\`\\".
 
 :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again.",
   Array [],
@@ -97,7 +97,7 @@ Array [
 
 :vertical_traffic_light: **Automerge**: Enabled.
 
-:recycle: **Rebasing**: Whenever PR is conflicted, or if you add the label \`rebase\` to trigger it manually.
+:recycle: **Rebasing**: Whenever PR becomes conflicted, or if you modify the PR title to begin with \\"\`rebase!\`\\".
 
 :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again.",
   Array [],
@@ -154,7 +154,7 @@ note 2
 
 :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied.
 
-:recycle: **Rebasing**: Whenever PR is conflicted, or if you add the label \`rebase\` to trigger it manually.
+:recycle: **Rebasing**: Whenever PR becomes conflicted, or if you modify the PR title to begin with \\"\`rebase!\`\\".
 
 :ghost: **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/config-help/issues) if that's undesired.",
   Array [],
@@ -194,7 +194,7 @@ Array [
 
 :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied.
 
-:recycle: **Rebasing**: Whenever PR is conflicted, or if you add the label \`rebase\` to trigger it manually.
+:recycle: **Rebasing**: Whenever PR becomes conflicted, or if you modify the PR title to begin with \\"\`rebase!\`\\".
 
 :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again.",
   Array [],
@@ -232,7 +232,7 @@ Object {
 
 :vertical_traffic_light: **Automerge**: Enabled.
 
-:recycle: **Rebasing**: Whenever PR is conflicted, or if you add the label \`rebase\` to trigger it manually.
+:recycle: **Rebasing**: Whenever PR becomes conflicted, or if you modify the PR title to begin with \\"\`rebase!\`\\".
 
 :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again.",
   "canRebase": true,
@@ -270,7 +270,7 @@ Object {
 
 :vertical_traffic_light: **Automerge**: Enabled.
 
-:recycle: **Rebasing**: Whenever PR is conflicted, or if you add the label \`rebase\` to trigger it manually.
+:recycle: **Rebasing**: Whenever PR becomes conflicted, or if you modify the PR title to begin with \\"\`rebase!\`\\".
 
 :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again.",
   "canRebase": true,
-- 
GitLab