diff options
author | Duarte Meneses <duarte.meneses@sonarsource.com> | 2019-08-05 16:04:11 -0500 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2019-09-24 20:21:12 +0200 |
commit | d2bba782392ad2390d790b15c8eddb24f37acd1e (patch) | |
tree | a1fc476f5cc1164e77f1c5872cd0304c94fae977 | |
parent | 09a0e34e0e4f22bb848a7339d6fe0153ac1ae97b (diff) | |
download | sonarqube-d2bba782392ad2390d790b15c8eddb24f37acd1e.tar.gz sonarqube-d2bba782392ad2390d790b15c8eddb24f37acd1e.zip |
SONAR-12366 Create WS to read/write New Code Periods
11 files changed, 504 insertions, 161 deletions
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/NewCodePeriodDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/NewCodePeriodDao.java index 6ef05723cff..4ffc6cd4dd6 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/NewCodePeriodDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/NewCodePeriodDao.java @@ -64,11 +64,6 @@ public class NewCodePeriodDao implements Dao { } } - public void update(DbSession dbSession, NewCodePeriodDto dto) { - requireNonNull(dto.getType(), "Type of NewCodePeriod must be specified."); - mapper(dbSession).update(dto.setUpdatedAt(system2.now())); - } - public Optional<NewCodePeriodDto> selectByProject(DbSession dbSession, String projectUuid) { requireNonNull(projectUuid, "Project uuid must be specified."); return Optional.ofNullable(mapper(dbSession).selectByProject(projectUuid)); diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/newcodeperiod/NewCodePeriodDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/newcodeperiod/NewCodePeriodDaoTest.java index 14f2fe68bf9..f9d675c9e30 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/newcodeperiod/NewCodePeriodDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/newcodeperiod/NewCodePeriodDaoTest.java @@ -69,36 +69,6 @@ public class NewCodePeriodDaoTest { } @Test - public void update_new_code_period() { - when(uuidFactory.create()).thenReturn("uuid-1"); - - NewCodePeriodDto dto = db.newCodePeriods().insert(new NewCodePeriodDto() - .setProjectUuid("proj-uuid") - .setBranchUuid("branch-uuid") - .setType(NewCodePeriodType.NUMBER_OF_DAYS) - .setValue("5")); - - underTest.update(dbSession, new NewCodePeriodDto() - .setUuid(dto.getUuid()) - .setType(NewCodePeriodType.SPECIFIC_ANALYSIS) - .setValue("analysis-uuid")); - - Optional<NewCodePeriodDto> resultOpt = underTest.selectByUuid(dbSession, "uuid-1"); - - assertThat(resultOpt).isNotNull(); - assertThat(resultOpt).isNotEmpty(); - - NewCodePeriodDto result = resultOpt.get(); - assertThat(result.getUuid()).isEqualTo("uuid-1"); - assertThat(result.getProjectUuid()).isEqualTo("proj-uuid"); - assertThat(result.getBranchUuid()).isEqualTo("branch-uuid"); - assertThat(result.getType()).isEqualTo(NewCodePeriodType.SPECIFIC_ANALYSIS); - assertThat(result.getValue()).isEqualTo("analysis-uuid"); - assertThat(result.getCreatedAt()).isNotEqualTo(0); - assertThat(result.getUpdatedAt()).isNotEqualTo(0); - } - - @Test public void insert_with_upsert() { when(uuidFactory.create()).thenReturn("uuid-1"); @@ -135,6 +105,8 @@ public class NewCodePeriodDaoTest { underTest.upsert(dbSession, new NewCodePeriodDto() .setType(NewCodePeriodType.SPECIFIC_ANALYSIS) + .setProjectUuid("proj-uuid") + .setBranchUuid("branch-uuid") .setValue("analysis-uuid")); Optional<NewCodePeriodDto> resultOpt = underTest.selectByUuid(dbSession, "uuid-1"); @@ -167,7 +139,7 @@ public class NewCodePeriodDaoTest { assertThat(resultOpt).isNotEmpty(); NewCodePeriodDto result = resultOpt.get(); - assertThat(result.getUuid()).isEqualTo("uuid-1"); + assertThat(result.getUuid()).isEqualTo("1"); assertThat(result.getProjectUuid()).isEqualTo("proj-uuid"); assertThat(result.getBranchUuid()).isEqualTo("branch-uuid"); assertThat(result.getType()).isEqualTo(NewCodePeriodType.NUMBER_OF_DAYS); @@ -191,7 +163,7 @@ public class NewCodePeriodDaoTest { assertThat(resultOpt).isNotEmpty(); NewCodePeriodDto result = resultOpt.get(); - assertThat(result.getUuid()).isEqualTo("uuid-1"); + assertThat(result.getUuid()).isEqualTo("1"); assertThat(result.getProjectUuid()).isEqualTo("proj-uuid"); assertThat(result.getBranchUuid()).isNull(); assertThat(result.getType()).isEqualTo(NewCodePeriodType.NUMBER_OF_DAYS); @@ -211,7 +183,7 @@ public class NewCodePeriodDaoTest { .setValue("30")); NewCodePeriodDto result = underTest.selectGlobal(dbSession); - assertThat(result.getUuid()).isEqualTo("uuid-1"); + assertThat(result.getUuid()).isEqualTo("1"); assertThat(result.getProjectUuid()).isNull(); assertThat(result.getBranchUuid()).isNull(); assertThat(result.getType()).isEqualTo(NewCodePeriodType.NUMBER_OF_DAYS); diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v80/CreateNewCodePeriodTableTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v80/CreateNewCodePeriodTableTest.java index 06a3664429d..dfee7c48dea 100644 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v80/CreateNewCodePeriodTableTest.java +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v80/CreateNewCodePeriodTableTest.java @@ -50,7 +50,7 @@ public class CreateNewCodePeriodTableTest { dbTester.assertColumnDefinition(TABLE_NAME, "project_uuid", VARCHAR, 40, true); dbTester.assertColumnDefinition(TABLE_NAME, "branch_uuid", VARCHAR, 40, true); dbTester.assertColumnDefinition(TABLE_NAME, "type", VARCHAR, 30, false); - dbTester.assertColumnDefinition(TABLE_NAME, "value", VARCHAR, 40, false); + dbTester.assertColumnDefinition(TABLE_NAME, "value", VARCHAR, 40, true); dbTester.assertColumnDefinition(TABLE_NAME, "updated_at", BIGINT, 20, false); dbTester.assertColumnDefinition(TABLE_NAME, "created_at", BIGINT, 20, false); diff --git a/server/sonar-server/src/main/java/org/sonar/server/setting/ws/GetNewCodePeriodAction.java b/server/sonar-server/src/main/java/org/sonar/server/setting/ws/GetNewCodePeriodAction.java deleted file mode 100644 index 47d00ddd82a..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/setting/ws/GetNewCodePeriodAction.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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.setting.ws; - -import org.sonar.api.server.ws.Request; -import org.sonar.api.server.ws.Response; -import org.sonar.api.server.ws.WebService; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.newcodeperiod.NewCodePeriodDao; -import org.sonar.server.user.UserSession; - -public class GetNewCodePeriodAction implements SettingsWsAction { - private final DbClient dbClient; - private final UserSession userSession; - private final NewCodePeriodDao newCodePeriodDao; - - public GetNewCodePeriodAction(DbClient dbClient, UserSession userSession, NewCodePeriodDao newCodePeriodDao) { - this.dbClient = dbClient; - this.userSession = userSession; - this.newCodePeriodDao = newCodePeriodDao; - } - - @Override - public void define(WebService.NewController context) { - context.createAction("get_new_code_period") - .setDescription("Updates the setting for the New Code Period.<br>" + - "Requires one of the following permissions: " + - "<ul>" + - "<li>'Administer System'</li>" + - "<li>'Administer' rights on the specified component</li>" + - "</ul>") - .setSince("8.0") - .setResponseExample(getClass().getResource("generate_secret_key-example.json")) - .setHandler(this); - } - - @Override - public void handle(Request request, Response response) throws Exception { - userSession.checkIsSystemAdministrator(); - try (DbSession dbSession = dbClient.openSession(false)) { - // TODO should it fall back branch->project->global? - } - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/setting/ws/ShowNewCodePeriodAction.java b/server/sonar-server/src/main/java/org/sonar/server/setting/ws/ShowNewCodePeriodAction.java new file mode 100644 index 00000000000..2c033bae81b --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/setting/ws/ShowNewCodePeriodAction.java @@ -0,0 +1,175 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.setting.ws; + +import java.util.Optional; +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.newcodeperiod.NewCodePeriodDao; +import org.sonar.db.newcodeperiod.NewCodePeriodDto; +import org.sonar.db.newcodeperiod.NewCodePeriodType; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.user.UserSession; +import org.sonarqube.ws.Settings; +import org.sonarqube.ws.Settings.ShowNewCodePeriodResponse; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.lang.String.format; +import static org.sonar.server.component.ComponentFinder.ParamNames.PROJECT_ID_AND_KEY; +import static org.sonar.server.ws.WsUtils.writeProtobuf; + +public class ShowNewCodePeriodAction implements SettingsWsAction { + private static final String PARAM_BRANCH = "branch"; + private static final String PARAM_PROJECT = "project"; + + private final DbClient dbClient; + private final UserSession userSession; + private final ComponentFinder componentFinder; + private final NewCodePeriodDao newCodePeriodDao; + + public ShowNewCodePeriodAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder, NewCodePeriodDao newCodePeriodDao) { + this.dbClient = dbClient; + this.userSession = userSession; + this.componentFinder = componentFinder; + this.newCodePeriodDao = newCodePeriodDao; + } + + @Override + public void define(WebService.NewController context) { + WebService.NewAction action = context.createAction("show_new_code_period") + .setDescription("Shows a setting for the New Code Period.<br>" + + "Requires one of the following permissions: " + + "<ul>" + + "<li>'Administer System'</li>" + + "<li>'Administer' rights on the specified component</li>" + + "</ul>") + .setSince("8.0") + .setResponseExample(getClass().getResource("generate_secret_key-example.json")) + .setHandler(this); + + action.createParam(PARAM_PROJECT) + .setDescription("Project key"); + action.createParam(PARAM_BRANCH) + .setDescription("Branch key"); + } + + @Override + public void handle(Request request, Response response) throws Exception { + String projectStr = request.getParam(PARAM_PROJECT).emptyAsNull().or(() -> null); + String branchStr = request.getParam(PARAM_BRANCH).emptyAsNull().or(() -> null); + + if (projectStr == null && branchStr != null) { + throw new IllegalArgumentException("If branch key is specified, project key needs to be specified too"); + } + + try (DbSession dbSession = dbClient.openSession(false)) { + + ComponentDto projectBranch = null; + String projectUuid = null; + String branchUuid = null; + + if (projectStr != null) { + projectBranch = getProject(dbSession, projectStr, branchStr); + userSession.checkComponentPermission(UserRole.ADMIN, projectBranch); + if (branchStr != null) { + branchUuid = projectBranch.uuid(); + } + // depending whether it's the main branch or not + projectUuid = projectBranch.getMainBranchProjectUuid() != null ? projectBranch.getMainBranchProjectUuid() : projectBranch.uuid(); + } + + ShowNewCodePeriodResponse.Builder builder = get(dbSession, projectUuid, branchUuid, false); + + if (projectStr != null) { + builder.setProjectKey(projectStr); + } + if (branchStr != null) { + builder.setBranchKey(branchStr); + } + writeProtobuf(builder.build(), request, response); + } + } + + private ShowNewCodePeriodResponse.Builder get(DbSession dbSession, @Nullable String projectUuid, @Nullable String branchUuid, boolean inherited) { + if (projectUuid == null) { + return build(newCodePeriodDao.selectGlobal(dbSession), inherited); + } + if (branchUuid == null) { + Optional<NewCodePeriodDto> dto = newCodePeriodDao.selectByProject(dbSession, projectUuid); + return dto.map(d -> build(d, inherited)) + .orElseGet(() -> get(dbSession, null, null, true)); + } + + Optional<NewCodePeriodDto> dto = newCodePeriodDao.selectByBranch(dbSession, projectUuid, branchUuid); + return dto.map(d -> build(d, inherited)) + .orElseGet(() -> get(dbSession, projectUuid, null, true)); + } + + private ShowNewCodePeriodResponse.Builder build(NewCodePeriodDto dto, boolean inherited) { + ShowNewCodePeriodResponse.Builder builder = ShowNewCodePeriodResponse.newBuilder() + .setType(convertType(dto.getType())) + .setInherited(inherited); + + if (dto.getValue() != null) { + builder.setValue(dto.getValue()); + } + return builder; + } + + private Settings.NewCodePeriodType convertType(NewCodePeriodType type) { + switch (type) { + case NUMBER_OF_DAYS: + return Settings.NewCodePeriodType.NUMBER_OF_DAYS; + case DATE: + return Settings.NewCodePeriodType.DATE; + case PREVIOUS_VERSION: + return Settings.NewCodePeriodType.PREVIOUS_VERSION; + case SPECIFIC_ANALYSIS: + return Settings.NewCodePeriodType.SPECIFIC_ANALYSIS; + default: + throw new IllegalStateException("Unexpected type: " + type); + } + } + + private ComponentDto getProject(DbSession dbSession, String projectKey, @Nullable String branchKey) { + if (branchKey == null) { + return componentFinder.getByUuidOrKey(dbSession, null, projectKey, PROJECT_ID_AND_KEY); + } + ComponentDto project = componentFinder.getByKeyAndBranch(dbSession, projectKey, branchKey); + + BranchDto branchDto = dbClient.branchDao().selectByUuid(dbSession, project.uuid()) + .orElseThrow(() -> new NotFoundException(format("Branch '%s' is not found", branchKey))); + + checkArgument(branchDto.getBranchType() == BranchType.LONG, + "Not a long-living branch: '%s'", branchKey); + + return project; + } + +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/setting/ws/SetNewCodePeriodAction.java b/server/sonar-server/src/main/java/org/sonar/server/setting/ws/UpdateNewCodePeriodAction.java index bc8259c6fef..d3126956172 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/setting/ws/SetNewCodePeriodAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/setting/ws/UpdateNewCodePeriodAction.java @@ -50,9 +50,9 @@ import static org.sonar.db.newcodeperiod.NewCodePeriodType.PREVIOUS_VERSION; import static org.sonar.db.newcodeperiod.NewCodePeriodType.SPECIFIC_ANALYSIS; import static org.sonar.server.component.ComponentFinder.ParamNames.PROJECT_ID_AND_KEY; -public class SetNewCodePeriodAction implements SettingsWsAction { - private static final String PARAM_BRANCH = "branchKey"; - private static final String PARAM_PROJECT = "projectKey"; +public class UpdateNewCodePeriodAction implements SettingsWsAction { + private static final String PARAM_BRANCH = "branch"; + private static final String PARAM_PROJECT = "project"; private static final String PARAM_TYPE = "type"; private static final String PARAM_VALUE = "value"; private static final Set<NewCodePeriodType> OVERALL_TYPES = ImmutableSet.of(PREVIOUS_VERSION, NUMBER_OF_DAYS); @@ -64,7 +64,7 @@ public class SetNewCodePeriodAction implements SettingsWsAction { private final ComponentFinder componentFinder; private final NewCodePeriodDao newCodePeriodDao; - public SetNewCodePeriodAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder, NewCodePeriodDao newCodePeriodDao) { + public UpdateNewCodePeriodAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder, NewCodePeriodDao newCodePeriodDao) { this.dbClient = dbClient; this.userSession = userSession; this.componentFinder = componentFinder; @@ -73,15 +73,14 @@ public class SetNewCodePeriodAction implements SettingsWsAction { @Override public void define(WebService.NewController context) { - WebService.NewAction action = context.createAction("set_new_code_period") + WebService.NewAction action = context.createAction("update_new_code_period") .setDescription("Updates the setting for the New Code Period.<br>" + "Requires one of the following permissions: " + "<ul>" + - "<li>'Administer System'</li>" + - "<li>'Administer' rights on the specified component</li>" + + "<li>'Administer System' to change the global setting</li>" + + "<li>'Administer' rights for a specified component</li>" + "</ul>") .setSince("8.0") - .setResponseExample(getClass().getResource("generate_secret_key-example.json")) .setHandler(this); action.createParam(PARAM_PROJECT) @@ -116,15 +115,19 @@ public class SetNewCodePeriodAction implements SettingsWsAction { if (projectStr != null) { projectBranch = getProject(dbSession, projectStr, branchStr); userSession.checkComponentPermission(UserRole.ADMIN, projectBranch); - dto.setProjectUuid(projectBranch.projectUuid()); + if (branchStr != null) { + dto.setBranchUuid(projectBranch.uuid()); + } + // depending whether it's the main branch or not + dto.setProjectUuid(projectBranch.getMainBranchProjectUuid() != null ? projectBranch.getMainBranchProjectUuid() : projectBranch.uuid()); } else { userSession.checkIsSystemAdministrator(); } setValue(dbSession, dto, type, projectBranch, branchStr, valueStr); - // TODO upsert? - newCodePeriodDao.insert(dbSession, dto); + newCodePeriodDao.upsert(dbSession, dto); + dbSession.commit(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/setting/ws/ShowNewCodePeriodActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/setting/ws/ShowNewCodePeriodActionTest.java new file mode 100644 index 00000000000..de1b36af126 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/setting/ws/ShowNewCodePeriodActionTest.java @@ -0,0 +1,247 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.setting.ws; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.server.ws.WebService; +import org.sonar.api.utils.System2; +import org.sonar.api.web.UserRole; +import org.sonar.core.util.UuidFactoryFast; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.DbTester; +import org.sonar.db.component.BranchType; +import org.sonar.db.component.ComponentDbTester; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.newcodeperiod.NewCodePeriodDao; +import org.sonar.db.newcodeperiod.NewCodePeriodDbTester; +import org.sonar.db.newcodeperiod.NewCodePeriodDto; +import org.sonar.db.newcodeperiod.NewCodePeriodType; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.component.TestComponentFinder; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.WsActionTester; +import org.sonarqube.ws.Settings; +import org.sonarqube.ws.Settings.ShowNewCodePeriodResponse; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ShowNewCodePeriodActionTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + + private ComponentDbTester componentDb = new ComponentDbTester(db); + private DbClient dbClient = db.getDbClient(); + private DbSession dbSession = db.getSession(); + private ComponentFinder componentFinder = TestComponentFinder.from(db); + private NewCodePeriodDao dao = new NewCodePeriodDao(System2.INSTANCE, UuidFactoryFast.getInstance()); + private NewCodePeriodDbTester tester = new NewCodePeriodDbTester(db); + private ShowNewCodePeriodAction underTest = new ShowNewCodePeriodAction(dbClient, userSession, componentFinder, dao); + private WsActionTester ws = new WsActionTester(underTest); + + @Test + public void test_definition() { + WebService.Action definition = ws.getDef(); + + assertThat(definition.key()).isEqualTo("show_new_code_period"); + assertThat(definition.isInternal()).isFalse(); + assertThat(definition.since()).isEqualTo("8.0"); + assertThat(definition.isPost()).isFalse(); + + assertThat(definition.params()).extracting(WebService.Param::key).containsOnly("project", "branch"); + assertThat(definition.param("project").isRequired()).isFalse(); + assertThat(definition.param("branch").isRequired()).isFalse(); + } + + @Test + public void throw_IAE_if_branch_is_specified_without_project() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("If branch key is specified, project key needs to be specified too"); + + ws.newRequest() + .setParam("branch", "branch") + .execute(); + } + + @Test + public void throw_NFE_if_project_not_found() { + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Component key 'unknown' not found"); + + ws.newRequest() + .setParam("project", "unknown") + .execute(); + } + + @Test + public void throw_NFE_if_branch_not_found() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Component '" + project.getKey() + "' on branch 'unknown' not found"); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("branch", "unknown") + .execute(); + } + + @Test + public void throw_IAE_if_branch_is_a_SLB() { + ComponentDto project = componentDb.insertMainBranch(); + ComponentDto branch = componentDb.insertProjectBranch(project, b -> b.setKey("branch").setBranchType(BranchType.SHORT)); + logInAsProjectAdministrator(project); + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Not a long-living branch: 'branch'"); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("branch", "branch") + .execute(); + } + + @Test + public void throw_NFE_if_no_project_permission() { + ComponentDto project = componentDb.insertMainBranch(); + expectedException.expect(ForbiddenException.class); + expectedException.expectMessage("Insufficient privileges"); + + ws.newRequest() + .setParam("project", project.getKey()) + .execute(); + } + + @Test + public void show_global_setting() { + tester.insert(new NewCodePeriodDto().setType(NewCodePeriodType.PREVIOUS_VERSION)); + + ShowNewCodePeriodResponse response = ws.newRequest() + .executeProtobuf(ShowNewCodePeriodResponse.class); + + assertResponse(response, "", "", Settings.NewCodePeriodType.PREVIOUS_VERSION, "", false); + } + + @Test + public void show_project_setting() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + + tester.insert(new NewCodePeriodDto() + .setProjectUuid(project.uuid()) + .setType(NewCodePeriodType.NUMBER_OF_DAYS) + .setValue("4")); + + ShowNewCodePeriodResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(ShowNewCodePeriodResponse.class); + + assertResponse(response, project.getKey(), "", Settings.NewCodePeriodType.NUMBER_OF_DAYS, "4", false); + } + + @Test + public void show_branch_setting() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + + ComponentDto branch = componentDb.insertProjectBranch(project, b -> b.setKey("branch")); + + tester.insert(new NewCodePeriodDto() + .setProjectUuid(project.uuid()) + .setBranchUuid(branch.uuid()) + .setType(NewCodePeriodType.DATE) + .setValue("2018-04-05")); + + ShowNewCodePeriodResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .setParam("branch", "branch") + .executeProtobuf(ShowNewCodePeriodResponse.class); + + assertResponse(response, project.getKey(), "branch", Settings.NewCodePeriodType.DATE, "2018-04-05", false); + } + + @Test + public void show_inherited_project_setting() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + tester.insert(new NewCodePeriodDto().setType(NewCodePeriodType.PREVIOUS_VERSION)); + + ShowNewCodePeriodResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(ShowNewCodePeriodResponse.class); + + assertResponse(response, project.getKey(), "", Settings.NewCodePeriodType.PREVIOUS_VERSION, "", true); + } + + @Test + public void show_inherited_branch_setting_from_project() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + + ComponentDto branch = componentDb.insertProjectBranch(project, b -> b.setKey("branch")); + + tester.insert(new NewCodePeriodDto() + .setProjectUuid(project.uuid()) + .setType(NewCodePeriodType.DATE) + .setValue("2018-04-05")); + + ShowNewCodePeriodResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .setParam("branch", "branch") + .executeProtobuf(ShowNewCodePeriodResponse.class); + + assertResponse(response, project.getKey(), "branch", Settings.NewCodePeriodType.DATE, "2018-04-05", true); + } + + @Test + public void show_inherited_branch_setting_from_global() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + ComponentDto branch = componentDb.insertProjectBranch(project, b -> b.setKey("branch")); + tester.insert(new NewCodePeriodDto().setType(NewCodePeriodType.NUMBER_OF_DAYS).setValue("3")); + + ShowNewCodePeriodResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .setParam("branch", "branch") + .executeProtobuf(ShowNewCodePeriodResponse.class); + + assertResponse(response, project.getKey(), "branch", Settings.NewCodePeriodType.NUMBER_OF_DAYS, "3", true); + } + + private void assertResponse(ShowNewCodePeriodResponse response, String projectKey, String branchKey, Settings.NewCodePeriodType type, String value, boolean inherited) { + assertThat(response.getBranchKey()).isEqualTo(branchKey); + assertThat(response.getProjectKey()).isEqualTo(projectKey); + assertThat(response.getInherited()).isEqualTo(inherited); + assertThat(response.getValue()).isEqualTo(value); + assertThat(response.getType()).isEqualTo(type); + } + + private void logInAsProjectAdministrator(ComponentDto project) { + userSession.logIn().addProjectPermission(UserRole.ADMIN, project); + } + +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/setting/ws/SetNewCodePeriodActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/setting/ws/UpdateNewCodePeriodActionTest.java index d0d5c9400a0..740bf44d85d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/setting/ws/SetNewCodePeriodActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/setting/ws/UpdateNewCodePeriodActionTest.java @@ -26,6 +26,7 @@ import org.junit.rules.ExpectedException; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.System2; import org.sonar.api.web.UserRole; +import org.sonar.core.util.UuidFactoryFast; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.DbTester; @@ -45,7 +46,7 @@ import org.sonar.server.ws.WsActionTester; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; -public class SetNewCodePeriodActionTest { +public class UpdateNewCodePeriodActionTest { @Rule public ExpectedException expectedException = ExpectedException.none(); @Rule @@ -57,28 +58,25 @@ public class SetNewCodePeriodActionTest { private DbClient dbClient = db.getDbClient(); private DbSession dbSession = db.getSession(); private ComponentFinder componentFinder = TestComponentFinder.from(db); - private NewCodePeriodDao dao = new NewCodePeriodDao(System2.INSTANCE); - private DbTester dbTester = DbTester.create(); + private NewCodePeriodDao dao = new NewCodePeriodDao(System2.INSTANCE, UuidFactoryFast.getInstance()); - private SetNewCodePeriodAction underTest = new SetNewCodePeriodAction(dbClient, userSession, componentFinder, dao); + private UpdateNewCodePeriodAction underTest = new UpdateNewCodePeriodAction(dbClient, userSession, componentFinder, dao); private WsActionTester ws = new WsActionTester(underTest); @Test public void test_definition() { WebService.Action definition = ws.getDef(); - assertThat(definition.key()).isEqualTo("set_new_code_period"); + assertThat(definition.key()).isEqualTo("update_new_code_period"); assertThat(definition.isInternal()).isFalse(); - //assertThat(definition.responseExampleAsString()).isNotEmpty(); assertThat(definition.since()).isEqualTo("8.0"); assertThat(definition.isPost()).isFalse(); - assertThat(definition.params()).extracting(WebService.Param::key).containsOnly("value", "type", "projectKey", "branchKey"); + assertThat(definition.params()).extracting(WebService.Param::key).containsOnly("value", "type", "project", "branch"); assertThat(definition.param("value").isRequired()).isFalse(); assertThat(definition.param("type").isRequired()).isTrue(); - assertThat(definition.param("projectKey").isRequired()).isFalse(); - assertThat(definition.param("branchKey").isRequired()).isFalse(); - + assertThat(definition.param("project").isRequired()).isFalse(); + assertThat(definition.param("branch").isRequired()).isFalse(); } // validation of type @@ -104,7 +102,7 @@ public class SetNewCodePeriodActionTest { @Test public void throw_IAE_if_type_is_invalid_for_global() { expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Invalid type 'DATE'. Overall setting can only be set with types: [PREVIOUS_VERSION, DAYS]"); + expectedException.expectMessage("Invalid type 'DATE'. Overall setting can only be set with types: [PREVIOUS_VERSION, NUMBER_OF_DAYS]"); ws.newRequest() .setParam("type", "date") @@ -117,10 +115,10 @@ public class SetNewCodePeriodActionTest { logInAsProjectAdministrator(project); expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Invalid type 'ANALYSIS'. Projects can only be set with types: [DATE, PREVIOUS_VERSION, DAYS]"); + expectedException.expectMessage("Invalid type 'SPECIFIC_ANALYSIS'. Projects can only be set with types: [DATE, PREVIOUS_VERSION, NUMBER_OF_DAYS]"); ws.newRequest() - .setParam("projectKey", project.getKey()) + .setParam("project", project.getKey()) .setParam("type", "specific_analysis") .execute(); } @@ -134,7 +132,7 @@ public class SetNewCodePeriodActionTest { expectedException.expectMessage("New Code Period type 'DATE' requires a value"); ws.newRequest() - .setParam("projectKey", project.getKey()) + .setParam("project", project.getKey()) .setParam("type", "date") .execute(); } @@ -144,11 +142,11 @@ public class SetNewCodePeriodActionTest { ComponentDto project = componentDb.insertMainBranch(); logInAsProjectAdministrator(project); expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("New Code Period type 'DAYS' requires a value"); + expectedException.expectMessage("New Code Period type 'NUMBER_OF_DAYS' requires a value"); ws.newRequest() - .setParam("projectKey", project.getKey()) - .setParam("branchKey", "master") + .setParam("project", project.getKey()) + .setParam("branch", "master") .setParam("type", "number_of_days") .execute(); } @@ -158,12 +156,12 @@ public class SetNewCodePeriodActionTest { ComponentDto project = componentDb.insertMainBranch(); logInAsProjectAdministrator(project); expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("New Code Period type 'ANALYSIS' requires a value"); + expectedException.expectMessage("New Code Period type 'SPECIFIC_ANALYSIS' requires a value"); ws.newRequest() - .setParam("projectKey", project.getKey()) + .setParam("project", project.getKey()) .setParam("type", "specific_analysis") - .setParam("branchKey", "master") + .setParam("branch", "master") .execute(); } @@ -175,9 +173,9 @@ public class SetNewCodePeriodActionTest { expectedException.expectMessage("Failed to parse date: unknown"); ws.newRequest() - .setParam("projectKey", project.getKey()) + .setParam("project", project.getKey()) .setParam("type", "date") - .setParam("branchKey", "master") + .setParam("branch", "master") .setParam("value", "unknown") .execute(); } @@ -190,9 +188,9 @@ public class SetNewCodePeriodActionTest { expectedException.expectMessage("Failed to parse number of days: unknown"); ws.newRequest() - .setParam("projectKey", project.getKey()) + .setParam("project", project.getKey()) .setParam("type", "number_of_days") - .setParam("branchKey", "master") + .setParam("branch", "master") .setParam("value", "unknown") .execute(); } @@ -205,9 +203,9 @@ public class SetNewCodePeriodActionTest { expectedException.expectMessage("Analysis 'unknown' is not found"); ws.newRequest() - .setParam("projectKey", project.getKey()) + .setParam("project", project.getKey()) .setParam("type", "specific_analysis") - .setParam("branchKey", "master") + .setParam("branch", "master") .setParam("value", "unknown") .execute(); } @@ -225,9 +223,9 @@ public class SetNewCodePeriodActionTest { expectedException.expectMessage("Analysis '" + analysisBranch.getUuid() + "' does not belong to branch 'master' of project '" + project.getKey() + "'"); ws.newRequest() - .setParam("projectKey", project.getKey()) - .setParam("type", "analysis") - .setParam("branchKey", "master") + .setParam("project", project.getKey()) + .setParam("type", "specific_analysis") + .setParam("branch", "master") .setParam("value", analysisBranch.getUuid()) .execute(); } @@ -239,7 +237,7 @@ public class SetNewCodePeriodActionTest { expectedException.expectMessage("If branch key is specified, project key needs to be specified too"); ws.newRequest() - .setParam("branchKey", "branch") + .setParam("branch", "branch") .execute(); } @@ -250,7 +248,7 @@ public class SetNewCodePeriodActionTest { ws.newRequest() .setParam("type", "previous_version") - .setParam("projectKey", "unknown") + .setParam("project", "unknown") .execute(); } @@ -262,9 +260,9 @@ public class SetNewCodePeriodActionTest { expectedException.expectMessage("Component '" + project.getKey() + "' on branch 'unknown' not found"); ws.newRequest() - .setParam("projectKey", project.getKey()) + .setParam("project", project.getKey()) .setParam("type", "previous_version") - .setParam("branchKey", "unknown") + .setParam("branch", "unknown") .execute(); } @@ -277,9 +275,9 @@ public class SetNewCodePeriodActionTest { expectedException.expectMessage("Not a long-living branch: 'branch'"); ws.newRequest() - .setParam("projectKey", project.getKey()) + .setParam("project", project.getKey()) .setParam("type", "previous_version") - .setParam("branchKey", "branch") + .setParam("branch", "branch") .execute(); } @@ -291,7 +289,7 @@ public class SetNewCodePeriodActionTest { expectedException.expectMessage("Insufficient privileges"); ws.newRequest() - .setParam("projectKey", project.getKey()) + .setParam("project", project.getKey()) .setParam("type", "previous_version") .execute(); } @@ -322,11 +320,11 @@ public class SetNewCodePeriodActionTest { ComponentDto project = componentDb.insertMainBranch(); logInAsProjectAdministrator(project); ws.newRequest() - .setParam("projectKey", project.getKey()) + .setParam("project", project.getKey()) .setParam("type", "number_of_days") .setParam("value", "5") .execute(); - assertTableContainsOnly(project.getKey(), null, NewCodePeriodType.NUMBER_OF_DAYS, "5"); + assertTableContainsOnly(project.uuid(), null, NewCodePeriodType.NUMBER_OF_DAYS, "5"); } @@ -341,20 +339,19 @@ public class SetNewCodePeriodActionTest { logInAsProjectAdministrator(project); ws.newRequest() - .setParam("projectKey", project.getKey()) + .setParam("project", project.getKey()) .setParam("type", "specific_analysis") - .setParam("branchKey", "branch") + .setParam("branch", "branch") .setParam("value", analysisBranch.getUuid()) .execute(); - assertTableContainsOnly(project.getKey(), "branch", NewCodePeriodType.SPECIFIC_ANALYSIS, analysisBranch.getUuid()); - + assertTableContainsOnly(project.uuid(), branch.uuid(), NewCodePeriodType.SPECIFIC_ANALYSIS, analysisBranch.getUuid()); } - private void assertTableContainsOnly(@Nullable String projectKey, @Nullable String branchKey, NewCodePeriodType type, @Nullable String value) { - dbTester.countRowsOfTable(dbSession, "new_code_period"); - assertThat(dbTester.selectFirst(dbSession, "select projectKey, branchKey, type, value from new_code_period")) - .containsOnly(entry("projectKey", projectKey), entry("branchKey", branchKey), entry("type", type), entry("value", value)); + private void assertTableContainsOnly(@Nullable String projectUuid, @Nullable String branchUuid, NewCodePeriodType type, @Nullable String value) { + assertThat(db.countRowsOfTable(dbSession, "new_code_periods")).isEqualTo(1); + assertThat(db.selectFirst(dbSession, "select project_uuid, branch_uuid, type, value from new_code_periods")) + .containsOnly(entry("PROJECT_UUID", projectUuid), entry("BRANCH_UUID", branchUuid), entry("TYPE", type.name()), entry("VALUE", value)); } private void logInAsProjectAdministrator(ComponentDto project) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingsWsModule.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingsWsModule.java index 61371ee1e3d..7b21556d6bb 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingsWsModule.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingsWsModule.java @@ -35,6 +35,8 @@ public class SettingsWsModule extends Module { GenerateSecretKeyAction.class, CheckSecretKeyAction.class, SettingsUpdater.class, - SettingValidations.class); + SettingValidations.class, + ShowNewCodePeriodAction.class, + UpdateNewCodePeriodAction.class); } } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SettingsWsModuleTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SettingsWsModuleTest.java index b3dd8904a60..a13ca7fe359 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SettingsWsModuleTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SettingsWsModuleTest.java @@ -29,6 +29,6 @@ public class SettingsWsModuleTest { public void verify_count_of_added_components() { ComponentContainer container = new ComponentContainer(); new SettingsWsModule().configure(container); - assertThat(container.size()).isEqualTo(11 + 2); + assertThat(container.size()).isEqualTo(13 + 2); } } diff --git a/sonar-ws/src/main/protobuf/ws-settings.proto b/sonar-ws/src/main/protobuf/ws-settings.proto index db185b54446..180e7d4c463 100644 --- a/sonar-ws/src/main/protobuf/ws-settings.proto +++ b/sonar-ws/src/main/protobuf/ws-settings.proto @@ -44,6 +44,21 @@ message CheckSecretKeyWsResponse { bool secretKeyAvailable = 1; } +message ShowNewCodePeriodResponse { + string projectKey = 1; + string branchKey = 2; + NewCodePeriodType type = 3; + string value = 4; + bool inherited = 5; +} + +enum NewCodePeriodType { + PREVIOUS_VERSION = 0; + NUMBER_OF_DAYS = 1; + DATE = 2; + SPECIFIC_ANALYSIS = 3; +} + message Definition { string key = 1; oneof nameOneOf {string name = 2;} |