import static org.sonar.api.utils.DateUtils.parseStartingDateOrDateTime;
import static org.sonar.core.util.Protobuf.setNullable;
import static org.sonar.db.component.SnapshotDto.STATUS_PROCESSED;
+import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.ACTION_SEARCH_HISTORY;
+import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_BRANCH;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_COMPONENT;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_FROM;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_METRICS;
private static SearchHistoryRequest toWsRequest(Request request) {
return SearchHistoryRequest.builder()
.setComponent(request.mandatoryParam(PARAM_COMPONENT))
+ .setBranch(request.param(PARAM_BRANCH))
.setMetrics(request.mandatoryParamAsStrings(PARAM_METRICS))
.setFrom(request.param(PARAM_FROM))
.setTo(request.param(PARAM_TO))
.setRequired(true)
.setExampleValue(KeyExamples.KEY_PROJECT_EXAMPLE_001);
+ action.createParam(PARAM_BRANCH)
+ .setDescription("Branch key")
+ .setSince("6.6")
+ .setInternal(true)
+ .setExampleValue(KEY_BRANCH_EXAMPLE_001);
+
action.createParam(PARAM_METRICS)
.setDescription("Comma-separated list of metric keys")
.setRequired(true)
}
private ComponentDto searchComponent(SearchHistoryRequest request, DbSession dbSession) {
- ComponentDto component = componentFinder.getByKey(dbSession, request.getComponent());
+ ComponentDto component = loadComponent(dbSession, request);
userSession.checkComponentPermission(UserRole.USER, component);
return component;
}
return metrics;
}
+ private ComponentDto loadComponent(DbSession dbSession, SearchHistoryRequest request) {
+ String componentKey = request.getComponent();
+ String branch = request.getBranch();
+ if (branch != null) {
+ return componentFinder.getByKeyAndBranch(dbSession, componentKey, branch);
+ }
+ return componentFinder.getByKey(dbSession, componentKey);
+ }
+
}
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.SnapshotDto;
+import org.sonar.db.measure.MeasureDto;
import org.sonar.db.metric.MetricDto;
import org.sonar.server.component.TestComponentFinder;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonarqube.ws.client.measure.SearchHistoryRequest;
import static com.google.common.collect.Lists.newArrayList;
+import static java.lang.Double.parseDouble;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.sonar.db.measure.MeasureTesting.newMeasureDto;
import static org.sonar.db.metric.MetricTesting.newMetricDto;
import static org.sonar.test.JsonAssert.assertJson;
+import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_BRANCH;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_COMPONENT;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_FROM;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_METRICS;
assertThat(result.getMeasures(0).getHistory(0).hasValue()).isFalse();
}
+ @Test
+ public void branch() {
+ ComponentDto project = db.components().insertPrivateProject();
+ userSession.addProjectPermission(UserRole.USER, project);
+ ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
+ ComponentDto file = db.components().insertComponent(newFileDto(branch));
+ SnapshotDto analysis = db.components().insertSnapshot(branch);
+ MeasureDto measure = db.measures().insertMeasure(file, analysis, nclocMetric, m -> m.setValue(2d));
+
+ SearchHistoryResponse result = ws.newRequest()
+ .setParam(PARAM_COMPONENT, file.getKey())
+ .setParam(PARAM_BRANCH, "my_branch")
+ .setParam(PARAM_METRICS, "ncloc")
+ .executeProtobuf(SearchHistoryResponse.class);
+
+ assertThat(result.getMeasuresList()).extracting(HistoryMeasure::getMetric).hasSize(1);
+ HistoryMeasure historyMeasure = result.getMeasures(0);
+ assertThat(historyMeasure.getMetric()).isEqualTo(nclocMetric.getKey());
+ assertThat(historyMeasure.getHistoryList())
+ .extracting(m -> parseDouble(m.getValue()))
+ .containsExactlyInAnyOrder(measure.getValue());
+ }
+
@Test
public void fail_if_unknown_metric() {
wsRequest.setMetrics(newArrayList(complexityMetric.getKey(), nclocMetric.getKey(), "METRIC_42", "42_METRIC"));
.execute();
}
+ @Test
+ public void fail_if_branch_does_not_exist() {
+ ComponentDto project = db.components().insertPrivateProject();
+ ComponentDto file = db.components().insertComponent(newFileDto(project));
+ userSession.addProjectPermission(UserRole.USER, project);
+ db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
+
+ expectedException.expect(NotFoundException.class);
+ expectedException.expectMessage(String.format("Component '%s' on branch '%s' not found", file.getKey(), "another_branch"));
+
+ ws.newRequest()
+ .setParam(PARAM_COMPONENT, file.getKey())
+ .setParam(PARAM_BRANCH, "another_branch")
+ .setParam(PARAM_METRICS, "ncloc")
+ .execute();
+ }
+
@Test
public void definition() {
WebService.Action definition = ws.getDef();
assertThat(definition.isPost()).isFalse();
assertThat(definition.isInternal()).isFalse();
assertThat(definition.since()).isEqualTo("6.3");
+ assertThat(definition.params()).hasSize(7);
+
+ Param branch = definition.param("branch");
+ assertThat(branch.since()).isEqualTo("6.6");
+ assertThat(branch.isInternal()).isTrue();
+ assertThat(branch.isRequired()).isFalse();
}
@Test
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_ADDITIONAL_FIELDS;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_BASE_COMPONENT_ID;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_BASE_COMPONENT_KEY;
+import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_BRANCH;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_COMPONENT;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_COMPONENT_ID;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_COMPONENT_KEY;
public SearchHistoryResponse searchHistory(SearchHistoryRequest request) {
GetRequest getRequest = new GetRequest(path(ACTION_SEARCH_HISTORY))
.setParam(PARAM_COMPONENT, request.getComponent())
+ .setParam(PARAM_BRANCH, request.getBranch())
.setParam(PARAM_METRICS, inlineMultipleParamValue(request.getMetrics()))
.setParam(PARAM_FROM, request.getFrom())
.setParam(PARAM_TO, request.getTo())
public static final String PARAM_BASE_COMPONENT_ID = "baseComponentId";
public static final String PARAM_BASE_COMPONENT_KEY = "baseComponentKey";
public static final String PARAM_COMPONENT = "component";
+ public static final String PARAM_BRANCH = "branch";
public static final String PARAM_STRATEGY = "strategy";
public static final String PARAM_QUALIFIERS = "qualifiers";
public static final String PARAM_METRICS = "metrics";
import java.util.List;
import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import static java.lang.String.format;
public static final int DEFAULT_PAGE_SIZE = 100;
private final String component;
+ private final String branch;
private final List<String> metrics;
private final String from;
private final String to;
public SearchHistoryRequest(Builder builder) {
this.component = builder.component;
+ this.branch = builder.branch;
this.metrics = builder.metrics;
this.from = builder.from;
this.to = builder.to;
return component;
}
+ @CheckForNull
+ public String getBranch() {
+ return branch;
+ }
+
public List<String> getMetrics() {
return metrics;
}
public static class Builder {
private String component;
+ private String branch;
private List<String> metrics;
private String from;
private String to;
return this;
}
+ public Builder setBranch(@Nullable String branch) {
+ this.branch = branch;
+ return this;
+ }
+
public Builder setMetrics(List<String> metrics) {
this.metrics = metrics;
return this;
}
- public Builder setFrom(String from) {
+ public Builder setFrom(@Nullable String from) {
this.from = from;
return this;
}
- public Builder setTo(String to) {
+ public Builder setTo(@Nullable String to) {
this.to = to;
return this;
}
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_ADDITIONAL_FIELDS;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_BASE_COMPONENT_ID;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_BASE_COMPONENT_KEY;
+import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_BRANCH;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_COMPONENT;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_DEVELOPER_ID;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_DEVELOPER_KEY;
public void search_history() {
SearchHistoryRequest request = SearchHistoryRequest.builder()
.setComponent(VALUE_COMPONENT)
+ .setBranch("my_branch")
.setMetrics(VALUE_METRICS)
.setFrom(VALUE_FROM)
.setTo(VALUE_TO)
assertThat(serviceTester.getGetParser()).isSameAs(WsMeasures.SearchHistoryResponse.parser());
serviceTester.assertThat(getRequest)
.hasParam(PARAM_COMPONENT, VALUE_COMPONENT)
+ .hasParam(PARAM_BRANCH, "my_branch")
.hasParam(PARAM_METRICS, "ncloc,complexity")
.hasParam(PARAM_FROM, VALUE_FROM)
.hasParam(PARAM_TO, VALUE_TO)
public void full_example() {
SearchHistoryRequest result = underTest
.setComponent("C1")
+ .setBranch("my_branch")
.setMetrics(singletonList("new_lines"))
.setFrom("2017-01-15")
.setTo("2017-01-20")
.build();
assertThat(result)
- .extracting(SearchHistoryRequest::getComponent, SearchHistoryRequest::getMetrics, SearchHistoryRequest::getFrom, SearchHistoryRequest::getTo,
+ .extracting(SearchHistoryRequest::getComponent, SearchHistoryRequest::getBranch, SearchHistoryRequest::getMetrics, SearchHistoryRequest::getFrom, SearchHistoryRequest::getTo,
SearchHistoryRequest::getPage, SearchHistoryRequest::getPageSize)
- .containsExactly("C1", singletonList("new_lines"), "2017-01-15", "2017-01-20", 23, 42);
+ .containsExactly("C1", "my_branch", singletonList("new_lines"), "2017-01-15", "2017-01-20", 23, 42);
}
@Test