]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10040 move projectbranch ws to package branch
authorGuillaume Jambet <guillaume.jambet@sonarsource.com>
Thu, 2 Nov 2017 14:31:34 +0000 (15:31 +0100)
committerGuillaume Jambet <guillaume.jambet@gmail.com>
Wed, 8 Nov 2017 12:51:31 +0000 (13:51 +0100)
28 files changed:
server/sonar-server/src/main/java/org/sonar/server/branch/ws/BranchWsAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/branch/ws/BranchWsModule.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/branch/ws/BranchesWs.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/branch/ws/DeleteAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/branch/ws/ListAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/branch/ws/RenameAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/branch/ws/package-info.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
server/sonar-server/src/main/java/org/sonar/server/projectbranch/package-info.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchWsAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchWsModule.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchesWs.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/DeleteAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/ListAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/RenameAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/package-info.java [deleted file]
server/sonar-server/src/main/resources/org/sonar/server/branch/ws/list-example.json [new file with mode: 0644]
server/sonar-server/src/main/resources/org/sonar/server/projectbranch/ws/list-example.json [deleted file]
server/sonar-server/src/test/java/org/sonar/server/branch/ws/BranchWsModuleTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/branch/ws/BranchesWsTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/branch/ws/DeleteActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/branch/ws/ListActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/branch/ws/RenameActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/BranchWsModuleTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/BranchesWsTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/DeleteActionTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ListActionTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/RenameActionTest.java [deleted file]

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 (file)
index 0000000..8f19fc4
--- /dev/null
@@ -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 (file)
index 0000000..73d421d
--- /dev/null
@@ -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 (file)
index 0000000..7275130
--- /dev/null
@@ -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 (file)
index 0000000..a04f6de
--- /dev/null
@@ -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.<br/>" +
+        "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 (file)
index 0000000..078fb44
--- /dev/null
@@ -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.<br/>" +
+        "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<BranchDto> branches = dbClient.branchDao().selectByComponent(dbSession, project);
+      MetricDto qualityGateMetric = dbClient.metricDao().selectOrFailByKey(dbSession, ALERT_STATUS_KEY);
+      Map<String, BranchDto> mergeBranchesByUuid = dbClient.branchDao()
+        .selectByUuids(dbSession, branches.stream().map(BranchDto::getMergeBranchUuid).filter(Objects::nonNull).collect(toList()))
+        .stream().collect(uniqueIndex(BranchDto::getUuid));
+      Map<String, MeasureDto> qualityGateMeasuresByComponentUuids = dbClient.measureDao()
+        .selectByComponentsAndMetrics(dbSession, branches.stream().map(BranchDto::getUuid).collect(toList()), singletonList(qualityGateMetric.getId()))
+        .stream().collect(uniqueIndex(MeasureDto::getComponentUuid));
+      Map<String, BranchStatistics> 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<String, String> 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<String, BranchDto> 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<BranchDto> 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 (file)
index 0000000..9e4c6fb
--- /dev/null
@@ -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.<br/>"
+        + "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<BranchDto> 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 (file)
index 0000000..6e4b5e8
--- /dev/null
@@ -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;
index ccb703b4414fb2f9321cf0d27db9ce05e85d471a..5df9ecf476c3264bd9f910eb0fe24174eb7034ee 100644 (file)
@@ -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 (file)
index 6aa3bb3..0000000
+++ /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 (file)
index 7a2c3f9..0000000
+++ /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 (file)
index da41f7a..0000000
+++ /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 (file)
index 64657b9..0000000
+++ /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 (file)
index 50c4191..0000000
+++ /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.<br/>" +
-        "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 (file)
index cc575a3..0000000
+++ /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.<br/>" +
-        "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<BranchDto> branches = dbClient.branchDao().selectByComponent(dbSession, project);
-      MetricDto qualityGateMetric = dbClient.metricDao().selectOrFailByKey(dbSession, ALERT_STATUS_KEY);
-      Map<String, BranchDto> mergeBranchesByUuid = dbClient.branchDao()
-        .selectByUuids(dbSession, branches.stream().map(BranchDto::getMergeBranchUuid).filter(Objects::nonNull).collect(toList()))
-        .stream().collect(uniqueIndex(BranchDto::getUuid));
-      Map<String, MeasureDto> qualityGateMeasuresByComponentUuids = dbClient.measureDao()
-        .selectByComponentsAndMetrics(dbSession, branches.stream().map(BranchDto::getUuid).collect(toList()), singletonList(qualityGateMetric.getId()))
-        .stream().collect(uniqueIndex(MeasureDto::getComponentUuid));
-      Map<String, BranchStatistics> 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<String, String> 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<String, BranchDto> 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<BranchDto> 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 (file)
index 3928c0a..0000000
+++ /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.<br/>"
-        + "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<BranchDto> 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 (file)
index 86bd1e8..0000000
+++ /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 (file)
index 0000000..9d28588
--- /dev/null
@@ -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 (file)
index 9d28588..0000000
+++ /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 (file)
index 0000000..4b6c7d9
--- /dev/null
@@ -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 (file)
index 0000000..4866279
--- /dev/null
@@ -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 (file)
index 0000000..5f40c2f
--- /dev/null
@@ -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<ComponentDto> 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 (file)
index 0000000..e008e9f
--- /dev/null
@@ -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 (file)
index 0000000..85b6fc6
--- /dev/null
@@ -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<BranchDto> mainBranch = db.getDbClient().branchDao().selectByUuid(db.getSession(), project.uuid());
+    assertThat(mainBranch.get().getKey()).isEqualTo("master");
+
+    Optional<BranchDto> 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<BranchDto> mainBranch = db.getDbClient().branchDao().selectByUuid(db.getSession(), project.uuid());
+    assertThat(mainBranch.get().getKey()).isEqualTo("master");
+
+    Optional<BranchDto> 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 (file)
index 2ecb8a8..0000000
+++ /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 (file)
index 9938bd9..0000000
+++ /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 (file)
index 9112fe3..0000000
+++ /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<ComponentDto> 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 (file)
index 81174c3..0000000
+++ /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 (file)
index e1dca43..0000000
+++ /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<BranchDto> mainBranch = db.getDbClient().branchDao().selectByUuid(db.getSession(), project.uuid());
-    assertThat(mainBranch.get().getKey()).isEqualTo("master");
-
-    Optional<BranchDto> 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<BranchDto> mainBranch = db.getDbClient().branchDao().selectByUuid(db.getSession(), project.uuid());
-    assertThat(mainBranch.get().getKey()).isEqualTo("master");
-
-    Optional<BranchDto> 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();
-  }
-}