From: Guillaume Jambet Date: Thu, 2 Nov 2017 14:31:34 +0000 (+0100) Subject: SONAR-10040 move projectbranch ws to package branch X-Git-Tag: 7.0-RC1~363 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=c8b9191e461a5ad31860e961ee49f2f2098927e9;p=sonarqube.git SONAR-10040 move projectbranch ws to package branch --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/branch/ws/BranchWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/branch/ws/BranchWsAction.java new file mode 100644 index 00000000000..8f19fc4ac0d --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/branch/ws/BranchWsAction.java @@ -0,0 +1,26 @@ +/* + * 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.branch.ws; + +import org.sonar.server.ws.WsAction; + +public interface BranchWsAction extends WsAction { + // marker interface +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/branch/ws/BranchWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/branch/ws/BranchWsModule.java new file mode 100644 index 00000000000..73d421d28c6 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/branch/ws/BranchWsModule.java @@ -0,0 +1,33 @@ +/* + * 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.branch.ws; + +import org.sonar.core.platform.Module; + +public class BranchWsModule extends Module { + @Override + protected void configureModule() { + add( + ListAction.class, + DeleteAction.class, + RenameAction.class, + BranchesWs.class); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/branch/ws/BranchesWs.java b/server/sonar-server/src/main/java/org/sonar/server/branch/ws/BranchesWs.java new file mode 100644 index 00000000000..7275130e1f3 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/branch/ws/BranchesWs.java @@ -0,0 +1,62 @@ +/* + * 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.branch.ws; + +import java.util.Arrays; +import org.sonar.api.server.ws.WebService; + +import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; +import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.CONTROLLER; +import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.PARAM_BRANCH; +import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.PARAM_PROJECT; + +public class BranchesWs implements WebService { + private final BranchWsAction[] actions; + + public BranchesWs(BranchWsAction... actions) { + this.actions = actions; + } + + @Override + public void define(Context context) { + NewController controller = context.createController(CONTROLLER) + .setSince("6.6") + .setDescription("Manage branch (only available when the Branch plugin is installed)"); + Arrays.stream(actions).forEach(action -> action.define(controller)); + controller.done(); + } + + static void addProjectParam(NewAction action) { + action + .createParam(PARAM_PROJECT) + .setDescription("Project key") + .setExampleValue(KEY_PROJECT_EXAMPLE_001) + .setRequired(true); + } + + static void addBranchParam(NewAction action) { + action + .createParam(PARAM_BRANCH) + .setDescription("Name of the branch") + .setExampleValue("branch1") + .setRequired(true); + } + +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/branch/ws/DeleteAction.java b/server/sonar-server/src/main/java/org/sonar/server/branch/ws/DeleteAction.java new file mode 100644 index 00000000000..a04f6deed31 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/branch/ws/DeleteAction.java @@ -0,0 +1,97 @@ +/* + * 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.branch.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.ComponentDto; +import org.sonar.server.component.ComponentCleanerService; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.user.UserSession; + +import static org.sonar.server.branch.ws.BranchesWs.addBranchParam; +import static org.sonar.server.branch.ws.BranchesWs.addProjectParam; +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 'Administer' rights on the specified project.") + .setResponseExample(Resources.getResource(getClass(), "list-example.json")) + .setPost(true) + .setHandler(this); + + addProjectParam(action); + addBranchParam(action); + } + + @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(), 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.checkComponentPermission(UserRole.ADMIN, project); + } + +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/branch/ws/ListAction.java b/server/sonar-server/src/main/java/org/sonar/server/branch/ws/ListAction.java new file mode 100644 index 00000000000..078fb44ce6e --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/branch/ws/ListAction.java @@ -0,0 +1,162 @@ +/* + * 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.branch.ws; + +import com.google.common.io.Resources; +import java.util.Collection; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; +import javax.annotation.Nullable; +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.web.UserRole; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.component.BranchDto; +import org.sonar.db.component.BranchType; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.SnapshotDto; +import org.sonar.db.measure.MeasureDto; +import org.sonar.db.metric.MetricDto; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.issue.index.BranchStatistics; +import org.sonar.server.issue.index.IssueIndex; +import org.sonar.server.user.UserSession; +import org.sonar.server.ws.WsUtils; +import org.sonarqube.ws.Common; +import org.sonarqube.ws.WsBranches; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Collections.singletonList; +import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; +import static org.sonar.api.resources.Qualifiers.PROJECT; +import static org.sonar.api.utils.DateUtils.formatDateTime; +import static org.sonar.core.util.Protobuf.setNullable; +import static org.sonar.core.util.stream.MoreCollectors.toList; +import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; +import static org.sonar.db.component.BranchType.LONG; +import static org.sonar.db.component.BranchType.SHORT; +import static org.sonar.server.branch.ws.BranchesWs.addProjectParam; +import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.ACTION_LIST; +import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.PARAM_PROJECT; + +public class ListAction implements BranchWsAction { + + private final DbClient dbClient; + private final UserSession userSession; + private final ComponentFinder componentFinder; + private final IssueIndex issueIndex; + + public ListAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder, IssueIndex issueIndex) { + this.dbClient = dbClient; + this.userSession = userSession; + this.componentFinder = componentFinder; + this.issueIndex = issueIndex; + } + + @Override + public void define(WebService.NewController context) { + WebService.NewAction action = context.createAction(ACTION_LIST) + .setSince("6.6") + .setDescription("List the branches of a project.
" + + "Requires 'Administer' rights on the specified project.") + .setResponseExample(Resources.getResource(getClass(), "list-example.json")) + .setHandler(this); + + addProjectParam(action); + } + + @Override + public void handle(Request request, Response response) throws Exception { + String projectKey = request.mandatoryParam(PARAM_PROJECT); + + try (DbSession dbSession = dbClient.openSession(false)) { + ComponentDto project = componentFinder.getByKey(dbSession, projectKey); + userSession.checkComponentPermission(UserRole.USER, project); + checkArgument(project.isEnabled() && PROJECT.equals(project.qualifier()), "Invalid project key"); + + Collection branches = dbClient.branchDao().selectByComponent(dbSession, project); + MetricDto qualityGateMetric = dbClient.metricDao().selectOrFailByKey(dbSession, ALERT_STATUS_KEY); + Map mergeBranchesByUuid = dbClient.branchDao() + .selectByUuids(dbSession, branches.stream().map(BranchDto::getMergeBranchUuid).filter(Objects::nonNull).collect(toList())) + .stream().collect(uniqueIndex(BranchDto::getUuid)); + Map qualityGateMeasuresByComponentUuids = dbClient.measureDao() + .selectByComponentsAndMetrics(dbSession, branches.stream().map(BranchDto::getUuid).collect(toList()), singletonList(qualityGateMetric.getId())) + .stream().collect(uniqueIndex(MeasureDto::getComponentUuid)); + Map branchStatisticsByBranchUuid = issueIndex.searchBranchStatistics(project.uuid(), branches.stream() + .filter(b -> b.getBranchType().equals(SHORT)) + .map(BranchDto::getUuid).collect(toList())) + .stream().collect(uniqueIndex(BranchStatistics::getBranchUuid, Function.identity())); + Map analysisDateByBranchUuid = dbClient.snapshotDao() + .selectLastAnalysesByRootComponentUuids(dbSession, branches.stream().map(BranchDto::getUuid).collect(Collectors.toList())) + .stream().collect(uniqueIndex(SnapshotDto::getComponentUuid, s -> formatDateTime(s.getCreatedAt()))); + + WsBranches.ListWsResponse.Builder protobufResponse = WsBranches.ListWsResponse.newBuilder(); + branches.stream() + .forEach(b -> addBranch(protobufResponse, b, mergeBranchesByUuid, qualityGateMeasuresByComponentUuids.get(b.getUuid()), branchStatisticsByBranchUuid.get(b.getUuid()), + analysisDateByBranchUuid.get(b.getUuid()))); + WsUtils.writeProtobuf(protobufResponse.build(), request, response); + } + } + + private static void addBranch(WsBranches.ListWsResponse.Builder response, BranchDto branch, Map mergeBranchesByUuid, @Nullable MeasureDto qualityGateMeasure, + BranchStatistics branchStatistics, @Nullable String analysisDate) { + WsBranches.Branch.Builder builder = toBranchBuilder(branch, Optional.ofNullable(mergeBranchesByUuid.get(branch.getMergeBranchUuid()))); + setBranchStatus(builder, branch, qualityGateMeasure, branchStatistics); + if (analysisDate != null) { + builder.setAnalysisDate(analysisDate); + } + response.addBranches(builder); + } + + private static WsBranches.Branch.Builder toBranchBuilder(BranchDto branch, Optional mergeBranch) { + WsBranches.Branch.Builder builder = WsBranches.Branch.newBuilder(); + String branchKey = branch.getKey(); + setNullable(branchKey, builder::setName); + builder.setIsMain(branch.isMain()); + builder.setType(Common.BranchType.valueOf(branch.getBranchType().name())); + if (branch.getBranchType().equals(SHORT)) { + if (mergeBranch.isPresent()) { + String mergeBranchKey = mergeBranch.get().getKey(); + builder.setMergeBranch(mergeBranchKey); + } else { + builder.setIsOrphan(true); + } + } + return builder; + } + + private static void setBranchStatus(WsBranches.Branch.Builder builder, BranchDto branch, @Nullable MeasureDto qualityGateMeasure, @Nullable BranchStatistics branchStatistics) { + WsBranches.Branch.Status.Builder statusBuilder = WsBranches.Branch.Status.newBuilder(); + if (branch.getBranchType() == LONG && qualityGateMeasure != null) { + statusBuilder.setQualityGateStatus(qualityGateMeasure.getData()); + } + if (branch.getBranchType() == BranchType.SHORT) { + statusBuilder.setBugs(branchStatistics == null ? 0L : branchStatistics.getBugs()); + statusBuilder.setVulnerabilities(branchStatistics == null ? 0L : branchStatistics.getVulnerabilities()); + statusBuilder.setCodeSmells(branchStatistics == null ? 0L : branchStatistics.getCodeSmells()); + } + builder.setStatus(statusBuilder); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/branch/ws/RenameAction.java b/server/sonar-server/src/main/java/org/sonar/server/branch/ws/RenameAction.java new file mode 100644 index 00000000000..9e4c6fb6561 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/branch/ws/RenameAction.java @@ -0,0 +1,93 @@ +/* + * 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.branch.ws; + +import java.util.Optional; +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.ComponentDto; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.user.UserSession; + +import static com.google.common.base.Preconditions.checkArgument; +import static org.sonar.server.branch.ws.BranchesWs.addProjectParam; +import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.ACTION_RENAME; +import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.PARAM_NAME; +import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.PARAM_PROJECT; + +public class RenameAction implements BranchWsAction { + private final ComponentFinder componentFinder; + private final UserSession userSession; + private final DbClient dbClient; + + public RenameAction(DbClient dbClient, ComponentFinder componentFinder, UserSession userSession) { + this.dbClient = dbClient; + this.componentFinder = componentFinder; + this.userSession = userSession; + } + + @Override + public void define(NewController context) { + WebService.NewAction action = context.createAction(ACTION_RENAME) + .setSince("6.6") + .setDescription("Rename the main branch of a project.
" + + "Requires 'Administer' permission on the specified project.") + .setPost(true) + .setHandler(this); + + addProjectParam(action); + action + .createParam(PARAM_NAME) + .setDescription("New name of the main branch") + .setExampleValue("branch1") + .setRequired(true); + } + + @Override + public void handle(Request request, Response response) throws Exception { + userSession.checkLoggedIn(); + String projectKey = request.mandatoryParam(PARAM_PROJECT); + String newBranchName = request.mandatoryParam(PARAM_NAME); + + try (DbSession dbSession = dbClient.openSession(false)) { + ComponentDto project = componentFinder.getRootComponentByUuidOrKey(dbSession, null, projectKey); + checkPermission(project); + + Optional existingBranch = dbClient.branchDao().selectByKey(dbSession, project.uuid(), newBranchName); + checkArgument(!existingBranch.filter(b -> !b.isMain()).isPresent(), + "Impossible to update branch name: a branch with name \"%s\" already exists in the project.", newBranchName); + + dbClient.branchDao().updateMainBranchName(dbSession, project.uuid(), newBranchName); + dbSession.commit(); + response.noContent(); + } + } + + private void checkPermission(ComponentDto project) { + userSession.checkComponentPermission(UserRole.ADMIN, project); + } + +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/branch/ws/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/branch/ws/package-info.java new file mode 100644 index 00000000000..6e4b5e85b31 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/branch/ws/package-info.java @@ -0,0 +1,23 @@ +/* + * 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.server.branch.ws; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index ccb703b4414..5df9ecf476c 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -38,6 +38,7 @@ import org.sonar.server.authentication.AuthenticationModule; import org.sonar.server.authentication.LogOAuthWarning; import org.sonar.server.batch.BatchWsModule; import org.sonar.server.branch.BranchFeatureProxyImpl; +import org.sonar.server.branch.ws.BranchWsModule; import org.sonar.server.ce.ws.CeWsModule; import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.component.ComponentFinder; @@ -149,7 +150,6 @@ import org.sonar.server.plugins.ws.UninstallAction; import org.sonar.server.plugins.ws.UpdatesAction; import org.sonar.server.project.ws.ProjectsWsModule; import org.sonar.server.projectanalysis.ProjectAnalysisModule; -import org.sonar.server.projectbranch.ws.BranchWsModule; import org.sonar.server.projectlink.ws.ProjectLinksModule; import org.sonar.server.projecttag.ws.ProjectTagsWsModule; import org.sonar.server.property.InternalPropertiesImpl; diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/package-info.java deleted file mode 100644 index 6aa3bb36dc4..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ -@ParametersAreNonnullByDefault -package org.sonar.server.projectbranch; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchWsAction.java deleted file mode 100644 index 7a2c3f983b0..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchWsAction.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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.sonar.server.ws.WsAction; - -public interface BranchWsAction extends WsAction { - // marker interface -} 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 deleted file mode 100644 index da41f7aec81..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchWsModule.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.sonar.core.platform.Module; - -public class BranchWsModule extends Module { - @Override - protected void configureModule() { - add( - ListAction.class, - DeleteAction.class, - RenameAction.class, - BranchesWs.class); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchesWs.java b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchesWs.java deleted file mode 100644 index 64657b98a15..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchesWs.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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 java.util.Arrays; -import org.sonar.api.server.ws.WebService; - -import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; -import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.CONTROLLER; -import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.PARAM_BRANCH; -import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.PARAM_PROJECT; - -public class BranchesWs implements WebService { - private final BranchWsAction[] actions; - - public BranchesWs(BranchWsAction... actions) { - this.actions = actions; - } - - @Override - public void define(Context context) { - NewController controller = context.createController(CONTROLLER) - .setSince("6.6") - .setDescription("Manage branch (only available when the Branch plugin is installed)"); - Arrays.stream(actions).forEach(action -> action.define(controller)); - controller.done(); - } - - static void addProjectParam(NewAction action) { - action - .createParam(PARAM_PROJECT) - .setDescription("Project key") - .setExampleValue(KEY_PROJECT_EXAMPLE_001) - .setRequired(true); - } - - static void addBranchParam(NewAction action) { - action - .createParam(PARAM_BRANCH) - .setDescription("Name of the branch") - .setExampleValue("branch1") - .setRequired(true); - } - -} 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 deleted file mode 100644 index 50c41916245..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/DeleteAction.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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.ComponentDto; -import org.sonar.server.component.ComponentCleanerService; -import org.sonar.server.component.ComponentFinder; -import org.sonar.server.user.UserSession; - -import static org.sonar.server.projectbranch.ws.BranchesWs.addBranchParam; -import static org.sonar.server.projectbranch.ws.BranchesWs.addProjectParam; -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 'Administer' rights on the specified project.") - .setResponseExample(Resources.getResource(getClass(), "list-example.json")) - .setPost(true) - .setHandler(this); - - addProjectParam(action); - addBranchParam(action); - } - - @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(), 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.checkComponentPermission(UserRole.ADMIN, project); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/ListAction.java b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/ListAction.java deleted file mode 100644 index cc575a3868a..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/ListAction.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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 java.util.Collection; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -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.web.UserRole; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.BranchType; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.SnapshotDto; -import org.sonar.db.measure.MeasureDto; -import org.sonar.db.metric.MetricDto; -import org.sonar.server.component.ComponentFinder; -import org.sonar.server.issue.index.BranchStatistics; -import org.sonar.server.issue.index.IssueIndex; -import org.sonar.server.user.UserSession; -import org.sonar.server.ws.WsUtils; -import org.sonarqube.ws.Common; -import org.sonarqube.ws.WsBranches; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.util.Collections.singletonList; -import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; -import static org.sonar.api.resources.Qualifiers.PROJECT; -import static org.sonar.api.utils.DateUtils.formatDateTime; -import static org.sonar.core.util.Protobuf.setNullable; -import static org.sonar.core.util.stream.MoreCollectors.toList; -import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; -import static org.sonar.db.component.BranchType.LONG; -import static org.sonar.db.component.BranchType.SHORT; -import static org.sonar.server.projectbranch.ws.BranchesWs.addProjectParam; -import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.ACTION_LIST; -import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.PARAM_PROJECT; - -public class ListAction implements BranchWsAction { - - private final DbClient dbClient; - private final UserSession userSession; - private final ComponentFinder componentFinder; - private final IssueIndex issueIndex; - - public ListAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder, IssueIndex issueIndex) { - this.dbClient = dbClient; - this.userSession = userSession; - this.componentFinder = componentFinder; - this.issueIndex = issueIndex; - } - - @Override - public void define(WebService.NewController context) { - WebService.NewAction action = context.createAction(ACTION_LIST) - .setSince("6.6") - .setDescription("List the branches of a project.
" + - "Requires 'Administer' rights on the specified project.") - .setResponseExample(Resources.getResource(getClass(), "list-example.json")) - .setHandler(this); - - addProjectParam(action); - } - - @Override - public void handle(Request request, Response response) throws Exception { - String projectKey = request.mandatoryParam(PARAM_PROJECT); - - try (DbSession dbSession = dbClient.openSession(false)) { - ComponentDto project = componentFinder.getByKey(dbSession, projectKey); - userSession.checkComponentPermission(UserRole.USER, project); - checkArgument(project.isEnabled() && PROJECT.equals(project.qualifier()), "Invalid project key"); - - Collection branches = dbClient.branchDao().selectByComponent(dbSession, project); - MetricDto qualityGateMetric = dbClient.metricDao().selectOrFailByKey(dbSession, ALERT_STATUS_KEY); - Map mergeBranchesByUuid = dbClient.branchDao() - .selectByUuids(dbSession, branches.stream().map(BranchDto::getMergeBranchUuid).filter(Objects::nonNull).collect(toList())) - .stream().collect(uniqueIndex(BranchDto::getUuid)); - Map qualityGateMeasuresByComponentUuids = dbClient.measureDao() - .selectByComponentsAndMetrics(dbSession, branches.stream().map(BranchDto::getUuid).collect(toList()), singletonList(qualityGateMetric.getId())) - .stream().collect(uniqueIndex(MeasureDto::getComponentUuid)); - Map branchStatisticsByBranchUuid = issueIndex.searchBranchStatistics(project.uuid(), branches.stream() - .filter(b -> b.getBranchType().equals(SHORT)) - .map(BranchDto::getUuid).collect(toList())) - .stream().collect(uniqueIndex(BranchStatistics::getBranchUuid, Function.identity())); - Map analysisDateByBranchUuid = dbClient.snapshotDao() - .selectLastAnalysesByRootComponentUuids(dbSession, branches.stream().map(BranchDto::getUuid).collect(Collectors.toList())) - .stream().collect(uniqueIndex(SnapshotDto::getComponentUuid, s -> formatDateTime(s.getCreatedAt()))); - - WsBranches.ListWsResponse.Builder protobufResponse = WsBranches.ListWsResponse.newBuilder(); - branches.stream() - .forEach(b -> addBranch(protobufResponse, b, mergeBranchesByUuid, qualityGateMeasuresByComponentUuids.get(b.getUuid()), branchStatisticsByBranchUuid.get(b.getUuid()), - analysisDateByBranchUuid.get(b.getUuid()))); - WsUtils.writeProtobuf(protobufResponse.build(), request, response); - } - } - - private static void addBranch(WsBranches.ListWsResponse.Builder response, BranchDto branch, Map mergeBranchesByUuid, @Nullable MeasureDto qualityGateMeasure, - BranchStatistics branchStatistics, @Nullable String analysisDate) { - WsBranches.Branch.Builder builder = toBranchBuilder(branch, Optional.ofNullable(mergeBranchesByUuid.get(branch.getMergeBranchUuid()))); - setBranchStatus(builder, branch, qualityGateMeasure, branchStatistics); - if (analysisDate != null) { - builder.setAnalysisDate(analysisDate); - } - response.addBranches(builder); - } - - private static WsBranches.Branch.Builder toBranchBuilder(BranchDto branch, Optional mergeBranch) { - WsBranches.Branch.Builder builder = WsBranches.Branch.newBuilder(); - String branchKey = branch.getKey(); - setNullable(branchKey, builder::setName); - builder.setIsMain(branch.isMain()); - builder.setType(Common.BranchType.valueOf(branch.getBranchType().name())); - if (branch.getBranchType().equals(SHORT)) { - if (mergeBranch.isPresent()) { - String mergeBranchKey = mergeBranch.get().getKey(); - builder.setMergeBranch(mergeBranchKey); - } else { - builder.setIsOrphan(true); - } - } - return builder; - } - - private static void setBranchStatus(WsBranches.Branch.Builder builder, BranchDto branch, @Nullable MeasureDto qualityGateMeasure, @Nullable BranchStatistics branchStatistics) { - WsBranches.Branch.Status.Builder statusBuilder = WsBranches.Branch.Status.newBuilder(); - if (branch.getBranchType() == LONG && qualityGateMeasure != null) { - statusBuilder.setQualityGateStatus(qualityGateMeasure.getData()); - } - if (branch.getBranchType() == BranchType.SHORT) { - statusBuilder.setBugs(branchStatistics == null ? 0L : branchStatistics.getBugs()); - statusBuilder.setVulnerabilities(branchStatistics == null ? 0L : branchStatistics.getVulnerabilities()); - statusBuilder.setCodeSmells(branchStatistics == null ? 0L : branchStatistics.getCodeSmells()); - } - builder.setStatus(statusBuilder); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/RenameAction.java b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/RenameAction.java deleted file mode 100644 index 3928c0aae00..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/RenameAction.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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 java.util.Optional; -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.ComponentDto; -import org.sonar.server.component.ComponentFinder; -import org.sonar.server.user.UserSession; - -import static com.google.common.base.Preconditions.checkArgument; -import static org.sonar.server.projectbranch.ws.BranchesWs.addProjectParam; -import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.ACTION_RENAME; -import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.PARAM_NAME; -import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.PARAM_PROJECT; - -public class RenameAction implements BranchWsAction { - private final ComponentFinder componentFinder; - private final UserSession userSession; - private final DbClient dbClient; - - public RenameAction(DbClient dbClient, ComponentFinder componentFinder, UserSession userSession) { - this.dbClient = dbClient; - this.componentFinder = componentFinder; - this.userSession = userSession; - } - - @Override - public void define(NewController context) { - WebService.NewAction action = context.createAction(ACTION_RENAME) - .setSince("6.6") - .setDescription("Rename the main branch of a project.
" - + "Requires 'Administer' permission on the specified project.") - .setPost(true) - .setHandler(this); - - addProjectParam(action); - action - .createParam(PARAM_NAME) - .setDescription("New name of the main branch") - .setExampleValue("branch1") - .setRequired(true); - } - - @Override - public void handle(Request request, Response response) throws Exception { - userSession.checkLoggedIn(); - String projectKey = request.mandatoryParam(PARAM_PROJECT); - String newBranchName = request.mandatoryParam(PARAM_NAME); - - try (DbSession dbSession = dbClient.openSession(false)) { - ComponentDto project = componentFinder.getRootComponentByUuidOrKey(dbSession, null, projectKey); - checkPermission(project); - - Optional existingBranch = dbClient.branchDao().selectByKey(dbSession, project.uuid(), newBranchName); - checkArgument(!existingBranch.filter(b -> !b.isMain()).isPresent(), - "Impossible to update branch name: a branch with name \"%s\" already exists in the project.", newBranchName); - - dbClient.branchDao().updateMainBranchName(dbSession, project.uuid(), newBranchName); - dbSession.commit(); - response.noContent(); - } - } - - private void checkPermission(ComponentDto project) { - userSession.checkComponentPermission(UserRole.ADMIN, project); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/package-info.java deleted file mode 100644 index 86bd1e8363d..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ -@ParametersAreNonnullByDefault -package org.sonar.server.projectbranch.ws; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/resources/org/sonar/server/branch/ws/list-example.json b/server/sonar-server/src/main/resources/org/sonar/server/branch/ws/list-example.json new file mode 100644 index 00000000000..9d285888732 --- /dev/null +++ b/server/sonar-server/src/main/resources/org/sonar/server/branch/ws/list-example.json @@ -0,0 +1,17 @@ +{ + "branches": [ + { + "name": "feature/bar", + "isMain": false, + "type": "LONG", + "analysisDate": "2017-04-01T01:15:42+0100" + }, + { + "name": "feature/foo", + "isMain": false, + "type": "SHORT", + "mergeBranch": "feature/bar", + "analysisDate": "2017-04-03T13:37:00+0100" + } + ] +} diff --git a/server/sonar-server/src/main/resources/org/sonar/server/projectbranch/ws/list-example.json b/server/sonar-server/src/main/resources/org/sonar/server/projectbranch/ws/list-example.json deleted file mode 100644 index 9d285888732..00000000000 --- a/server/sonar-server/src/main/resources/org/sonar/server/projectbranch/ws/list-example.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "branches": [ - { - "name": "feature/bar", - "isMain": false, - "type": "LONG", - "analysisDate": "2017-04-01T01:15:42+0100" - }, - { - "name": "feature/foo", - "isMain": false, - "type": "SHORT", - "mergeBranch": "feature/bar", - "analysisDate": "2017-04-03T13:37:00+0100" - } - ] -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/branch/ws/BranchWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/branch/ws/BranchWsModuleTest.java new file mode 100644 index 00000000000..4b6c7d93e09 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/branch/ws/BranchWsModuleTest.java @@ -0,0 +1,35 @@ +/* + * 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.branch.ws; + +import org.junit.Test; +import org.sonar.core.platform.ComponentContainer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER; + +public class BranchWsModuleTest { + @Test + public void verify_count_of_added_components() { + ComponentContainer container = new ComponentContainer(); + new BranchWsModule().configure(container); + assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 4); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/branch/ws/BranchesWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/branch/ws/BranchesWsTest.java new file mode 100644 index 00000000000..4866279afa0 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/branch/ws/BranchesWsTest.java @@ -0,0 +1,51 @@ +/* + * 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.branch.ws; + +import org.junit.Test; +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; +import org.sonar.api.server.ws.WebService; + +import static org.assertj.core.api.Assertions.assertThat; + +public class BranchesWsTest { + + @Test + public void define_ws() { + BranchesWs underTest = new BranchesWs(new BranchWsAction() { + @Override + public void define(WebService.NewController context) { + context.createAction("foo").setHandler(this); + } + + @Override + public void handle(Request request, Response response) throws Exception { + + } + }); + + WebService.Context context = new WebService.Context(); + underTest.define(context); + + assertThat(context.controller("api/project_branches").action("foo")).isNotNull(); + } + +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/branch/ws/DeleteActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/branch/ws/DeleteActionTest.java new file mode 100644 index 00000000000..5f40c2f106d --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/branch/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.branch.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()).isFalse(); + 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 argument = ArgumentCaptor.forClass(ComponentDto.class); + verify(componentCleanerService).deleteBranch(any(DbSession.class), argument.capture()); + assertThat(argument.getValue().getDbKey()).isEqualTo(key); + } + +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/branch/ws/ListActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/branch/ws/ListActionTest.java new file mode 100644 index 00000000000..e008e9fe9b4 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/branch/ws/ListActionTest.java @@ -0,0 +1,396 @@ +/* + * 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.branch.ws; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.resources.ResourceTypes; +import org.sonar.api.server.ws.WebService; +import org.sonar.api.utils.DateUtils; +import org.sonar.api.utils.System2; +import org.sonar.api.web.UserRole; +import org.sonar.db.DbTester; +import org.sonar.db.component.BranchType; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.ComponentTesting; +import org.sonar.db.component.ResourceTypesRule; +import org.sonar.db.component.SnapshotDto; +import org.sonar.db.component.SnapshotTesting; +import org.sonar.db.metric.MetricDto; +import org.sonar.db.organization.OrganizationDto; +import org.sonar.db.rule.RuleDefinitionDto; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.es.EsTester; +import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.issue.index.IssueIndex; +import org.sonar.server.issue.index.IssueIndexDefinition; +import org.sonar.server.issue.index.IssueIndexer; +import org.sonar.server.issue.index.IssueIteratorFactory; +import org.sonar.server.permission.index.AuthorizationTypeSupport; +import org.sonar.server.permission.index.PermissionIndexerTester; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.WsActionTester; +import org.sonarqube.ws.Common; +import org.sonarqube.ws.MediaTypes; +import org.sonarqube.ws.WsBranches; +import org.sonarqube.ws.WsBranches.Branch; +import org.sonarqube.ws.WsBranches.ListWsResponse; + +import static java.lang.String.format; +import static java.util.Collections.emptySet; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; +import static org.sonar.api.issue.Issue.RESOLUTION_FALSE_POSITIVE; +import static org.sonar.api.issue.Issue.RESOLUTION_FIXED; +import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; +import static org.sonar.api.resources.Qualifiers.PROJECT; +import static org.sonar.api.rules.RuleType.BUG; +import static org.sonar.api.rules.RuleType.CODE_SMELL; +import static org.sonar.api.rules.RuleType.VULNERABILITY; +import static org.sonar.api.utils.DateUtils.dateToLong; +import static org.sonar.api.utils.DateUtils.parseDateTime; +import static org.sonar.test.JsonAssert.assertJson; +import static org.sonarqube.ws.WsBranches.Branch.Status; + +public class ListActionTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + @Rule + public EsTester es = new EsTester(new IssueIndexDefinition(new MapSettings().asConfig())); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + + private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(PROJECT); + private IssueIndexer issueIndexer = new IssueIndexer(es.client(), db.getDbClient(), new IssueIteratorFactory(db.getDbClient())); + private IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSession, new AuthorizationTypeSupport(userSession)); + private PermissionIndexerTester permissionIndexerTester = new PermissionIndexerTester(es, issueIndexer); + + private MetricDto qualityGateStatus; + + public WsActionTester ws = new WsActionTester(new ListAction(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), resourceTypes), issueIndex)); + + @Before + public void setUp() throws Exception { + qualityGateStatus = db.measures().insertMetric(m -> m.setKey(ALERT_STATUS_KEY)); + } + + @Test + public void test_definition() { + WebService.Action definition = ws.getDef(); + assertThat(definition.key()).isEqualTo("list"); + assertThat(definition.isPost()).isFalse(); + assertThat(definition.isInternal()).isFalse(); + assertThat(definition.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("project"); + assertThat(definition.since()).isEqualTo("6.6"); + } + + @Test + public void test_example() { + ComponentDto project = db.components().insertPrivateProject(p -> p.setDbKey("sonarqube")); + ComponentDto longLivingBranch = db.components().insertProjectBranch(project, b -> b.setKey("feature/bar").setBranchType(BranchType.LONG)); + ComponentDto shortLivingBranch = db.components().insertProjectBranch(project, b -> b.setKey("feature/foo").setBranchType(BranchType.SHORT).setMergeBranchUuid(longLivingBranch.uuid())); + userSession.logIn().addProjectPermission(UserRole.USER, project); + + db.getDbClient().snapshotDao().insert(db.getSession(), SnapshotTesting.newAnalysis(longLivingBranch).setLast(true).setCreatedAt(DateUtils.parseDateTime("2017-04-01T01:15:42+0100").getTime())); + db.getDbClient().snapshotDao().insert(db.getSession(), SnapshotTesting.newAnalysis(shortLivingBranch).setLast(true).setCreatedAt(DateUtils.parseDateTime("2017-04-03T13:37:00+0100").getTime())); + db.commit(); + + String json = ws.newRequest() + .setParam("project", project.getDbKey()) + .execute() + .getInput(); + + assertJson(json).isSimilarTo(ws.getDef().responseExampleAsString()); + } + + @Test + public void main_branch() { + ComponentDto project = db.components().insertMainBranch(); + userSession.logIn().addProjectPermission(UserRole.USER, project); + + ListWsResponse response = ws.newRequest() + .setParam("project", project.getDbKey()) + .executeProtobuf(ListWsResponse.class); + + assertThat(response.getBranchesList()) + .extracting(Branch::getName, Branch::getIsMain, Branch::getType) + .containsExactlyInAnyOrder(tuple("master", true, Common.BranchType.LONG)); + } + + @Test + public void main_branch_with_specified_name() { + OrganizationDto organization = db.organizations().insert(); + ComponentDto project = db.components().insertMainBranch(organization, "head"); + userSession.logIn().addProjectPermission(UserRole.USER, project); + + ListWsResponse response = ws.newRequest() + .setParam("project", project.getDbKey()) + .executeProtobuf(ListWsResponse.class); + + assertThat(response.getBranchesList()) + .extracting(Branch::getName, Branch::getIsMain, Branch::getType) + .containsExactlyInAnyOrder(tuple("head", true, Common.BranchType.LONG)); + } + + @Test + public void test_project_with_zero_branches() { + ComponentDto project = db.components().insertPrivateProject(); + userSession.logIn().addProjectPermission(UserRole.USER, project); + + String json = ws.newRequest() + .setParam("project", project.getDbKey()) + .setMediaType(MediaTypes.JSON) + .execute() + .getInput(); + assertJson(json).isSimilarTo("{\"branches\": []}"); + } + + @Test + public void test_project_with_branches() { + ComponentDto project = db.components().insertMainBranch(); + db.components().insertProjectBranch(project, b -> b.setKey("feature/bar")); + db.components().insertProjectBranch(project, b -> b.setKey("feature/foo")); + userSession.logIn().addProjectPermission(UserRole.USER, project); + + ListWsResponse response = ws.newRequest() + .setParam("project", project.getDbKey()) + .executeProtobuf(ListWsResponse.class); + + assertThat(response.getBranchesList()) + .extracting(Branch::getName, Branch::getType) + .containsExactlyInAnyOrder( + tuple("master", Common.BranchType.LONG), + tuple("feature/foo", Common.BranchType.LONG), + tuple("feature/bar", Common.BranchType.LONG)); + } + + @Test + public void short_living_branches() { + ComponentDto project = db.components().insertMainBranch(); + userSession.logIn().addProjectPermission(UserRole.USER, project); + ComponentDto longLivingBranch = db.components().insertProjectBranch(project, + b -> b.setKey("long").setBranchType(BranchType.LONG)); + ComponentDto shortLivingBranch = db.components().insertProjectBranch(project, + b -> b.setKey("short").setBranchType(BranchType.SHORT).setMergeBranchUuid(longLivingBranch.uuid())); + ComponentDto shortLivingBranchOnMaster = db.components().insertProjectBranch(project, + b -> b.setKey("short_on_master").setBranchType(BranchType.SHORT).setMergeBranchUuid(project.uuid())); + + ListWsResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(ListWsResponse.class); + + assertThat(response.getBranchesList()) + .extracting(Branch::getName, Branch::getType, Branch::getMergeBranch) + .containsExactlyInAnyOrder( + tuple("master", Common.BranchType.LONG, ""), + tuple(longLivingBranch.getBranch(), Common.BranchType.LONG, ""), + tuple(shortLivingBranch.getBranch(), Common.BranchType.SHORT, longLivingBranch.getBranch()), + tuple(shortLivingBranchOnMaster.getBranch(), Common.BranchType.SHORT, "master")); + } + + @Test + public void mergeBranch_is_using_default_main_name_when_main_branch_has_no_name() { + ComponentDto project = db.components().insertMainBranch(); + userSession.logIn().addProjectPermission(UserRole.USER, project); + ComponentDto shortLivingBranch = db.components().insertProjectBranch(project, + b -> b.setKey("short").setBranchType(BranchType.SHORT).setMergeBranchUuid(project.uuid())); + + WsBranches.ShowWsResponse response = ws.newRequest() + .setParam("project", shortLivingBranch.getKey()) + .executeProtobuf(WsBranches.ShowWsResponse.class); + + assertThat(response.getBranch()) + .extracting(Branch::getName, Branch::getType, Branch::getMergeBranch) + .containsExactlyInAnyOrder(shortLivingBranch.getBranch(), Common.BranchType.SHORT, "master"); + } + + @Test + public void short_living_branch_on_removed_branch() { + ComponentDto project = db.components().insertMainBranch(); + userSession.logIn().addProjectPermission(UserRole.USER, project); + ComponentDto shortLivingBranch = db.components().insertProjectBranch(project, + b -> b.setKey("short").setBranchType(BranchType.SHORT).setMergeBranchUuid("unknown")); + + ListWsResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(ListWsResponse.class); + + assertThat(response.getBranchesList()) + .extracting(Branch::getName, Branch::getType, Branch::hasMergeBranch, Branch::getIsOrphan) + .containsExactlyInAnyOrder( + tuple("master", Common.BranchType.LONG, false, false), + tuple(shortLivingBranch.getBranch(), Common.BranchType.SHORT, false, true)); + } + + @Test + public void status_on_long_living_branch() { + ComponentDto project = db.components().insertMainBranch(); + userSession.logIn().addProjectPermission(UserRole.USER, project); + ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.LONG)); + SnapshotDto branchAnalysis = db.components().insertSnapshot(branch); + db.measures().insertMeasure(branch, branchAnalysis, qualityGateStatus, m -> m.setData("OK")); + + ListWsResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(ListWsResponse.class); + + assertThat(response.getBranchesList()) + .extracting(b -> b.getStatus().hasQualityGateStatus(), b -> b.getStatus().getQualityGateStatus()) + .containsExactlyInAnyOrder(tuple(false, ""), tuple(true, "OK")); + } + + @Test + public void status_on_short_living_branches() { + ComponentDto project = db.components().insertMainBranch(); + userSession.logIn().addProjectPermission(UserRole.USER, project); + ComponentDto longLivingBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.LONG)); + ComponentDto shortLivingBranch = db.components().insertProjectBranch(project, + b -> b.setBranchType(BranchType.SHORT).setMergeBranchUuid(longLivingBranch.uuid())); + RuleDefinitionDto rule = db.rules().insert(); + db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(BUG).setResolution(null)); + db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(BUG).setResolution(RESOLUTION_FIXED)); + db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(VULNERABILITY).setResolution(null)); + db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(VULNERABILITY).setResolution(null)); + db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(CODE_SMELL).setResolution(null)); + db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(CODE_SMELL).setResolution(null)); + db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(CODE_SMELL).setResolution(null)); + db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(CODE_SMELL).setResolution(RESOLUTION_FALSE_POSITIVE)); + issueIndexer.indexOnStartup(emptySet()); + permissionIndexerTester.allowOnlyAnyone(project); + + ListWsResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(ListWsResponse.class); + + assertThat(response.getBranchesList().stream().map(WsBranches.Branch::getStatus)) + .extracting(Status::hasBugs, Status::getBugs, Status::hasVulnerabilities, Status::getVulnerabilities, Status::hasCodeSmells, Status::getCodeSmells) + .containsExactlyInAnyOrder( + tuple(false, 0L, false, 0L, false, 0L), + tuple(false, 0L, false, 0L, false, 0L), + tuple(true, 1L, true, 2L, true, 3L)); + } + + @Test + public void status_on_short_living_branch_with_no_issue() { + ComponentDto project = db.components().insertMainBranch(); + userSession.logIn().addProjectPermission(UserRole.USER, project); + ComponentDto longLivingBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.LONG)); + db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.SHORT).setMergeBranchUuid(longLivingBranch.uuid())); + issueIndexer.indexOnStartup(emptySet()); + permissionIndexerTester.allowOnlyAnyone(project); + + ListWsResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(ListWsResponse.class); + + assertThat(response.getBranchesList().stream().filter(b -> b.getType().equals(Common.BranchType.SHORT)).map(WsBranches.Branch::getStatus)) + .extracting(Status::getBugs, Status::getVulnerabilities, Status::getCodeSmells) + .containsExactlyInAnyOrder(tuple(0L, 0L, 0L)); + } + + @Test + public void response_contains_date_of_last_analysis() { + Long lastAnalysisLongLivingBranch = dateToLong(parseDateTime("2017-04-01T00:00:00+0100")); + Long previousAnalysisShortLivingBranch = dateToLong(parseDateTime("2017-04-02T00:00:00+0100")); + Long lastAnalysisShortLivingBranch = dateToLong(parseDateTime("2017-04-03T00:00:00+0100")); + + ComponentDto project = db.components().insertMainBranch(); + userSession.logIn().addProjectPermission(UserRole.USER, project); + ComponentDto shortLivingBranch1 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.SHORT).setMergeBranchUuid(project.uuid())); + ComponentDto longLivingBranch2 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.LONG)); + ComponentDto shortLivingBranch2 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.SHORT).setMergeBranchUuid(longLivingBranch2.uuid())); + db.getDbClient().snapshotDao().insert(db.getSession(), + SnapshotTesting.newAnalysis(longLivingBranch2).setCreatedAt(lastAnalysisLongLivingBranch)); + db.getDbClient().snapshotDao().insert(db.getSession(), + SnapshotTesting.newAnalysis(shortLivingBranch2).setCreatedAt(previousAnalysisShortLivingBranch).setLast(false)); + db.getDbClient().snapshotDao().insert(db.getSession(), + SnapshotTesting.newAnalysis(shortLivingBranch2).setCreatedAt(lastAnalysisShortLivingBranch)); + db.commit(); + issueIndexer.indexOnStartup(emptySet()); + permissionIndexerTester.allowOnlyAnyone(project); + + ListWsResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(ListWsResponse.class); + + assertThat(response.getBranchesList()) + .extracting(WsBranches.Branch::getType, WsBranches.Branch::hasAnalysisDate, b -> "".equals(b.getAnalysisDate()) ? null : dateToLong(parseDateTime(b.getAnalysisDate()))) + .containsExactlyInAnyOrder( + tuple(Common.BranchType.LONG, false, null), + tuple(Common.BranchType.SHORT, false, null), + tuple(Common.BranchType.LONG, true, lastAnalysisLongLivingBranch), + tuple(Common.BranchType.SHORT, true, lastAnalysisShortLivingBranch) + ); + } + + @Test + public void fail_when_using_branch_db_key() throws Exception { + OrganizationDto organization = db.organizations().insert(); + ComponentDto project = db.components().insertMainBranch(organization); + userSession.logIn().addProjectPermission(UserRole.USER, project); + ComponentDto branch = db.components().insertProjectBranch(project); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage(format("Component key '%s' not found", branch.getDbKey())); + + ws.newRequest() + .setParam("project", branch.getDbKey()) + .execute(); + } + + @Test + public void fail_if_missing_project_parameter() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("The 'project' parameter is missing"); + + ws.newRequest().execute(); + } + + @Test + public void fail_if_not_a_reference_on_project() { + ComponentDto project = db.components().insertPrivateProject(); + ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); + userSession.logIn().addProjectPermission(UserRole.USER, project); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Invalid project key"); + + ws.newRequest() + .setParam("project", file.getDbKey()) + .execute(); + } + + @Test + public void fail_if_project_does_not_exist() { + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Component key 'foo' not found"); + + ws.newRequest() + .setParam("project", "foo") + .execute(); + } + +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/branch/ws/RenameActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/branch/ws/RenameActionTest.java new file mode 100644 index 00000000000..85b6fc6b202 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/branch/ws/RenameActionTest.java @@ -0,0 +1,181 @@ +/* + * 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.branch.ws; + +import java.util.Optional; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.resources.ResourceTypes; +import org.sonar.api.server.ws.WebService; +import org.sonar.api.utils.System2; +import org.sonar.api.web.UserRole; +import org.sonar.db.DbTester; +import org.sonar.db.component.BranchDto; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.ResourceTypesRule; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.exceptions.ForbiddenException; +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.sonar.api.resources.Qualifiers.PROJECT; + +public class RenameActionTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + + private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(PROJECT); + private ComponentFinder componentFinder = new ComponentFinder(db.getDbClient(), resourceTypes); + private WsActionTester tester = new WsActionTester(new RenameAction(db.getDbClient(), componentFinder, userSession)); + + @Test + public void test_definition() { + WebService.Action definition = tester.getDef(); + assertThat(definition.key()).isEqualTo("rename"); + assertThat(definition.isPost()).isTrue(); + assertThat(definition.isInternal()).isFalse(); + assertThat(definition.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("project", "name"); + 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 'name' 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(); + } + + @Test + public void fail_if_no_administer_permission() { + userSession.logIn(); + ComponentDto project = db.components().insertMainBranch(); + + expectedException.expect(ForbiddenException.class); + expectedException.expectMessage("Insufficient privileges"); + + tester.newRequest() + .setParam("project", project.getKey()) + .setParam("name", "branch1") + .execute(); + } + + @Test + public void rename() { + userSession.logIn(); + ComponentDto project = db.components().insertMainBranch(); + ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("branch")); + userSession.addProjectPermission(UserRole.ADMIN, project); + + tester.newRequest() + .setParam("project", project.getKey()) + .setParam("name", "master") + .execute(); + + assertThat(db.countRowsOfTable("project_branches")).isEqualTo(2); + Optional mainBranch = db.getDbClient().branchDao().selectByUuid(db.getSession(), project.uuid()); + assertThat(mainBranch.get().getKey()).isEqualTo("master"); + + Optional unchangedBranch = db.getDbClient().branchDao().selectByUuid(db.getSession(), branch.uuid()); + assertThat(unchangedBranch.get().getKey()).isEqualTo("branch"); + } + + @Test + public void rename_with_same_name() { + userSession.logIn(); + ComponentDto project = db.components().insertMainBranch(); + ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("branch")); + userSession.addProjectPermission(UserRole.ADMIN, project); + + tester.newRequest() + .setParam("project", project.getKey()) + .setParam("name", "master") + .execute(); + + tester.newRequest() + .setParam("project", project.getKey()) + .setParam("name", "master") + .execute(); + + assertThat(db.countRowsOfTable("project_branches")).isEqualTo(2); + Optional mainBranch = db.getDbClient().branchDao().selectByUuid(db.getSession(), project.uuid()); + assertThat(mainBranch.get().getKey()).isEqualTo("master"); + + Optional unchangedBranch = db.getDbClient().branchDao().selectByUuid(db.getSession(), branch.uuid()); + assertThat(unchangedBranch.get().getKey()).isEqualTo("branch"); + } + + @Test + public void fail_if_name_already_used() { + userSession.logIn(); + ComponentDto project = db.components().insertMainBranch(); + userSession.addProjectPermission(UserRole.ADMIN, project); + db.components().insertProjectBranch(project, b -> b.setKey("branch")); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Impossible to update branch name: a branch with name \"branch\" already exists"); + + tester.newRequest() + .setParam("project", project.getKey()) + .setParam("name", "branch") + .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("name", "branch1") + .execute(); + } +} 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 deleted file mode 100644 index 2ecb8a885a2..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/BranchWsModuleTest.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.Test; -import org.sonar.core.platform.ComponentContainer; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER; - -public class BranchWsModuleTest { - @Test - public void verify_count_of_added_components() { - ComponentContainer container = new ComponentContainer(); - new BranchWsModule().configure(container); - assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 4); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/BranchesWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/BranchesWsTest.java deleted file mode 100644 index 9938bd991c0..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/BranchesWsTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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.Test; -import org.sonar.api.server.ws.Request; -import org.sonar.api.server.ws.Response; -import org.sonar.api.server.ws.WebService; - -import static org.assertj.core.api.Assertions.assertThat; - -public class BranchesWsTest { - - @Test - public void define_ws() { - BranchesWs underTest = new BranchesWs(new BranchWsAction() { - @Override - public void define(WebService.NewController context) { - context.createAction("foo").setHandler(this); - } - - @Override - public void handle(Request request, Response response) throws Exception { - - } - }); - - WebService.Context context = new WebService.Context(); - underTest.define(context); - - assertThat(context.controller("api/project_branches").action("foo")).isNotNull(); - } - -} 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 deleted file mode 100644 index 9112fe35ffa..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/DeleteActionTest.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * 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()).isFalse(); - 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 argument = ArgumentCaptor.forClass(ComponentDto.class); - verify(componentCleanerService).deleteBranch(any(DbSession.class), argument.capture()); - assertThat(argument.getValue().getDbKey()).isEqualTo(key); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ListActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ListActionTest.java deleted file mode 100644 index 81174c3c290..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ListActionTest.java +++ /dev/null @@ -1,396 +0,0 @@ -/* - * 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.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.config.internal.MapSettings; -import org.sonar.api.resources.ResourceTypes; -import org.sonar.api.server.ws.WebService; -import org.sonar.api.utils.DateUtils; -import org.sonar.api.utils.System2; -import org.sonar.api.web.UserRole; -import org.sonar.db.DbTester; -import org.sonar.db.component.BranchType; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.ComponentTesting; -import org.sonar.db.component.ResourceTypesRule; -import org.sonar.db.component.SnapshotDto; -import org.sonar.db.component.SnapshotTesting; -import org.sonar.db.metric.MetricDto; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.server.component.ComponentFinder; -import org.sonar.server.es.EsTester; -import org.sonar.server.exceptions.NotFoundException; -import org.sonar.server.issue.index.IssueIndex; -import org.sonar.server.issue.index.IssueIndexDefinition; -import org.sonar.server.issue.index.IssueIndexer; -import org.sonar.server.issue.index.IssueIteratorFactory; -import org.sonar.server.permission.index.AuthorizationTypeSupport; -import org.sonar.server.permission.index.PermissionIndexerTester; -import org.sonar.server.tester.UserSessionRule; -import org.sonar.server.ws.WsActionTester; -import org.sonarqube.ws.Common; -import org.sonarqube.ws.MediaTypes; -import org.sonarqube.ws.WsBranches; -import org.sonarqube.ws.WsBranches.Branch; -import org.sonarqube.ws.WsBranches.ListWsResponse; - -import static java.lang.String.format; -import static java.util.Collections.emptySet; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; -import static org.sonar.api.issue.Issue.RESOLUTION_FALSE_POSITIVE; -import static org.sonar.api.issue.Issue.RESOLUTION_FIXED; -import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; -import static org.sonar.api.resources.Qualifiers.PROJECT; -import static org.sonar.api.rules.RuleType.BUG; -import static org.sonar.api.rules.RuleType.CODE_SMELL; -import static org.sonar.api.rules.RuleType.VULNERABILITY; -import static org.sonar.api.utils.DateUtils.dateToLong; -import static org.sonar.api.utils.DateUtils.parseDateTime; -import static org.sonar.test.JsonAssert.assertJson; -import static org.sonarqube.ws.WsBranches.Branch.Status; - -public class ListActionTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Rule - public DbTester db = DbTester.create(System2.INSTANCE); - @Rule - public EsTester es = new EsTester(new IssueIndexDefinition(new MapSettings().asConfig())); - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - - private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(PROJECT); - private IssueIndexer issueIndexer = new IssueIndexer(es.client(), db.getDbClient(), new IssueIteratorFactory(db.getDbClient())); - private IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSession, new AuthorizationTypeSupport(userSession)); - private PermissionIndexerTester permissionIndexerTester = new PermissionIndexerTester(es, issueIndexer); - - private MetricDto qualityGateStatus; - - public WsActionTester ws = new WsActionTester(new ListAction(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), resourceTypes), issueIndex)); - - @Before - public void setUp() throws Exception { - qualityGateStatus = db.measures().insertMetric(m -> m.setKey(ALERT_STATUS_KEY)); - } - - @Test - public void test_definition() { - WebService.Action definition = ws.getDef(); - assertThat(definition.key()).isEqualTo("list"); - assertThat(definition.isPost()).isFalse(); - assertThat(definition.isInternal()).isFalse(); - assertThat(definition.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("project"); - assertThat(definition.since()).isEqualTo("6.6"); - } - - @Test - public void test_example() { - ComponentDto project = db.components().insertPrivateProject(p -> p.setDbKey("sonarqube")); - ComponentDto longLivingBranch = db.components().insertProjectBranch(project, b -> b.setKey("feature/bar").setBranchType(BranchType.LONG)); - ComponentDto shortLivingBranch = db.components().insertProjectBranch(project, b -> b.setKey("feature/foo").setBranchType(BranchType.SHORT).setMergeBranchUuid(longLivingBranch.uuid())); - userSession.logIn().addProjectPermission(UserRole.USER, project); - - db.getDbClient().snapshotDao().insert(db.getSession(), SnapshotTesting.newAnalysis(longLivingBranch).setLast(true).setCreatedAt(DateUtils.parseDateTime("2017-04-01T01:15:42+0100").getTime())); - db.getDbClient().snapshotDao().insert(db.getSession(), SnapshotTesting.newAnalysis(shortLivingBranch).setLast(true).setCreatedAt(DateUtils.parseDateTime("2017-04-03T13:37:00+0100").getTime())); - db.commit(); - - String json = ws.newRequest() - .setParam("project", project.getDbKey()) - .execute() - .getInput(); - - assertJson(json).isSimilarTo(ws.getDef().responseExampleAsString()); - } - - @Test - public void main_branch() { - ComponentDto project = db.components().insertMainBranch(); - userSession.logIn().addProjectPermission(UserRole.USER, project); - - ListWsResponse response = ws.newRequest() - .setParam("project", project.getDbKey()) - .executeProtobuf(ListWsResponse.class); - - assertThat(response.getBranchesList()) - .extracting(Branch::getName, Branch::getIsMain, Branch::getType) - .containsExactlyInAnyOrder(tuple("master", true, Common.BranchType.LONG)); - } - - @Test - public void main_branch_with_specified_name() { - OrganizationDto organization = db.organizations().insert(); - ComponentDto project = db.components().insertMainBranch(organization, "head"); - userSession.logIn().addProjectPermission(UserRole.USER, project); - - ListWsResponse response = ws.newRequest() - .setParam("project", project.getDbKey()) - .executeProtobuf(ListWsResponse.class); - - assertThat(response.getBranchesList()) - .extracting(Branch::getName, Branch::getIsMain, Branch::getType) - .containsExactlyInAnyOrder(tuple("head", true, Common.BranchType.LONG)); - } - - @Test - public void test_project_with_zero_branches() { - ComponentDto project = db.components().insertPrivateProject(); - userSession.logIn().addProjectPermission(UserRole.USER, project); - - String json = ws.newRequest() - .setParam("project", project.getDbKey()) - .setMediaType(MediaTypes.JSON) - .execute() - .getInput(); - assertJson(json).isSimilarTo("{\"branches\": []}"); - } - - @Test - public void test_project_with_branches() { - ComponentDto project = db.components().insertMainBranch(); - db.components().insertProjectBranch(project, b -> b.setKey("feature/bar")); - db.components().insertProjectBranch(project, b -> b.setKey("feature/foo")); - userSession.logIn().addProjectPermission(UserRole.USER, project); - - ListWsResponse response = ws.newRequest() - .setParam("project", project.getDbKey()) - .executeProtobuf(ListWsResponse.class); - - assertThat(response.getBranchesList()) - .extracting(Branch::getName, Branch::getType) - .containsExactlyInAnyOrder( - tuple("master", Common.BranchType.LONG), - tuple("feature/foo", Common.BranchType.LONG), - tuple("feature/bar", Common.BranchType.LONG)); - } - - @Test - public void short_living_branches() { - ComponentDto project = db.components().insertMainBranch(); - userSession.logIn().addProjectPermission(UserRole.USER, project); - ComponentDto longLivingBranch = db.components().insertProjectBranch(project, - b -> b.setKey("long").setBranchType(BranchType.LONG)); - ComponentDto shortLivingBranch = db.components().insertProjectBranch(project, - b -> b.setKey("short").setBranchType(BranchType.SHORT).setMergeBranchUuid(longLivingBranch.uuid())); - ComponentDto shortLivingBranchOnMaster = db.components().insertProjectBranch(project, - b -> b.setKey("short_on_master").setBranchType(BranchType.SHORT).setMergeBranchUuid(project.uuid())); - - ListWsResponse response = ws.newRequest() - .setParam("project", project.getKey()) - .executeProtobuf(ListWsResponse.class); - - assertThat(response.getBranchesList()) - .extracting(Branch::getName, Branch::getType, Branch::getMergeBranch) - .containsExactlyInAnyOrder( - tuple("master", Common.BranchType.LONG, ""), - tuple(longLivingBranch.getBranch(), Common.BranchType.LONG, ""), - tuple(shortLivingBranch.getBranch(), Common.BranchType.SHORT, longLivingBranch.getBranch()), - tuple(shortLivingBranchOnMaster.getBranch(), Common.BranchType.SHORT, "master")); - } - - @Test - public void mergeBranch_is_using_default_main_name_when_main_branch_has_no_name() { - ComponentDto project = db.components().insertMainBranch(); - userSession.logIn().addProjectPermission(UserRole.USER, project); - ComponentDto shortLivingBranch = db.components().insertProjectBranch(project, - b -> b.setKey("short").setBranchType(BranchType.SHORT).setMergeBranchUuid(project.uuid())); - - WsBranches.ShowWsResponse response = ws.newRequest() - .setParam("project", shortLivingBranch.getKey()) - .executeProtobuf(WsBranches.ShowWsResponse.class); - - assertThat(response.getBranch()) - .extracting(Branch::getName, Branch::getType, Branch::getMergeBranch) - .containsExactlyInAnyOrder(shortLivingBranch.getBranch(), Common.BranchType.SHORT, "master"); - } - - @Test - public void short_living_branch_on_removed_branch() { - ComponentDto project = db.components().insertMainBranch(); - userSession.logIn().addProjectPermission(UserRole.USER, project); - ComponentDto shortLivingBranch = db.components().insertProjectBranch(project, - b -> b.setKey("short").setBranchType(BranchType.SHORT).setMergeBranchUuid("unknown")); - - ListWsResponse response = ws.newRequest() - .setParam("project", project.getKey()) - .executeProtobuf(ListWsResponse.class); - - assertThat(response.getBranchesList()) - .extracting(Branch::getName, Branch::getType, Branch::hasMergeBranch, Branch::getIsOrphan) - .containsExactlyInAnyOrder( - tuple("master", Common.BranchType.LONG, false, false), - tuple(shortLivingBranch.getBranch(), Common.BranchType.SHORT, false, true)); - } - - @Test - public void status_on_long_living_branch() { - ComponentDto project = db.components().insertMainBranch(); - userSession.logIn().addProjectPermission(UserRole.USER, project); - ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.LONG)); - SnapshotDto branchAnalysis = db.components().insertSnapshot(branch); - db.measures().insertMeasure(branch, branchAnalysis, qualityGateStatus, m -> m.setData("OK")); - - ListWsResponse response = ws.newRequest() - .setParam("project", project.getKey()) - .executeProtobuf(ListWsResponse.class); - - assertThat(response.getBranchesList()) - .extracting(b -> b.getStatus().hasQualityGateStatus(), b -> b.getStatus().getQualityGateStatus()) - .containsExactlyInAnyOrder(tuple(false, ""), tuple(true, "OK")); - } - - @Test - public void status_on_short_living_branches() { - ComponentDto project = db.components().insertMainBranch(); - userSession.logIn().addProjectPermission(UserRole.USER, project); - ComponentDto longLivingBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.LONG)); - ComponentDto shortLivingBranch = db.components().insertProjectBranch(project, - b -> b.setBranchType(BranchType.SHORT).setMergeBranchUuid(longLivingBranch.uuid())); - RuleDefinitionDto rule = db.rules().insert(); - db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(BUG).setResolution(null)); - db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(BUG).setResolution(RESOLUTION_FIXED)); - db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(VULNERABILITY).setResolution(null)); - db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(VULNERABILITY).setResolution(null)); - db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(CODE_SMELL).setResolution(null)); - db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(CODE_SMELL).setResolution(null)); - db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(CODE_SMELL).setResolution(null)); - db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(CODE_SMELL).setResolution(RESOLUTION_FALSE_POSITIVE)); - issueIndexer.indexOnStartup(emptySet()); - permissionIndexerTester.allowOnlyAnyone(project); - - ListWsResponse response = ws.newRequest() - .setParam("project", project.getKey()) - .executeProtobuf(ListWsResponse.class); - - assertThat(response.getBranchesList().stream().map(WsBranches.Branch::getStatus)) - .extracting(Status::hasBugs, Status::getBugs, Status::hasVulnerabilities, Status::getVulnerabilities, Status::hasCodeSmells, Status::getCodeSmells) - .containsExactlyInAnyOrder( - tuple(false, 0L, false, 0L, false, 0L), - tuple(false, 0L, false, 0L, false, 0L), - tuple(true, 1L, true, 2L, true, 3L)); - } - - @Test - public void status_on_short_living_branch_with_no_issue() { - ComponentDto project = db.components().insertMainBranch(); - userSession.logIn().addProjectPermission(UserRole.USER, project); - ComponentDto longLivingBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.LONG)); - db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.SHORT).setMergeBranchUuid(longLivingBranch.uuid())); - issueIndexer.indexOnStartup(emptySet()); - permissionIndexerTester.allowOnlyAnyone(project); - - ListWsResponse response = ws.newRequest() - .setParam("project", project.getKey()) - .executeProtobuf(ListWsResponse.class); - - assertThat(response.getBranchesList().stream().filter(b -> b.getType().equals(Common.BranchType.SHORT)).map(WsBranches.Branch::getStatus)) - .extracting(Status::getBugs, Status::getVulnerabilities, Status::getCodeSmells) - .containsExactlyInAnyOrder(tuple(0L, 0L, 0L)); - } - - @Test - public void response_contains_date_of_last_analysis() { - Long lastAnalysisLongLivingBranch = dateToLong(parseDateTime("2017-04-01T00:00:00+0100")); - Long previousAnalysisShortLivingBranch = dateToLong(parseDateTime("2017-04-02T00:00:00+0100")); - Long lastAnalysisShortLivingBranch = dateToLong(parseDateTime("2017-04-03T00:00:00+0100")); - - ComponentDto project = db.components().insertMainBranch(); - userSession.logIn().addProjectPermission(UserRole.USER, project); - ComponentDto shortLivingBranch1 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.SHORT).setMergeBranchUuid(project.uuid())); - ComponentDto longLivingBranch2 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.LONG)); - ComponentDto shortLivingBranch2 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.SHORT).setMergeBranchUuid(longLivingBranch2.uuid())); - db.getDbClient().snapshotDao().insert(db.getSession(), - SnapshotTesting.newAnalysis(longLivingBranch2).setCreatedAt(lastAnalysisLongLivingBranch)); - db.getDbClient().snapshotDao().insert(db.getSession(), - SnapshotTesting.newAnalysis(shortLivingBranch2).setCreatedAt(previousAnalysisShortLivingBranch).setLast(false)); - db.getDbClient().snapshotDao().insert(db.getSession(), - SnapshotTesting.newAnalysis(shortLivingBranch2).setCreatedAt(lastAnalysisShortLivingBranch)); - db.commit(); - issueIndexer.indexOnStartup(emptySet()); - permissionIndexerTester.allowOnlyAnyone(project); - - ListWsResponse response = ws.newRequest() - .setParam("project", project.getKey()) - .executeProtobuf(ListWsResponse.class); - - assertThat(response.getBranchesList()) - .extracting(WsBranches.Branch::getType, WsBranches.Branch::hasAnalysisDate, b -> "".equals(b.getAnalysisDate()) ? null : dateToLong(parseDateTime(b.getAnalysisDate()))) - .containsExactlyInAnyOrder( - tuple(Common.BranchType.LONG, false, null), - tuple(Common.BranchType.SHORT, false, null), - tuple(Common.BranchType.LONG, true, lastAnalysisLongLivingBranch), - tuple(Common.BranchType.SHORT, true, lastAnalysisShortLivingBranch) - ); - } - - @Test - public void fail_when_using_branch_db_key() throws Exception { - OrganizationDto organization = db.organizations().insert(); - ComponentDto project = db.components().insertMainBranch(organization); - userSession.logIn().addProjectPermission(UserRole.USER, project); - ComponentDto branch = db.components().insertProjectBranch(project); - - expectedException.expect(NotFoundException.class); - expectedException.expectMessage(format("Component key '%s' not found", branch.getDbKey())); - - ws.newRequest() - .setParam("project", branch.getDbKey()) - .execute(); - } - - @Test - public void fail_if_missing_project_parameter() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("The 'project' parameter is missing"); - - ws.newRequest().execute(); - } - - @Test - public void fail_if_not_a_reference_on_project() { - ComponentDto project = db.components().insertPrivateProject(); - ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); - userSession.logIn().addProjectPermission(UserRole.USER, project); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Invalid project key"); - - ws.newRequest() - .setParam("project", file.getDbKey()) - .execute(); - } - - @Test - public void fail_if_project_does_not_exist() { - expectedException.expect(NotFoundException.class); - expectedException.expectMessage("Component key 'foo' not found"); - - ws.newRequest() - .setParam("project", "foo") - .execute(); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/RenameActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/RenameActionTest.java deleted file mode 100644 index e1dca4371db..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/RenameActionTest.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * 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 java.util.Optional; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.resources.ResourceTypes; -import org.sonar.api.server.ws.WebService; -import org.sonar.api.utils.System2; -import org.sonar.api.web.UserRole; -import org.sonar.db.DbTester; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.ResourceTypesRule; -import org.sonar.server.component.ComponentFinder; -import org.sonar.server.exceptions.ForbiddenException; -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.sonar.api.resources.Qualifiers.PROJECT; - -public class RenameActionTest { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Rule - public DbTester db = DbTester.create(System2.INSTANCE); - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - - private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(PROJECT); - private ComponentFinder componentFinder = new ComponentFinder(db.getDbClient(), resourceTypes); - private WsActionTester tester = new WsActionTester(new RenameAction(db.getDbClient(), componentFinder, userSession)); - - @Test - public void test_definition() { - WebService.Action definition = tester.getDef(); - assertThat(definition.key()).isEqualTo("rename"); - assertThat(definition.isPost()).isTrue(); - assertThat(definition.isInternal()).isFalse(); - assertThat(definition.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("project", "name"); - 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 'name' 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(); - } - - @Test - public void fail_if_no_administer_permission() { - userSession.logIn(); - ComponentDto project = db.components().insertMainBranch(); - - expectedException.expect(ForbiddenException.class); - expectedException.expectMessage("Insufficient privileges"); - - tester.newRequest() - .setParam("project", project.getKey()) - .setParam("name", "branch1") - .execute(); - } - - @Test - public void rename() { - userSession.logIn(); - ComponentDto project = db.components().insertMainBranch(); - ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("branch")); - userSession.addProjectPermission(UserRole.ADMIN, project); - - tester.newRequest() - .setParam("project", project.getKey()) - .setParam("name", "master") - .execute(); - - assertThat(db.countRowsOfTable("project_branches")).isEqualTo(2); - Optional mainBranch = db.getDbClient().branchDao().selectByUuid(db.getSession(), project.uuid()); - assertThat(mainBranch.get().getKey()).isEqualTo("master"); - - Optional unchangedBranch = db.getDbClient().branchDao().selectByUuid(db.getSession(), branch.uuid()); - assertThat(unchangedBranch.get().getKey()).isEqualTo("branch"); - } - - @Test - public void rename_with_same_name() { - userSession.logIn(); - ComponentDto project = db.components().insertMainBranch(); - ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("branch")); - userSession.addProjectPermission(UserRole.ADMIN, project); - - tester.newRequest() - .setParam("project", project.getKey()) - .setParam("name", "master") - .execute(); - - tester.newRequest() - .setParam("project", project.getKey()) - .setParam("name", "master") - .execute(); - - assertThat(db.countRowsOfTable("project_branches")).isEqualTo(2); - Optional mainBranch = db.getDbClient().branchDao().selectByUuid(db.getSession(), project.uuid()); - assertThat(mainBranch.get().getKey()).isEqualTo("master"); - - Optional unchangedBranch = db.getDbClient().branchDao().selectByUuid(db.getSession(), branch.uuid()); - assertThat(unchangedBranch.get().getKey()).isEqualTo("branch"); - } - - @Test - public void fail_if_name_already_used() { - userSession.logIn(); - ComponentDto project = db.components().insertMainBranch(); - userSession.addProjectPermission(UserRole.ADMIN, project); - db.components().insertProjectBranch(project, b -> b.setKey("branch")); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Impossible to update branch name: a branch with name \"branch\" already exists"); - - tester.newRequest() - .setParam("project", project.getKey()) - .setParam("name", "branch") - .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("name", "branch1") - .execute(); - } -}