From 83b4bead4885cdeb97cf5d898a011b1ccbca2fda Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@arkins.net>
Date: Sun, 16 Dec 2018 13:47:05 +0100
Subject: [PATCH] fix: ensureIssue logic (#2957)

if ensureIssue once, and the first matching issue was closed, then any other matching open ones are also closed.

If ensureIssue regular, and all are closed, then reopen the latest one.
---
 lib/platform/github/index.js       | 66 +++++++++++++++++-------------
 test/platform/github/index.spec.js | 24 +++++++++++
 2 files changed, 61 insertions(+), 29 deletions(-)

diff --git a/lib/platform/github/index.js b/lib/platform/github/index.js
index f4992d4030..a7590cc1e1 100644
--- a/lib/platform/github/index.js
+++ b/lib/platform/github/index.js
@@ -602,7 +602,7 @@ async function getIssueList() {
     logger.debug('Retrieving issueList');
     const res = await get(
       `repos/${config.parentRepo ||
-        config.repository}/issues?filter=created&state=all&per_page=100&sort=updated`,
+        config.repository}/issues?filter=created&state=all&per_page=100&sort=created&direction=asc`,
       { paginate: true, useCache: false }
     );
     // istanbul ignore if
@@ -647,48 +647,56 @@ async function ensureIssue(title, body, once = false) {
   logger.debug(`ensureIssue()`);
   try {
     const issueList = await getIssueList();
-    const issues = issueList.filter(i => i.title === title).reverse();
+    const issues = issueList.filter(i => i.title === title);
     if (issues.length) {
-      if (issues.length > 1) {
+      if (once && issues[0].state === 'closed') {
+        // Close all other matching issues and return
         for (const issue of issues.slice(1)) {
           if (issue.state === 'open') {
             logger.warn('Closing duplicate issue ' + issue.number);
             await closeIssue(issue.number);
           }
         }
-      }
-      const [issue] = issues;
-      if (once && issue.state === 'closed') {
-        logger.debug('Issue is closed - skipping');
         return null;
       }
+      const issue =
+        issues.find(i => i.state === 'open') || issues[issues.length - 1];
+      logger.info({ issue });
+      for (const i of issues) {
+        if (i.state === 'open' && i.number !== issue.number) {
+          logger.warn('Closing duplicate issue ' + i.number);
+          await closeIssue(i.number);
+        }
+      }
       const issueBody = (await get(
         `repos/${config.parentRepo || config.repository}/issues/${issue.number}`
       )).body.body;
-      if (issueBody !== body) {
-        logger.info('Issue updated');
-        await get.patch(
-          `repos/${config.parentRepo || config.repository}/issues/${
-            issue.number
-          }`,
-          {
-            body: { body },
-          }
-        );
-        return 'updated';
+      if (issueBody === body && issue.state === 'open') {
+        logger.info('Issue is open and up to date - nothing to do');
+        return null;
       }
-    } else {
-      await get.post(`repos/${config.parentRepo || config.repository}/issues`, {
-        body: {
-          title,
-          body,
-        },
-      });
-      logger.info('Issue created');
-      // reset issueList so that it will be fetched again as-needed
-      delete config.issueList;
-      return 'created';
+      logger.info('Patching issue');
+      await get.patch(
+        `repos/${config.parentRepo || config.repository}/issues/${
+          issue.number
+        }`,
+        {
+          body: { body, state: 'open' },
+        }
+      );
+      logger.info('Issue updated');
+      return 'updated';
     }
+    await get.post(`repos/${config.parentRepo || config.repository}/issues`, {
+      body: {
+        title,
+        body,
+      },
+    });
+    logger.info('Issue created');
+    // reset issueList so that it will be fetched again as-needed
+    delete config.issueList;
+    return 'created';
   } catch (err) /* istanbul ignore next */ {
     if (err.message.startsWith('Issues are disabled for this repo')) {
       logger.info(
diff --git a/test/platform/github/index.spec.js b/test/platform/github/index.spec.js
index 9545da9b62..7d07145af2 100644
--- a/test/platform/github/index.spec.js
+++ b/test/platform/github/index.spec.js
@@ -1077,6 +1077,30 @@ describe('platform/github', () => {
       const res = await github.ensureIssue('title-1', 'new-content', once);
       expect(res).toEqual(null);
     });
+    it('closes others if ensuring only once', async () => {
+      get.mockImplementationOnce(() => ({
+        body: [
+          {
+            number: 1,
+            title: 'title-1',
+            state: 'closed',
+          },
+          {
+            number: 2,
+            title: 'title-2',
+            state: 'open',
+          },
+          {
+            number: 3,
+            title: 'title-1',
+            state: 'open',
+          },
+        ],
+      }));
+      const once = true;
+      const res = await github.ensureIssue('title-1', 'new-content', once);
+      expect(res).toEqual(null);
+    });
     it('updates issue', async () => {
       get.mockReturnValueOnce({
         body: [
-- 
GitLab