Merge "DocServletTest: Add missing license header"
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index aa174c6..76009bf 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -62,6 +62,7 @@
 import static java.util.stream.Collectors.joining;
 import static java.util.stream.Collectors.toList;
 import static java.util.stream.Collectors.toSet;
+import static org.eclipse.jgit.lib.Constants.HEAD;
 
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheStats;
@@ -217,6 +218,7 @@
 import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.RefUpdate;
 import org.eclipse.jgit.lib.RefUpdate.Result;
@@ -1764,6 +1766,53 @@
   }
 
   @Test
+  public void cannotRebaseOntoBaseThatIsNotPresentInTargetBranch() throws Exception {
+    ObjectId initial = repo().exactRef(HEAD).getLeaf().getObjectId();
+
+    BranchInput branchInput = new BranchInput();
+    branchInput.revision = initial.getName();
+    gApi.projects().name(project.get()).branch("foo").create(branchInput);
+
+    PushOneCommit.Result r1 =
+        pushFactory
+            .create(admin.newIdent(), testRepo, "Change on foo branch", "a.txt", "a-content")
+            .to("refs/for/foo");
+    approve(r1.getChangeId());
+    gApi.changes().id(r1.getChangeId()).current().submit();
+
+    // reset HEAD in order to create a sibling of the first change
+    testRepo.reset(initial);
+
+    PushOneCommit.Result r2 =
+        pushFactory
+            .create(admin.newIdent(), testRepo, "Change on master branch", "b.txt", "b-content")
+            .to("refs/for/master");
+
+    RebaseInput rebaseInput = new RebaseInput();
+    rebaseInput.base = r1.getCommit().getName();
+    ResourceConflictException thrown =
+        assertThrows(
+            ResourceConflictException.class,
+            () -> gApi.changes().id(r2.getChangeId()).current().rebase(rebaseInput));
+    assertThat(thrown)
+        .hasMessageThat()
+        .contains(
+            String.format(
+                "base change is targeting wrong branch: %s,refs/heads/foo", project.get()));
+
+    rebaseInput.base = "refs/heads/foo";
+    thrown =
+        assertThrows(
+            ResourceConflictException.class,
+            () -> gApi.changes().id(r2.getChangeId()).current().rebase(rebaseInput));
+    assertThat(thrown)
+        .hasMessageThat()
+        .contains(
+            String.format(
+                "base revision is missing from the destination branch: %s", rebaseInput.base));
+  }
+
+  @Test
   @TestProjectInput(createEmptyCommit = false)
   public void changeNoParentToOneParent() throws Exception {
     // create initial commit with no parent and push it as change, so that patch
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts
index 6603149..d291ebb 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts
@@ -8,19 +8,13 @@
 import {ChangeInfo, DownloadInfo, PatchSetNum} from '../../../types/common';
 import {GrDownloadCommands} from '../../shared/gr-download-commands/gr-download-commands';
 import {GrButton} from '../../shared/gr-button/gr-button';
-import {
-  copyToClipbard,
-  hasOwnProperty,
-  queryAndAssert,
-} from '../../../utils/common-util';
-import {GrOverlayStops} from '../../shared/gr-overlay/gr-overlay';
+import {copyToClipbard, hasOwnProperty} from '../../../utils/common-util';
 import {fireEvent} from '../../../utils/event-util';
 import {fontStyles} from '../../../styles/gr-font-styles';
 import {sharedStyles} from '../../../styles/shared-styles';
 import {LitElement, PropertyValues, html, css} from 'lit';
 import {customElement, property, state, query} from 'lit/decorators.js';
 import {assertIsDefined} from '../../../utils/common-util';
-import {PaperTabsElement} from '@polymer/paper-tabs/paper-tabs';
 import {BindValueChangeEvent} from '../../../types/events';
 import {ShortcutController} from '../../lit/shortcut-controller';
 
@@ -243,19 +237,6 @@
     }
   }
 
-  getFocusStops(): GrOverlayStops {
-    assertIsDefined(this.downloadCommands, 'downloadCommands');
-    assertIsDefined(this.closeButton, 'closeButton');
-    const downloadTabs = queryAndAssert<PaperTabsElement>(
-      this.downloadCommands,
-      '#downloadTabs'
-    );
-    return {
-      start: downloadTabs,
-      end: this.closeButton,
-    };
-  }
-
   private computeDownloadCommands() {
     let commandObj;
     if (!this.change || !this.selectedScheme) return [];
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 28d65f4..d3e5ef8 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
@@ -84,7 +84,7 @@
   UnsavedInfo,
 } from '../../../utils/comment-util';
 import {GrAccountChip} from '../../shared/gr-account-chip/gr-account-chip';
-import {GrOverlay, GrOverlayStops} from '../../shared/gr-overlay/gr-overlay';
+import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
 import {
   getApprovalInfo,
   getMaxAccounts,
@@ -1287,15 +1287,6 @@
     this.focusOn(FocusTarget.ANY);
   }
 
-  getFocusStops(): GrOverlayStops | undefined {
-    const end = this.sendDisabled ? this.cancelButton : this.sendButton;
-    if (!this.reviewersList?.focusStart || !end) return undefined;
-    return {
-      start: this.reviewersList.focusStart,
-      end,
-    };
-  }
-
   private handleIncludeCommentsChanged(e: Event) {
     if (!(e.target instanceof HTMLInputElement)) return;
     this.includeComments = e.target.checked;
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 4ad76f4..38478ee 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
@@ -2609,36 +2609,6 @@
     });
   });
 
-  test('getFocusStops', async () => {
-    // Setting draftCommentThreads to an empty object causes _sendDisabled to be
-    // computed to false.
-    element.draftCommentThreads = [];
-    await element.updateComplete;
-
-    assert.equal(
-      element.getFocusStops()!.end,
-      queryAndAssert<GrButton>(element, '#cancelButton')
-    );
-    element.draftCommentThreads = [
-      {
-        ...createCommentThread([
-          {
-            ...createDraft(),
-            path: 'test',
-            line: 1,
-            patch_set: 1 as RevisionPatchSetNum,
-          },
-        ]),
-      },
-    ];
-    await element.updateComplete;
-
-    assert.equal(
-      element.getFocusStops()!.end,
-      queryAndAssert<GrButton>(element, '#sendButton')
-    );
-  });
-
   test('setPluginMessage', async () => {
     element.setPluginMessage('foo');
     await element.updateComplete;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.ts b/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.ts
index cc1b1f2..531d2ae 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.ts
@@ -6,7 +6,6 @@
 import '../../shared/gr-button/gr-button';
 import '../../shared/gr-diff-preferences/gr-diff-preferences';
 import {GrDiffPreferences} from '../../shared/gr-diff-preferences/gr-diff-preferences';
-import {GrButton} from '../../shared/gr-button/gr-button';
 import {assertIsDefined} from '../../../utils/common-util';
 import {sharedStyles} from '../../../styles/shared-styles';
 import {LitElement, html, css} from 'lit';
@@ -18,10 +17,6 @@
 export class GrDiffPreferencesDialog extends LitElement {
   @query('#diffPreferences') private diffPreferences?: GrDiffPreferences;
 
-  @query('#saveButton') private saveButton?: GrButton;
-
-  @query('#cancelButton') private cancelButton?: GrButton;
-
   @query('#diffPrefsModal') private diffPrefsModal?: HTMLDialogElement;
 
   @state() diffPrefsChanged?: boolean;
@@ -104,16 +99,6 @@
     `;
   }
 
-  getFocusStops() {
-    assertIsDefined(this.diffPreferences, 'diffPreferences');
-    assertIsDefined(this.saveButton, 'saveButton');
-    assertIsDefined(this.cancelButton, 'cancelbutton');
-    return {
-      start: this.diffPreferences.contextSelect!,
-      end: this.saveButton.disabled ? this.cancelButton : this.saveButton,
-    };
-  }
-
   resetFocus() {
     assertIsDefined(this.diffPreferences, 'diffPreferences');
 
diff --git a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.ts b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.ts
index ea5540e..0e0f143 100644
--- a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.ts
+++ b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.ts
@@ -60,14 +60,9 @@
   // private but used in test
   _boundHandleClose: () => void = () => super.close();
 
-  private focusableNodes?: Node[];
-
   private returnFocusTo?: HTMLElement;
 
   override get _focusableNodes() {
-    if (this.focusableNodes) {
-      return this.focusableNodes;
-    }
     return Array.from(getFocusableElements(this));
   }
 
@@ -110,13 +105,6 @@
   }
 
   /**
-   * Override the focus stops that iron-overlay-behavior tries to find.
-   */
-  setFocusStops(stops: GrOverlayStops) {
-    this.focusableNodes = [stops.start, stops.end];
-  }
-
-  /**
    * NOTE: (wyatta) Slightly hacky way to listen to the overlay actually
    * opening. Eventually replace with a direct way to listen to the overlay.
    */