aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java6
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java2
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml9
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java42
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchWsModule.java1
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/DeleteAction.java4
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/RenameAction.java99
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/BranchWsModuleTest.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/RenameActionTest.java181
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/projectbranches/ProjectBranchesParameters.java1
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/projectbranches/ProjectBranchesService.java8
-rw-r--r--sonar-ws/src/test/java/org/sonarqube/ws/client/projectbranches/ProjectBranchesServiceTest.java12
12 files changed, 355 insertions, 12 deletions
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java
index 50ff5f66deb..2e4fcb111d4 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java
@@ -49,6 +49,11 @@ public class BranchDao implements Dao {
}
}
+ public int updateMainBranchName(DbSession dbSession, String projectUuid, String newBranchKey) {
+ long now = system2.now();
+ return mapper(dbSession).updateMainBranchName(projectUuid, newBranchKey, now);
+ }
+
public Optional<BranchDto> selectByKey(DbSession dbSession, String projectUuid, BranchKeyType keyType, @Nullable String key) {
String keyInDb = BranchDto.convertKeyToDb(key);
return Optional.ofNullable(mapper(dbSession).selectByKey(projectUuid, keyType, keyInDb));
@@ -70,7 +75,6 @@ public class BranchDao implements Dao {
return Optional.ofNullable(mapper(session).selectByUuid(uuid));
}
-
private static BranchMapper mapper(DbSession dbSession) {
return dbSession.getMapper(BranchMapper.class);
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java
index 0c978360aec..ae4fc73dc03 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java
@@ -29,6 +29,8 @@ public interface BranchMapper {
int update(@Param("dto") BranchDto dto, @Param("now") long now);
+ int updateMainBranchName(@Param("projectUuid") String projectUuid, @Param("newBranchName") String newBranchName, @Param("now") long now);
+
BranchDto selectByKey(@Param("projectUuid") String projectUuid,
@Param("keyType") BranchKeyType keyType, @Param("key") String key);
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml
index 9c39fff0ac1..a3a24d7913f 100644
--- a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml
+++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml
@@ -36,6 +36,15 @@
)
</insert>
+ <update id="updateMainBranchName" parameterType="map">
+ update project_branches
+ set
+ kee = #{newBranchName, jdbcType=VARCHAR},
+ updated_at = #{now, jdbcType=BIGINT}
+ where
+ uuid = #{projectUuid, jdbcType=VARCHAR}
+ </update>
+
<update id="update" parameterType="map" useGeneratedKeys="false">
update project_branches
set
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java
index 616a6e1cde1..43b6f6aa14b 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java
@@ -69,8 +69,34 @@ public class BranchDaoTest {
entry("mergeBranchUuid", null),
entry("pullRequestTitle", null),
entry("createdAt", 1_000L),
- entry("updatedAt", 1_000L)
- );
+ entry("updatedAt", 1_000L));
+ }
+
+ @Test
+ public void update_main_branch_name() {
+ BranchDto dto = new BranchDto();
+ dto.setProjectUuid("U1");
+ dto.setUuid("U1");
+ dto.setBranchType(BranchType.LONG);
+ dto.setKeeType(BranchKeyType.BRANCH);
+ dto.setKey(null);
+ underTest.insert(dbSession, dto);
+
+ BranchDto dto2 = new BranchDto();
+ dto2.setProjectUuid("U2");
+ dto2.setUuid("U2");
+ dto2.setBranchType(BranchType.LONG);
+ dto2.setKeeType(BranchKeyType.BRANCH);
+ dto2.setKey("branch");
+ underTest.insert(dbSession, dto2);
+
+ underTest.updateMainBranchName(dbSession, "U1", "master");
+ BranchDto loaded = underTest.selectByKey(dbSession, "U1", BranchKeyType.BRANCH, "master").get();
+ assertThat(loaded.getMergeBranchUuid()).isNull();
+ assertThat(loaded.getPullRequestTitle()).isNull();
+ assertThat(loaded.getProjectUuid()).isEqualTo("U1");
+ assertThat(loaded.getBranchType()).isEqualTo(BranchType.LONG);
+ assertThat(loaded.getKeeType()).isEqualTo(BranchKeyType.BRANCH);
}
@Test
@@ -87,11 +113,11 @@ public class BranchDaoTest {
underTest.insert(dbSession, dto);
Map<String, Object> map = db.selectFirst(dbSession, SELECT_FROM + " where uuid='" + dto.getUuid() + "'");
- assertThat((String)map.get("projectUuid")).contains("a").isEqualTo(dto.getProjectUuid());
- assertThat((String)map.get("uuid")).contains("b").isEqualTo(dto.getUuid());
- assertThat((String)map.get("kee")).contains("c").isEqualTo(dto.getKey());
- assertThat((String)map.get("mergeBranchUuid")).contains("d").isEqualTo(dto.getMergeBranchUuid());
- assertThat((String)map.get("pullRequestTitle")).contains("e").isEqualTo(dto.getPullRequestTitle());
+ assertThat((String) map.get("projectUuid")).contains("a").isEqualTo(dto.getProjectUuid());
+ assertThat((String) map.get("uuid")).contains("b").isEqualTo(dto.getUuid());
+ assertThat((String) map.get("kee")).contains("c").isEqualTo(dto.getKey());
+ assertThat((String) map.get("mergeBranchUuid")).contains("d").isEqualTo(dto.getMergeBranchUuid());
+ assertThat((String) map.get("pullRequestTitle")).contains("e").isEqualTo(dto.getPullRequestTitle());
}
@Test
@@ -183,7 +209,7 @@ public class BranchDaoTest {
assertThat(underTest.selectByUuids(db.getSession(), asList(branch1.uuid(), branch2.uuid(), branch3.uuid())))
.extracting(BranchDto::getUuid)
- .containsExactlyInAnyOrder(branch1.uuid(), branch2.uuid(), branch3.uuid());
+ .containsExactlyInAnyOrder(branch1.uuid(), branch2.uuid(), branch3.uuid());
assertThat(underTest.selectByUuids(db.getSession(), singletonList(branch1.uuid())))
.extracting(BranchDto::getUuid)
.containsExactlyInAnyOrder(branch1.uuid());
diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchWsModule.java
index d47f197991c..270ceef8ad9 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchWsModule.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchWsModule.java
@@ -28,6 +28,7 @@ public class BranchWsModule extends Module {
ListAction.class,
ShowAction.class,
DeleteAction.class,
+ RenameAction.class,
BranchesWs.class);
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/DeleteAction.java b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/DeleteAction.java
index 89e3b9bb631..fa61c63d39e 100644
--- 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
@@ -38,7 +38,7 @@ import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.ACTION_DELETE;
import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.PARAM_BRANCH;
-import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.PARAM_PROJECT;;
+import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.PARAM_PROJECT;
public class DeleteAction implements BranchWsAction {
private final DbClient dbClient;
@@ -99,7 +99,7 @@ public class DeleteAction implements BranchWsAction {
}
private void checkPermission(ComponentDto project) {
- userSession.hasComponentPermission(UserRole.ADMIN, project);
+ userSession.checkComponentPermission(UserRole.ADMIN, project);
}
}
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
new file mode 100644
index 00000000000..3cf4e7d93fa
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/RenameAction.java
@@ -0,0 +1,99 @@
+/*
+ * 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.BranchKeyType;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.user.UserSession;
+
+import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
+import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.ACTION_RENAME;
+import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.PARAM_BRANCH;
+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.")
+ .setInternal(true)
+ .setPost(true)
+ .setHandler(this);
+
+ action
+ .createParam(PARAM_PROJECT)
+ .setDescription("Project key")
+ .setExampleValue(KEY_PROJECT_EXAMPLE_001)
+ .setRequired(true);
+ action
+ .createParam(PARAM_BRANCH)
+ .setDescription("New name of the main branch")
+ .setExampleValue("master")
+ .setRequired(true);
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+ userSession.checkLoggedIn();
+ String projectKey = request.mandatoryParam(PARAM_PROJECT);
+ String branchKey = request.mandatoryParam(PARAM_BRANCH);
+
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ ComponentDto project = componentFinder.getRootComponentByUuidOrKey(dbSession, null, projectKey);
+ checkPermission(project);
+
+ Optional<BranchDto> branch = dbClient.branchDao().selectByKey(dbSession, project.uuid(), BranchKeyType.BRANCH, branchKey);
+ if (branch.isPresent() && !branch.get().isMain()) {
+ throw new IllegalArgumentException("Impossible to update branch name: a branch with name \"" + branchKey + "\" already exists in the project.");
+ }
+
+ dbClient.branchDao().updateMainBranchName(dbSession, project.uuid(), branchKey);
+ dbSession.commit();
+ response.noContent();
+ }
+ }
+
+ private void checkPermission(ComponentDto project) {
+ userSession.checkComponentPermission(UserRole.ADMIN, project);
+ }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/BranchWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/BranchWsModuleTest.java
index 2ecb8a885a2..8018bcb7094 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/BranchWsModuleTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/BranchWsModuleTest.java
@@ -30,6 +30,6 @@ public class BranchWsModuleTest {
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new BranchWsModule().configure(container);
- assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 4);
+ assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 5);
}
}
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
new file mode 100644
index 00000000000..bab33b6927e
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/RenameActionTest.java
@@ -0,0 +1,181 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.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()).isTrue();
+ assertThat(definition.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("project", "branch");
+ assertThat(definition.since()).isEqualTo("6.6");
+ }
+
+ @Test
+ public void fail_if_missing_project_parameter() {
+ userSession.logIn();
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("The 'project' parameter is missing");
+
+ tester.newRequest().execute();
+ }
+
+ @Test
+ public void fail_if_missing_branch_parameter() {
+ userSession.logIn();
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("The 'branch' parameter is missing");
+
+ tester.newRequest().setParam("project", "projectName").execute();
+ }
+
+ @Test
+ public void fail_if_not_logged_in() {
+ expectedException.expect(UnauthorizedException.class);
+ expectedException.expectMessage("Authentication is required");
+
+ tester.newRequest().execute();
+ }
+
+ @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("branch", "branch1")
+ .execute();
+ }
+
+ @Test
+ public void successfully_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("branch", "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 successfully_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("branch", "master")
+ .execute();
+
+ tester.newRequest()
+ .setParam("project", project.getKey())
+ .setParam("branch", "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("branch", "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("branch", "branch1")
+ .execute();
+ }
+}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/projectbranches/ProjectBranchesParameters.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/projectbranches/ProjectBranchesParameters.java
index c1370b92093..32501503293 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/projectbranches/ProjectBranchesParameters.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/projectbranches/ProjectBranchesParameters.java
@@ -27,6 +27,7 @@ public class ProjectBranchesParameters {
public static final String ACTION_LIST = "list";
public static final String ACTION_SHOW = "show";
public static final String ACTION_DELETE = "delete";
+ public static final String ACTION_RENAME = "rename";
// parameters
public static final String PARAM_PROJECT = "project";
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/projectbranches/ProjectBranchesService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/projectbranches/ProjectBranchesService.java
index 0a0b23a09aa..52d25fb4614 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/projectbranches/ProjectBranchesService.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/projectbranches/ProjectBranchesService.java
@@ -29,6 +29,7 @@ import org.sonarqube.ws.client.WsConnector;
import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.ACTION_LIST;
import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.ACTION_SHOW;
import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.ACTION_DELETE;
+import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.ACTION_RENAME;
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;
@@ -59,4 +60,11 @@ public class ProjectBranchesService extends BaseService {
call(post);
}
+ public void rename(String project, String branch) {
+ PostRequest post = new PostRequest(path(ACTION_RENAME))
+ .setParam(PARAM_PROJECT, project)
+ .setParam(PARAM_BRANCH, branch);
+ call(post);
+ }
+
}
diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/projectbranches/ProjectBranchesServiceTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/projectbranches/ProjectBranchesServiceTest.java
index 6a5b894e035..a1596299511 100644
--- a/sonar-ws/src/test/java/org/sonarqube/ws/client/projectbranches/ProjectBranchesServiceTest.java
+++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/projectbranches/ProjectBranchesServiceTest.java
@@ -80,4 +80,16 @@ public class ProjectBranchesServiceTest {
.andNoOtherParam();
}
+ @Test
+ public void rename() {
+ underTest.rename("projectKey", "my_branch");
+
+ PostRequest postRequest = serviceTester.getPostRequest();
+ serviceTester.assertThat(postRequest)
+ .hasPath("rename")
+ .hasParam(PARAM_PROJECT, "projectKey")
+ .hasParam(PARAM_BRANCH, "my_branch")
+ .andNoOtherParam();
+ }
+
}