Merge branch 'stable-2.14' into stable-2.15

* stable-2.14:
  Upgrade mockito-core to 2.25.1

Change-Id: I30690bc9df26ad2e34be44fc2d4f81fee5fa326d
diff --git a/WORKSPACE b/WORKSPACE
index 14313b4..41a5288 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -3,7 +3,7 @@
 load("//:bazlets.bzl", "load_bazlets")
 
 load_bazlets(
-    commit = "a920e0c1801a67a2e0803dc149923ff3b81ccc6a",
+    commit = "f4fcc606a6afa8ce27a013bcf62e495a5ec2505c",
     #local_path = "/home/<user>/projects/bazlets",
 )
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/deleteproject/DeleteAction.java b/src/main/java/com/googlesource/gerrit/plugins/deleteproject/DeleteAction.java
index 459d819..040f7e4 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/deleteproject/DeleteAction.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/deleteproject/DeleteAction.java
@@ -16,6 +16,7 @@
 
 import com.google.gerrit.extensions.webui.UiAction;
 import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.notedb.NotesMigration;
 import com.google.gerrit.server.project.ProjectResource;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -36,7 +37,8 @@
       DeleteLog deleteLog,
       DeletePreconditions preConditions,
       Configuration cfg,
-      HideProject hideProject) {
+      HideProject hideProject,
+      NotesMigration migration) {
     super(
         dbHandler,
         fsHandler,
@@ -45,7 +47,8 @@
         deleteLog,
         preConditions,
         cfg,
-        hideProject);
+        hideProject,
+        migration);
     this.protectedProjects = protectedProjects;
   }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/deleteproject/DeletePreconditions.java b/src/main/java/com/googlesource/gerrit/plugins/deleteproject/DeletePreconditions.java
index 47ef932..5543961 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/deleteproject/DeletePreconditions.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/deleteproject/DeletePreconditions.java
@@ -19,6 +19,7 @@
 import static java.util.stream.Collectors.joining;
 
 import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.extensions.api.access.PluginPermission;
 import com.google.gerrit.extensions.common.ProjectInfo;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
@@ -26,10 +27,13 @@
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.account.CapabilityControl;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.MergeOpRepoManager;
+import com.google.gerrit.server.git.SubmoduleException;
 import com.google.gerrit.server.git.SubmoduleOp;
+import com.google.gerrit.server.permissions.GlobalPermission;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.project.ListChildProjects;
 import com.google.gerrit.server.project.ProjectResource;
 import com.google.gerrit.server.query.change.ChangeData;
@@ -59,6 +63,7 @@
   private final SubmoduleOp.Factory subOpFactory;
   private final Provider<CurrentUser> userProvider;
   private final ProtectedProjects protectedProjects;
+  private final PermissionBackend permissionBackend;
 
   @Inject
   public DeletePreconditions(
@@ -70,7 +75,8 @@
       GitRepositoryManager repoManager,
       SubmoduleOp.Factory subOpFactory,
       Provider<CurrentUser> userProvider,
-      ProtectedProjects protectedProjects) {
+      ProtectedProjects protectedProjects,
+      PermissionBackend permissionBackend) {
     this.config = config;
     this.listChildProjectsProvider = listChildProjectsProvider;
     this.mergeOpProvider = mergeOpProvider;
@@ -80,6 +86,7 @@
     this.subOpFactory = subOpFactory;
     this.userProvider = userProvider;
     this.protectedProjects = protectedProjects;
+    this.permissionBackend = permissionBackend;
   }
 
   void assertDeletePermission(ProjectResource rsrc) throws AuthException {
@@ -88,11 +95,12 @@
     }
   }
 
-  boolean canDelete(ProjectResource rsrc) {
-    CapabilityControl ctl = userProvider.get().getCapabilities();
-    return ctl.canAdministrateServer()
-        || ctl.canPerform(pluginName + "-" + DELETE_PROJECT)
-        || (ctl.canPerform(pluginName + "-" + DELETE_OWN_PROJECT) && rsrc.getControl().isOwner());
+  protected boolean canDelete(ProjectResource rsrc) {
+    PermissionBackend.WithUser userPermission = permissionBackend.user(userProvider);
+    return userPermission.testOrFalse(GlobalPermission.ADMINISTRATE_SERVER)
+        || userPermission.testOrFalse(new PluginPermission(pluginName, DELETE_PROJECT))
+        || (userPermission.testOrFalse(new PluginPermission(pluginName, DELETE_OWN_PROJECT))
+            && rsrc.getControl().isOwner());
   }
 
   void assertCanBeDeleted(ProjectResource rsrc, Input input) throws ResourceConflictException {
@@ -125,11 +133,16 @@
   }
 
   private void assertHasNoChildProjects(ProjectResource rsrc) throws CannotDeleteProjectException {
-    List<ProjectInfo> children = listChildProjectsProvider.get().apply(rsrc);
-    if (!children.isEmpty()) {
+    try {
+      List<ProjectInfo> children = listChildProjectsProvider.get().apply(rsrc);
+      if (!children.isEmpty()) {
+        throw new CannotDeleteProjectException(
+            "Cannot delete project because it has children: "
+                + children.stream().map(info -> info.name).collect(joining(",")));
+      }
+    } catch (PermissionBackendException e) {
       throw new CannotDeleteProjectException(
-          "Cannot delete project because it has children: "
-              + children.stream().map(info -> info.name).collect(joining(",")));
+          String.format("Unable to verify if '%s' has children projects.", rsrc.getName()));
     }
   }
 
@@ -150,7 +163,7 @@
     } catch (RepositoryNotFoundException e) {
       // we're trying to delete the repository,
       // so this exception should not stop us
-    } catch (IOException e) {
+    } catch (IOException | SubmoduleException e) {
       throw new CannotDeleteProjectException("Project is subscribed by other projects.");
     }
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/deleteproject/DeleteProject.java b/src/main/java/com/googlesource/gerrit/plugins/deleteproject/DeleteProject.java
index 5d83c80..58844eb 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/deleteproject/DeleteProject.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/deleteproject/DeleteProject.java
@@ -22,6 +22,7 @@
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.notedb.NotesMigration;
 import com.google.gerrit.server.project.ProjectResource;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
@@ -50,6 +51,7 @@
   private final DeleteLog deleteLog;
   private final Configuration cfg;
   private final HideProject hideProject;
+  private NotesMigration migration;
 
   @Inject
   DeleteProject(
@@ -60,7 +62,8 @@
       DeleteLog deleteLog,
       DeletePreconditions preConditions,
       Configuration cfg,
-      HideProject hideProject) {
+      HideProject hideProject,
+      NotesMigration migration) {
     this.dbHandler = dbHandler;
     this.fsHandler = fsHandler;
     this.cacheHandler = cacheHandler;
@@ -69,6 +72,7 @@
     this.preConditions = preConditions;
     this.cfg = cfg;
     this.hideProject = hideProject;
+    this.migration = migration;
   }
 
   @Override
@@ -89,7 +93,9 @@
     Exception ex = null;
     try {
       if (!preserve || !cfg.projectOnPreserveHidden()) {
-        dbHandler.delete(project);
+        if (!migration.disableChangeReviewDb()) {
+          dbHandler.delete(project);
+        }
         try {
           fsHandler.delete(project, preserve);
         } catch (RepositoryNotFoundException e) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/deleteproject/HideProject.java b/src/main/java/com/googlesource/gerrit/plugins/deleteproject/HideProject.java
index 397a65c..8b60ae3 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/deleteproject/HideProject.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/deleteproject/HideProject.java
@@ -24,6 +24,7 @@
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.project.CreateProject;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectResource;
@@ -88,7 +89,8 @@
       } catch (BadRequestException
           | UnprocessableEntityException
           | ResourceNotFoundException
-          | ConfigInvalidException e) {
+          | ConfigInvalidException
+          | PermissionBackendException e) {
         throw new ResourceConflictException(
             String.format("Failed to create project %s", projectName));
       }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/deleteproject/DeletePreconditionsTest.java b/src/test/java/com/googlesource/gerrit/plugins/deleteproject/DeletePreconditionsTest.java
index 125041a..b02763d 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/deleteproject/DeletePreconditionsTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/deleteproject/DeletePreconditionsTest.java
@@ -23,15 +23,17 @@
 import static org.mockito.Mockito.when;
 
 import com.google.common.collect.ImmutableList;
+import com.google.gerrit.extensions.api.access.PluginPermission;
 import com.google.gerrit.extensions.common.ProjectInfo;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.account.CapabilityControl;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.MergeOpRepoManager;
 import com.google.gerrit.server.git.SubmoduleOp;
+import com.google.gerrit.server.permissions.GlobalPermission;
+import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.project.ListChildProjects;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.project.ProjectResource;
@@ -50,9 +52,6 @@
 @RunWith(MockitoJUnitRunner.class)
 public class DeletePreconditionsTest {
   private static final String PLUGIN_NAME = "delete-project";
-  private static final String DELETE_OWN_PROJECT_PERMISSION =
-      PLUGIN_NAME + "-" + DELETE_OWN_PROJECT;
-  private static final String DELETE_PROJECT_PERMISSION = PLUGIN_NAME + "-" + DELETE_PROJECT;
   private static final Project.NameKey PROJECT_NAMEKEY = new Project.NameKey("test-project");
 
   @Mock private Configuration config;
@@ -63,10 +62,9 @@
   @Mock private SubmoduleOp.Factory subOpFactory;
   @Mock private Provider<CurrentUser> userProvider;
   @Mock private ProtectedProjects protectedProjects;
-
   @Mock private ProjectControl control;
-  @Mock private CapabilityControl ctl;
-  @Mock private CurrentUser user;
+  @Mock private PermissionBackend permissionBackend;
+  @Mock private PermissionBackend.WithUser userPermission;
 
   @Rule public ExpectedException expectedException = ExpectedException.none();
 
@@ -86,44 +84,37 @@
             repoManager,
             subOpFactory,
             userProvider,
-            protectedProjects);
+            protectedProjects,
+            permissionBackend);
   }
 
   @Test
   public void testUserCanDeleteIfAdmin() {
-    when(ctl.canAdministrateServer()).thenReturn(true);
-    when(userProvider.get()).thenReturn(user);
-    when(user.getCapabilities()).thenReturn(ctl);
+    when(permissionBackend.user(userProvider)).thenReturn(userPermission);
+    when(userPermission.testOrFalse(GlobalPermission.ADMINISTRATE_SERVER)).thenReturn(true);
     assertThat(preConditions.canDelete(rsrc)).isTrue();
   }
 
   @Test
   public void testUserCanDeleteIfHasDeletePermission() {
-    when(ctl.canAdministrateServer()).thenReturn(false);
-    when(ctl.canPerform(DELETE_PROJECT_PERMISSION)).thenReturn(true);
-    when(userProvider.get()).thenReturn(user);
-    when(user.getCapabilities()).thenReturn(ctl);
+    when(permissionBackend.user(userProvider)).thenReturn(userPermission);
+    when(userPermission.testOrFalse(new PluginPermission(PLUGIN_NAME, DELETE_PROJECT)))
+        .thenReturn(true);
     assertThat(preConditions.canDelete(rsrc)).isTrue();
   }
 
   @Test
   public void testUserCanDeleteIfIsOwnerAndHasDeleteOwnPermission() {
-    when(ctl.canAdministrateServer()).thenReturn(false);
-    when(ctl.canPerform(DELETE_PROJECT_PERMISSION)).thenReturn(false);
-    when(ctl.canPerform(DELETE_OWN_PROJECT_PERMISSION)).thenReturn(true);
-    when(userProvider.get()).thenReturn(user);
-    when(user.getCapabilities()).thenReturn(ctl);
+    when(permissionBackend.user(userProvider)).thenReturn(userPermission);
+    when(userPermission.testOrFalse(new PluginPermission(PLUGIN_NAME, DELETE_OWN_PROJECT)))
+        .thenReturn(true);
     when(control.isOwner()).thenReturn(true);
     assertThat(preConditions.canDelete(rsrc)).isTrue();
   }
 
   @Test
   public void testUserCannotDelete() throws Exception {
-    when(ctl.canAdministrateServer()).thenReturn(false);
-    when(ctl.canPerform(DELETE_PROJECT_PERMISSION)).thenReturn(false);
-    when(ctl.canPerform(DELETE_OWN_PROJECT_PERMISSION)).thenReturn(false);
-    when(userProvider.get()).thenReturn(user);
-    when(user.getCapabilities()).thenReturn(ctl);
+    when(permissionBackend.user(userProvider)).thenReturn(userPermission);
     expectedException.expect(AuthException.class);
     expectedException.expectMessage("not allowed to delete project");
     preConditions.assertDeletePermission(rsrc);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/deleteproject/DeleteProjectIT.java b/src/test/java/com/googlesource/gerrit/plugins/deleteproject/DeleteProjectIT.java
index af3ff0d..a68edf8 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/deleteproject/DeleteProjectIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/deleteproject/DeleteProjectIT.java
@@ -20,7 +20,6 @@
 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
 
 import com.google.common.base.Joiner;
-import com.google.common.base.MoreObjects;
 import com.google.gerrit.acceptance.GerritConfig;
 import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
 import com.google.gerrit.acceptance.RestResponse;
@@ -94,7 +93,7 @@
   @Test
   @UseLocalDisk
   public void testHttpDeleteProjectWithWatches() throws Exception {
-    watch(project.get(), null);
+    watch(project.get());
     RestResponse r = httpDeleteProjectHelper(true);
     r.assertNoContent();
     assertThat(projectDir.exists()).isFalse();
@@ -211,8 +210,8 @@
   @UseLocalDisk
   @GerritConfig(name = "plugin.delete-project.allowDeletionOfReposWithTags", value = "false")
   public void testDeleteProjWithTags() throws Exception {
-    grant(Permission.CREATE, project, "refs/tags/*", false, REGISTERED_USERS);
-    pushTagOldCommitNotForce(Status.OK);
+    grant(project, "refs/tags/*", Permission.CREATE, false, REGISTERED_USERS);
+    pushTagOldCommitNotForce();
 
     String cmd = createDeleteCommand(project.get());
     adminSshSession.exec(cmd);
@@ -295,19 +294,18 @@
         .join(PLUGIN, "delete", "--yes-really-delete", cmd, Joiner.on(" ").join(params));
   }
 
-  private String pushTagOldCommitNotForce(Status expectedStatus) throws Exception {
+  private void pushTagOldCommitNotForce() throws Exception {
     testRepo = cloneProject(project, user);
     commitBuilder().ident(user.getIdent()).message("subject (" + System.nanoTime() + ")").create();
-    String tagName = MoreObjects.firstNonNull(null, "v1_" + System.nanoTime());
+    String tagName = "v1_" + System.nanoTime();
 
-    grant(Permission.SUBMIT, project, "refs/for/refs/heads/master", false, REGISTERED_USERS);
+    grant(project, "refs/for/refs/heads/master", Permission.SUBMIT, false, REGISTERED_USERS);
     pushHead(testRepo, "refs/for/master%submit");
 
     String tagRef = RefNames.REFS_TAGS + tagName;
     PushResult r = pushHead(testRepo, tagRef, false, false);
     RemoteRefUpdate refUpdate = r.getRemoteUpdate(tagRef);
-    assertThat(refUpdate.getStatus()).named("LIGHTWEIGHT").isEqualTo(expectedStatus);
-    return tagName;
+    assertThat(refUpdate.getStatus()).named("LIGHTWEIGHT").isEqualTo(Status.OK);
   }
 
   private boolean isEmpty(Path dir) throws IOException {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/deleteproject/fs/ArchiveRepositoryRemoverTest.java b/src/test/java/com/googlesource/gerrit/plugins/deleteproject/fs/ArchiveRepositoryRemoverTest.java
index bd976ab..64634b9 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/deleteproject/fs/ArchiveRepositoryRemoverTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/deleteproject/fs/ArchiveRepositoryRemoverTest.java
@@ -28,7 +28,6 @@
 
 import com.google.common.base.Joiner;
 import com.google.gerrit.server.git.WorkQueue;
-import com.google.gerrit.server.git.WorkQueue.Executor;
 import com.google.inject.Provider;
 import com.googlesource.gerrit.plugins.deleteproject.Configuration;
 import com.googlesource.gerrit.plugins.deleteproject.TimeMachine;
@@ -38,6 +37,7 @@
 import java.nio.file.Path;
 import java.time.Instant;
 import java.util.List;
+import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.StreamSupport;
@@ -59,7 +59,7 @@
   private static final int NUMBER_OF_REPOS = 10;
   private static final String PLUGIN_NAME = "delete-project";
 
-  @Mock private Executor executorMock;
+  @Mock private ScheduledExecutorService executorMock;
   @Mock private ScheduledFuture<?> scheduledFutureMock;
   @Mock private WorkQueue workQueueMock;
   @Mock private Provider<RepositoryCleanupTask> cleanupTaskProviderMock;