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.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
import static org.sonar.server.ws.WsParameterBuilder.createQualifiersParameter;
import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.DEPRECATED_PARAM_BASE_COMPONENT_ID;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.DEPRECATED_PARAM_BASE_COMPONENT_KEY;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_ADDITIONAL_FIELDS;
+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;
.setExampleValue(KEY_PROJECT_EXAMPLE_001)
.setDeprecatedKey(DEPRECATED_PARAM_BASE_COMPONENT_KEY, "6.6");
+ action.createParam(PARAM_BRANCH)
+ .setDescription("Branch key")
+ .setExampleValue(KEY_BRANCH_EXAMPLE_001)
+ .setInternal(true)
+ .setSince("6.6");
+
action.createParam(PARAM_METRIC_SORT)
.setDescription(
format("Metric key to sort by. The '%s' parameter must contain the '%s' or '%s' value. It must be part of the '%s' parameter", Param.SORT, METRIC_SORT, METRIC_PERIOD_SORT,
ComponentTreeWsRequest componentTreeWsRequest = new ComponentTreeWsRequest()
.setBaseComponentId(request.param(DEPRECATED_PARAM_BASE_COMPONENT_ID))
.setComponent(request.param(PARAM_COMPONENT))
+ .setBranch(request.param(PARAM_BRANCH))
.setMetricKeys(metricKeys)
.setStrategy(request.mandatoryParam(PARAM_STRATEGY))
.setQualifiers(request.paramAsStrings(PARAM_QUALIFIERS))
import static org.sonar.server.measure.ws.ComponentTreeAction.STRATEGIES;
import static org.sonar.server.measure.ws.ComponentTreeAction.WITH_MEASURES_ONLY_METRIC_SORT_FILTER;
import static org.sonar.server.measure.ws.SnapshotDtoToWsPeriods.snapshotToWsPeriods;
+import static org.sonarqube.ws.client.measure.MeasuresWsParameters.DEPRECATED_PARAM_BASE_COMPONENT_ID;
+import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_BRANCH;
public class ComponentTreeDataLoader {
private static final Set<String> QUALIFIERS_ELIGIBLE_FOR_BEST_VALUE = ImmutableSet.of(Qualifiers.FILE, Qualifiers.UNIT_TEST_FILE);
ComponentTreeData load(ComponentTreeWsRequest wsRequest) {
try (DbSession dbSession = dbClient.openSession(false)) {
- ComponentDto baseComponent = componentFinder.getByUuidOrKey(dbSession, wsRequest.getBaseComponentId(), wsRequest.getComponent(), BASE_COMPONENT_ID_AND_KEY);
+ ComponentDto baseComponent = loadComponent(dbSession, wsRequest);
checkPermissions(baseComponent);
Optional<SnapshotDto> baseSnapshot = dbClient.snapshotDao().selectLastAnalysisByRootComponentUuid(dbSession, baseComponent.projectUuid());
if (!baseSnapshot.isPresent()) {
}
}
+ private ComponentDto loadComponent(DbSession dbSession, ComponentTreeWsRequest request) {
+ String componentKey = request.getComponent();
+ String componentId = request.getBaseComponentId();
+ String branch = request.getBranch();
+ checkArgument(componentId == null || branch == null, "'%s' and '%s' parameters cannot be used at the same time", DEPRECATED_PARAM_BASE_COMPONENT_ID, PARAM_BRANCH);
+ return branch == null
+ ? componentFinder.getByUuidOrKey(dbSession, componentId, componentKey, BASE_COMPONENT_ID_AND_KEY)
+ : componentFinder.getByKeyAndBranch(dbSession, componentKey, branch);
+ }
+
@CheckForNull
private Long searchDeveloperId(DbSession dbSession, ComponentTreeWsRequest wsRequest) {
if (wsRequest.getDeveloperId() == null && wsRequest.getDeveloperKey() == null) {
import com.google.common.base.Joiner;
import java.util.List;
import java.util.stream.IntStream;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ResourceTypesRule;
import org.sonar.db.component.SnapshotDto;
+import org.sonar.db.measure.MeasureDto;
import org.sonar.db.metric.MetricDto;
import org.sonar.db.metric.MetricTesting;
import org.sonar.server.component.ComponentFinder;
import org.sonarqube.ws.WsMeasures;
import org.sonarqube.ws.WsMeasures.ComponentTreeWsResponse;
+import static java.lang.Double.parseDouble;
import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.sonar.api.measures.Metric.ValueType.FLOAT;
import static org.sonar.api.measures.Metric.ValueType.INT;
import static org.sonar.api.measures.Metric.ValueType.RATING;
+import static org.sonar.api.resources.Qualifiers.DIRECTORY;
+import static org.sonar.api.resources.Qualifiers.FILE;
+import static org.sonar.api.resources.Qualifiers.MODULE;
+import static org.sonar.api.resources.Qualifiers.PROJECT;
+import static org.sonar.api.resources.Qualifiers.UNIT_TEST_FILE;
import static org.sonar.api.server.ws.WebService.Param.SORT;
import static org.sonar.api.utils.DateUtils.parseDateTime;
import static org.sonar.api.web.UserRole.USER;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.ADDITIONAL_PERIODS;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.DEPRECATED_PARAM_BASE_COMPONENT_KEY;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_ADDITIONAL_FIELDS;
+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_METRIC_KEYS;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_METRIC_PERIOD_SORT;
public class ComponentTreeActionTest {
@Rule
- public UserSessionRule userSession = UserSessionRule.standalone();
+ public UserSessionRule userSession = UserSessionRule.standalone().logIn().setRoot();
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
private I18nRule i18n = new I18nRule();
- private ResourceTypesRule resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT);
+ private ResourceTypesRule resourceTypes = new ResourceTypesRule()
+ .setRootQualifiers(PROJECT)
+ .setChildrenQualifiers(MODULE, FILE, DIRECTORY)
+ .setLeavesQualifiers(FILE, UNIT_TEST_FILE);
private ComponentDbTester componentDb = new ComponentDbTester(db);
private DbClient dbClient = db.getDbClient();
private DbSession dbSession = db.getSession();
new ComponentTreeDataLoader(dbClient, new ComponentFinder(dbClient, resourceTypes), userSession, resourceTypes),
i18n, resourceTypes));
- @Before
- public void setUp() {
- userSession.logIn().setRoot();
- resourceTypes.setChildrenQualifiers(Qualifiers.MODULE, Qualifiers.FILE, Qualifiers.DIRECTORY);
- resourceTypes.setLeavesQualifiers(Qualifiers.FILE, Qualifiers.UNIT_TEST_FILE);
- }
-
@Test
public void json_example() {
ComponentDto project = db.components().insertPrivateProject(p -> p.setDbKey("MY_PROJECT")
.setDbKey("com.sonarsource:java-markdown:src/main/java/com/sonarsource/markdown/impl/ElementImpl.java")
.setName("ElementImpl.java")
.setLanguage("java")
- .setQualifier(Qualifiers.FILE)
+ .setQualifier(FILE)
.setPath("src/main/java/com/sonarsource/markdown/impl/ElementImpl.java"));
ComponentDto file2 = componentDb.insertComponent(newFileDto(project, null)
.setUuid("AVIwDXE_bJbJqrw6wFwJ")
.setDbKey("com.sonarsource:java-markdown:src/test/java/com/sonarsource/markdown/impl/ElementImplTest.java")
.setName("ElementImplTest.java")
.setLanguage("java")
- .setQualifier(Qualifiers.UNIT_TEST_FILE)
+ .setQualifier(UNIT_TEST_FILE)
.setPath("src/test/java/com/sonarsource/markdown/impl/ElementImplTest.java"));
ComponentDto dir = componentDb.insertComponent(newDirectory(project, "src/main/java/com/sonarsource/markdown/impl")
.setUuid("AVIwDXE-bJbJqrw6wFv8")
.setDbKey("com.sonarsource:java-markdown:src/main/java/com/sonarsource/markdown/impl")
- .setQualifier(Qualifiers.DIRECTORY));
+ .setQualifier(DIRECTORY));
MetricDto complexity = insertComplexityMetric();
dbClient.measureDao().insert(dbSession,
assertThat(result.getComponentsCount()).isEqualTo(0);
}
+ @Test
+ public void branch() {
+ ComponentDto project = db.components().insertPrivateProject();
+ ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
+ SnapshotDto analysis = db.components().insertSnapshot(branch);
+ ComponentDto file = db.components().insertComponent(newFileDto(branch));
+ MetricDto complexity = insertComplexityMetric();
+ MeasureDto measure = db.measures().insertMeasure(file, analysis, complexity, m -> m.setValue(12.0d));
+
+ ComponentTreeWsResponse response = ws.newRequest()
+ .setParam(PARAM_COMPONENT, file.getKey())
+ .setParam(PARAM_BRANCH, file.getBranch())
+ .setParam(PARAM_METRIC_KEYS, complexity.getKey())
+ .executeProtobuf(WsMeasures.ComponentTreeWsResponse.class);
+
+ assertThat(response.getBaseComponent()).extracting(WsMeasures.Component::getKey, WsMeasures.Component::getBranch)
+ .containsExactlyInAnyOrder(file.getKey(), file.getBranch());
+ assertThat(response.getBaseComponent().getMeasuresList())
+ .extracting(WsMeasures.Measure::getMetric, m -> parseDouble(m.getValue()))
+ .containsExactlyInAnyOrder(tuple(complexity.getKey(), measure.getValue()));
+ }
+
@Test
public void return_deprecated_id_in_the_response() {
ComponentDto project = db.components().insertPrivateProject();
.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_METRIC_KEYS, "ncloc")
+ .execute();
+ }
+
private static MetricDto newMetricDto() {
return MetricTesting.newMetricDto()
.setWorstValue(null)