diff options
author | Duarte Meneses <duarte.meneses@sonarsource.com> | 2017-08-21 16:01:34 +0200 |
---|---|---|
committer | Janos Gyerik <janos.gyerik@sonarsource.com> | 2017-09-12 11:34:48 +0200 |
commit | b6b7953d88cdcca4edabc6b40101500df93fad6d (patch) | |
tree | 6c8a3b629c520ea299ce28036c27969b3dbbdac7 /server | |
parent | 60b1fcc8948c4eeeb3e8843002fe0211994ddb7f (diff) | |
download | sonarqube-b6b7953d88cdcca4edabc6b40101500df93fad6d.tar.gz sonarqube-b6b7953d88cdcca4edabc6b40101500df93fad6d.zip |
SONAR-9616 Ability to manually delete a non-main branch
Diffstat (limited to 'server')
13 files changed, 331 insertions, 22 deletions
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java index 9cf7789d96b..91039c40d61 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java @@ -256,9 +256,9 @@ class PurgeCommands { profiler.stop(); } - void deleteBranches(String rootUuid) { - profiler.start("deleteBranches (project_branches)"); - purgeMapper.deleteBranchesByProjectUuid(rootUuid); + void deleteBranch(String rootUuid) { + profiler.start("deleteBranch (project_branches)"); + purgeMapper.deleteBranchByUuid(rootUuid); session.commit(); profiler.stop(); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java index 4a9fc5d79b8..de29166e268 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java @@ -166,7 +166,14 @@ public class PurgeDao implements Dao { return result; } - public void deleteRootComponent(DbSession session, String uuid) { + public void deleteBranch(DbSession session, String uuid) { + PurgeProfiler profiler = new PurgeProfiler(); + PurgeMapper purgeMapper = mapper(session); + PurgeCommands purgeCommands = new PurgeCommands(session, profiler); + deleteRootComponent(uuid, purgeMapper, purgeCommands); + } + + public void deleteProject(DbSession session, String uuid) { PurgeProfiler profiler = new PurgeProfiler(); PurgeMapper purgeMapper = mapper(session); PurgeCommands purgeCommands = new PurgeCommands(session, profiler); @@ -196,7 +203,7 @@ public class PurgeDao implements Dao { commands.deleteCeActivity(rootUuid); commands.deleteCeQueue(rootUuid); commands.deleteWebhookDeliveries(rootUuid); - commands.deleteBranches(rootUuid); + commands.deleteBranch(rootUuid); } /** diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java index 86928616be0..6ea97e7aa28 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java @@ -94,5 +94,5 @@ public interface PurgeMapper { void deleteWebhookDeliveriesByProjectUuid(@Param("projectUuid") String projectUuid); - void deleteBranchesByProjectUuid(@Param("projectUuid") String projectUuid); + void deleteBranchByUuid(@Param("uuid") String uuid); } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml index 026672b7190..1b167408045 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml @@ -320,8 +320,8 @@ delete from webhook_deliveries where component_uuid=#{projectUuid,jdbcType=VARCHAR} </delete> - <delete id="deleteBranchesByProjectUuid"> - delete from project_branches where project_uuid=#{projectUuid,jdbcType=VARCHAR} + <delete id="deleteBranchByUuid"> + delete from project_branches where uuid=#{uuid,jdbcType=VARCHAR} </delete> </mapper> diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentTesting.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentTesting.java index d57256a2a4d..7695b2d77ea 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentTesting.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentTesting.java @@ -221,7 +221,6 @@ public class ComponentTesting { return new BranchDto() .setKey(key) .setUuid(branchComponent.uuid()) - // MainBranchProjectUuid will be null if it's a main branch .setProjectUuid(projectUuid) .setKeeType(BRANCH) .setBranchType(branchType); diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java index 92259a36b2a..39698bf8df4 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java @@ -178,7 +178,7 @@ public class PurgeDaoTest { public void delete_project_and_associated_data() { dbTester.prepareDbUnit(getClass(), "shouldDeleteProject.xml"); - underTest.deleteRootComponent(dbSession, "A"); + underTest.deleteProject(dbSession, "A"); dbSession.commit(); assertThat(dbTester.countRowsOfTable("projects")).isZero(); @@ -189,6 +189,17 @@ public class PurgeDaoTest { } @Test + public void delete_branch_and_associated_data() { + ComponentDto project = dbTester.components().insertMainBranch(); + ComponentDto branch = dbTester.components().insertProjectBranch(project); + + underTest.deleteBranch(dbSession, project.uuid()); + dbSession.commit(); + assertThat(dbTester.countRowsOfTable("project_branches")).isEqualTo(1); + assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(1); + } + + @Test public void delete_project_in_ce_activity_when_deleting_project() { ComponentDto projectToBeDeleted = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()); ComponentDto anotherLivingProject = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()); @@ -199,7 +210,7 @@ public class PurgeDaoTest { insertCeActivity(anotherLivingProject); dbSession.commit(); - underTest.deleteRootComponent(dbSession, projectToBeDeleted.uuid()); + underTest.deleteProject(dbSession, projectToBeDeleted.uuid()); dbSession.commit(); assertThat(dbTester.countRowsOfTable("ce_activity")).isEqualTo(1); @@ -217,7 +228,7 @@ public class PurgeDaoTest { dbClient.ceQueueDao().insert(dbSession, createCeQueue(anotherLivingProject, Status.PENDING)); dbSession.commit(); - underTest.deleteRootComponent(dbSession, projectToBeDeleted.uuid()); + underTest.deleteProject(dbSession, projectToBeDeleted.uuid()); dbSession.commit(); assertThat(dbTester.countRowsOfTable("ce_queue")).isEqualTo(1); @@ -249,7 +260,7 @@ public class PurgeDaoTest { assertThat(dbTester.countRowsOfTable("issues")).isGreaterThan(issueCount); assertThat(dbTester.countRowsOfTable("project_branches")).isGreaterThan(branchCount); - underTest.deleteRootComponent(dbSession, projectToDelete.uuid()); + underTest.deleteProject(dbSession, projectToDelete.uuid()); dbSession.commit(); assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(projectEntryCount); @@ -261,7 +272,7 @@ public class PurgeDaoTest { public void delete_view_and_child() { dbTester.prepareDbUnit(getClass(), "view_sub_view_and_tech_project.xml"); - underTest.deleteRootComponent(dbSession, "A"); + underTest.deleteProject(dbSession, "A"); dbSession.commit(); assertThat(dbTester.countSql("select count(1) from projects where uuid='A'")).isZero(); assertThat(dbTester.countRowsOfTable("projects")).isZero(); @@ -275,7 +286,7 @@ public class PurgeDaoTest { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("Couldn't find root component with uuid " + module.uuid()); - underTest.deleteRootComponent(dbSession, module.uuid()); + underTest.deleteProject(dbSession, module.uuid()); } @Test @@ -286,7 +297,7 @@ public class PurgeDaoTest { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("Couldn't find root component with uuid " + directory.uuid()); - underTest.deleteRootComponent(dbSession, directory.uuid()); + underTest.deleteProject(dbSession, directory.uuid()); } @Test @@ -297,7 +308,7 @@ public class PurgeDaoTest { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("Couldn't find root component with uuid " + file.uuid()); - underTest.deleteRootComponent(dbSession, file.uuid()); + underTest.deleteProject(dbSession, file.uuid()); } @Test @@ -308,7 +319,7 @@ public class PurgeDaoTest { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("Couldn't find root component with uuid " + subview.uuid()); - underTest.deleteRootComponent(dbSession, subview.uuid()); + underTest.deleteProject(dbSession, subview.uuid()); } @Test @@ -316,7 +327,7 @@ public class PurgeDaoTest { dbTester.prepareDbUnit(getClass(), "view_sub_view_and_tech_project.xml"); // view - underTest.deleteRootComponent(dbSession, "A"); + underTest.deleteProject(dbSession, "A"); dbSession.commit(); assertThat(dbTester.countSql("select count(1) from projects where uuid='A'")).isZero(); } @@ -356,7 +367,7 @@ public class PurgeDaoTest { dbClient.webhookDeliveryDao().insert(dbSession, newWebhookDeliveryDto().setComponentUuid(project.uuid()).setUuid("D1")); dbClient.webhookDeliveryDao().insert(dbSession, newWebhookDeliveryDto().setComponentUuid("P2").setUuid("D2")); - underTest.deleteRootComponent(dbSession, project.uuid()); + underTest.deleteProject(dbSession, project.uuid()); assertThat(selectAllDeliveryUuids(dbTester, dbSession)).containsOnly("D2"); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java index 8c840c4749d..ffd9ce378c2 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java @@ -51,11 +51,17 @@ public class ComponentCleanerService { } } + public void deleteBranch(DbSession dbSession, ComponentDto branch) { + // TODO: detect if other branches depend on it? + dbClient.purgeDao().deleteBranch(dbSession, branch.uuid()); + projectIndexers.commitAndIndex(dbSession, singletonList(branch), ProjectIndexer.Cause.PROJECT_DELETION); + } + public void delete(DbSession dbSession, ComponentDto project) { if (hasNotProjectScope(project) || isNotDeletable(project)) { throw new IllegalArgumentException("Only projects can be deleted"); } - dbClient.purgeDao().deleteRootComponent(dbSession, project.uuid()); + dbClient.purgeDao().deleteProject(dbSession, project.uuid()); projectIndexers.commitAndIndex(dbSession, singletonList(project), ProjectIndexer.Cause.PROJECT_DELETION); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentFinder.java b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentFinder.java index dc2f394bb11..a9f26f817a5 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentFinder.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentFinder.java @@ -151,6 +151,9 @@ public class ComponentFinder { return checkFoundWithOptional(organizationDto, "Organization with uuid '%s' not found", organizationUuid); } + /** + * Components of the main branch won't be found + */ public ComponentDto getByKeyAndBranch(DbSession dbSession, String key, String branch) { return checkComponent(dbClient.componentDao().selectByKeyAndBranch(dbSession, key, branch), "Component '%s' on branch '%s' not found", key, branch); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchWsModule.java index 0a0d4c2cd80..d47f197991c 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchWsModule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchWsModule.java @@ -27,6 +27,7 @@ public class BranchWsModule extends Module { add( ListAction.class, ShowAction.class, + DeleteAction.class, BranchesWs.class); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/DeleteAction.java b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/DeleteAction.java new file mode 100644 index 00000000000..89e3b9bb631 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/DeleteAction.java @@ -0,0 +1,105 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.projectbranch.ws; + +import com.google.common.io.Resources; +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; +import org.sonar.api.server.ws.WebService; +import org.sonar.api.server.ws.WebService.NewController; +import org.sonar.api.web.UserRole; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.component.BranchDto; +import org.sonar.db.component.BranchKeyType; +import org.sonar.db.component.ComponentDto; +import org.sonar.server.component.ComponentCleanerService; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.user.UserSession; + +import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; +import static org.sonar.server.ws.WsUtils.checkFoundWithOptional; +import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.ACTION_DELETE; +import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.PARAM_BRANCH; +import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.PARAM_PROJECT;; + +public class DeleteAction implements BranchWsAction { + private final DbClient dbClient; + private final UserSession userSession; + private final ComponentCleanerService componentCleanerService; + private final ComponentFinder componentFinder; + + public DeleteAction(DbClient dbClient, ComponentFinder componentFinder, UserSession userSession, ComponentCleanerService componentCleanerService) { + this.dbClient = dbClient; + this.componentFinder = componentFinder; + this.userSession = userSession; + this.componentCleanerService = componentCleanerService; + } + + @Override + public void define(NewController context) { + WebService.NewAction action = context.createAction(ACTION_DELETE) + .setSince("6.6") + .setDescription("Delete a non-main branch of a project. Requires permission to administer the project.") + .setResponseExample(Resources.getResource(getClass(), "list-example.json")) + .setInternal(true) + .setPost(true) + .setHandler(this); + + action + .createParam(PARAM_PROJECT) + .setDescription("Project key") + .setExampleValue(KEY_PROJECT_EXAMPLE_001) + .setRequired(true); + action + .createParam(PARAM_BRANCH) + .setDescription("Name of the branch to delete. Can't be the main branch of the project.") + .setExampleValue("branch1") + .setRequired(true); + } + + @Override + public void handle(Request request, Response response) throws Exception { + userSession.checkLoggedIn(); + String projectKey = request.mandatoryParam(PARAM_PROJECT); + String branchKey = request.mandatoryParam(PARAM_BRANCH); + + try (DbSession dbSession = dbClient.openSession(false)) { + ComponentDto project = componentFinder.getRootComponentByUuidOrKey(dbSession, null, projectKey); + checkPermission(project); + + BranchDto branch = checkFoundWithOptional( + dbClient.branchDao().selectByKey(dbSession, project.uuid(), BranchKeyType.BRANCH, branchKey), + "Branch '%s' not found for project '%s'", branchKey, projectKey); + + if (branch.isMain()) { + throw new IllegalArgumentException("Only non-main branches can be deleted"); + } + ComponentDto branchComponent = componentFinder.getByKeyAndBranch(dbSession, projectKey, branchKey); + componentCleanerService.deleteBranch(dbSession, branchComponent); + response.noContent(); + } + } + + private void checkPermission(ComponentDto project) { + userSession.hasComponentPermission(UserRole.ADMIN, project); + } + +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentCleanerServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentCleanerServiceTest.java index 6e390230fe2..7a8256beb98 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentCleanerServiceTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentCleanerServiceTest.java @@ -91,6 +91,20 @@ public class ComponentCleanerServiceTest { } @Test + public void delete_branch() { + DbData data1 = insertData(1); + DbData data2 = insertData(2); + DbData data3 = insertData(3); + + underTest.deleteBranch(dbSession, data1.project); + dbSession.commit(); + + assertNotExists(data1); + assertExists(data2); + assertExists(data3); + } + + @Test public void fail_with_IAE_if_not_a_project() throws Exception { mockResourceTypeAsValidProject(); ComponentDto project = ComponentTesting.newPrivateProjectDto(db.organizations().insert()); diff --git a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/BranchWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/BranchWsModuleTest.java index 39810004936..2ecb8a885a2 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/BranchWsModuleTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/BranchWsModuleTest.java @@ -30,6 +30,6 @@ public class BranchWsModuleTest { public void verify_count_of_added_components() { ComponentContainer container = new ComponentContainer(); new BranchWsModule().configure(container); - assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 3); + assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 4); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/DeleteActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/DeleteActionTest.java new file mode 100644 index 00000000000..b467725bb7a --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/DeleteActionTest.java @@ -0,0 +1,163 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.projectbranch.ws; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.ArgumentCaptor; +import org.sonar.api.server.ws.WebService; +import org.sonar.api.utils.System2; +import org.sonar.api.web.UserRole; +import org.sonar.db.DbSession; +import org.sonar.db.DbTester; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.ComponentTesting; +import org.sonar.server.component.ComponentCleanerService; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.component.TestComponentFinder; +import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.exceptions.UnauthorizedException; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.WsActionTester; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +public class DeleteActionTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + + private ComponentCleanerService componentCleanerService = mock(ComponentCleanerService.class); + private ComponentFinder componentFinder = TestComponentFinder.from(db); + + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + + public WsActionTester tester = new WsActionTester(new DeleteAction(db.getDbClient(), componentFinder, userSession, componentCleanerService)); + + @Test + public void test_definition() { + WebService.Action definition = tester.getDef(); + assertThat(definition.key()).isEqualTo("delete"); + assertThat(definition.isPost()).isTrue(); + assertThat(definition.isInternal()).isTrue(); + assertThat(definition.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("project", "branch"); + assertThat(definition.since()).isEqualTo("6.6"); + } + + @Test + public void fail_if_missing_project_parameter() { + userSession.logIn(); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("The 'project' parameter is missing"); + + tester.newRequest().execute(); + } + + @Test + public void fail_if_missing_branch_parameter() { + userSession.logIn(); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("The 'branch' parameter is missing"); + + tester.newRequest().setParam("project", "projectName").execute(); + } + + @Test + public void fail_if_not_logged_in() { + expectedException.expect(UnauthorizedException.class); + expectedException.expectMessage("Authentication is required"); + + tester.newRequest().execute(); + } + + public void fail_branch_does_not_exist() { + ComponentDto project = db.components().insertPrivateProject(); + ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); + userSession.logIn().addProjectPermission(UserRole.ADMIN, project); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Branch 'branch1' not found"); + + tester.newRequest() + .setParam("project", file.getDbKey()) + .setParam("branch", "branch1") + .execute(); + } + + @Test + public void fail_if_project_does_not_exist() { + userSession.logIn(); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Project key 'foo' not found"); + + tester.newRequest() + .setParam("project", "foo") + .setParam("branch", "branch1") + .execute(); + } + + @Test + public void fail_if_branch_is_main() { + ComponentDto project = db.components().insertMainBranch(); + db.executeUpdateSql("UPDATE project_branches set KEE = 'main'"); + userSession.logIn().addProjectPermission(UserRole.ADMIN, project); + + // not found because the DB keys don't contain the name + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Only non-main branches can be deleted"); + + tester.newRequest() + .setParam("project", project.getKey()) + .setParam("branch", "main") + .execute(); + } + + @Test + public void delete_branch() { + + ComponentDto project = db.components().insertMainBranch(); + ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("branch1")); + + userSession.logIn().addProjectPermission(UserRole.ADMIN, project); + + tester.newRequest() + .setParam("project", project.getKey()) + .setParam("branch", "branch1") + .execute(); + verifyDeletedKey(branch.getDbKey()); + } + + private void verifyDeletedKey(String key) { + ArgumentCaptor<ComponentDto> argument = ArgumentCaptor.forClass(ComponentDto.class); + verify(componentCleanerService).deleteBranch(any(DbSession.class), argument.capture()); + assertThat(argument.getValue().getDbKey()).isEqualTo(key); + } + +} |