]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-22728 Increase max metric in Component Tree Action
authorOrlovAlexander <35396155+OrlovAlexander85@users.noreply.github.com>
Tue, 20 Aug 2024 12:59:10 +0000 (14:59 +0200)
committersonartech <sonartech@sonarsource.com>
Mon, 26 Aug 2024 20:03:07 +0000 (20:03 +0000)
server/sonar-webserver-webapi/src/it/java/org/sonar/server/measure/ws/ComponentTreeActionIT.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentTreeAction.java

index 62165b7ab7a2b1e1013c7b9dc37e8c4c44b81ae0..e94a5d399224e433bc22d2bddd925acdfaa20010 100644 (file)
@@ -132,7 +132,8 @@ class ComponentTreeActionIT {
       .setName("My Project"));
     ComponentDto mainBranch = projectData.getMainBranchComponent();
     addProjectPermission(projectData);
-    SnapshotDto analysis = db.components().insertSnapshot(mainBranch, s -> s.setPeriodDate(parseDateTime("2016-01-11T10:49:50+0100").getTime())
+    db.components().insertSnapshot(mainBranch,
+      s -> s.setPeriodDate(parseDateTime("2016-01-11T10:49:50+0100").getTime())
       .setPeriodMode("previous_version")
       .setPeriodParam("1.0-SNAPSHOT"));
     ComponentDto file1 = db.components().insertComponent(newFileDto(mainBranch)
@@ -197,7 +198,8 @@ class ComponentTreeActionIT {
       .setName("My Project"));
     addProjectPermission(projectData);
     ComponentDto mainBranch = projectData.getMainBranchComponent();
-    SnapshotDto analysis = db.components().insertSnapshot(mainBranch, s -> s.setPeriodDate(parseDateTime("2016-01-11T10:49:50+0100").getTime())
+    db.components().insertSnapshot(mainBranch,
+      s -> s.setPeriodDate(parseDateTime("2016-01-11T10:49:50+0100").getTime())
       .setPeriodMode("previous_version")
       .setPeriodParam("1.0-SNAPSHOT"));
 
@@ -395,15 +397,24 @@ class ComponentTreeActionIT {
     ComponentDto mainBranch = projectData.getMainBranchComponent();
     addProjectPermission(projectData);
     SnapshotDto projectSnapshot = db.components().insertSnapshot(mainBranch);
-    ComponentDto file9 = db.components().insertComponent(newFileDto(mainBranch, null, "file-uuid-9").setName("file-1").setKey("file-9-key"));
-    ComponentDto file8 = db.components().insertComponent(newFileDto(mainBranch, null, "file-uuid-8").setName("file-1").setKey("file-8-key"));
-    ComponentDto file7 = db.components().insertComponent(newFileDto(mainBranch, null, "file-uuid-7").setName("file-1").setKey("file-7-key"));
-    ComponentDto file6 = db.components().insertComponent(newFileDto(mainBranch, null, "file-uuid-6").setName("file-1").setKey("file-6-key"));
-    ComponentDto file5 = db.components().insertComponent(newFileDto(mainBranch, null, "file-uuid-5").setName("file-1").setKey("file-5-key"));
-    ComponentDto file4 = db.components().insertComponent(newFileDto(mainBranch, null, "file-uuid-4").setName("file-1").setKey("file-4-key"));
-    ComponentDto file3 = db.components().insertComponent(newFileDto(mainBranch, null, "file-uuid-3").setName("file-1").setKey("file-3-key"));
-    ComponentDto file2 = db.components().insertComponent(newFileDto(mainBranch, null, "file-uuid-2").setName("file-1").setKey("file-2-key"));
-    ComponentDto file1 = db.components().insertComponent(newFileDto(mainBranch, null, "file-uuid-1").setName("file-1").setKey("file-1-key"));
+    ComponentDto file9 = db.components().insertComponent(newFileDto(mainBranch, null, "file-uuid-9").setName("file-1").setKey("file-9-key"
+    ));
+    ComponentDto file8 = db.components().insertComponent(newFileDto(mainBranch, null, "file-uuid-8").setName("file-1").setKey("file-8-key"
+    ));
+    ComponentDto file7 = db.components().insertComponent(newFileDto(mainBranch, null, "file-uuid-7").setName("file-1").setKey("file-7-key"
+    ));
+    ComponentDto file6 = db.components().insertComponent(newFileDto(mainBranch, null, "file-uuid-6").setName("file-1").setKey("file-6-key"
+    ));
+    ComponentDto file5 = db.components().insertComponent(newFileDto(mainBranch, null, "file-uuid-5").setName("file-1").setKey("file-5-key"
+    ));
+    ComponentDto file4 = db.components().insertComponent(newFileDto(mainBranch, null, "file-uuid-4").setName("file-1").setKey("file-4-key"
+    ));
+    ComponentDto file3 = db.components().insertComponent(newFileDto(mainBranch, null, "file-uuid-3").setName("file-1").setKey("file-3-key"
+    ));
+    ComponentDto file2 = db.components().insertComponent(newFileDto(mainBranch, null, "file-uuid-2").setName("file-1").setKey("file-2-key"
+    ));
+    ComponentDto file1 = db.components().insertComponent(newFileDto(mainBranch, null, "file-uuid-1").setName("file-1").setKey("file-1-key"
+    ));
     MetricDto coverage = insertCoverageMetric();
     db.commit();
     db.measures().insertLiveMeasure(file1, coverage, m -> m.setValue(1.0d));
@@ -762,7 +773,8 @@ class ComponentTreeActionIT {
     ComponentDto application = applicationData.getMainBranchComponent();
     userSession.registerApplication(applicationData.getProjectDto());
     String branchName = "app-branch";
-    ComponentDto applicationBranch = db.components().insertProjectBranch(application, a -> a.setKey(branchName), a -> a.setUuid("custom-uuid"));
+    ComponentDto applicationBranch = db.components().insertProjectBranch(application, a -> a.setKey(branchName), a -> a.setUuid("custom" +
+      "-uuid"));
     userSession.addProjectBranchMapping(applicationData.projectUuid(), applicationBranch);
     ProjectData projectData = db.components().insertPrivateProject(p -> p.setKey("project-key"));
     ComponentDto mainBranch = projectData.getMainBranchComponent();
@@ -919,7 +931,7 @@ class ComponentTreeActionIT {
     List<Measure> dataMeasures = response.getComponents(0).getMeasuresList();
 
     assertThat(dataMeasures)
-      .extracting(Measure::getMetric, m-> m.getPeriod().getValue())
+      .extracting(Measure::getMetric, m -> m.getPeriod().getValue())
       .containsExactlyInAnyOrder(tuple(NEW_SECURITY_ISSUES_KEY, NEW_SECURITY_ISSUES_KEY + "_data"),
         tuple(NEW_MAINTAINABILITY_ISSUES_KEY, NEW_MAINTAINABILITY_ISSUES_KEY + "_data"),
         tuple(NEW_RELIABILITY_ISSUES_KEY, NEW_RELIABILITY_ISSUES_KEY + "_data")
@@ -927,10 +939,10 @@ class ComponentTreeActionIT {
   }
 
   @Test
-  void fail_when_setting_more_than_15_metric_keys() {
+  void fail_when_setting_more_than_25_metric_keys() {
     ComponentDto mainBranch = db.components().insertPrivateProject().getMainBranchComponent();
     db.components().insertSnapshot(mainBranch);
-    List<String> metrics = IntStream.range(0, 20)
+    List<String> metrics = IntStream.range(0, 26)
       .mapToObj(i -> "metric" + i)
       .toList();
     db.commit();
@@ -942,7 +954,7 @@ class ComponentTreeActionIT {
         .execute();
     })
       .isInstanceOf(IllegalArgumentException.class)
-      .hasMessage("'metricKeys' can contains only 15 values, got 20");
+      .hasMessage("'metricKeys' can contains only 25 values, got 26");
   }
 
   @Test
@@ -1012,7 +1024,8 @@ class ComponentTreeActionIT {
         .executeProtobuf(ComponentTreeWsResponse.class);
     })
       .isInstanceOf(BadRequestException.class)
-      .hasMessage("To sort by a metric, the 's' parameter must contain 'metric' or 'metricPeriod', and a metric key must be provided in the 'metricSort' parameter");
+      .hasMessage("To sort by a metric, the 's' parameter must contain 'metric' or 'metricPeriod', and a metric key must be provided in " +
+        "the 'metricSort' parameter");
   }
 
   @Test
@@ -1081,7 +1094,8 @@ class ComponentTreeActionIT {
         .executeProtobuf(ComponentTreeWsResponse.class);
     })
       .isInstanceOf(BadRequestException.class)
-      .hasMessage("To filter components based on the sort metric, the 's' parameter must contain 'metric' or 'metricPeriod' and the 'metricSort' parameter must be provided");
+      .hasMessage("To filter components based on the sort metric, the 's' parameter must contain 'metric' or 'metricPeriod' and the " +
+        "'metricSort' parameter must be provided");
   }
 
   @Test
@@ -1160,7 +1174,7 @@ class ComponentTreeActionIT {
       .setOptimizedBestValue(false);
   }
 
-  private void insertMetricAndLiveMeasure(ComponentDto dto,  String key, String additionalData) {
+  private void insertMetricAndLiveMeasure(ComponentDto dto, String key, String additionalData) {
     MetricDto dataMetric = dbClient.metricDao().insert(dbSession, newDataMetricDto(key));
     db.measures().insertLiveMeasure(dto, dataMetric, c -> c.setData(key + additionalData));
 
index 67d8d3409f33b10294957998b5fee6c51a9261d2..5ee3d95b34a0ace996798e20e75e45f70947674f 100644 (file)
@@ -74,6 +74,7 @@ import org.sonarqube.ws.client.component.ComponentsWsParameters;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkState;
+import static java.lang.String.*;
 import static java.lang.String.format;
 import static java.util.Collections.emptyList;
 import static java.util.Collections.emptyMap;
@@ -150,7 +151,7 @@ public class ComponentTreeAction implements MeasuresWsAction {
   static final String ALL_METRIC_SORT_FILTER = "all";
   static final String WITH_MEASURES_ONLY_METRIC_SORT_FILTER = "withMeasuresOnly";
   static final Set<String> METRIC_SORT_FILTERS = ImmutableSortedSet.of(ALL_METRIC_SORT_FILTER, WITH_MEASURES_ONLY_METRIC_SORT_FILTER);
-  private static final int MAX_METRIC_KEYS = 15;
+  private static final int MAX_METRIC_KEYS = 25;
   private static final String COMMA_JOIN_SEPARATOR = ", ";
   private static final Set<String> QUALIFIERS_ELIGIBLE_FOR_BEST_VALUE = Set.of(Qualifiers.FILE, Qualifiers.UNIT_TEST_FILE);
 
@@ -173,29 +174,37 @@ public class ComponentTreeAction implements MeasuresWsAction {
   public void define(WebService.NewController context) {
     WebService.NewAction action = context.createAction(ACTION_COMPONENT_TREE)
       .setDescription(format("Navigate through components based on the chosen strategy with specified measures.<br>" +
-                             "Requires the following permission: 'Browse' on the specified project.<br>" +
-                             "For applications, it also requires 'Browse' permission on its child projects. <br>" +
-                             "When limiting search with the %s parameter, directories are not returned.", Param.TEXT_QUERY))
+        "Requires the following permission: 'Browse' on the specified project.<br>" +
+        "For applications, it also requires 'Browse' permission on its child projects. <br>" +
+        "When limiting search with the %s parameter, directories are not returned.", Param.TEXT_QUERY))
       .setResponseExample(getClass().getResource("component_tree-example.json"))
       .setSince("5.4")
       .setHandler(this)
       .addPagingParams(100, MAX_SIZE)
       .setChangelog(
-        new Change("10.7", "Added new accepted values for the 'metricKeys' param: %s".formatted(MeasuresWsModule.getNewMetricsInSonarQube107())),
-        new Change("10.5", "Added new accepted values for the 'metricKeys' param: 'new_maintainability_issues', 'new_reliability_issues', 'new_security_issues'"),
-        new Change("10.5", String.format("The metrics %s are now deprecated " +
-                                         "without exact replacement. Use 'maintainability_issues', 'reliability_issues' and 'security_issues' instead.",
+        new Change("10.7", format("Number of metric keys is limited to %s", 25)),
+        new Change("10.7",
+          "Added new accepted values for the 'metricKeys' param: %s".formatted(MeasuresWsModule.getNewMetricsInSonarQube107())),
+        new Change("10.5", "Added new accepted values for the 'metricKeys' param: 'new_maintainability_issues', 'new_reliability_issues'," +
+          " 'new_security_issues'"),
+        new Change("10.5", format("The metrics %s are now deprecated " +
+            "without exact replacement. Use 'maintainability_issues', 'reliability_issues' and 'security_issues' instead.",
           MeasuresWsModule.getDeprecatedMetricsInSonarQube105())),
-        new Change("10.5", "Added new accepted values for the 'metricKeys' param: 'maintainability_issues', 'reliability_issues', 'security_issues'"),
-        new Change("10.4", String.format("The metrics %s are now deprecated " +
-                                         "without exact replacement. Use 'maintainability_issues', 'reliability_issues' and 'security_issues' instead.",
+        new Change("10.5", "Added new accepted values for the 'metricKeys' param: 'maintainability_issues', 'reliability_issues', " +
+          "'security_issues'"),
+        new Change("10.4", format("The metrics %s are now deprecated " +
+            "without exact replacement. Use 'maintainability_issues', 'reliability_issues' and 'security_issues' instead.",
           MeasuresWsModule.getDeprecatedMetricsInSonarQube104())),
-        new Change("10.4", "The metrics 'open_issues', 'reopened_issues' and 'confirmed_issues' are now deprecated in the response. Consume 'violations' instead."),
-        new Change("10.4", "The use of 'open_issues', 'reopened_issues' and 'confirmed_issues' values in 'metricKeys' param are now deprecated. Use 'violations' instead."),
+        new Change("10.4", "The metrics 'open_issues', 'reopened_issues' and 'confirmed_issues' are now deprecated in the response. " +
+          "Consume 'violations' instead."),
+        new Change("10.4", "The use of 'open_issues', 'reopened_issues' and 'confirmed_issues' values in 'metricKeys' param are now " +
+          "deprecated. Use 'violations' instead."),
         new Change("10.4", "The metric 'wont_fix_issues' is now deprecated in the response. Consume 'accepted_issues' instead."),
-        new Change("10.4", "The use of 'wont_fix_issues' value in 'metricKeys' and 'metricSort' params is now deprecated. Use 'accepted_issues' instead."),
+        new Change("10.4", "The use of 'wont_fix_issues' value in 'metricKeys' and 'metricSort' params is now deprecated. Use " +
+          "'accepted_issues' instead."),
         new Change("10.4", "Added new accepted value for the 'metricKeys' and 'metricSort' param: 'accepted_issues'."),
-        new Change("10.1", String.format("The use of 'BRC' as value for parameter '%s' is removed", ComponentsWsParameters.PARAM_QUALIFIERS)),
+        new Change("10.1", format("The use of 'BRC' as value for parameter '%s' is removed",
+          ComponentsWsParameters.PARAM_QUALIFIERS)),
         new Change("10.0", format("The use of the following metrics in 'metricKeys' parameter is not deprecated anymore: %s",
           MeasuresWsModule.getDeprecatedMetricsInSonarQube93())),
         new Change("10.0", "the response field periods under measures field is removed."),
@@ -211,7 +220,7 @@ public class ComponentTreeAction implements MeasuresWsAction {
         new Change("8.1", "the response field periods is deprecated. Use period instead."),
         new Change("7.6", format("The use of module keys in parameter '%s' is deprecated", PARAM_COMPONENT)),
         new Change("7.2", "field 'bestValue' is added to the response"),
-        new Change("6.3", format("Number of metric keys is limited to %s", MAX_METRIC_KEYS)),
+        new Change("6.3", format("Number of metric keys is limited to %s", 15)),
         new Change("6.6", "the response field 'id' is deprecated. Use 'key' instead."),
         new Change("6.6", "the response field 'refId' is deprecated. Use 'refKey' instead."));
 
@@ -221,9 +230,9 @@ public class ComponentTreeAction implements MeasuresWsAction {
 
     action.createParam(Param.TEXT_QUERY)
       .setDescription("Limit search to: <ul>" +
-                      "<li>component names that contain the supplied string</li>" +
-                      "<li>component keys that are exactly the same as the supplied string</li>" +
-                      "</ul>")
+        "<li>component names that contain the supplied string</li>" +
+        "<li>component keys that are exactly the same as the supplied string</li>" +
+        "</ul>")
       .setMinimumLength(QUERY_MINIMUM_LENGTH)
       .setExampleValue("FILE_NAM");
 
@@ -244,40 +253,43 @@ public class ComponentTreeAction implements MeasuresWsAction {
 
     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,
+        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,
           PARAM_METRIC_KEYS))
       .setExampleValue("ncloc");
 
     action.createParam(PARAM_METRIC_PERIOD_SORT)
-      .setDescription(format("Sort measures by leak period or not ?. The '%s' parameter must contain the '%s' value.", Param.SORT, METRIC_PERIOD_SORT))
+      .setDescription(format("Sort measures by leak period or not ?. The '%s' parameter must contain the '%s' value.", Param.SORT,
+        METRIC_PERIOD_SORT))
       .setSince("5.5")
       .setPossibleValues(1);
 
     action.createParam(PARAM_METRIC_SORT_FILTER)
       .setDescription(format("Filter components. Sort must be on a metric. Possible values are: " +
-                             "<ul>" +
-                             "<li>%s: return all components</li>" +
-                             "<li>%s: filter out components that do not have a measure on the sorted metric</li>" +
-                             "</ul>", ALL_METRIC_SORT_FILTER, WITH_MEASURES_ONLY_METRIC_SORT_FILTER))
+        "<ul>" +
+        "<li>%s: return all components</li>" +
+        "<li>%s: filter out components that do not have a measure on the sorted metric</li>" +
+        "</ul>", ALL_METRIC_SORT_FILTER, WITH_MEASURES_ONLY_METRIC_SORT_FILTER))
       .setDefaultValue(ALL_METRIC_SORT_FILTER)
       .setPossibleValues(METRIC_SORT_FILTERS);
 
     createMetricKeysParameter(action)
       .setDescription("Comma-separated list of metric keys. Types %s are not allowed. For type %s only %s metrics are supported",
-        String.join(COMMA_JOIN_SEPARATOR, UnsupportedMetrics.FORBIDDEN_METRIC_TYPES),
+        join(COMMA_JOIN_SEPARATOR, UnsupportedMetrics.FORBIDDEN_METRIC_TYPES),
         DATA.name(),
-        String.join(COMMA_JOIN_SEPARATOR, UnsupportedMetrics.PARTIALLY_SUPPORTED_METRICS.get(DATA.name())))
+        join(COMMA_JOIN_SEPARATOR, UnsupportedMetrics.PARTIALLY_SUPPORTED_METRICS.get(DATA.name())))
       .setMaxValuesAllowed(MAX_METRIC_KEYS);
     createAdditionalFieldsParameter(action);
     createQualifiersParameter(action, newQualifierParameterContext(i18n, resourceTypes));
 
     action.createParam(PARAM_STRATEGY)
       .setDescription("Strategy to search for base component descendants:" +
-                      "<ul>" +
-                      "<li>children: return the children components of the base component. Grandchildren components are not returned</li>" +
-                      "<li>all: return all the descendants components of the base component. Grandchildren are returned.</li>" +
-                      "<li>leaves: return all the descendant components (files, in general) which don't have other children. They are the leaves of the component tree.</li>" +
-                      "</ul>")
+        "<ul>" +
+        "<li>children: return the children components of the base component. Grandchildren components are not returned</li>" +
+        "<li>all: return all the descendants components of the base component. Grandchildren are returned.</li>" +
+        "<li>leaves: return all the descendant components (files, in general) which don't have other children. They are the leaves of the" +
+        " component tree.</li>" +
+        "</ul>")
       .setPossibleValues(STRATEGIES.keySet())
       .setDefaultValue(ALL_STRATEGY);
   }
@@ -355,7 +367,8 @@ public class ComponentTreeAction implements MeasuresWsAction {
     return additionalFields != null && additionalFields.contains(ADDITIONAL_METRICS);
   }
 
-  private static ComponentTreeWsResponse emptyResponse(@Nullable ComponentDto baseComponent, @Nullable BranchDto branch, ComponentTreeRequest request) {
+  private static ComponentTreeWsResponse emptyResponse(@Nullable ComponentDto baseComponent, @Nullable BranchDto branch,
+    ComponentTreeRequest request) {
     ComponentTreeWsResponse.Builder response = ComponentTreeWsResponse.newBuilder();
     response.getPagingBuilder()
       .setPageIndex(request.getPage())
@@ -363,14 +376,16 @@ public class ComponentTreeAction implements MeasuresWsAction {
       .setTotal(0);
     if (baseComponent != null) {
       boolean isMainBranch = branch == null || branch.isMain();
-      response.setBaseComponent(componentDtoToWsComponent(baseComponent, isMainBranch ? null : request.getBranch(), request.getPullRequest()));
+      response.setBaseComponent(componentDtoToWsComponent(baseComponent, isMainBranch ? null : request.getBranch(),
+        request.getPullRequest()));
     }
     return response.build();
   }
 
   private static ComponentTreeRequest toComponentTreeWsRequest(Request request) {
     List<String> metricKeys = request.mandatoryParamAsStrings(PARAM_METRIC_KEYS);
-    checkArgument(metricKeys.size() <= MAX_METRIC_KEYS, "Number of metrics keys is limited to %s, got %s", MAX_METRIC_KEYS, metricKeys.size());
+    checkArgument(metricKeys.size() <= MAX_METRIC_KEYS, "Number of metrics keys is limited to %s, got %s", MAX_METRIC_KEYS,
+      metricKeys.size());
     ComponentTreeRequest componentTreeRequest = new ComponentTreeRequest()
       .setComponent(request.mandatoryParam(PARAM_COMPONENT))
       .setBranch(request.param(PARAM_BRANCH))
@@ -388,7 +403,8 @@ public class ComponentTreeAction implements MeasuresWsAction {
       .setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE))
       .setQuery(request.param(Param.TEXT_QUERY));
     String metricSortValue = componentTreeRequest.getMetricSort();
-    checkRequest(!componentTreeRequest.getMetricKeys().isEmpty(), "The '%s' parameter must contain at least one metric key", PARAM_METRIC_KEYS);
+    checkRequest(!componentTreeRequest.getMetricKeys().isEmpty(), "The '%s' parameter must contain at least one metric key",
+      PARAM_METRIC_KEYS);
     List<String> sorts = ofNullable(componentTreeRequest.getSort()).orElse(emptyList());
     checkRequest(metricSortValue == null ^ sorts.contains(METRIC_SORT) ^ sorts.contains(METRIC_PERIOD_SORT),
       "To sort by a metric, the '%s' parameter must contain '%s' or '%s', and a metric key must be provided in the '%s' parameter",
@@ -396,7 +412,8 @@ public class ComponentTreeAction implements MeasuresWsAction {
     checkRequest(metricSortValue == null ^ componentTreeRequest.getMetricKeys().contains(metricSortValue),
       "To sort by the '%s' metric, it must be in the list of metric keys in the '%s' parameter", metricSortValue, PARAM_METRIC_KEYS);
     checkRequest(componentTreeRequest.getMetricPeriodSort() == null ^ sorts.contains(METRIC_PERIOD_SORT),
-      "To sort by a metric period, the '%s' parameter must contain '%s' and the '%s' must be provided.", Param.SORT, METRIC_PERIOD_SORT, PARAM_METRIC_PERIOD_SORT);
+      "To sort by a metric period, the '%s' parameter must contain '%s' and the '%s' must be provided.", Param.SORT, METRIC_PERIOD_SORT,
+      PARAM_METRIC_PERIOD_SORT);
     checkRequest(ALL_METRIC_SORT_FILTER.equals(componentTreeRequest.getMetricSortFilter()) || metricSortValue != null,
       "To filter components based on the sort metric, the '%s' parameter must contain '%s' or '%s' and the '%s' parameter must be provided",
       Param.SORT, METRIC_SORT, METRIC_PERIOD_SORT, PARAM_METRIC_SORT);
@@ -404,7 +421,8 @@ public class ComponentTreeAction implements MeasuresWsAction {
   }
 
   private static Measures.Component.Builder toWsComponent(ComponentDto component, Map<MetricDto, ComponentTreeData.Measure> measures,
-    Map<String, ComponentDto> referenceComponentsByUuid, @Nullable String branch, @Nullable String pullRequest, List<String> requestedMetrics) {
+    Map<String, ComponentDto> referenceComponentsByUuid, @Nullable String branch, @Nullable String pullRequest,
+    List<String> requestedMetrics) {
     Measures.Component.Builder wsComponent = componentDtoToWsComponent(component, branch, pullRequest);
     ComponentDto referenceComponent = referenceComponentsByUuid.get(component.getCopyComponentUuid());
     if (referenceComponent != null) {
@@ -440,7 +458,8 @@ public class ComponentTreeAction implements MeasuresWsAction {
       // portfolios don't have branches
       BranchDto branchDto = dbClient.branchDao().selectByUuid(dbSession, baseComponent.branchUuid()).orElse(null);
 
-      Optional<SnapshotDto> baseSnapshot = dbClient.snapshotDao().selectLastAnalysisByRootComponentUuid(dbSession, baseComponent.branchUuid());
+      Optional<SnapshotDto> baseSnapshot = dbClient.snapshotDao().selectLastAnalysisByRootComponentUuid(dbSession,
+        baseComponent.branchUuid());
       if (baseSnapshot.isEmpty()) {
         return ComponentTreeData.builder()
           .setBranch(branchDto)
@@ -451,8 +470,10 @@ public class ComponentTreeAction implements MeasuresWsAction {
       ComponentTreeQuery componentTreeQuery = toComponentTreeQuery(wsRequest, baseComponent);
       List<ComponentDto> components = searchComponents(dbSession, componentTreeQuery);
 
-      List<MetricDto> metrics = searchMetrics(dbSession, new HashSet<>(withRemovedMetricAlias(ofNullable(wsRequest.getMetricKeys()).orElse(List.of()))));
-      Table<String, MetricDto, ComponentTreeData.Measure> measuresByComponentUuidAndMetric = searchMeasuresByComponentUuidAndMetric(dbSession, baseComponent, componentTreeQuery,
+      List<MetricDto> metrics = searchMetrics(dbSession,
+        new HashSet<>(withRemovedMetricAlias(ofNullable(wsRequest.getMetricKeys()).orElse(List.of()))));
+      Table<String, MetricDto, ComponentTreeData.Measure> measuresByComponentUuidAndMetric =
+        searchMeasuresByComponentUuidAndMetric(dbSession, baseComponent, componentTreeQuery,
         components, metrics);
 
       components = filterComponents(components, measuresByComponentUuidAndMetric, metrics, wsRequest);
@@ -521,18 +542,21 @@ public class ComponentTreeAction implements MeasuresWsAction {
         new LinkedHashSet<>(metricKeys),
         new LinkedHashSet<>(foundMetricKeys));
 
-      throw new NotFoundException(format("The following metric keys are not found: %s", String.join(COMMA_JOIN_SEPARATOR, missingMetricKeys)));
+      throw new NotFoundException(format("The following metric keys are not found: %s", join(COMMA_JOIN_SEPARATOR,
+        missingMetricKeys)));
     }
     String forbiddenMetrics = metrics.stream()
       .filter(UnsupportedMetrics.INSTANCE)
       .map(MetricDto::getKey)
       .sorted()
       .collect(Collectors.joining(COMMA_JOIN_SEPARATOR));
-    checkArgument(forbiddenMetrics.isEmpty(), "Metrics %s can't be requested in this web service. Please use api/measures/component", forbiddenMetrics);
+    checkArgument(forbiddenMetrics.isEmpty(), "Metrics %s can't be requested in this web service. Please use api/measures/component",
+      forbiddenMetrics);
     return metrics;
   }
 
-  private Table<String, MetricDto, ComponentTreeData.Measure> searchMeasuresByComponentUuidAndMetric(DbSession dbSession, ComponentDto baseComponent,
+  private Table<String, MetricDto, ComponentTreeData.Measure> searchMeasuresByComponentUuidAndMetric(DbSession dbSession,
+    ComponentDto baseComponent,
     ComponentTreeQuery componentTreeQuery, List<ComponentDto> components, List<MetricDto> metrics) {
 
     Map<String, MetricDto> metricsByUuid = Maps.uniqueIndex(metrics, MetricDto::getUuid);
@@ -543,7 +567,8 @@ public class ComponentTreeAction implements MeasuresWsAction {
       .setMetricUuids(new ArrayList<>(metricsByUuid.keySet()))
       .build();
 
-    Table<String, MetricDto, ComponentTreeData.Measure> measuresByComponentUuidAndMetric = HashBasedTable.create(components.size(), metrics.size());
+    Table<String, MetricDto, ComponentTreeData.Measure> measuresByComponentUuidAndMetric = HashBasedTable.create(components.size(),
+      metrics.size());
     dbClient.liveMeasureDao().selectTreeByQuery(dbSession, baseComponent, measureQuery, result -> {
       LiveMeasureDto measureDto = result.getResultObject();
       measuresByComponentUuidAndMetric.put(
@@ -564,7 +589,8 @@ public class ComponentTreeAction implements MeasuresWsAction {
    * <li>metric is optimized for best value</li>
    * </ul>
    */
-  private static void addBestValuesToMeasures(Table<String, MetricDto, ComponentTreeData.Measure> measuresByComponentUuidAndMetric, List<ComponentDto> components,
+  private static void addBestValuesToMeasures(Table<String, MetricDto, ComponentTreeData.Measure> measuresByComponentUuidAndMetric,
+    List<ComponentDto> components,
     List<MetricDto> metrics) {
     List<MetricDtoWithBestValue> metricDtosWithBestValueMeasure = metrics.stream()
       .filter(MetricDtoFunctions.isOptimizedForBestValue())
@@ -586,7 +612,8 @@ public class ComponentTreeAction implements MeasuresWsAction {
   }
 
   private static List<ComponentDto> filterComponents(List<ComponentDto> components,
-    Table<String, MetricDto, ComponentTreeData.Measure> measuresByComponentUuidAndMetric, List<MetricDto> metrics, ComponentTreeRequest wsRequest) {
+    Table<String, MetricDto, ComponentTreeData.Measure> measuresByComponentUuidAndMetric, List<MetricDto> metrics,
+    ComponentTreeRequest wsRequest) {
     if (!componentWithMeasuresOnly(wsRequest)) {
       return components;
     }
@@ -637,7 +664,8 @@ public class ComponentTreeAction implements MeasuresWsAction {
       return requestQualifiers;
     }
 
-    Sets.SetView<String> qualifiersIntersection = Sets.intersection(new HashSet<>(childrenQualifiers), new HashSet<Object>(requestQualifiers));
+    Sets.SetView<String> qualifiersIntersection = Sets.intersection(new HashSet<>(childrenQualifiers),
+      new HashSet<Object>(requestQualifiers));
 
     return new ArrayList<>(qualifiersIntersection);
   }