]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7924 Modify WS api/qualitygates/select to accept project key (#1126)
authorStas Vilchik <vilchiks@gmail.com>
Fri, 29 Jul 2016 15:41:48 +0000 (17:41 +0200)
committerGitHub <noreply@github.com>
Fri, 29 Jul 2016 15:41:48 +0000 (17:41 +0200)
server/sonar-server/src/main/java/org/sonar/server/component/ComponentFinder.java
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SelectAction.java
server/sonar-server/src/test/java/org/sonar/server/component/ComponentFinderTest.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/AppActionTest.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGatesWsTest.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/SelectActionTest.java [new file with mode: 0644]
sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesService.java
sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/SelectWsRequest.java [new file with mode: 0644]
sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/QualityGatesServiceTest.java [new file with mode: 0644]

index 41554dd51cee82579ea7b61e1e12acecba8d30f1..1f4efe50b402b30f50b60f3de9147a58a368a31d 100644 (file)
@@ -37,6 +37,7 @@ import static org.sonar.server.ws.WsUtils.checkRequest;
 
 public class ComponentFinder {
   private static final String MSG_COMPONENT_ID_OR_KEY_TEMPLATE = "Either '%s' or '%s' must be provided, not both";
+  public static final String MSG_PARAMETER_MUST_NOT_BE_EMPTY = "The '%s' parameter must not be empty";
 
   private final DbClient dbClient;
 
@@ -48,11 +49,22 @@ public class ComponentFinder {
     checkArgument(componentUuid != null ^ componentKey != null, MSG_COMPONENT_ID_OR_KEY_TEMPLATE, parameterNames.getUuidParam(), parameterNames.getKeyParam());
 
     if (componentUuid != null) {
-      checkArgument(!componentUuid.isEmpty(), "The '%s' parameter must not be empty", parameterNames.getUuidParam());
+      checkArgument(!componentUuid.isEmpty(), MSG_PARAMETER_MUST_NOT_BE_EMPTY, parameterNames.getUuidParam());
       return getByUuid(dbSession, componentUuid);
     }
 
-    checkArgument(!componentKey.isEmpty(), "The '%s' parameter must not be empty", parameterNames.getKeyParam());
+    checkArgument(!componentKey.isEmpty(), MSG_PARAMETER_MUST_NOT_BE_EMPTY, parameterNames.getKeyParam());
+    return getByKey(dbSession, componentKey);
+  }
+
+  public ComponentDto getByIdOrKey(DbSession dbSession, @Nullable Long componentId, @Nullable String componentKey, ParamNames parameterNames) {
+    checkArgument(componentId != null ^ componentKey != null, MSG_COMPONENT_ID_OR_KEY_TEMPLATE, parameterNames.getUuidParam(), parameterNames.getKeyParam());
+
+    if (componentId != null) {
+      return getById(dbSession, componentId);
+    }
+
+    checkArgument(!componentKey.isEmpty(), MSG_PARAMETER_MUST_NOT_BE_EMPTY, parameterNames.getKeyParam());
     return getByKey(dbSession, componentKey);
   }
 
@@ -64,6 +76,10 @@ public class ComponentFinder {
     return getIfPresentOrFail(dbClient.componentDao().selectByUuid(dbSession, uuid), format("Component id '%s' not found", uuid));
   }
 
+  public ComponentDto getById(DbSession dbSession, long id) {
+    return getIfPresentOrFail(dbClient.componentDao().selectById(dbSession, id), format("Component id '%s' not found", id));
+  }
+
   /**
    * A project can be:
    * <ul>
index 8f55ba0d85efdfe8fee2825c641fb176a7ca9ea2..5e16247924413b8ea9ce354f20da6ae96a657e5c 100644 (file)
  */
 package org.sonar.server.qualitygate.ws;
 
+import org.elasticsearch.common.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.server.qualitygate.QualityGates;
-import org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.property.PropertyDto;
+import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.component.ComponentFinder.ParamNames;
+import org.sonar.server.user.UserSession;
+import org.sonarqube.ws.client.qualitygate.SelectWsRequest;
 
+import static org.sonar.server.qualitygate.QualityGates.SONAR_QUALITYGATE_PROPERTY;
+import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
+import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
+import static org.sonar.server.ws.WsUtils.checkFound;
+import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_GATE_ID;
 import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_ID;
+import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_KEY;
 
 public class SelectAction implements QualityGatesWsAction {
+  private final DbClient dbClient;
+  private final UserSession userSession;
+  private final ComponentFinder componentFinder;
 
-  private final QualityGates qualityGates;
-
-  public SelectAction(QualityGates qualityGates) {
-    this.qualityGates = qualityGates;
+  public SelectAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder) {
+    this.dbClient = dbClient;
+    this.userSession = userSession;
+    this.componentFinder = componentFinder;
   }
 
   @Override
   public void define(WebService.NewController controller) {
     WebService.NewAction action = controller.createAction("select")
-      .setDescription("Associate a project to a quality gate. Require Administer Quality Gates permission")
+      .setDescription("Associate a project to a quality gate.<br>" +
+        "The '%s' or '%s' must be provided.<br>" +
+        "Require Administer Quality Gates permission.",
+        PARAM_PROJECT_ID, PARAM_PROJECT_KEY)
       .setPost(true)
       .setSince("4.3")
       .setHandler(this);
 
-    action.createParam(QualityGatesWsParameters.PARAM_GATE_ID)
-      .setDescription("Quality Gate ID")
+    action.createParam(PARAM_GATE_ID)
+      .setDescription("Quality gate id")
       .setRequired(true)
       .setExampleValue("1");
 
     action.createParam(PARAM_PROJECT_ID)
-      .setDescription("Project ID")
-      .setRequired(true)
-      .setExampleValue("12");
+      .setDescription("Project id")
+      .setExampleValue("12")
+      .setDeprecatedSince("6.1");
+
+    action.createParam(PARAM_PROJECT_KEY)
+      .setDescription("Project key")
+      .setExampleValue(KEY_PROJECT_EXAMPLE_001)
+      .setSince("6.1");
   }
 
   @Override
   public void handle(Request request, Response response) {
-    qualityGates.associateProject(QualityGatesWs.parseId(request, QualityGatesWsParameters.PARAM_GATE_ID), QualityGatesWs.parseId(request, PARAM_PROJECT_ID));
+    doHandle(toSelectWsRequest(request));
     response.noContent();
   }
 
+  private void doHandle(SelectWsRequest request) {
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      checkQualityGate(dbClient, request.getGateId());
+      ComponentDto project = getProject(dbSession, request.getProjectId(), request.getProjectKey());
+
+      dbClient.propertiesDao().insertProperty(dbSession, new PropertyDto()
+        .setKey(SONAR_QUALITYGATE_PROPERTY)
+        .setResourceId(project.getId())
+        .setValue(String.valueOf(request.getGateId())));
+
+      dbSession.commit();
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  private static SelectWsRequest toSelectWsRequest(Request request) {
+    return new SelectWsRequest()
+      .setGateId(request.mandatoryParamAsLong(PARAM_GATE_ID))
+      .setProjectId(request.paramAsLong(PARAM_PROJECT_ID))
+      .setProjectKey(request.param(PARAM_PROJECT_KEY));
+  }
+
+  private ComponentDto getProject(DbSession dbSession, @Nullable Long projectId, @Nullable String projectKey) {
+    ComponentDto project = componentFinder.getByIdOrKey(dbSession, projectId, projectKey, ParamNames.PROJECT_ID_AND_KEY);
+
+    if (!userSession.hasPermission(GlobalPermissions.QUALITY_GATE_ADMIN) &&
+      !userSession.hasComponentUuidPermission(UserRole.ADMIN, project.uuid())) {
+      throw insufficientPrivilegesException();
+    }
+
+    return project;
+  }
+
+  private static void checkQualityGate(DbClient dbClient, long id) {
+    checkFound(dbClient.qualityGateDao().selectById(id), "There is no quality gate with id=" + id);
+  }
 }
index 8902b9a0a599b1d0484722a24cfd38c2ec7b748c..4df8ea6cef012cb191e282c7bf1018fd657be237 100644 (file)
@@ -94,6 +94,47 @@ public class ComponentFinderTest {
     underTest.getByUuidOrKey(dbSession, null, "project-key", ID_AND_KEY);
   }
 
+  @Test
+  public void getByIdOrKey_fail_when_id_and_key_are_null() {
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Either 'id' or 'key' must be provided, not both");
+
+    underTest.getByIdOrKey(dbSession, null, null, ID_AND_KEY);
+  }
+
+  @Test
+  public void getByIdOrKey_fail_when_both_id_and_key_are_provided() {
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Either 'id' or 'key' must be provided, not both");
+
+    underTest.getByIdOrKey(dbSession, 1L, "project-key", ID_AND_KEY);
+  }
+
+  @Test
+  public void getByIdOrKey_fail_when_key_is_empty() {
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("The 'key' parameter must not be empty");
+
+    underTest.getByIdOrKey(dbSession, null, "", ID_AND_KEY);
+  }
+
+
+  @Test
+  public void getByIdOrKey_fail_when_component_id_not_found() {
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage("Component id '175' not found");
+
+    underTest.getByIdOrKey(dbSession, 175L, null, ID_AND_KEY);
+  }
+
+  @Test
+  public void getByIdOrKey_fail_when_component_key_not_found() {
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage("Component key 'project-key' not found");
+
+    underTest.getByIdOrKey(dbSession, null, "project-key", ID_AND_KEY);
+  }
+
   @Test
   public void get_component_by_uuid() {
     componentDb.insertComponent(newProjectDto("project-uuid"));
@@ -111,4 +152,22 @@ public class ComponentFinderTest {
 
     assertThat(component.key()).isEqualTo("project-key");
   }
+
+  @Test
+  public void getByIdOrKey_get_component_by_id() {
+    ComponentDto source = componentDb.insertComponent(newProjectDto());
+
+    ComponentDto component = underTest.getByIdOrKey(dbSession, source.getId(), null, ID_AND_KEY);
+
+    assertThat(component.getId()).isEqualTo(source.getId());
+  }
+
+  @Test
+  public void getByIdOrKey_get_component_by_key() {
+    componentDb.insertComponent(newProjectDto().setKey("project-key"));
+
+    ComponentDto component = underTest.getByIdOrKey(dbSession, null, "project-key", ID_AND_KEY);
+
+    assertThat(component.key()).isEqualTo("project-key");
+  }
 }
index 70b98ba5878ae28d2777ab734c9e213bee26e8c7..619fee9c63886e746666e1cf63fef330f587f526 100644 (file)
@@ -32,8 +32,11 @@ import org.sonar.api.i18n.I18n;
 import org.sonar.api.measures.Metric;
 import org.sonar.api.measures.Metric.ValueType;
 import org.sonar.core.timemachine.Periods;
+import org.sonar.db.DbClient;
+import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.qualitygate.QgateProjectFinder;
 import org.sonar.server.qualitygate.QualityGates;
+import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.WsTester;
 
 import java.util.Collection;
@@ -62,12 +65,14 @@ public class AppActionTest {
 
   @Before
   public void setUp() {
+    SelectAction selectAction = new SelectAction(mock(DbClient.class), mock(UserSessionRule.class), mock(ComponentFinder.class));
+
     tester = new WsTester(new QualityGatesWs(
       new ListAction(qGates), new ShowAction(qGates), new SearchAction(mock(QgateProjectFinder.class)),
       new CreateAction(qGates), new CopyAction(qGates), new DestroyAction(qGates), new RenameAction(qGates),
       new SetAsDefaultAction(qGates), new UnsetDefaultAction(qGates),
       new CreateConditionAction(qGates), new UpdateConditionAction(qGates), new DeleteConditionAction(qGates),
-      new SelectAction(qGates), new DeselectAction(qGates), new AppAction(qGates)));
+      selectAction, new DeselectAction(qGates), new AppAction(qGates)));
   }
 
   @Test
index 7ae85a1d2f50257e0d9f95dfc55c13d17fcf601a..fce093f1e564d8959d0bd5bfe1b291ae8c21e67b 100644 (file)
@@ -21,6 +21,7 @@ package org.sonar.server.qualitygate.ws;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
+import java.util.List;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -29,18 +30,19 @@ import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.sonar.api.server.ws.WebService.Action;
 import org.sonar.api.server.ws.WebService.Controller;
+import org.sonar.db.DbClient;
 import org.sonar.db.qualitygate.ProjectQgateAssociation;
 import org.sonar.db.qualitygate.ProjectQgateAssociationQuery;
 import org.sonar.db.qualitygate.QualityGateConditionDto;
 import org.sonar.db.qualitygate.QualityGateDto;
+import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.qualitygate.QgateProjectFinder;
 import org.sonar.server.qualitygate.QgateProjectFinder.Association;
 import org.sonar.server.qualitygate.QualityGates;
+import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.WsTester;
 
-import java.util.List;
-
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
@@ -64,12 +66,14 @@ public class QualityGatesWsTest {
 
   @Before
   public void setUp() {
+    SelectAction selectAction = new SelectAction(mock(DbClient.class), mock(UserSessionRule.class), mock(ComponentFinder.class));
+
     tester = new WsTester(new QualityGatesWs(
       new ListAction(qGates), new ShowAction(qGates), new SearchAction(projectFinder),
       new CreateAction(qGates), new CopyAction(qGates), new DestroyAction(qGates), new RenameAction(qGates),
       new SetAsDefaultAction(qGates), new UnsetDefaultAction(qGates),
       new CreateConditionAction(qGates), new UpdateConditionAction(qGates), new DeleteConditionAction(qGates),
-      new SelectAction(qGates), new DeselectAction(qGates), new AppAction(qGates)));
+      selectAction, new DeselectAction(qGates), new AppAction(qGates)));
   }
 
   @Test
@@ -426,18 +430,6 @@ public class QualityGatesWsTest {
     assertThat(query.membership()).isEqualTo(ProjectQgateAssociationQuery.IN);
   }
 
-  @Test
-  public void select_nominal() throws Exception {
-    long gateId = 42L;
-    long projectId = 666L;
-    tester.newPostRequest("api/qualitygates", "select")
-      .setParam("gateId", Long.toString(gateId))
-      .setParam("projectId", Long.toString(projectId))
-      .execute()
-      .assertNoContent();
-    verify(qGates).associateProject(gateId, projectId);
-  }
-
   @Test
   public void deselect_nominal() throws Exception {
     long gateId = 42L;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/SelectActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/SelectActionTest.java
new file mode 100644 (file)
index 0000000..3cfc31a
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.api.web.UserRole;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.qualitygate.QualityGateDto;
+import org.sonar.server.component.ComponentFinder;
+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 static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.core.permission.GlobalPermissions.QUALITY_GATE_ADMIN;
+import static org.sonar.core.permission.GlobalPermissions.QUALITY_PROFILE_ADMIN;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
+import static org.sonar.db.component.ComponentTesting.newProjectDto;
+import static org.sonar.server.qualitygate.QualityGates.SONAR_QUALITYGATE_PROPERTY;
+
+public class SelectActionTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
+  @Rule
+  public DbTester db = DbTester.create(System2.INSTANCE);
+  DbClient dbClient = db.getDbClient();
+  DbSession dbSession = db.getSession();
+  ComponentDbTester componentDb = new ComponentDbTester(db);
+
+  WsActionTester ws;
+
+  SelectAction underTest;
+
+  @Before
+  public void setUp() {
+    ComponentFinder componentFinder = new ComponentFinder(dbClient);
+    underTest = new SelectAction(dbClient, userSession, componentFinder);
+    ws = new WsActionTester(underTest);
+
+    userSession.login("login").setGlobalPermissions(QUALITY_GATE_ADMIN);
+  }
+
+  @Test
+  public void select_by_id() throws Exception {
+    ComponentDto project = insertProject();
+    QualityGateDto gate = insertQualityGate();
+    String gateId = String.valueOf(gate.getId());
+
+    callById(gateId, project.getId());
+    assertSelected(gateId, project.getId());
+  }
+
+  @Test
+  public void select_by_key() throws Exception {
+    ComponentDto project = insertProject();
+    QualityGateDto gate = insertQualityGate();
+    String gateId = String.valueOf(gate.getId());
+
+    callByKey(gateId, project.getKey());
+    assertSelected(gateId, project.getId());
+  }
+
+  @Test
+  public void project_admin() throws Exception {
+    ComponentDto project = insertProject();
+    QualityGateDto gate = insertQualityGate();
+    String gateId = String.valueOf(gate.getId());
+
+    userSession.login("login").addProjectUuidPermissions(UserRole.ADMIN, project.uuid());
+
+    callByKey(gateId, project.getKey());
+    assertSelected(gateId, project.getId());
+  }
+
+  @Test
+  public void system_admin() throws Exception {
+    ComponentDto project = insertProject();
+    QualityGateDto gate = insertQualityGate();
+    String gateId = String.valueOf(gate.getId());
+
+    userSession.login("login").setGlobalPermissions(SYSTEM_ADMIN);
+
+    callByKey(gateId, project.getKey());
+    assertSelected(gateId, project.getId());;
+  }
+
+  @Test
+  public void fail_when_no_quality_gate() throws Exception {
+    ComponentDto project = insertProject();
+
+    expectedException.expect(NotFoundException.class);
+    callByKey("1", project.getKey());
+  }
+
+  @Test
+  public void fail_when_no_project_id() throws Exception {
+    QualityGateDto gate = insertQualityGate();
+    String gateId = String.valueOf(gate.getId());
+
+    expectedException.expect(NotFoundException.class);
+    callById(gateId, 1L);
+  }
+
+  @Test
+  public void fail_when_no_project_key() throws Exception {
+    QualityGateDto gate = insertQualityGate();
+    String gateId = String.valueOf(gate.getId());
+
+    expectedException.expect(NotFoundException.class);
+    callByKey(gateId, "unknown");
+  }
+
+  @Test
+  public void fail_when_anonymous() throws Exception {
+    ComponentDto project = insertProject();
+    QualityGateDto gate = insertQualityGate();
+    String gateId = String.valueOf(gate.getId());
+
+    userSession.anonymous();
+
+    expectedException.expect(ForbiddenException.class);
+    callByKey(gateId, project.getKey());
+  }
+
+  @Test
+  public void fail_when_not_project_admin() throws Exception {
+    ComponentDto project = insertProject();
+    QualityGateDto gate = insertQualityGate();
+    String gateId = String.valueOf(gate.getId());
+
+    userSession.login("login").addProjectUuidPermissions(UserRole.ISSUE_ADMIN, project.uuid());
+
+    expectedException.expect(ForbiddenException.class);
+    callByKey(gateId, project.getKey());
+  }
+
+  @Test
+  public void fail_when_not_quality_gates_admin() throws Exception {
+    ComponentDto project = insertProject();
+    QualityGateDto gate = insertQualityGate();
+    String gateId = String.valueOf(gate.getId());
+
+    userSession.login("login").setGlobalPermissions(QUALITY_PROFILE_ADMIN);
+
+    expectedException.expect(ForbiddenException.class);
+    callByKey(gateId, project.getKey());
+  }
+
+  private ComponentDto insertProject() {
+    return componentDb.insertComponent(newProjectDto());
+  }
+
+  private QualityGateDto insertQualityGate() {
+    QualityGateDto gate = new QualityGateDto().setName("Custom");
+    dbClient.qualityGateDao().insert(dbSession, gate);
+    dbSession.commit();
+    return gate;
+  }
+
+  private void callByKey(String gateId, String projectKey) {
+    ws.newRequest()
+      .setMethod("POST")
+      .setParam("gateId", String.valueOf(gateId))
+      .setParam("projectKey", projectKey)
+      .execute();
+  }
+
+  private void callById(String gateId, Long projectId) {
+    ws.newRequest()
+      .setMethod("POST")
+      .setParam("gateId", String.valueOf(gateId))
+      .setParam("projectId", String.valueOf(projectId))
+      .execute();
+  }
+
+  private void assertSelected(String gateId, Long projectId) {
+    assertThat(dbClient.propertiesDao().selectProjectProperty(projectId, SONAR_QUALITYGATE_PROPERTY).getValue()).isEqualTo(gateId);
+  }
+}
index bd00874f57a6ba11be01f767b17c5a198880f891..fa8a57ab4b9b7566fa595fe59c9ef39ef1f37cf4 100644 (file)
@@ -22,9 +22,11 @@ package org.sonarqube.ws.client.qualitygate;
 import org.sonarqube.ws.WsQualityGates.ProjectStatusWsResponse;
 import org.sonarqube.ws.client.BaseService;
 import org.sonarqube.ws.client.GetRequest;
+import org.sonarqube.ws.client.PostRequest;
 import org.sonarqube.ws.client.WsConnector;
 
 import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_ANALYSIS_ID;
+import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_GATE_ID;
 import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_ID;
 import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_KEY;
 
@@ -41,4 +43,11 @@ public class QualityGatesService extends BaseService {
       .setParam(PARAM_PROJECT_KEY, request.getProjectKey()),
       ProjectStatusWsResponse.parser());
   }
+
+  public void associateProject(SelectWsRequest request) {
+    call(new PostRequest(path("select"))
+      .setParam(PARAM_GATE_ID, request.getGateId())
+      .setParam(PARAM_PROJECT_ID, request.getProjectId())
+      .setParam(PARAM_PROJECT_KEY, request.getProjectKey()));
+  }
 }
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/SelectWsRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/SelectWsRequest.java
new file mode 100644 (file)
index 0000000..a3dc530
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.sonarqube.ws.client.qualitygate;
+
+import javax.annotation.CheckForNull;
+
+public class SelectWsRequest {
+  private long gateId;
+  private Long projectId;
+  private String projectKey;
+
+  public long getGateId() {
+    return gateId;
+  }
+
+  public SelectWsRequest setGateId(long gateId) {
+    this.gateId = gateId;
+    return this;
+  }
+
+  @CheckForNull
+  public Long getProjectId() {
+    return projectId;
+  }
+
+  public SelectWsRequest setProjectId(Long projectId) {
+    this.projectId = projectId;
+    return this;
+  }
+
+  @CheckForNull
+  public String getProjectKey() {
+    return projectKey;
+  }
+
+  public SelectWsRequest setProjectKey(String projectKey) {
+    this.projectKey = projectKey;
+    return this;
+  }
+}
diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/QualityGatesServiceTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/QualityGatesServiceTest.java
new file mode 100644 (file)
index 0000000..3000be6
--- /dev/null
@@ -0,0 +1,63 @@
+
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.sonarqube.ws.client.qualitygate;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonarqube.ws.client.PostRequest;
+import org.sonarqube.ws.client.ServiceTester;
+import org.sonarqube.ws.client.WsConnector;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_ID;
+import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_KEY;
+import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_GATE_ID;
+
+public class QualityGatesServiceTest {
+  private static final Long PROJECT_ID_VALUE = 195L;
+  private static final String PROJECT_KEY_VALUE = "project_key_value";
+  private static final Long GATE_ID_VALUE = 243L;
+
+  @Rule
+  public ServiceTester<QualityGatesService> serviceTester = new ServiceTester<>(new QualityGatesService(mock(WsConnector.class)));
+
+  private QualityGatesService underTest = serviceTester.getInstanceUnderTest();
+
+  @Test
+  public void associate_project_does_POST_request() {
+    underTest.associateProject(new SelectWsRequest()
+      .setGateId(GATE_ID_VALUE)
+      .setProjectId(PROJECT_ID_VALUE)
+      .setProjectKey(PROJECT_KEY_VALUE));
+
+    assertThat(serviceTester.getPostParser()).isNull();
+
+    PostRequest postRequest = serviceTester.getPostRequest();
+
+    serviceTester.assertThat(postRequest)
+      .hasPath("select")
+      .hasParam(PARAM_GATE_ID, String.valueOf(GATE_ID_VALUE))
+      .hasParam(PARAM_PROJECT_ID, String.valueOf(PROJECT_ID_VALUE))
+      .hasParam(PARAM_PROJECT_KEY, PROJECT_KEY_VALUE)
+      .andNoOtherParam();
+  }
+}