]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7528 WS api/measures/component handles developer measures 889/head
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Wed, 6 Apr 2016 17:19:51 +0000 (19:19 +0200)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Thu, 7 Apr 2016 11:55:39 +0000 (13:55 +0200)
server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentAction.java
server/sonar-server/src/test/java/org/sonar/server/measure/ws/ComponentActionTest.java
sonar-db/src/main/java/org/sonar/db/measure/MeasureMapper.java
sonar-db/src/main/resources/org/sonar/db/measure/MeasureMapper.xml
sonar-ws/src/main/java/org/sonarqube/ws/client/measure/ComponentWsRequest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/measure/MeasuresService.java

index 2c8b748e8ae452bbcda7722aba09d9d9243bf0e6..4ee10da7ab69c9fbbb168b02abc97a0a73ee0da1 100644 (file)
@@ -30,6 +30,7 @@ import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.sonar.api.resources.Qualifiers;
 import org.sonar.api.server.ws.Request;
@@ -57,11 +58,12 @@ import static com.google.common.base.Objects.firstNonNull;
 import static com.google.common.collect.FluentIterable.from;
 import static java.lang.String.format;
 import static java.util.Collections.emptyList;
-import static java.util.Collections.singletonList;
 import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
 import static org.sonar.server.component.ComponentFinder.ParamNames.COMPONENT_ID_AND_KEY;
+import static org.sonar.server.component.ComponentFinder.ParamNames.DEVELOPER_ID_AND_KEY;
 import static org.sonar.server.measure.ws.ComponentDtoToWsComponent.componentDtoToWsComponent;
 import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createAdditionalFieldsParameter;
+import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createDeveloperParameters;
 import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createMetricKeysParameter;
 import static org.sonar.server.measure.ws.MetricDtoToWsMetric.metricDtoToWsMetric;
 import static org.sonar.server.measure.ws.SnapshotDtoToWsPeriods.snapshotToWsPeriods;
@@ -75,6 +77,8 @@ import static org.sonarqube.ws.client.measure.MeasuresWsParameters.ADDITIONAL_PE
 import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_ADDITIONAL_FIELDS;
 import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_COMPONENT_ID;
 import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_COMPONENT_KEY;
+import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_DEVELOPER_ID;
+import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_DEVELOPER_KEY;
 import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_METRIC_KEYS;
 
 public class ComponentAction implements MeasuresWsAction {
@@ -115,6 +119,7 @@ public class ComponentAction implements MeasuresWsAction {
 
     createMetricKeysParameter(action);
     createAdditionalFieldsParameter(action);
+    createDeveloperParameters(action);
   }
 
   @Override
@@ -127,12 +132,13 @@ public class ComponentAction implements MeasuresWsAction {
     DbSession dbSession = dbClient.openSession(false);
     try {
       ComponentDto component = componentFinder.getByUuidOrKey(dbSession, request.getComponentId(), request.getComponentKey(), COMPONENT_ID_AND_KEY);
+      Long developerId = searchDeveloperId(dbSession, request);
       Optional<ComponentDto> refComponent = getReferenceComponent(dbSession, component);
       checkPermissions(component);
       SnapshotDto lastSnapshot = dbClient.snapshotDao().selectLastSnapshotByComponentId(dbSession, component.getId());
       List<MetricDto> metrics = searchMetrics(dbSession, request);
       List<WsMeasures.Period> periods = snapshotToWsPeriods(lastSnapshot);
-      List<MeasureDto> measures = searchMeasures(dbSession, component, lastSnapshot, metrics, periods);
+      List<MeasureDto> measures = searchMeasures(dbSession, component, lastSnapshot, metrics, periods, developerId);
 
       return buildResponse(request, component, refComponent, measures, metrics, periods);
     } finally {
@@ -140,6 +146,15 @@ public class ComponentAction implements MeasuresWsAction {
     }
   }
 
+  @CheckForNull
+  private Long searchDeveloperId(DbSession dbSession, ComponentWsRequest request) {
+    if ((request.getDeveloperId() == null && request.getDeveloperKey() == null)) {
+      return null;
+    }
+
+    return componentFinder.getByUuidOrKey(dbSession, request.getDeveloperId(), request.getDeveloperKey(), DEVELOPER_ID_AND_KEY).getId();
+  }
+
   private Optional<ComponentDto> getReferenceComponent(DbSession dbSession, ComponentDto component) {
     if (component.getCopyResourceId() == null) {
       return Optional.absent();
@@ -193,13 +208,14 @@ public class ComponentAction implements MeasuresWsAction {
     return metrics;
   }
 
-  private List<MeasureDto> searchMeasures(DbSession dbSession, ComponentDto component, @Nullable SnapshotDto snapshot, List<MetricDto> metrics, List<WsMeasures.Period> periods) {
+  private List<MeasureDto> searchMeasures(DbSession dbSession, ComponentDto component, @Nullable SnapshotDto snapshot, List<MetricDto> metrics, List<WsMeasures.Period> periods,
+    @Nullable Long developerId) {
     if (snapshot == null) {
       return emptyList();
     }
 
     List<Integer> metricIds = Lists.transform(metrics, MetricDtoFunctions.toId());
-    List<MeasureDto> measures = dbClient.measureDao().selectBySnapshotIdsAndMetricIds(dbSession, singletonList(snapshot.getId()), metricIds);
+    List<MeasureDto> measures = dbClient.measureDao().selectByDeveloperForSnapshotAndMetrics(dbSession, developerId, snapshot.getId(), metricIds);
     addBestValuesToMeasures(measures, component, metrics, periods);
 
     return measures;
@@ -235,7 +251,9 @@ public class ComponentAction implements MeasuresWsAction {
       .setComponentId(request.param(PARAM_COMPONENT_ID))
       .setComponentKey(request.param(PARAM_COMPONENT_KEY))
       .setAdditionalFields(request.paramAsStrings(PARAM_ADDITIONAL_FIELDS))
-      .setMetricKeys(request.mandatoryParamAsStrings(PARAM_METRIC_KEYS));
+      .setMetricKeys(request.mandatoryParamAsStrings(PARAM_METRIC_KEYS))
+      .setDeveloperId(request.param(PARAM_DEVELOPER_ID))
+      .setDeveloperKey(request.param(PARAM_DEVELOPER_KEY));
     checkRequest(!componentWsRequest.getMetricKeys().isEmpty(), "At least one metric key must be provided");
     return componentWsRequest;
   }
index 804c274a89873bbdbec81925a89aabdee665c273..343ad0613b6c8b5531db166906ea9fbe43ac703b 100644 (file)
@@ -42,12 +42,14 @@ import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
 import org.sonar.server.ws.WsActionTester;
 import org.sonarqube.ws.MediaTypes;
 import org.sonarqube.ws.WsMeasures.ComponentWsResponse;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.api.utils.DateUtils.parseDateTime;
+import static org.sonar.db.component.ComponentTesting.newDeveloper;
 import static org.sonar.db.component.ComponentTesting.newFileDto;
 import static org.sonar.db.component.ComponentTesting.newProjectCopy;
 import static org.sonar.db.component.ComponentTesting.newProjectDto;
@@ -58,9 +60,10 @@ import static org.sonar.db.metric.MetricTesting.newMetricDto;
 import static org.sonar.test.JsonAssert.assertJson;
 import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_ADDITIONAL_FIELDS;
 import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_COMPONENT_ID;
+import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_DEVELOPER_ID;
+import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_DEVELOPER_KEY;
 import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_METRIC_KEYS;
 
-
 public class ComponentActionTest {
   private static final String PROJECT_UUID = "project-uuid";
 
@@ -140,6 +143,67 @@ public class ComponentActionTest {
     assertThat(response.getComponent().getRefKey()).isEqualTo("project-key");
   }
 
+  @Test
+  public void developer_measure_by_developer_uuid() {
+    ComponentDto developer = newDeveloper("developer-name");
+    componentDb.insertDeveloperAndSnapshot(developer);
+    ComponentDto project = newProjectDto("project-uuid");
+    SnapshotDto projectSnapshot = componentDb.insertProjectAndSnapshot(project);
+    ComponentDto file = newFileDto(project, "file-uuid");
+    SnapshotDto fileSnapshot = componentDb.insertComponentAndSnapshot(file, projectSnapshot);
+    MetricDto ncloc = insertNclocMetric();
+    dbClient.measureDao().insert(dbSession,
+      newMeasureDto(ncloc, fileSnapshot.getId()).setValue(42.0d).setDeveloperId(null),
+      newMeasureDto(ncloc, fileSnapshot.getId()).setValue(1984.0d).setDeveloperId(developer.getId()));
+    db.commit();
+
+    ComponentWsResponse result = call(ws.newRequest()
+      .setParam(PARAM_COMPONENT_ID, "file-uuid")
+      .setParam(PARAM_DEVELOPER_ID, developer.uuid())
+      .setParam(PARAM_METRIC_KEYS, "ncloc"));
+
+    assertThat(result.getComponent().getMeasuresCount()).isEqualTo(1);
+    assertThat(result.getComponent().getMeasures(0).getValue()).isEqualTo("1984");
+  }
+
+  @Test
+  public void developer_measure_by_developer_key() {
+    ComponentDto developer = newDeveloper("developer-name");
+    componentDb.insertDeveloperAndSnapshot(developer);
+    ComponentDto project = newProjectDto(PROJECT_UUID);
+    SnapshotDto projectSnapshot = componentDb.insertProjectAndSnapshot(project);
+    ComponentDto file = newFileDto(project, "file-uuid");
+    SnapshotDto fileSnapshot = componentDb.insertComponentAndSnapshot(file, projectSnapshot);
+    MetricDto ncloc = insertNclocMetric();
+    dbClient.measureDao().insert(dbSession,
+      newMeasureDto(ncloc, fileSnapshot.getId()).setValue(42.0d).setDeveloperId(null),
+      newMeasureDto(ncloc, fileSnapshot.getId()).setValue(1984.0d).setDeveloperId(developer.getId()));
+    db.commit();
+
+    ComponentWsResponse result = call(ws.newRequest()
+      .setParam(PARAM_COMPONENT_ID, "file-uuid")
+      .setParam(PARAM_DEVELOPER_KEY, developer.key())
+      .setParam(PARAM_METRIC_KEYS, "ncloc"));
+
+    assertThat(result.getComponent().getMeasuresCount()).isEqualTo(1);
+    assertThat(result.getComponent().getMeasures(0).getValue()).isEqualTo("1984");
+  }
+
+  @Test
+  public void fail_when_developer_is_not_found() {
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage("Component id 'unknown-developer-id' not found");
+
+    componentDb.insertProjectAndSnapshot(newProjectDto(PROJECT_UUID));
+    insertNclocMetric();
+
+    call(ws.newRequest()
+      .setParam(PARAM_COMPONENT_ID, PROJECT_UUID)
+      .setParam(PARAM_METRIC_KEYS, "ncloc")
+      .setParam(PARAM_DEVELOPER_ID, "unknown-developer-id")
+    );
+  }
+
   @Test
   public void fail_when_a_metric_is_not_found() {
     componentDb.insertProjectAndSnapshot(newProjectDto(PROJECT_UUID));
@@ -174,13 +238,16 @@ public class ComponentActionTest {
   }
 
   private ComponentWsResponse newRequest(String componentUuid, String metricKeys) {
-    InputStream responseStream = ws.newRequest()
-      .setMediaType(MediaTypes.PROTOBUF)
+    return call(ws.newRequest()
       .setParam(PARAM_COMPONENT_ID, componentUuid)
       .setParam(PARAM_METRIC_KEYS, metricKeys)
-      .setParam(PARAM_ADDITIONAL_FIELDS, "metrics,periods")
-      .execute()
-      .getInputStream();
+      .setParam(PARAM_ADDITIONAL_FIELDS, "metrics,periods"));
+  }
+
+  private ComponentWsResponse call(TestRequest request) {
+    InputStream responseStream = request
+      .setMediaType(MediaTypes.PROTOBUF)
+      .execute().getInputStream();
 
     try {
       return ComponentWsResponse.parseFrom(responseStream);
index fb9d7254bcc14a5cdeec95b4041bc00a9da68fbe..5c0910167c0ae7d04203be362d66200662c4e18a 100644 (file)
@@ -33,7 +33,7 @@ public interface MeasureMapper {
 
   List<MeasureDto> selectBySnapshotAndMetricKeys(@Param("snapshotId") long snapshotId, @Param("metricKeys") List<String> metricKeys);
 
-  List<MeasureDto> selectByDeveloperForSnapshotAndMetrics(@Param("developerId") long developerId, @Param("snapshotId") long snapshotId,
+  List<MeasureDto> selectByDeveloperForSnapshotAndMetrics(@Nullable @Param("developerId") Long developerId, @Param("snapshotId") long snapshotId,
     @Param("metricIds") List<Integer> metricIds);
 
   List<MeasureDto> selectBySnapshotAndMetrics(@Param("snapshotId") long snapshotId, @Param("metricIds") List<Integer> input);
index 7c97ed532e9ba0c80f6bac8c6b5b43ccd4c3d9ee..eb938f119ba986b03eb91bc74517d9f2bdc91a97 100644 (file)
     FROM project_measures pm
     <where>
       pm.snapshot_id = #{snapshotId}
-      AND pm.person_id = #{developerId}
+      <if test="developerId!=null">
+        AND pm.person_id = #{developerId}
+      </if>
+      <if test="developerId==null">
+        AND pm.person_id is NULL
+      </if>
       AND
       <foreach item="metricId" index="index" collection="metricIds" open="(" separator=" or " close=")">
         pm.metric_id=#{metricId}
index df6a800f9d54b186c2fb50e9a3d81eeef7da4971..7230293033ac6bc69e7a70a24b7d92f3e6fea50d 100644 (file)
@@ -28,6 +28,8 @@ public class ComponentWsRequest {
   private String componentKey;
   private List<String> metricKeys;
   private List<String> additionalFields;
+  private String developerId;
+  private String developerKey;
 
   @CheckForNull
   public String getComponentId() {
@@ -67,4 +69,24 @@ public class ComponentWsRequest {
     this.additionalFields = additionalFields;
     return this;
   }
+
+  @CheckForNull
+  public String getDeveloperId() {
+    return developerId;
+  }
+
+  public ComponentWsRequest setDeveloperId(@Nullable String developerId) {
+    this.developerId = developerId;
+    return this;
+  }
+
+  @CheckForNull
+  public String getDeveloperKey() {
+    return developerKey;
+  }
+
+  public ComponentWsRequest setDeveloperKey(@Nullable String developerKey) {
+    this.developerKey = developerKey;
+    return this;
+  }
 }
index 829b170b9a9a98b1e32ed4296341d84a93f2817e..6eab2608301b6284f353b485897f337e9ceb684f 100644 (file)
@@ -70,7 +70,9 @@ public class MeasuresService extends BaseService {
       .setParam(PARAM_COMPONENT_ID, request.getComponentId())
       .setParam(PARAM_COMPONENT_KEY, request.getComponentKey())
       .setParam(PARAM_ADDITIONAL_FIELDS, inlineMultipleParamValue(request.getAdditionalFields()))
-      .setParam(PARAM_METRIC_KEYS, inlineMultipleParamValue(request.getMetricKeys()));
+      .setParam(PARAM_METRIC_KEYS, inlineMultipleParamValue(request.getMetricKeys()))
+      .setParam(PARAM_DEVELOPER_ID, request.getDeveloperId())
+      .setParam(PARAM_DEVELOPER_KEY, request.getDeveloperKey());
 
     return call(getRequest, ComponentWsResponse.parser());
   }