Merge branch 'stable-2.14' into stable-2.15 * stable-2.14: Upgrade bazlets to latest stable-2.14 to build with 2.14.18 API Change-Id: I2b7e2fe9332633ae132c09577d4d92d0b150b74b
diff --git a/WORKSPACE b/WORKSPACE index 632bf84..75d0368 100644 --- a/WORKSPACE +++ b/WORKSPACE
@@ -3,7 +3,7 @@ load("//:bazlets.bzl", "load_bazlets") load_bazlets( - commit = "2c39029a585bd1d5b785150948f162730f7b7e42", + commit = "d4e586bd341207f0b8aafcbe7dbcd4843f852826", #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/main/java/com/googlesource/gerrit/plugins/deleteproject/projectconfig/ProjectConfigDeleteHandler.java b/src/main/java/com/googlesource/gerrit/plugins/deleteproject/projectconfig/ProjectConfigDeleteHandler.java new file mode 100644 index 0000000..9906c6c --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/deleteproject/projectconfig/ProjectConfigDeleteHandler.java
@@ -0,0 +1,59 @@ +// Copyright (C) 2014 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.googlesource.gerrit.plugins.deleteproject.projectconfig; + +import static java.util.stream.Collectors.joining; + +import com.google.gerrit.extensions.common.ProjectInfo; +import com.google.gerrit.server.permissions.PermissionBackendException; +import com.google.gerrit.server.project.ListChildProjects; +import com.google.gerrit.server.project.ProjectResource; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.googlesource.gerrit.plugins.deleteproject.CannotDeleteProjectException; +import com.googlesource.gerrit.plugins.deleteproject.ProtectedProjects; +import java.util.List; + +public class ProjectConfigDeleteHandler { + + private final ProtectedProjects protectedProjects; + private final Provider<ListChildProjects> listChildProjectsProvider; + + @Inject + public ProjectConfigDeleteHandler( + ProtectedProjects protectedProjects, Provider<ListChildProjects> listChildProjectsProvider) { + this.protectedProjects = protectedProjects; + this.listChildProjectsProvider = listChildProjectsProvider; + } + + public void assertCanDelete(ProjectResource rsrc) throws CannotDeleteProjectException { + protectedProjects.assertIsNotProtected(rsrc); + assertHasNoChildProjects(rsrc); + } + + private void assertHasNoChildProjects(ProjectResource rsrc) throws CannotDeleteProjectException { + 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 of failure in permission backend."); + } + } +}
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;