From b5d74a8ffbe394f6bb3b679c6fcbfc0881baa53f Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@arkins.net>
Date: Wed, 17 May 2023 23:04:38 +0200
Subject: [PATCH] feat: allow previously merged PRs, but block automerge
 (#22279)

---
 .../repository/update/branch/index.spec.ts        | 15 +++++++++++++++
 lib/workers/repository/update/branch/index.ts     | 15 +++++++++++++--
 .../update/pr/body/config-description.spec.ts     | 10 ++++++++++
 .../update/pr/body/config-description.ts          |  2 ++
 lib/workers/types.ts                              |  1 +
 5 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/lib/workers/repository/update/branch/index.spec.ts b/lib/workers/repository/update/branch/index.spec.ts
index aaec7534c8..5a4ad531e6 100644
--- a/lib/workers/repository/update/branch/index.spec.ts
+++ b/lib/workers/repository/update/branch/index.spec.ts
@@ -289,6 +289,21 @@ describe('workers/repository/update/branch/index', () => {
       expect(scm.deleteBranch).toHaveBeenCalledTimes(1);
     });
 
+    it('allows branch but disables automerge if merged PR found', async () => {
+      schedule.isScheduledNow.mockReturnValueOnce(false);
+      scm.branchExists.mockResolvedValue(true);
+      config.automerge = true;
+      config.updateType = 'digest';
+      checkExisting.prAlreadyExisted.mockResolvedValueOnce(
+        partial<Pr>({
+          number: 13,
+          state: 'merged',
+        })
+      );
+      await branchWorker.processBranch(config);
+      expect(reuse.shouldReuseExistingBranch).toHaveBeenCalledTimes(0);
+    });
+
     it('skips branch if closed minor PR found', async () => {
       schedule.isScheduledNow.mockReturnValueOnce(false);
       scm.branchExists.mockResolvedValue(true);
diff --git a/lib/workers/repository/update/branch/index.ts b/lib/workers/repository/update/branch/index.ts
index 7b61df3f66..562a08f615 100644
--- a/lib/workers/repository/update/branch/index.ts
+++ b/lib/workers/repository/update/branch/index.ts
@@ -113,8 +113,19 @@ export async function processBranch(
   const artifactErrorTopic = emojify(':warning: Artifact update problem');
   try {
     // Check if branch already existed
-    const existingPr = branchPr ? undefined : await prAlreadyExisted(config);
-    if (existingPr && !dependencyDashboardCheck) {
+    const existingPr =
+      !branchPr || config.automerge
+        ? await prAlreadyExisted(config)
+        : undefined;
+    if (existingPr?.state === 'merged') {
+      logger.debug(`Matching PR #${existingPr.number} was merged previously`);
+      if (config.automerge) {
+        logger.debug('Disabling automerge because PR was merged previously');
+        config.automerge = false;
+        config.automergedPreviously = true;
+      }
+    }
+    if (!branchPr && existingPr && !dependencyDashboardCheck) {
       logger.debug(
         { prTitle: config.prTitle },
         'Closed PR already exists. Skipping branch.'
diff --git a/lib/workers/repository/update/pr/body/config-description.spec.ts b/lib/workers/repository/update/pr/body/config-description.spec.ts
index 9465753fd4..435c37258c 100644
--- a/lib/workers/repository/update/pr/body/config-description.spec.ts
+++ b/lib/workers/repository/update/pr/body/config-description.spec.ts
@@ -87,5 +87,15 @@ describe('workers/repository/update/pr/body/config-description', () => {
       const res = getPrConfigDescription({ ...config, automerge: true });
       expect(res).toContain(`**Automerge**: Enabled.`);
     });
+
+    it('renders blocked automerge', () => {
+      const res = getPrConfigDescription({
+        ...config,
+        automergedPreviously: true,
+      });
+      expect(res).toContain(
+        `**Automerge**: Disabled because a matching PR was automerged previously.`
+      );
+    });
   });
 });
diff --git a/lib/workers/repository/update/pr/body/config-description.ts b/lib/workers/repository/update/pr/body/config-description.ts
index f3d0757c1a..11d1aeed01 100644
--- a/lib/workers/repository/update/pr/body/config-description.ts
+++ b/lib/workers/repository/update/pr/body/config-description.ts
@@ -15,6 +15,8 @@ export function getPrConfigDescription(config: BranchConfig): string {
   prBody += emojify(':vertical_traffic_light: **Automerge**: ');
   if (config.automerge) {
     prBody += 'Enabled.';
+  } else if (config.automergedPreviously) {
+    prBody += 'Disabled because a matching PR was automerged previously.';
   } else {
     prBody +=
       'Disabled by config. Please merge this manually once you are satisfied.';
diff --git a/lib/workers/types.ts b/lib/workers/types.ts
index 3a14f60295..b2ba4e1c26 100644
--- a/lib/workers/types.ts
+++ b/lib/workers/types.ts
@@ -111,6 +111,7 @@ export interface BranchConfig
     PlatformPrOptions {
   automergeComment?: string;
   automergeType?: string;
+  automergedPreviously?: boolean;
   baseBranch: string;
   errors?: ValidationMessage[];
   hasTypes?: boolean;
-- 
GitLab