Ignore removal request from reviewer when removing an owner

Change 342254 relied on calculating the difference between
existing reviewers and the reviewers list in GrAccountList to
decide which users were removed.

However in some cases, the owner is returned as a reviewer in the
ChangeInfo object, and trying to remove the owner returns in a
500 server error.

Hence explicitly filter out removal of owner from the review input.

Verified on staging that the similar behaviour does not happen for
uploader. Ie if the uploader voted on the change before, they are
not returned as a reviewer.

Release-Notes: skip
Google-bug-id: b/236921879
Change-Id: I3fa6a5ce8ba7bf3e540701d695abbdcc8f3a9558
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
index da5ad14..95805fa 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
@@ -1379,7 +1379,16 @@
     ).map(v => toReviewInput(v, ReviewerState.REMOVED));
     reviewers.push(...removals);
 
-    return reviewers;
+    // The owner is returned as a reviewer in the ChangeInfo object in some
+    // cases, and trying to remove the owner as a reviewer returns in a
+    // 500 server error.
+    return reviewers.filter(
+      reviewerInput =>
+        !(
+          this.change?.owner._account_id === reviewerInput.reviewer &&
+          reviewerInput.state === ReviewerState.REMOVED
+        )
+    );
   }
 
   send(includeComments: boolean, startReview: boolean) {
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.ts
index d0d95c3..50c170c 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.ts
@@ -2040,6 +2040,30 @@
     });
   });
 
+  test('Ignore removal requests from reviewer if owner', async () => {
+    await element.updateComplete;
+    const reviewer1 = makeAccount();
+    element.reviewers = [reviewer1];
+    element._ccs = [];
+    element.change!.owner = reviewer1;
+
+    element.change!.reviewers = {
+      [ReviewerState.CC]: [],
+      [ReviewerState.REVIEWER]: [{_account_id: reviewer1._account_id}],
+    };
+
+    await element.updateComplete;
+
+    const mutations: ReviewerInput[] = [];
+
+    stubSaveReview((review: ReviewInput) => {
+      mutations.push(...review.reviewers!);
+    });
+
+    await element.send(false, false);
+    expect(mutations).to.have.lengthOf(0);
+  });
+
   test('emits cancel on esc key', async () => {
     const cancelHandler = sinon.spy();
     element.addEventListener('cancel', cancelHandler);