From 1762ee68a0690da5bb2f6d6c03e845fd93032b05 Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@arkins.net>
Date: Fri, 4 May 2018 06:55:01 +0200
Subject: [PATCH] feat: automergeComment (#1906)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Adds new option “pr-comment” for `automergeType` and a new option `automergeComment` to use in such a case.
---
 lib/config/definitions.js                    |  9 ++++++-
 lib/platform/github/index.js                 | 28 ++++++++++++++------
 lib/workers/branch/automerge.js              |  2 +-
 lib/workers/pr/index.js                      |  8 ++++--
 test/config/__snapshots__/index.spec.js.snap |  1 +
 test/platform/github/index.spec.js           | 10 +++++++
 test/workers/pr/index.spec.js                |  9 +++++++
 website/docs/configuration-options.md        | 18 +++++++++----
 8 files changed, 68 insertions(+), 17 deletions(-)

diff --git a/lib/config/definitions.js b/lib/config/definitions.js
index 8646c7e745..1690e0aba5 100644
--- a/lib/config/definitions.js
+++ b/lib/config/definitions.js
@@ -626,10 +626,17 @@ const options = [
   {
     name: 'automergeType',
     description:
-      'How to automerge - "branch-merge-commit", "branch-push" or "pr". Branch support is GitHub-only',
+      'How to automerge - "branch-merge-commit", "branch-push", "pr-comment" or "pr". Branch support is GitHub-only',
     type: 'string',
     default: 'pr',
   },
+  {
+    name: 'automergeComment',
+    description:
+      'PR comment to add to trigger automerge. Used only if automergeType=pr-comment',
+    type: 'string',
+    default: 'automergeComment',
+  },
   {
     name: 'requiredStatusChecks',
     description:
diff --git a/lib/platform/github/index.js b/lib/platform/github/index.js
index f8b1a9c38d..5eaeb26172 100644
--- a/lib/platform/github/index.js
+++ b/lib/platform/github/index.js
@@ -736,17 +736,29 @@ async function deleteComment(commentId) {
 }
 
 async function ensureComment(issueNo, topic, content) {
-  logger.debug(`Ensuring comment "${topic}" in #${issueNo}`);
-  const body = `### ${topic}\n\n${content}`;
   const comments = await getComments(issueNo);
+  let body;
   let commentId;
   let commentNeedsUpdating;
-  comments.forEach(comment => {
-    if (comment.body.startsWith(`### ${topic}\n\n`)) {
-      commentId = comment.id;
-      commentNeedsUpdating = comment.body !== body;
-    }
-  });
+  if (topic) {
+    logger.debug(`Ensuring comment "${topic}" in #${issueNo}`);
+    body = `### ${topic}\n\n${content}`;
+    comments.forEach(comment => {
+      if (comment.body.startsWith(`### ${topic}\n\n`)) {
+        commentId = comment.id;
+        commentNeedsUpdating = comment.body !== body;
+      }
+    });
+  } else {
+    logger.debug(`Ensuring content-only comment in #${issueNo}`);
+    body = `${content}`;
+    comments.forEach(comment => {
+      if (comment.body === body) {
+        commentId = comment.id;
+        commentNeedsUpdating = false;
+      }
+    });
+  }
   if (!commentId) {
     await addComment(issueNo, body);
     logger.info({ repository: config.repository, issueNo }, 'Added comment');
diff --git a/lib/workers/branch/automerge.js b/lib/workers/branch/automerge.js
index 95ebdcbde4..b9f94eec86 100644
--- a/lib/workers/branch/automerge.js
+++ b/lib/workers/branch/automerge.js
@@ -4,7 +4,7 @@ module.exports = {
 
 async function tryBranchAutomerge(config) {
   logger.debug('Checking if we can automerge branch');
-  if (!config.automerge || config.automergeType === 'pr') {
+  if (!config.automerge || config.automergeType.startsWith('pr')) {
     return 'no automerge';
   }
   const existingPr = await platform.getBranchPr(config.branchName);
diff --git a/lib/workers/pr/index.js b/lib/workers/pr/index.js
index aec92e5a0c..964fa43811 100644
--- a/lib/workers/pr/index.js
+++ b/lib/workers/pr/index.js
@@ -387,8 +387,12 @@ async function checkAutoMerge(pr, config) {
       return false;
     }
     // Let's merge this
-    logger.info(`Automerging #${pr.number}`);
-    return platform.mergePr(pr.number, config.branchName);
+    if (config.automergeType === 'pr') {
+      logger.info(`Automerging #${pr.number}`);
+      return platform.mergePr(pr.number, config.branchName);
+    }
+    logger.info(`Applying automerge comment: ${config.automergeComment}`);
+    return platform.ensureComment(pr.number, null, config.automergeComment);
   }
   logger.debug('No automerge');
   return false;
diff --git a/test/config/__snapshots__/index.spec.js.snap b/test/config/__snapshots__/index.spec.js.snap
index e32179a523..658a946430 100644
--- a/test/config/__snapshots__/index.spec.js.snap
+++ b/test/config/__snapshots__/index.spec.js.snap
@@ -12,6 +12,7 @@ Object {
   "assignees": Array [],
   "autodiscover": false,
   "automerge": false,
+  "automergeComment": "automergeComment",
   "automergeType": "pr",
   "baseBranches": Array [],
   "bazel": Object {
diff --git a/test/platform/github/index.spec.js b/test/platform/github/index.spec.js
index e50b69584f..590e03b03d 100644
--- a/test/platform/github/index.spec.js
+++ b/test/platform/github/index.spec.js
@@ -1106,6 +1106,16 @@ describe('platform/github', () => {
       expect(get.post.mock.calls).toHaveLength(0);
       expect(get.patch.mock.calls).toHaveLength(0);
     });
+    it('handles comment with no description', async () => {
+      await initRepo({
+        repository: 'some/repo',
+        token: 'token',
+      });
+      get.mockReturnValueOnce({ body: [{ id: 1234, body: '!merge' }] });
+      await github.ensureComment(42, null, '!merge');
+      expect(get.post.mock.calls).toHaveLength(0);
+      expect(get.patch.mock.calls).toHaveLength(0);
+    });
   });
   describe('ensureCommentRemoval', () => {
     it('deletes comment if found', async () => {
diff --git a/test/workers/pr/index.spec.js b/test/workers/pr/index.spec.js
index 18ea14a669..7e6ae67432 100644
--- a/test/workers/pr/index.spec.js
+++ b/test/workers/pr/index.spec.js
@@ -60,6 +60,15 @@ describe('workers/pr', () => {
       await prWorker.checkAutoMerge(pr, config);
       expect(platform.mergePr.mock.calls.length).toBe(1);
     });
+    it('should automerge comment', async () => {
+      config.automerge = true;
+      config.automergeType = 'pr-comment';
+      config.automergeComment = '!merge';
+      pr.canRebase = true;
+      platform.getBranchStatus.mockReturnValueOnce('success');
+      await prWorker.checkAutoMerge(pr, config);
+      expect(platform.ensureComment.mock.calls.length).toBe(1);
+    });
     it('should not automerge if enabled and pr is mergeable but cannot rebase', async () => {
       config.automerge = true;
       pr.canRebase = false;
diff --git a/website/docs/configuration-options.md b/website/docs/configuration-options.md
index 2e52a31670..8fde8b8509 100644
--- a/website/docs/configuration-options.md
+++ b/website/docs/configuration-options.md
@@ -69,15 +69,23 @@ Also note that this option can be combined with other nested settings, such as d
 
 Warning: GitHub currently has a bug where automerge won't work if a GitHub Organization has protected their master branch, and there is no way to configure around this. Hence, automerging will try and fail in such situations. This doc will be updated once that bug/limitation is fixed by GitHub.
 
+## automergeComment
+
+PR comment to add to trigger automerge. Used only if automergeType=pr-comment.
+
+| name | value  |
+| ---- | ------ |
+| type | string |
+
 ## automergeType
 
 Type of automerge approach to use.
 
-| name         | value                                        |
-| ------------ | -------------------------------------------- |
-| type         | string                                       |
-| valid values | "branch-merge-commit", "branch-push" or "pr" |
-| default      | "pr"                                         |
+| name         | value                                                      |
+| ------------ | ---------------------------------------------------------- |
+| type         | string                                                     |
+| valid values | "branch-merge-commit", "branch-push", "pr-comment" or "pr" |
+| default      | "pr"                                                       |
 
 Renovate will default to automerging after creating PRs, but you can override that to automerge _without_ PRs. There are two ways to merge branch upgrades: merge commits, and branch push.
 
-- 
GitLab