From f8a00f1a80567e38246c705798632fb4d2ce4630 Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Fri, 8 May 2020 10:51:55 -0500 Subject: [PATCH] SONAR-13300 Deprecate use of id in quality gate web services --- .../server/qualitygate/ws/CopyAction.java | 35 ++++++-- .../server/qualitygate/ws/CreateAction.java | 3 + .../qualitygate/ws/CreateConditionAction.java | 30 +++++-- .../server/qualitygate/ws/DestroyAction.java | 35 ++++++-- .../qualitygate/ws/GetByProjectAction.java | 3 +- .../server/qualitygate/ws/ListAction.java | 3 +- .../ws/QualityGatesWsParameters.java | 3 + .../qualitygate/ws/QualityGatesWsSupport.java | 6 ++ .../server/qualitygate/ws/RenameAction.java | 43 +++++++--- .../server/qualitygate/ws/SearchAction.java | 34 ++++++-- .../server/qualitygate/ws/SelectAction.java | 33 ++++++-- .../qualitygate/ws/SetAsDefaultAction.java | 35 ++++++-- .../server/qualitygate/ws/ShowAction.java | 3 +- .../server/qualitygate/ws/CopyActionTest.java | 5 +- .../ws/CreateConditionActionTest.java | 3 +- .../qualitygate/ws/DestroyActionTest.java | 5 +- .../ws/GetByProjectActionTest.java | 6 +- .../server/qualitygate/ws/ListActionTest.java | 8 +- .../qualitygate/ws/RenameActionTest.java | 5 +- .../qualitygate/ws/SearchActionTest.java | 3 +- .../ws/SetAsDefaultActionTest.java | 80 +++++++++++++++++++ 21 files changed, 315 insertions(+), 66 deletions(-) create mode 100644 server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/SetAsDefaultActionTest.java diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/CopyAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/CopyAction.java index 1351b083354..1589aedd111 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/CopyAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/CopyAction.java @@ -19,6 +19,7 @@ */ package org.sonar.server.qualitygate.ws; +import org.sonar.api.server.ws.Change; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; @@ -29,9 +30,12 @@ import org.sonar.db.qualitygate.QualityGateDto; import org.sonar.server.qualitygate.QualityGateUpdater; import org.sonar.server.user.UserSession; +import static com.google.common.base.Preconditions.checkArgument; import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_GATES; +import static org.sonar.server.qualitygate.ws.CreateAction.NAME_MAXIMUM_LENGTH; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ID; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_NAME; +import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_SOURCE_NAME; import static org.sonar.server.ws.WsUtils.writeProtobuf; import static org.sonarqube.ws.Qualitygates.QualityGate.newBuilder; @@ -54,34 +58,53 @@ public class CopyAction implements QualityGatesWsAction { public void define(WebService.NewController controller) { WebService.NewAction action = controller.createAction("copy") .setDescription("Copy a Quality Gate.
" + - "Requires the 'Administer Quality Gates' permission.") + "Either 'sourceName' or 'id' must be provided. Requires the 'Administer Quality Gates' permission.") .setPost(true) + .setChangelog( + new Change("8.4", "Parameter 'sourceName' added"), + new Change("8.4", "Parameter 'id' is deprecated. Use 'sourceName' instead.")) .setSince("4.3") .setHandler(this); action.createParam(PARAM_ID) - .setDescription("The ID of the source quality gate") - .setRequired(true) + .setDescription("The ID of the source quality gate. This parameter is deprecated. Use 'sourceName' instead.") + .setRequired(false) + .setDeprecatedSince("8.4") .setExampleValue("1"); + action.createParam(PARAM_SOURCE_NAME) + .setDescription("The name of the quality gate to copy") + .setRequired(false) + .setMaximumLength(NAME_MAXIMUM_LENGTH) + .setSince("8.4") + .setExampleValue("My Quality Gate"); + action.createParam(PARAM_NAME) .setDescription("The name of the quality gate to create") .setRequired(true) - .setExampleValue("My Quality Gate"); + .setExampleValue("My New Quality Gate"); wsSupport.createOrganizationParam(action); } @Override public void handle(Request request, Response response) { - String uuid = request.mandatoryParam(PARAM_ID); + String uuid = request.param(PARAM_ID); + String sourceName = request.param(PARAM_SOURCE_NAME); + checkArgument(sourceName != null ^ uuid != null, "Either 'id' or 'sourceName' must be provided, and not both"); + String destinationName = request.mandatoryParam(PARAM_NAME); try (DbSession dbSession = dbClient.openSession(false)) { OrganizationDto organization = wsSupport.getOrganization(dbSession, request); userSession.checkPermission(ADMINISTER_QUALITY_GATES, organization); - QualityGateDto qualityGate = wsSupport.getByOrganizationAndUuid(dbSession, organization, uuid); + QualityGateDto qualityGate; + if (uuid != null) { + qualityGate = wsSupport.getByOrganizationAndUuid(dbSession, organization, uuid); + } else { + qualityGate = wsSupport.getByOrganizationAndName(dbSession, organization, sourceName); + } QualityGateDto copy = qualityGateUpdater.copy(dbSession, organization, qualityGate, destinationName); dbSession.commit(); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/CreateAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/CreateAction.java index 89686dfa71e..41e00be21e3 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/CreateAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/CreateAction.java @@ -19,6 +19,7 @@ */ package org.sonar.server.qualitygate.ws; +import org.sonar.api.server.ws.Change; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; @@ -59,6 +60,8 @@ public class CreateAction implements QualityGatesWsAction { .setDescription("Create a Quality Gate.
" + "Requires the 'Administer Quality Gates' permission.") .setSince("4.3") + .setChangelog( + new Change("8.4", "Field 'id' in the response is deprecated.")) .setResponseExample(getClass().getResource("create-example.json")) .setHandler(this); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/CreateConditionAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/CreateConditionAction.java index 299b1c13b41..09f5a497a00 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/CreateConditionAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/CreateConditionAction.java @@ -31,10 +31,12 @@ import org.sonar.db.qualitygate.QualityGateConditionDto; import org.sonar.server.qualitygate.QualityGateConditionsUpdater; import org.sonarqube.ws.Qualitygates.CreateConditionResponse; +import static com.google.common.base.Preconditions.checkArgument; import static org.sonar.server.qualitygate.ws.QualityGatesWs.addConditionParams; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.ACTION_CREATE_CONDITION; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ERROR; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GATE_ID; +import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GATE_NAME; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_METRIC; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_OPERATOR; import static org.sonar.server.ws.WsUtils.writeProtobuf; @@ -56,35 +58,51 @@ public class CreateConditionAction implements QualityGatesWsAction { WebService.NewAction createCondition = controller.createAction(ACTION_CREATE_CONDITION) .setPost(true) .setDescription("Add a new condition to a quality gate.
" + - "Requires the 'Administer Quality Gates' permission.") + "Either 'gateId' or 'gateName' must be provided. Requires the 'Administer Quality Gates' permission.") .setSince("4.3") .setResponseExample(getClass().getResource("create-condition-example.json")) .setChangelog( new Change("7.6", "Removed optional 'warning' and 'period' parameters"), new Change("7.6", "Made 'error' parameter mandatory"), - new Change("7.6", "Reduced the possible values of 'op' parameter to LT and GT")) + new Change("7.6", "Reduced the possible values of 'op' parameter to LT and GT"), + new Change("8.4", "Parameter 'gateName' added"), + new Change("8.4", "Parameter 'gateId' is deprecated. Use 'gateName' instead.")) .setHandler(this); createCondition .createParam(PARAM_GATE_ID) - .setRequired(true) - .setDescription("ID of the quality gate") + .setDeprecatedSince("8.4") + .setRequired(false) + .setDescription("ID of the quality gate. This parameter is deprecated. Use 'gateName' instead.") .setExampleValue("1"); + createCondition + .createParam(PARAM_GATE_NAME) + .setRequired(false) + .setDescription("Name of the quality gate") + .setExampleValue("SonarSource way"); + addConditionParams(createCondition); wsSupport.createOrganizationParam(createCondition); } @Override public void handle(Request request, Response response) { - String gateUuid = request.mandatoryParam(PARAM_GATE_ID); + String gateUuid = request.param(PARAM_GATE_ID); + String gateName = request.param(PARAM_GATE_NAME); String metric = request.mandatoryParam(PARAM_METRIC); String operator = request.mandatoryParam(PARAM_OPERATOR); String error = request.mandatoryParam(PARAM_ERROR); + checkArgument(gateName != null ^ gateUuid != null, "One of 'gateId' or 'gateName' must be provided, and not both"); try (DbSession dbSession = dbClient.openSession(false)) { OrganizationDto organization = wsSupport.getOrganization(dbSession, request); - QGateWithOrgDto qualityGate = wsSupport.getByOrganizationAndUuid(dbSession, organization, gateUuid); + QGateWithOrgDto qualityGate; + if (gateUuid != null) { + qualityGate = wsSupport.getByOrganizationAndUuid(dbSession, organization, gateUuid); + } else { + qualityGate = wsSupport.getByOrganizationAndName(dbSession, organization, gateName); + } wsSupport.checkCanEdit(qualityGate); QualityGateConditionDto condition = qualityGateConditionsUpdater.createCondition(dbSession, qualityGate, metric, operator, error); CreateConditionResponse.Builder createConditionResponse = CreateConditionResponse.newBuilder() diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/DestroyAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/DestroyAction.java index 4b16cd41eab..197fc3d9ce6 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/DestroyAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/DestroyAction.java @@ -19,6 +19,7 @@ */ package org.sonar.server.qualitygate.ws; +import org.sonar.api.server.ws.Change; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; @@ -30,6 +31,7 @@ import org.sonar.db.qualitygate.QualityGateDto; import org.sonar.server.qualitygate.QualityGateFinder; import static com.google.common.base.Preconditions.checkArgument; +import static org.sonar.server.qualitygate.ws.CreateAction.NAME_MAXIMUM_LENGTH; public class DestroyAction implements QualityGatesWsAction { @@ -47,25 +49,48 @@ public class DestroyAction implements QualityGatesWsAction { public void define(WebService.NewController controller) { WebService.NewAction action = controller.createAction("destroy") .setDescription("Delete a Quality Gate.
" + - "Requires the 'Administer Quality Gates' permission.") + "Either 'id' or 'name' must be specified. Requires the 'Administer Quality Gates' permission.") .setSince("4.3") .setPost(true) + .setChangelog( + new Change("8.4", "Parameter 'name' added"), + new Change("8.4", "Parameter 'id' is deprecated. Use 'name' instead.")) .setHandler(this); action.createParam(QualityGatesWsParameters.PARAM_ID) - .setDescription("ID of the quality gate to delete") - .setRequired(true) + .setDescription("ID of the quality gate to delete. This parameter is deprecated. Use 'name' instead.") + .setRequired(false) + .setDeprecatedSince("8.4") .setExampleValue("1"); + action.createParam(QualityGatesWsParameters.PARAM_NAME) + .setDescription("Name of the quality gate to delete") + .setRequired(false) + .setMaximumLength(NAME_MAXIMUM_LENGTH) + .setSince("8.4") + .setExampleValue("SonarSource Way"); + wsSupport.createOrganizationParam(action); } @Override public void handle(Request request, Response response) { - String qualityGateUuid = request.mandatoryParam(QualityGatesWsParameters.PARAM_ID); + String uuid = request.param(QualityGatesWsParameters.PARAM_ID); + String name = request.param(QualityGatesWsParameters.PARAM_NAME); + + checkArgument(name != null ^ uuid != null, "One of 'id' or 'name' must be provided, and not both"); + try (DbSession dbSession = dbClient.openSession(false)) { OrganizationDto organization = wsSupport.getOrganization(dbSession, request); - QGateWithOrgDto qualityGate = wsSupport.getByOrganizationAndUuid(dbSession, organization, qualityGateUuid); + + QGateWithOrgDto qualityGate; + + if (uuid != null) { + qualityGate = wsSupport.getByOrganizationAndUuid(dbSession, organization, uuid); + } else { + qualityGate = wsSupport.getByOrganizationAndName(dbSession, organization, name); + } + QualityGateDto defaultQualityGate = finder.getDefault(dbSession, organization); checkArgument(!defaultQualityGate.getUuid().equals(qualityGate.getUuid()), "The default quality gate cannot be removed"); wsSupport.checkCanEdit(qualityGate); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/GetByProjectAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/GetByProjectAction.java index c17cd289bc7..c8a22df4944 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/GetByProjectAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/GetByProjectAction.java @@ -77,7 +77,8 @@ public class GetByProjectAction implements QualityGatesWsAction { .setChangelog( new Change("6.6", "The parameter 'projectId' has been removed"), new Change("6.6", "The parameter 'projectKey' has been renamed to 'project'"), - new Change("6.6", "This webservice is now part of the public API")); + new Change("6.6", "This webservice is now part of the public API"), + new Change("8.4", "Field 'id' in the response is deprecated.")); action.createParam(PARAM_PROJECT) .setDescription("Project key") diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ListAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ListAction.java index 7a12d64b284..f0456e6ea20 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ListAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ListAction.java @@ -60,7 +60,8 @@ public class ListAction implements QualityGatesWsAction { new Change("7.0", "'isDefault' field is added on quality gate"), new Change("7.0", "'default' field on root level is deprecated"), new Change("7.0", "'isBuiltIn' field is added in the response"), - new Change("7.0", "'actions' fields are added in the response")) + new Change("7.0", "'actions' fields are added in the response"), + new Change("8.4", "Field 'id' in the response is deprecated.")) .setHandler(this); wsSupport.createOrganizationParam(action); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsParameters.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsParameters.java index 651037c988b..8c7d8f7ab7a 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsParameters.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsParameters.java @@ -39,12 +39,15 @@ public class QualityGatesWsParameters { public static final String PARAM_PAGE_SIZE = "pageSize"; public static final String PARAM_PAGE = "page"; public static final String PARAM_QUERY = "query"; + public static final String PARAM_CURRENT_NAME = "currentName"; public static final String PARAM_NAME = "name"; public static final String PARAM_ERROR = "error"; public static final String PARAM_OPERATOR = "op"; public static final String PARAM_METRIC = "metric"; public static final String PARAM_GATE_ID = "gateId"; + public static final String PARAM_GATE_NAME = "gateName"; public static final String PARAM_ID = "id"; + public static final String PARAM_SOURCE_NAME = "sourceName"; private QualityGatesWsParameters() { // prevent instantiation diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java index 570ae99a186..87e54e916ed 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java @@ -68,6 +68,12 @@ public class QualityGatesWsSupport { "No quality gate has been found for id %s in organization %s", qualityGateUuid, organization.getName()); } + public QGateWithOrgDto getByOrganizationAndName(DbSession dbSession, OrganizationDto organization, String qualityGateName) { + return checkFound( + dbClient.qualityGateDao().selectByOrganizationAndName(dbSession, organization, qualityGateName), + "No quality gate has been found for name %s in organization %s", qualityGateName, organization.getName()); + } + QualityGateConditionDto getCondition(DbSession dbSession, String uuid) { return checkFound(dbClient.gateConditionDao().selectByUuid(uuid, dbSession), "No quality gate condition with uuid '%s'", uuid); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/RenameAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/RenameAction.java index df86210c0b2..acfb1487e0f 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/RenameAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/RenameAction.java @@ -19,6 +19,7 @@ */ package org.sonar.server.qualitygate.ws; +import org.sonar.api.server.ws.Change; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; @@ -31,6 +32,7 @@ import org.sonarqube.ws.Qualitygates.QualityGate; import static com.google.common.base.Preconditions.checkArgument; import static org.sonar.server.qualitygate.ws.CreateAction.NAME_MAXIMUM_LENGTH; +import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_CURRENT_NAME; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ID; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_NAME; import static org.sonar.server.ws.WsUtils.writeProtobuf; @@ -50,39 +52,60 @@ public class RenameAction implements QualityGatesWsAction { WebService.NewAction action = controller.createAction("rename") .setPost(true) .setDescription("Rename a Quality Gate.
" + - "Requires the 'Administer Quality Gates' permission.") + "Either 'id' or 'currentName' must be specified. Requires the 'Administer Quality Gates' permission.") .setSince("4.3") + .setChangelog( + new Change("8.4", "Parameter 'currentName' added"), + new Change("8.4", "Parameter 'id' is deprecated. Use 'currentName' instead.")) .setHandler(this); action.createParam(PARAM_ID) - .setRequired(true) - .setDescription("ID of the quality gate to rename") + .setRequired(false) + .setDeprecatedSince("8.4") + .setDescription("ID of the quality gate to rename. This parameter is deprecated. Use 'currentName' instead.") .setExampleValue("1"); + action.createParam(PARAM_CURRENT_NAME) + .setRequired(false) + .setMaximumLength(NAME_MAXIMUM_LENGTH) + .setSince("8.4") + .setDescription("Current name of the quality gate") + .setExampleValue("My Quality Gate"); + action.createParam(PARAM_NAME) .setRequired(true) .setMaximumLength(NAME_MAXIMUM_LENGTH) .setDescription("New name of the quality gate") - .setExampleValue("My Quality Gate"); + .setExampleValue("My New Quality Gate"); wsSupport.createOrganizationParam(action); } @Override public void handle(Request request, Response response) { - String uuid = request.mandatoryParam(PARAM_ID); + String uuid = request.param(PARAM_ID); + String currentName = request.param(PARAM_CURRENT_NAME); + + checkArgument(uuid != null ^ currentName != null, "One of 'id' or 'currentName' must be provided, and not both"); + try (DbSession dbSession = dbClient.openSession(false)) { OrganizationDto organization = wsSupport.getOrganization(dbSession, request); - QualityGateDto qualityGate = rename(dbSession, organization, uuid, request.mandatoryParam(PARAM_NAME)); + + QGateWithOrgDto qualityGate; + if (uuid != null) { + qualityGate = wsSupport.getByOrganizationAndUuid(dbSession, organization, uuid); + } else { + qualityGate = wsSupport.getByOrganizationAndName(dbSession, organization, currentName); + } + QualityGateDto renamedQualityGate = rename(dbSession, organization, qualityGate, request.mandatoryParam(PARAM_NAME)); writeProtobuf(QualityGate.newBuilder() - .setId(qualityGate.getUuid()) - .setName(qualityGate.getName()) + .setId(renamedQualityGate.getUuid()) + .setName(renamedQualityGate.getName()) .build(), request, response); } } - private QualityGateDto rename(DbSession dbSession, OrganizationDto organization, String uuid, String name) { - QGateWithOrgDto qualityGate = wsSupport.getByOrganizationAndUuid(dbSession, organization, uuid); + private QualityGateDto rename(DbSession dbSession, OrganizationDto organization, QGateWithOrgDto qualityGate, String name) { wsSupport.checkCanEdit(qualityGate); checkNotAlreadyExists(dbSession, organization, qualityGate, name); qualityGate.setName(name); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java index 06b8c226ebe..fd37423255e 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java @@ -38,11 +38,14 @@ import org.sonar.db.qualitygate.QGateWithOrgDto; import org.sonar.server.user.UserSession; import org.sonarqube.ws.Qualitygates; +import static com.google.common.base.Preconditions.checkArgument; import static java.util.stream.Collectors.toList; import static org.sonar.api.server.ws.WebService.Param.SELECTED; import static org.sonar.api.utils.Paging.forPageIndex; import static org.sonar.db.qualitygate.ProjectQgateAssociationQuery.ANY; +import static org.sonar.server.qualitygate.ws.CreateAction.NAME_MAXIMUM_LENGTH; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GATE_ID; +import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GATE_NAME; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PAGE; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PAGE_SIZE; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_QUERY; @@ -64,20 +67,30 @@ public class SearchAction implements QualityGatesWsAction { public void define(WebService.NewController controller) { WebService.NewAction action = controller.createAction("search") .setDescription("Search for projects associated (or not) to a quality gate.
" + - "Only authorized projects for current user will be returned.") + "Only authorized projects for the current user will be returned.") .setSince("4.3") .setResponseExample(Resources.getResource(this.getClass(), "search-example.json")) .setChangelog( new Change("7.9", "New field 'paging' in response"), new Change("7.9", "New field 'key' returning the project key in 'results' response"), - new Change("7.9", "Field 'more' is deprecated in the response")) + new Change("7.9", "Field 'more' is deprecated in the response"), + new Change("8.4", "Parameter 'gateName' added"), + new Change("8.4", "Parameter 'gateId' is deprecated. Use 'gateName' instead.")) .setHandler(this); action.createParam(PARAM_GATE_ID) - .setDescription("Quality Gate ID") - .setRequired(true) + .setDescription("Quality Gate ID. This parameter is deprecated. Use 'gateName' instead.") + .setRequired(false) + .setDeprecatedSince("8.4") .setExampleValue("1"); + action.createParam(PARAM_GATE_NAME) + .setDescription("Quality Gate name") + .setRequired(false) + .setMaximumLength(NAME_MAXIMUM_LENGTH) + .setSince("8.4") + .setExampleValue("SonarSource Way"); + action.createParam(PARAM_QUERY) .setDescription("To search for projects containing this string. If this parameter is set, \"selected\" is set to \"all\".") .setExampleValue("abc"); @@ -101,7 +114,18 @@ public class SearchAction implements QualityGatesWsAction { try (DbSession dbSession = dbClient.openSession(false)) { OrganizationDto organization = wsSupport.getOrganization(dbSession, request); - QGateWithOrgDto qualityGate = wsSupport.getByOrganizationAndUuid(dbSession, organization, request.mandatoryParam(PARAM_GATE_ID)); + + String gateUuid = request.param(PARAM_GATE_ID); + String gateName = request.param(PARAM_GATE_NAME); + + checkArgument(gateName != null ^ gateUuid != null, "One of 'gateId' or 'gateName' must be provided, and not both"); + + QGateWithOrgDto qualityGate; + if (gateUuid != null) { + qualityGate = wsSupport.getByOrganizationAndUuid(dbSession, organization, gateUuid); + } else { + qualityGate = wsSupport.getByOrganizationAndName(dbSession, organization, gateName); + } ProjectQgateAssociationQuery projectQgateAssociationQuery = ProjectQgateAssociationQuery.builder() .qualityGate(qualityGate) diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/SelectAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/SelectAction.java index 43355abe7eb..34f3199cba2 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/SelectAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/SelectAction.java @@ -30,8 +30,11 @@ import org.sonar.db.project.ProjectDto; import org.sonar.db.qualitygate.QGateWithOrgDto; import org.sonar.db.qualitygate.QualityGateDto; +import static com.google.common.base.Preconditions.checkArgument; +import static org.sonar.server.qualitygate.ws.CreateAction.NAME_MAXIMUM_LENGTH; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.ACTION_SELECT; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GATE_ID; +import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GATE_NAME; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PROJECT_KEY; import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; @@ -56,13 +59,24 @@ public class SelectAction implements QualityGatesWsAction { .setPost(true) .setSince("4.3") .setHandler(this) - .setChangelog(new Change("8.3", "The parameter 'projectId' was removed")); + .setChangelog( + new Change("8.3", "The parameter 'projectId' was removed"), + new Change("8.4", "Parameter 'gateName' added"), + new Change("8.4", "Parameter 'gateId' is deprecated. Use 'gateName' instead.")); action.createParam(PARAM_GATE_ID) - .setDescription("Quality gate id") - .setRequired(true) + .setDescription("Quality gate ID. This parameter is deprecated. Use 'gateName' instead.") + .setRequired(false) + .setDeprecatedSince("8.4") .setExampleValue("1"); + action.createParam(PARAM_GATE_NAME) + .setRequired(false) + .setDescription("Name of the quality gate") + .setMaximumLength(NAME_MAXIMUM_LENGTH) + .setSince("8.4") + .setExampleValue("SonarSource way"); + action.createParam(PARAM_PROJECT_KEY) .setRequired(true) .setDescription("Project key") @@ -74,12 +88,21 @@ public class SelectAction implements QualityGatesWsAction { @Override public void handle(Request request, Response response) { - String gateUuid = request.mandatoryParam(PARAM_GATE_ID); + String gateUuid = request.param(PARAM_GATE_ID); + String gateName = request.param(PARAM_GATE_NAME); String projectKey = request.mandatoryParam(PARAM_PROJECT_KEY); + checkArgument(gateName != null ^ gateUuid != null, "Either 'gateId' or 'gateName' must be provided, and not both"); + + try (DbSession dbSession = dbClient.openSession(false)) { OrganizationDto organization = wsSupport.getOrganization(dbSession, request); - QGateWithOrgDto qualityGate = wsSupport.getByOrganizationAndUuid(dbSession, organization, gateUuid); + QGateWithOrgDto qualityGate; + if (gateUuid != null) { + qualityGate = wsSupport.getByOrganizationAndUuid(dbSession, organization, gateUuid); + } else { + qualityGate = wsSupport.getByOrganizationAndName(dbSession, organization, gateName); + } ProjectDto project = wsSupport.getProject(dbSession, organization, projectKey); wsSupport.checkCanAdminProject(organization, project); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/SetAsDefaultAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/SetAsDefaultAction.java index 3ae2b14a163..4900f544662 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/SetAsDefaultAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/SetAsDefaultAction.java @@ -19,6 +19,7 @@ */ package org.sonar.server.qualitygate.ws; +import org.sonar.api.server.ws.Change; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; @@ -28,8 +29,11 @@ import org.sonar.db.organization.OrganizationDto; import org.sonar.db.qualitygate.QualityGateDto; import org.sonar.server.user.UserSession; +import static com.google.common.base.Preconditions.checkArgument; import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_GATES; +import static org.sonar.server.qualitygate.ws.CreateAction.NAME_MAXIMUM_LENGTH; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ID; +import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_NAME; public class SetAsDefaultAction implements QualityGatesWsAction { @@ -47,27 +51,46 @@ public class SetAsDefaultAction implements QualityGatesWsAction { public void define(WebService.NewController controller) { WebService.NewAction action = controller.createAction("set_as_default") .setDescription("Set a quality gate as the default quality gate.
" + - "Requires the 'Administer Quality Gates' permission.") + "Either 'id' or 'name' must be specified. Requires the 'Administer Quality Gates' permission.") .setSince("4.3") + .setChangelog( + new Change("8.4", "Parameter 'name' added"), + new Change("8.4", "Parameter 'id' is deprecated. Use 'name' instead.")) .setPost(true) .setHandler(this); - action.createParam(QualityGatesWsParameters.PARAM_ID) - .setDescription("ID of the quality gate to set as default") - .setRequired(true) + action.createParam(PARAM_ID) + .setDescription("ID of the quality gate to set as default. This parameter is deprecated. Use 'name' instead.") + .setDeprecatedSince("8.4") + .setRequired(false) .setExampleValue("1"); + action.createParam(PARAM_NAME) + .setDescription("Name of the quality gate to set as default") + .setRequired(false) + .setMaximumLength(NAME_MAXIMUM_LENGTH) + .setSince("8.4") + .setExampleValue("SonarSource Way"); + wsSupport.createOrganizationParam(action); } @Override public void handle(Request request, Response response) { - String uuid = request.mandatoryParam(PARAM_ID); + String uuid = request.param(PARAM_ID); + String name = request.param(PARAM_NAME); + checkArgument(name != null ^ uuid != null, "One of 'id' or 'name' must be provided, and not both"); try (DbSession dbSession = dbClient.openSession(false)) { OrganizationDto organization = wsSupport.getOrganization(dbSession, request); userSession.checkPermission(ADMINISTER_QUALITY_GATES, organization); - QualityGateDto qualityGate = wsSupport.getByOrganizationAndUuid(dbSession, organization, uuid); + QualityGateDto qualityGate; + + if (uuid != null) { + qualityGate = wsSupport.getByOrganizationAndUuid(dbSession, organization, uuid); + } else { + qualityGate = wsSupport.getByOrganizationAndName(dbSession, organization, name); + } organization.setDefaultQualityGateUuid(qualityGate.getUuid()); dbClient.organizationDao().update(dbSession, organization); dbSession.commit(); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java index 831e85d63cb..2387b363252 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java @@ -70,7 +70,8 @@ public class ShowAction implements QualityGatesWsAction { .setChangelog( new Change("7.6", "'period' and 'warning' fields of conditions are removed from the response"), new Change("7.0", "'isBuiltIn' field is added to the response"), - new Change("7.0", "'actions' field is added in the response")) + new Change("7.0", "'actions' field is added in the response"), + new Change("8.4", "Field 'id' in the response is deprecated.")) .setHandler(this); action.createParam(PARAM_ID) diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/CopyActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/CopyActionTest.java index f4052bdf7e7..f97d5147aaa 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/CopyActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/CopyActionTest.java @@ -90,7 +90,8 @@ public class CopyActionTest { assertThat(action.params()) .extracting(WebService.Param::key, WebService.Param::isRequired) .containsExactlyInAnyOrder( - tuple("id", true), + tuple("id", false), + tuple("sourceName", false), tuple("organization", false), tuple("name", true)); } @@ -232,7 +233,7 @@ public class CopyActionTest { userSession.addPermission(ADMINISTER_QUALITY_GATES, organization); expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("The 'id' parameter is missing"); + expectedException.expectMessage("Either 'id' or 'sourceName' must be provided, and not both"); ws.newRequest() .setParam(PARAM_NAME, "new-name") diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/CreateConditionActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/CreateConditionActionTest.java index c9e65b68511..c7c50703d66 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/CreateConditionActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/CreateConditionActionTest.java @@ -240,7 +240,8 @@ public class CreateConditionActionTest { assertThat(action.params()) .extracting(WebService.Param::key, WebService.Param::isRequired) .containsExactlyInAnyOrder( - tuple("gateId", true), + tuple("gateId", false), + tuple("gateName", false), tuple("metric", true), tuple("error", true), tuple("op", false), diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/DestroyActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/DestroyActionTest.java index 76158f5ef62..a679254307f 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/DestroyActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/DestroyActionTest.java @@ -164,7 +164,7 @@ public class DestroyActionTest { OrganizationDto organization = db.organizations().insert(); userSession.addPermission(ADMINISTER_QUALITY_GATES, organization); - expectedException.expect(IllegalArgumentException.class); + expectedException.expect(NotFoundException.class); ws.newRequest() .setParam(PARAM_ID, EMPTY) @@ -225,7 +225,8 @@ public class DestroyActionTest { assertThat(action.params()) .extracting(WebService.Param::key, WebService.Param::isRequired) .containsExactlyInAnyOrder( - tuple("id", true), + tuple("id", false), + tuple("name", false), tuple("organization", false)); } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/GetByProjectActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/GetByProjectActionTest.java index 4f0eb37cf4b..406dcf9f899 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/GetByProjectActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/GetByProjectActionTest.java @@ -22,7 +22,6 @@ package org.sonar.server.qualitygate.ws; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.sonar.api.server.ws.Change; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.System2; import org.sonar.api.web.UserRole; @@ -68,10 +67,7 @@ public class GetByProjectActionTest { assertThat(action.description()).isNotEmpty(); assertThat(action.isInternal()).isFalse(); assertThat(action.since()).isEqualTo("6.1"); - assertThat(action.changelog()).extracting(Change::getVersion, Change::getDescription).containsExactlyInAnyOrder( - tuple("6.6", "The parameter 'projectId' has been removed"), - tuple("6.6", "The parameter 'projectKey' has been renamed to 'project'"), - tuple("6.6", "This webservice is now part of the public API")); + assertThat(action.changelog()).isNotEmpty(); assertThat(action.params()) .extracting(WebService.Param::key, WebService.Param::isRequired) .containsExactlyInAnyOrder( diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/ListActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/ListActionTest.java index 831674a1db1..8dfef06364d 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/ListActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/ListActionTest.java @@ -22,7 +22,6 @@ package org.sonar.server.qualitygate.ws; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.sonar.api.server.ws.Change; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbClient; import org.sonar.db.DbTester; @@ -246,12 +245,7 @@ public class ListActionTest { assertThat(action.key()).isEqualTo("list"); assertThat(action.isPost()).isFalse(); assertThat(action.isInternal()).isFalse(); - assertThat(action.changelog()).extracting(Change::getVersion, Change::getDescription) - .containsExactlyInAnyOrder( - tuple("7.0", "'isDefault' field is added on quality gate"), - tuple("7.0", "'default' field on root level is deprecated"), - tuple("7.0", "'isBuiltIn' field is added in the response"), - tuple("7.0", "'actions' fields are added in the response")); + assertThat(action.changelog()).isNotEmpty(); assertThat(action.params()).extracting(WebService.Param::key, WebService.Param::isRequired) .containsExactlyInAnyOrder(tuple("organization", false)); } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/RenameActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/RenameActionTest.java index bb2cd9962ba..68b096b5a5f 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/RenameActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/RenameActionTest.java @@ -61,11 +61,12 @@ public class RenameActionTest { WebService.Action action = ws.getDef(); assertThat(action.key()).isEqualTo("rename"); assertThat(action.since()).isEqualTo("4.3"); - assertThat(action.changelog()).isEmpty(); + assertThat(action.changelog()).isNotEmpty(); assertThat(action.params()) .extracting(WebService.Param::key, WebService.Param::isRequired) .containsExactlyInAnyOrder( - tuple("id", true), + tuple("id", false), + tuple("currentName", false), tuple("name", true), tuple("organization", false)); } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/SearchActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/SearchActionTest.java index 6650f7c483e..2683259ab6e 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/SearchActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/SearchActionTest.java @@ -400,7 +400,8 @@ public class SearchActionTest { assertThat(action.params()) .extracting(WebService.Param::key, WebService.Param::isRequired) .containsExactlyInAnyOrder( - tuple("gateId", true), + tuple("gateId", false), + tuple("gateName", false), tuple("query", false), tuple("organization", false), tuple("selected", false), diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/SetAsDefaultActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/SetAsDefaultActionTest.java new file mode 100644 index 00000000000..a3e430feee3 --- /dev/null +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/SetAsDefaultActionTest.java @@ -0,0 +1,80 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 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.qualitygate.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.db.DbTester; +import org.sonar.db.organization.OrganizationDto; +import org.sonar.db.qualitygate.QGateWithOrgDto; +import org.sonar.server.component.TestComponentFinder; +import org.sonar.server.organization.DefaultOrganizationProvider; +import org.sonar.server.organization.TestDefaultOrganizationProvider; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.WsActionTester; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.tuple; +import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_GATES; + +public class SetAsDefaultActionTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + + private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); + + private WsActionTester ws = new WsActionTester( + new SetAsDefaultAction(db.getDbClient(), userSession, new QualityGatesWsSupport(db.getDbClient(), userSession, defaultOrganizationProvider, TestComponentFinder.from(db)))); + + @Test + public void verify_definition() { + WebService.Action action = ws.getDef(); + assertThat(action.key()).isEqualTo("set_as_default"); + assertThat(action.since()).isEqualTo("4.3"); + assertThat(action.changelog()).isNotEmpty(); + assertThat(action.params()) + .extracting(WebService.Param::key, WebService.Param::isRequired) + .containsExactlyInAnyOrder( + tuple("id", false), + tuple("organization", false), + tuple("name", false)); + } + + @Test + public void set_default() { + OrganizationDto organization = db.organizations().insert(); + userSession.logIn("john").addPermission(ADMINISTER_QUALITY_GATES, organization); + QGateWithOrgDto qualityGate = db.qualityGates().insertQualityGate(organization, qg -> qg.setName("name")); + + ws.newRequest() + .setParam("name", "name") + .setParam("organization", organization.getKey()) + .execute(); + + assertThat(db.getDbClient().organizationDao().selectByKey(db.getSession(), organization.getKey()).get().getDefaultQualityGateUuid()).isEqualTo(qualityGate.getUuid()); + } +} -- 2.39.5