]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-20892 Updated api/measures endpoints to return renamed metric
authorlukasz-jarocki-sonarsource <lukasz.jarocki@sonarsource.com>
Fri, 3 Nov 2023 13:54:02 +0000 (14:54 +0100)
committersonartech <sonartech@sonarsource.com>
Wed, 8 Nov 2023 20:02:52 +0000 (20:02 +0000)
30 files changed:
build.gradle
gradle.properties
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueCounter.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistLiveMeasuresStep.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueCounterTest.java
server/sonar-db-dao/src/main/java/org/sonar/db/metric/RemovedMetricConverter.java [new file with mode: 0644]
server/sonar-db-dao/src/test/java/org/sonar/db/metric/RemovedMetricConverterTest.java [new file with mode: 0644]
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v104/RenameWontFixIssuesMetric.java
server/sonar-webserver-core/src/it/java/org/sonar/server/startup/RegisterMetricsIT.java
server/sonar-webserver-core/src/main/java/org/sonar/server/startup/RegisterMetrics.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/measure/ws/ComponentActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/measure/ws/ComponentTreeActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/measure/ws/SearchActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/measure/ws/SearchHistoryActionIT.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/live/MeasureUpdateFormulaFactoryImpl.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentDtoToWsComponent.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentResponseCommon.java [new file with mode: 0644]
server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentTreeAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentTreeData.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentTreeRequest.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/MeasuresWsModule.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/MetricDtoToWsMetric.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/SearchAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/SearchHistoryAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/SearchHistoryResponseFactory.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/SearchHistoryResult.java
server/sonar-webserver-webapi/src/main/resources/org/sonar/server/measure/ws/component_tree-example.json
server/sonar-webserver-webapi/src/test/java/org/sonar/server/measure/live/MeasureUpdateFormulaFactoryImplTest.java
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 2c3868b1c6c3e40b24fcace45a9b200382218ea0..a058b18e45e348d1c39df6f1de4291f9f78b9974 100644 (file)
@@ -465,6 +465,44 @@ subprojects {
   }
 
   task generatePackageInfo {
+    doLast {
+      def allPathsContainingJavaFiles = [] as Set
+
+      fileTree('src/main/java/').matching() {
+        include "*/**/*.java"
+        exclude "*/**/package-info.java"
+      }.forEach {
+        allPathsContainingJavaFiles << it.toPath().toFile().getParent();
+      }
+
+      allPathsContainingJavaFiles.each {
+        String packageInfoPath = it + "/package-info.java"
+        File packageInfoFile = new File (packageInfoPath)
+        if (!packageInfoFile.exists()) {
+            logger.warn("Creating file: " + packageInfoPath)
+            def packageName = packageInfoFile.getParent().takeAfter("src/main/java/").replaceAll("/", "\\.")
+            String packageInfoContent = applyPackageInfoTemplate(packageName)
+            packageInfoFile << packageInfoContent
+        }
+      }
+
+      def allPackageInfoFiles = [] as Set
+
+      fileTree('src/main/java/').matching() {
+        include "*/**/package-info.java"
+      }.forEach {
+        allPackageInfoFiles << it.toPath().toFile();
+      }
+
+      allPackageInfoFiles.forEach {
+        File packageInfoFile = it;
+        if (!allPathsContainingJavaFiles.contains(packageInfoFile.getParent())) {
+          logger.warn("Deleting package info file: " + packageInfoFile)
+          packageInfoFile.delete();
+        }
+      }
+
+    }
   }
   build.dependsOn(generatePackageInfo)
   generatePackageInfo.finalizedBy(licenseFormat)
index 299b5e565bb57dc4e9464f090afd3d137f13b383..0f11af88c1388fc7c2ea5a4eb45ebb974683fc8c 100644 (file)
@@ -1,6 +1,6 @@
 group=org.sonarsource.sonarqube
 version=10.4
-pluginApiVersion=10.2.0.1908
+pluginApiVersion=10.3.0.1933
 description=Open source platform for continuous inspection of code quality
 projectTitle=SonarQube
 org.gradle.jvmargs=-Xmx2048m
index 2eeab2ff2c3954b943f0247d9b41fe67a923e77f..389f862adbe900df9593e013c7929427d7107862 100644 (file)
@@ -39,6 +39,7 @@ import static org.sonar.api.issue.Issue.RESOLUTION_WONT_FIX;
 import static org.sonar.api.issue.Issue.STATUS_CONFIRMED;
 import static org.sonar.api.issue.Issue.STATUS_OPEN;
 import static org.sonar.api.issue.Issue.STATUS_REOPENED;
+import static org.sonar.api.measures.CoreMetrics.ACCEPTED_ISSUES_KEY;
 import static org.sonar.api.measures.CoreMetrics.BLOCKER_VIOLATIONS_KEY;
 import static org.sonar.api.measures.CoreMetrics.BUGS_KEY;
 import static org.sonar.api.measures.CoreMetrics.CODE_SMELLS_KEY;
@@ -63,7 +64,6 @@ import static org.sonar.api.measures.CoreMetrics.REOPENED_ISSUES_KEY;
 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_KEY;
 import static org.sonar.api.measures.CoreMetrics.VIOLATIONS_KEY;
 import static org.sonar.api.measures.CoreMetrics.VULNERABILITIES_KEY;
-import static org.sonar.api.measures.CoreMetrics.WONT_FIX_ISSUES_KEY;
 import static org.sonar.api.rule.Severity.BLOCKER;
 import static org.sonar.api.rule.Severity.CRITICAL;
 import static org.sonar.api.rule.Severity.INFO;
@@ -169,7 +169,7 @@ public class IssueCounter extends IssueVisitor {
     addMeasure(component, REOPENED_ISSUES_KEY, currentCounters.counter().reopened);
     addMeasure(component, CONFIRMED_ISSUES_KEY, currentCounters.counter().confirmed);
     addMeasure(component, FALSE_POSITIVE_ISSUES_KEY, currentCounters.counter().falsePositives);
-    addMeasure(component, WONT_FIX_ISSUES_KEY, currentCounters.counter().wontFix);
+    addMeasure(component, ACCEPTED_ISSUES_KEY, currentCounters.counter().accepted);
   }
 
   private void addMeasuresByType(Component component) {
@@ -221,7 +221,7 @@ public class IssueCounter extends IssueVisitor {
     private int reopened = 0;
     private int confirmed = 0;
     private int falsePositives = 0;
-    private int wontFix = 0;
+    private int accepted = 0;
     private final Multiset<String> severityBag = HashMultiset.create();
     private final EnumMultiset<RuleType> typeBag = EnumMultiset.create(RuleType.class);
 
@@ -231,7 +231,7 @@ public class IssueCounter extends IssueVisitor {
       reopened += counter.reopened;
       confirmed += counter.confirmed;
       falsePositives += counter.falsePositives;
-      wontFix += counter.wontFix;
+      accepted += counter.accepted;
       severityBag.addAll(counter.severityBag);
       typeBag.addAll(counter.typeBag);
     }
@@ -250,7 +250,7 @@ public class IssueCounter extends IssueVisitor {
       } else if (RESOLUTION_FALSE_POSITIVE.equals(issue.resolution())) {
         falsePositives++;
       } else if (RESOLUTION_WONT_FIX.equals(issue.resolution())) {
-        wontFix++;
+        accepted++;
       }
       switch (issue.status()) {
         case STATUS_OPEN:
index 0d67496f255aeb34c54fc449138371e071f18847..3b922906b8a4115d5df8ca913d9f9269ca1dcda4 100644 (file)
@@ -43,6 +43,7 @@ import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.measure.LiveMeasureDto;
 
+import static org.sonar.api.measures.CoreMetrics.ACCEPTED_ISSUES_KEY;
 import static org.sonar.api.measures.CoreMetrics.BLOCKER_VIOLATIONS_KEY;
 import static org.sonar.api.measures.CoreMetrics.BUGS_KEY;
 import static org.sonar.api.measures.CoreMetrics.CLASSES_KEY;
@@ -108,7 +109,7 @@ public class PersistLiveMeasuresStep implements ComputationStep {
     MAJOR_VIOLATIONS_KEY, MINOR_VIOLATIONS_KEY, NCLOC_KEY, NCLOC_DATA_KEY, NCLOC_LANGUAGE_DISTRIBUTION_KEY, OPEN_ISSUES_KEY, RELIABILITY_RATING_KEY,
     RELIABILITY_REMEDIATION_EFFORT_KEY, REOPENED_ISSUES_KEY, SECURITY_HOTSPOTS_KEY, SECURITY_HOTSPOTS_REVIEWED_KEY, SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY,
     SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY, SECURITY_RATING_KEY, SECURITY_REMEDIATION_EFFORT_KEY, SECURITY_REVIEW_RATING_KEY, SQALE_DEBT_RATIO_KEY, TECHNICAL_DEBT_KEY,
-    SQALE_RATING_KEY, STATEMENTS_KEY, VIOLATIONS_KEY, VULNERABILITIES_KEY, WONT_FIX_ISSUES_KEY
+    SQALE_RATING_KEY, STATEMENTS_KEY, VIOLATIONS_KEY, VULNERABILITIES_KEY, ACCEPTED_ISSUES_KEY
   );
   private final DbClient dbClient;
   private final MetricRepository metricRepository;
index e7aa43128dcd6d5a4618abdfd6796a8affe7b7ce..a6d26b3b7c2ea15479d497ce533bc526e7993190 100644 (file)
@@ -50,6 +50,8 @@ import static org.sonar.api.issue.Issue.STATUS_CLOSED;
 import static org.sonar.api.issue.Issue.STATUS_CONFIRMED;
 import static org.sonar.api.issue.Issue.STATUS_OPEN;
 import static org.sonar.api.issue.Issue.STATUS_RESOLVED;
+import static org.sonar.api.measures.CoreMetrics.ACCEPTED_ISSUES;
+import static org.sonar.api.measures.CoreMetrics.ACCEPTED_ISSUES_KEY;
 import static org.sonar.api.measures.CoreMetrics.BLOCKER_VIOLATIONS;
 import static org.sonar.api.measures.CoreMetrics.BLOCKER_VIOLATIONS_KEY;
 import static org.sonar.api.measures.CoreMetrics.BUGS;
@@ -133,7 +135,7 @@ public class IssueCounterTest {
     .add(NEW_MINOR_VIOLATIONS)
     .add(NEW_INFO_VIOLATIONS)
     .add(FALSE_POSITIVE_ISSUES)
-    .add(WONT_FIX_ISSUES)
+    .add(ACCEPTED_ISSUES)
     .add(CODE_SMELLS)
     .add(BUGS)
     .add(VULNERABILITIES)
@@ -200,10 +202,10 @@ public class IssueCounterTest {
     underTest.beforeComponent(PROJECT);
     underTest.afterComponent(PROJECT);
 
-    assertMeasures(FILE1, entry(VIOLATIONS_KEY, 1), entry(FALSE_POSITIVE_ISSUES_KEY, 1), entry(WONT_FIX_ISSUES_KEY, 1));
-    assertMeasures(FILE2, entry(VIOLATIONS_KEY, 2), entry(FALSE_POSITIVE_ISSUES_KEY, 0), entry(WONT_FIX_ISSUES_KEY, 1));
+    assertMeasures(FILE1, entry(VIOLATIONS_KEY, 1), entry(FALSE_POSITIVE_ISSUES_KEY, 1), entry(ACCEPTED_ISSUES_KEY, 1));
+    assertMeasures(FILE2, entry(VIOLATIONS_KEY, 2), entry(FALSE_POSITIVE_ISSUES_KEY, 0), entry(ACCEPTED_ISSUES_KEY, 1));
     assertMeasures(FILE3, entry(VIOLATIONS_KEY, 0));
-    assertMeasures(PROJECT, entry(VIOLATIONS_KEY, 3), entry(FALSE_POSITIVE_ISSUES_KEY, 1), entry(WONT_FIX_ISSUES_KEY, 2));
+    assertMeasures(PROJECT, entry(VIOLATIONS_KEY, 3), entry(FALSE_POSITIVE_ISSUES_KEY, 1), entry(ACCEPTED_ISSUES_KEY, 2));
   }
 
   @Test
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/metric/RemovedMetricConverter.java b/server/sonar-db-dao/src/main/java/org/sonar/db/metric/RemovedMetricConverter.java
new file mode 100644 (file)
index 0000000..07c46ee
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info 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.db.metric;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.api.measures.CoreMetrics;
+
+/*
+* This class has been introduced to contain the usage of deprecated and renamed metric 'WONT_FIX' in one place.
+* It should be removed in SQ 11.0.
+*/
+public class RemovedMetricConverter {
+  public static final String REMOVED_METRIC = CoreMetrics.WONT_FIX_ISSUES_KEY;
+  public static final String REMOVED_METRIC_SHORT_NAME = CoreMetrics.WONT_FIX_ISSUES.getName();
+  public static final String REMOVED_METRIC_DESCRIPTION = CoreMetrics.WONT_FIX_ISSUES.getDescription();
+  public static final String DEPRECATED_METRIC_REPLACEMENT = CoreMetrics.ACCEPTED_ISSUES_KEY;
+
+  private RemovedMetricConverter() {
+    // static methods only
+  }
+
+  public static List<String> withRemovedMetricAlias(Collection<String> metrics) {
+    if (metrics.contains(REMOVED_METRIC)) {
+      Set<String> newMetrics = new HashSet<>(metrics);
+      newMetrics.remove(REMOVED_METRIC);
+      newMetrics.add(DEPRECATED_METRIC_REPLACEMENT);
+      return newMetrics.stream().toList();
+    } else {
+      return new ArrayList<>(metrics);
+    }
+  }
+
+  @CheckForNull
+  public static String includeRenamedMetrics(@Nullable String metric) {
+    if (REMOVED_METRIC.equals(metric)) {
+      return DEPRECATED_METRIC_REPLACEMENT;
+    } else {
+      return metric;
+    }
+  }
+}
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/metric/RemovedMetricConverterTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/metric/RemovedMetricConverterTest.java
new file mode 100644 (file)
index 0000000..f29df82
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info 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.db.metric;
+
+import java.util.List;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class RemovedMetricConverterTest {
+
+  @Test
+  public void withRemovedMetricAlias_whenListContainsWontFix_shouldReturnListWithAccepted() {
+    List<String> coreMetrics = List.of("wont_fix_issues", "blocker_violations", "critical_violations");
+
+    List<String> upToDateMetrics = RemovedMetricConverter.withRemovedMetricAlias(coreMetrics);
+
+    assertThat(upToDateMetrics).containsExactlyInAnyOrder("accepted_issues", "blocker_violations", "critical_violations");
+  }
+
+  @Test
+  public void withRemovedMetricAlias_whenListContainsAccepted_shouldReturnListWithAccepted() {
+    List<String> coreMetrics = List.of("accepted_issues", "blocker_violations", "critical_violations");
+
+    List<String> upToDateMetrics = RemovedMetricConverter.withRemovedMetricAlias(coreMetrics);
+
+    assertThat(upToDateMetrics).containsExactlyInAnyOrder("accepted_issues", "blocker_violations", "critical_violations");
+  }
+
+  @Test
+  public void includeRenamedMetrics_whenWontFixIssuesPassed_shouldReturnAccepted() {
+    String upToDateMetric = RemovedMetricConverter.includeRenamedMetrics("wont_fix_issues");
+
+    assertThat(upToDateMetric).isEqualTo("accepted_issues");
+  }
+
+  @Test
+  public void includeRenamedMetrics_whenAcceptedIssuesPassed_shouldReturnAccepted() {
+    String upToDateMetric = RemovedMetricConverter.includeRenamedMetrics("accepted_issues");
+
+    assertThat(upToDateMetric).isEqualTo("accepted_issues");
+  }
+}
\ No newline at end of file
index 5f35d1caadf4816302c7ab349d8bc3a00f7927b8..ea025607fd402a0da137c4b1667a4ccdd6539724 100644 (file)
@@ -27,7 +27,7 @@ import org.sonar.server.platform.db.migration.step.Upsert;
 public class RenameWontFixIssuesMetric extends DataChange {
 
   private static final String UPDATE_QUERY = """
-    update metrics set name='accepted_issues', description='Accepted issues' where name='wont_fix_issues'
+    update metrics set name='accepted_issues', description='Accepted issues', short_name='Accepted issues' where name='wont_fix_issues'
     """;
 
   public RenameWontFixIssuesMetric(Database db) {
index bf19912492ae50c3deb874e7d7719130d5581187..35bfa6854a8e8b8257333d7dabc0d8fdb7393e99 100644 (file)
@@ -136,10 +136,12 @@ public class RegisterMetricsIT {
   }
 
   @Test
-  public void insert_core_metrics() {
+  public void insert_core_metrics_without_removed_metric() {
     register.start();
 
-    assertThat(dbTester.countRowsOfTable("metrics")).isEqualTo(CoreMetrics.getMetrics().size());
+    // Metric CoreMetrics.WONT_FIX_ISSUES was renamed to CoreMetrics.ACCEPTED_ISSUES in 10.3.
+    // We don't want to insert it anymore
+    assertThat(dbTester.countRowsOfTable("metrics")).isEqualTo(CoreMetrics.getMetrics().size() - 1);
   }
 
   @Test
index 238c97dd8f6f76486a2b91de485c1efaa7d80315..8afa7232280a63d5d68d25e4b8896e529b318861 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.server.startup;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.FluentIterable;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -35,10 +36,11 @@ import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.metric.MetricDto;
 import org.sonar.server.metric.MetricToDto;
+import org.springframework.beans.factory.annotation.Autowired;
 
 import static com.google.common.collect.FluentIterable.concat;
 import static com.google.common.collect.Lists.newArrayList;
-import org.springframework.beans.factory.annotation.Autowired;
+import static org.sonar.db.metric.RemovedMetricConverter.REMOVED_METRIC;
 
 public class RegisterMetrics implements Startable {
 
@@ -65,7 +67,9 @@ public class RegisterMetrics implements Startable {
 
   @Override
   public void start() {
-    register(concat(CoreMetrics.getMetrics(), getPluginMetrics()));
+    FluentIterable<Metric> metricsToRegister = concat(CoreMetrics.getMetrics(), getPluginMetrics())
+      .filter(m -> !REMOVED_METRIC.equals(m.getKey()));
+    register(metricsToRegister);
   }
 
   @Override
index c95206420925dd0b22d3e5139f56f779c4d333ca..bee0bba79ce3f10573874dd2382dda6422591dc5 100644 (file)
@@ -46,6 +46,7 @@ import static java.lang.Double.parseDouble;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.assertj.core.api.Assertions.tuple;
+import static org.sonar.api.measures.Metric.ValueType.INT;
 import static org.sonar.api.utils.DateUtils.parseDateTime;
 import static org.sonar.api.web.UserRole.USER;
 import static org.sonar.db.component.BranchDto.DEFAULT_MAIN_BRANCH_NAME;
@@ -355,6 +356,26 @@ public class ComponentActionIT {
       .hasMessage(String.format("Component '%s' on branch '%s' not found", file.getKey(), "another_branch"));
   }
 
+  @Test
+  public void shouldReturnRenamedMetric() {
+    ProjectData projectData = db.components().insertPrivateProject(p -> p.setKey("MY_PROJECT")
+      .setName("My Project"));
+    userSession.addProjectPermission(USER, projectData.getProjectDto())
+      .registerBranches(projectData.getMainBranchDto());
+    ComponentDto mainBranch = projectData.getMainBranchComponent();
+    SnapshotDto analysis = db.components().insertSnapshot(mainBranch, s -> s.setPeriodDate(parseDateTime("2016-01-11T10:49:50+0100").getTime())
+      .setPeriodMode("previous_version")
+      .setPeriodParam("1.0-SNAPSHOT"));
+
+    MetricDto accepted_issues = insertAcceptedIssuesMetric();
+    db.measures().insertLiveMeasure(mainBranch, accepted_issues, m -> m.setValue(10d));
+
+    db.commit();
+
+    ComponentWsResponse response = newRequest(projectData.projectKey(), "wont_fix_issues");
+    assertThat(response.getMetrics().getMetrics(0).getKey()).isEqualTo("wont_fix_issues");
+  }
+
   @Test
   public void json_example() {
     ProjectData projectData = db.components().insertPrivateProject();
@@ -417,6 +438,20 @@ public class ComponentActionIT {
     assertJson(response).isSimilarTo(getClass().getResource("component-example.json"));
   }
 
+  private MetricDto insertAcceptedIssuesMetric() {
+    MetricDto acceptedIssues = db.measures().insertMetric(m -> m.setKey("accepted_issues")
+      .setShortName("Accepted Issues")
+      .setDescription("Accepted issues")
+      .setDomain("Issues")
+      .setValueType("INT")
+      .setDirection(-1)
+      .setQualitative(false)
+      .setHidden(false));
+    db.commit();
+    return acceptedIssues;
+  }
+
+
   private ComponentWsResponse newRequest(String componentKey, String metricKeys) {
     return ws.newRequest()
       .setParam(PARAM_COMPONENT, componentKey)
index 8b885bf3c126e0fde159ad549b6b7a7f6e621cc1..05a1513f222f7b5eba13d754ee76e92d535877a5 100644 (file)
@@ -162,11 +162,16 @@ public class ComponentTreeActionIT {
     db.measures().insertLiveMeasure(dir, newViolations, m -> m.setValue(25.0d));
     db.measures().insertLiveMeasure(mainBranch, newViolations, m -> m.setValue(255.0d));
 
+    MetricDto accepted_issues = insertAcceptedIssuesMetric();
+    db.measures().insertLiveMeasure(file1, accepted_issues, m -> m.setValue(10d));
+    db.measures().insertLiveMeasure(dir, accepted_issues, m -> m.setValue(10d));
+    db.measures().insertLiveMeasure(mainBranch, accepted_issues, m -> m.setValue(10d));
+
     db.commit();
 
     String response = ws.newRequest()
       .setParam(PARAM_COMPONENT, mainBranch.getKey())
-      .setParam(PARAM_METRIC_KEYS, "ncloc, complexity, new_violations")
+      .setParam(PARAM_METRIC_KEYS, "ncloc, complexity, new_violations, accepted_issues")
       .setParam(PARAM_ADDITIONAL_FIELDS, "metrics,period")
       .execute()
       .getInput();
@@ -179,6 +184,31 @@ public class ComponentTreeActionIT {
       .addProjectBranchMapping(projectData.projectUuid(), projectData.getMainBranchComponent());
   }
 
+  @Test
+  public void shouldReturnRenamedMetric() {
+    ProjectData projectData = db.components().insertPrivateProject(p -> p.setKey("MY_PROJECT")
+      .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())
+      .setPeriodMode("previous_version")
+      .setPeriodParam("1.0-SNAPSHOT"));
+
+    MetricDto accepted_issues = insertAcceptedIssuesMetric();
+    db.measures().insertLiveMeasure(mainBranch, accepted_issues, m -> m.setValue(10d));
+
+    db.commit();
+
+    ComponentTreeWsResponse response = ws.newRequest()
+      .setParam(PARAM_COMPONENT, mainBranch.getKey())
+      .setParam(PARAM_METRIC_KEYS, "wont_fix_issues")
+      .setParam(PARAM_ADDITIONAL_FIELDS, "metrics")
+      .executeProtobuf(ComponentTreeWsResponse.class);
+
+    assertThat(response.getMetrics().getMetrics(0).getKey()).isEqualTo("wont_fix_issues");
+    assertThat(response.getBaseComponent().getMeasures(0).getMetric()).isEqualTo("wont_fix_issues");
+  }
+
   @Test
   public void empty_response() {
     ProjectData projectData = db.components().insertPrivateProject();
@@ -1077,6 +1107,20 @@ public class ComponentTreeActionIT {
     return metric;
   }
 
+  private MetricDto insertAcceptedIssuesMetric() {
+    MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
+      .setKey("accepted_issues")
+      .setShortName("Accepted Issues")
+      .setDescription("Accepted issues")
+      .setDomain("Issues")
+      .setValueType(INT.name())
+      .setDirection(-1)
+      .setQualitative(false)
+      .setHidden(false));
+    db.commit();
+    return metric;
+  }
+
   private MetricDto insertNclocMetric() {
     MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
       .setKey("ncloc")
index b854fe6b1a72a3b450926d1e86e5e6da0dce1441..c81945d50edecb033f0ed80d355d2bdc165f0c3c 100644 (file)
@@ -117,6 +117,24 @@ public class SearchActionIT {
     assertThat(measure.getValue()).isEqualTo("15.5");
   }
 
+  @Test
+  public void search_shouldReturnAcceptedIssuesMetric_whenIsCalledWithDeprecatedWontFixIssuesMetric() {
+    ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
+    userSession.addProjectPermission(UserRole.USER, project);
+    MetricDto acceptedIssues = db.measures().insertMetric(m -> m.setValueType(INT.name())
+      .setKey("accepted_issues")
+      .setShortName("Accepted Issues"));
+    db.measures().insertLiveMeasure(project, acceptedIssues, m -> m.setValue(10d));
+
+    SearchWsResponse result = call(singletonList(project.getKey()), singletonList("wont_fix_issues"));
+
+    List<Measure> measures = result.getMeasuresList();
+    assertThat(measures).hasSize(1);
+    Measure measure = measures.get(0);
+    assertThat(measure.getMetric()).isEqualTo("wont_fix_issues");
+    assertThat(measure.getValue()).isEqualTo("10");
+  }
+
   @Test
   public void return_best_value() {
     ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
index 885f045241155d1af3762ad303ded12d4846c986..aeec043073fe152175f46f00016e4fdf05698a81 100644 (file)
@@ -90,6 +90,7 @@ public class SearchHistoryActionIT {
   private MetricDto nclocMetric;
   private MetricDto newViolationMetric;
   private MetricDto stringMetric;
+  private MetricDto acceptedIssuesMetric;
 
   @Before
   public void setUp() {
@@ -101,6 +102,7 @@ public class SearchHistoryActionIT {
     complexityMetric = insertComplexityMetric();
     newViolationMetric = insertNewViolationMetric();
     stringMetric = insertStringMetric();
+    acceptedIssuesMetric = insertAcceptedIssuesMetric();
   }
 
   @Test
@@ -145,18 +147,36 @@ public class SearchHistoryActionIT {
   @Test
   public void return_metrics() {
     dbClient.measureDao().insert(dbSession, newMeasureDto(complexityMetric, project.mainBranchUuid(), analysis).setValue(42.0d));
+    dbClient.measureDao().insert(dbSession, newMeasureDto(acceptedIssuesMetric, project.mainBranchUuid(), analysis).setValue(10.0d));
     db.commit();
 
     SearchHistoryRequest request = SearchHistoryRequest.builder()
       .setComponent(project.projectKey())
-      .setMetrics(asList(complexityMetric.getKey(), nclocMetric.getKey(), newViolationMetric.getKey()))
+      .setMetrics(asList(complexityMetric.getKey(), nclocMetric.getKey(), newViolationMetric.getKey(), acceptedIssuesMetric.getKey()))
       .build();
 
     SearchHistoryResponse result = call(request);
 
-    assertThat(result.getMeasuresList()).hasSize(3)
+    assertThat(result.getMeasuresList()).hasSize(4)
       .extracting(HistoryMeasure::getMetric)
-      .containsExactly(complexityMetric.getKey(), nclocMetric.getKey(), newViolationMetric.getKey());
+      .containsExactlyInAnyOrder(complexityMetric.getKey(), nclocMetric.getKey(), newViolationMetric.getKey(), acceptedIssuesMetric.getKey());
+  }
+
+  @Test
+  public void return_renamed_and_deprecated_metric() {
+    dbClient.measureDao().insert(dbSession, newMeasureDto(acceptedIssuesMetric, project.mainBranchUuid(), analysis).setValue(10.0d));
+    db.commit();
+
+    SearchHistoryRequest request = SearchHistoryRequest.builder()
+      .setComponent(project.projectKey())
+      .setMetrics(singletonList("wont_fix_issues"))
+      .build();
+
+    SearchHistoryResponse result = call(request);
+
+    assertThat(result.getMeasuresList()).hasSize(1)
+      .extracting(HistoryMeasure::getMetric)
+      .containsExactlyInAnyOrder("wont_fix_issues");
   }
 
   @Test
@@ -557,4 +577,16 @@ public class SearchHistoryActionIT {
     db.commit();
     return metric;
   }
+
+  private MetricDto insertAcceptedIssuesMetric() {
+    MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDtoWithoutOptimization()
+      .setKey("accepted_issues")
+      .setShortName("Accepted Issues")
+      .setValueType("INT"))
+      .setDirection(-1)
+      .setQualitative(true)
+      .setHidden(false);
+    db.commit();
+    return metric;
+  }
 }
index 8b807b8ded6088cb6678a91ac027feef02cfe663..93315bef07763cdead66861bae0b4c61f4eb3976 100644 (file)
@@ -78,7 +78,7 @@ public class MeasureUpdateFormulaFactoryImpl implements MeasureUpdateFormulaFact
     new MeasureUpdateFormula(CoreMetrics.FALSE_POSITIVE_ISSUES, false, new AddChildren(),
       (context, issues) -> context.setValue(issues.countByResolution(Issue.RESOLUTION_FALSE_POSITIVE, false))),
 
-    new MeasureUpdateFormula(CoreMetrics.WONT_FIX_ISSUES, false, new AddChildren(),
+    new MeasureUpdateFormula(CoreMetrics.ACCEPTED_ISSUES, false, new AddChildren(),
       (context, issues) -> context.setValue(issues.countByResolution(Issue.RESOLUTION_WONT_FIX, false))),
 
     new MeasureUpdateFormula(CoreMetrics.OPEN_ISSUES, false, new AddChildren(),
index 4ab014e88af9656135e972b0daaad0a6c737df22..939c4d4d2f2714104b2bea6fb338cee0b23e80e8 100644 (file)
@@ -55,6 +55,7 @@ import static java.lang.String.format;
 import static java.util.Collections.emptyMap;
 import static java.util.Collections.singletonList;
 import static java.util.Collections.singletonMap;
+import static org.sonar.db.metric.RemovedMetricConverter.withRemovedMetricAlias;
 import static org.sonar.server.component.ws.MeasuresWsParameters.ACTION_COMPONENT;
 import static org.sonar.server.component.ws.MeasuresWsParameters.ADDITIONAL_METRICS;
 import static org.sonar.server.component.ws.MeasuresWsParameters.ADDITIONAL_PERIOD;
@@ -65,9 +66,9 @@ import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRIC_KE
 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_PULL_REQUEST;
 import static org.sonar.server.exceptions.BadRequestException.checkRequest;
 import static org.sonar.server.measure.ws.ComponentDtoToWsComponent.componentDtoToWsComponent;
+import static org.sonar.server.measure.ws.ComponentResponseCommon.addMetricToResponseIncludingRenamedMetric;
 import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createAdditionalFieldsParameter;
 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.SnapshotDtoToWsPeriod.snapshotToWsPeriods;
 import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001;
 import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
@@ -95,14 +96,17 @@ public class ComponentAction implements MeasuresWsAction {
       .setResponseExample(getClass().getResource("component-example.json"))
       .setSince("5.4")
       .setChangelog(
+        new Change("10.3", "The metric 'wont_fix_issues' is now deprecated in the response. Consume 'accepted_issues' instead."),
+        new Change("10.3", "The use of 'wont_fix_issues' value in 'metricKeys' param is now deprecated. Use 'accepted_issues' instead."),
+        new Change("10.3", "Added new accepted value for the 'metricKeys' param: 'accepted_issues'."),
         new Change("10.1", String.format("The use of module keys in parameter '%s' is removed", PARAM_COMPONENT)),
         new Change("10.0", format("The use of the following metrics in 'metricKeys' parameter is not deprecated anymore: %s",
-          MeasuresWsModule.getDeprecatedMetrics())),
+          MeasuresWsModule.getDeprecatedMetricsInSonarQube93())),
         new Change("10.0", "the response field periods under measures field is removed."),
         new Change("10.0", "the option `periods` of 'additionalFields' request field is removed."),
         new Change("9.3", "When the new code period is set to 'reference branch', the response field 'date' under the 'period' field has been removed"),
         new Change("9.3", format("The use of the following metrics in 'metricKeys' parameter is deprecated: %s",
-          MeasuresWsModule.getDeprecatedMetrics())),
+          MeasuresWsModule.getDeprecatedMetricsInSonarQube93())),
         new Change("8.8", "deprecated response field 'id' has been removed"),
         new Change("8.8", "deprecated response field 'refId' has been removed."),
         new Change("8.1", "the response field periods under measures field is deprecated. Use period instead."),
@@ -145,13 +149,13 @@ public class ComponentAction implements MeasuresWsAction {
       checkPermissions(component);
       SnapshotDto analysis = dbClient.snapshotDao().selectLastAnalysisByRootComponentUuid(dbSession, component.branchUuid()).orElse(null);
 
-      List<MetricDto> metrics = searchMetrics(dbSession, new HashSet<>(request.getMetricKeys()));
+      List<MetricDto> metrics = searchMetrics(dbSession, new HashSet<>(withRemovedMetricAlias(request.getMetricKeys())));
       List<LiveMeasureDto> measures = searchMeasures(dbSession, component, metrics);
       Map<MetricDto, LiveMeasureDto> measuresByMetric = getMeasuresByMetric(measures, metrics);
 
       Optional<Measures.Period> period = snapshotToWsPeriods(analysis);
       Optional<RefComponent> reference = getReference(dbSession, component);
-      return buildResponse(dbSession, request, component, reference, measuresByMetric, metrics, period);
+      return buildResponse(dbSession, request, component, reference, measuresByMetric, metrics, period, request.getMetricKeys());
     }
   }
 
@@ -229,30 +233,33 @@ public class ComponentAction implements MeasuresWsAction {
   }
 
   private ComponentWsResponse buildResponse(DbSession dbSession, ComponentRequest request, ComponentDto component, Optional<RefComponent> reference,
-    Map<MetricDto, LiveMeasureDto> measuresByMetric, Collection<MetricDto> metrics, Optional<Measures.Period> period) {
+    Map<MetricDto, LiveMeasureDto> measuresByMetric, Collection<MetricDto> metrics, Optional<Measures.Period> period,
+    Collection<String> requestedMetrics) {
     ComponentWsResponse.Builder response = ComponentWsResponse.newBuilder();
 
     if (reference.isPresent()) {
       BranchDto refBranch = reference.get().getRefBranch();
       ComponentDto refComponent = reference.get().getComponent();
       response.setComponent(componentDtoToWsComponent(component, measuresByMetric, singletonMap(refComponent.uuid(), refComponent),
-        refBranch.isMain() ? null : refBranch.getBranchKey(), null));
+        refBranch.isMain() ? null : refBranch.getBranchKey(), null, requestedMetrics));
     } else {
       boolean isMainBranch = dbClient.branchDao().selectByUuid(dbSession, component.branchUuid()).map(BranchDto::isMain).orElse(true);
-      response.setComponent(componentDtoToWsComponent(component, measuresByMetric, emptyMap(), isMainBranch ? null : request.getBranch(), request.getPullRequest()));
+      response.setComponent(componentDtoToWsComponent(component, measuresByMetric, emptyMap(), isMainBranch ? null : request.getBranch(),
+        request.getPullRequest(), requestedMetrics));
     }
 
-    setAdditionalFields(request, metrics, period, response);
+    setAdditionalFields(request, metrics, period, response, requestedMetrics);
 
     return response.build();
   }
 
-  private static void setAdditionalFields(ComponentRequest request, Collection<MetricDto> metrics, Optional<Measures.Period> period, ComponentWsResponse.Builder response) {
+  private static void setAdditionalFields(ComponentRequest request, Collection<MetricDto> metrics, Optional<Measures.Period> period,
+    ComponentWsResponse.Builder response, Collection<String> requestedMetrics) {
     List<String> additionalFields = request.getAdditionalFields();
     if (additionalFields != null) {
       if (additionalFields.contains(ADDITIONAL_METRICS)) {
-        for (MetricDto metric : metrics) {
-          response.getMetricsBuilder().addMetrics(metricDtoToWsMetric(metric));
+        for (MetricDto metricDto : metrics) {
+          addMetricToResponseIncludingRenamedMetric(metric -> response.getMetricsBuilder().addMetrics(metric), requestedMetrics, metricDto);
         }
       }
 
index 55760a0070c51755eb8d2a194397407a41337371..4f31a2f3e92ecb0284b1f97f0c7673c32ba69ce6 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.measure.ws;
 
+import java.util.Collection;
 import java.util.Map;
 import javax.annotation.Nullable;
 import org.sonar.db.component.ComponentDto;
@@ -28,6 +29,7 @@ import org.sonarqube.ws.Measures;
 import org.sonarqube.ws.Measures.Component;
 
 import static java.util.Optional.ofNullable;
+import static org.sonar.server.measure.ws.ComponentResponseCommon.addMeasureIncludingRenamedMetric;
 
 class ComponentDtoToWsComponent {
   private ComponentDtoToWsComponent() {
@@ -36,7 +38,7 @@ class ComponentDtoToWsComponent {
 
   static Component.Builder componentDtoToWsComponent(ComponentDto component, Map<MetricDto, LiveMeasureDto> measuresByMetric,
                                                      Map<String, ComponentDto> referenceComponentsByUuid, @Nullable String branch,
-                                                     @Nullable String pullRequest) {
+                                                     @Nullable String pullRequest, Collection<String> requestedMetrics) {
     Component.Builder wsComponent = componentDtoToWsComponent(component, branch, pullRequest);
 
     ComponentDto referenceComponent = referenceComponentsByUuid.get(component.getCopyComponentUuid());
@@ -47,7 +49,7 @@ class ComponentDtoToWsComponent {
     Measures.Measure.Builder measureBuilder = Measures.Measure.newBuilder();
     for (Map.Entry<MetricDto, LiveMeasureDto> entry : measuresByMetric.entrySet()) {
       MeasureDtoToWsMeasure.updateMeasureBuilder(measureBuilder, entry.getKey(), entry.getValue());
-      wsComponent.addMeasures(measureBuilder);
+      addMeasureIncludingRenamedMetric(requestedMetrics, wsComponent, measureBuilder);
       measureBuilder.clear();
     }
 
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentResponseCommon.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentResponseCommon.java
new file mode 100644 (file)
index 0000000..2fa908b
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info 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.measure.ws;
+
+import java.util.Collection;
+import java.util.function.Consumer;
+import org.sonar.db.metric.MetricDto;
+import org.sonar.db.metric.RemovedMetricConverter;
+import org.sonarqube.ws.Measures;
+
+import static org.sonar.db.metric.RemovedMetricConverter.REMOVED_METRIC;
+import static org.sonar.db.metric.RemovedMetricConverter.DEPRECATED_METRIC_REPLACEMENT;
+import static org.sonar.server.measure.ws.MetricDtoToWsMetric.metricDtoToWsMetric;
+import static org.sonar.server.measure.ws.MetricDtoToWsMetric.wontFixToAcceptedWsMetric;
+
+public class ComponentResponseCommon {
+
+  private ComponentResponseCommon() {
+    // static methods only
+  }
+
+  static void addMetricToResponseIncludingRenamedMetric(Consumer<org.sonarqube.ws.Common.Metric> responseBuilder, Collection<String> requestedMetrics,
+    MetricDto metricDto) {
+    if (metricDto.getKey().equals(DEPRECATED_METRIC_REPLACEMENT)) {
+      if (requestedMetrics.contains(DEPRECATED_METRIC_REPLACEMENT)) {
+        responseBuilder.accept(metricDtoToWsMetric(metricDto));
+      }
+      if (requestedMetrics.contains(REMOVED_METRIC)) {
+        responseBuilder.accept(wontFixToAcceptedWsMetric(metricDto));
+      }
+    } else {
+      responseBuilder.accept(metricDtoToWsMetric(metricDto));
+    }
+  }
+
+  public static void addMetricToSearchHistoryResponseIncludingRenamedMetric(Measures.SearchHistoryResponse.Builder response,
+    Collection<String> requestedMetrics, Measures.SearchHistoryResponse.HistoryMeasure.Builder measure) {
+    if (measure.getMetric().equals(DEPRECATED_METRIC_REPLACEMENT)) {
+      if (requestedMetrics.contains(DEPRECATED_METRIC_REPLACEMENT)) {
+        response.addMeasures(measure.build());
+      }
+      if (requestedMetrics.contains(RemovedMetricConverter.REMOVED_METRIC)) {
+        response.addMeasures(measure.setMetric(RemovedMetricConverter.REMOVED_METRIC).build());
+      }
+    } else {
+      response.addMeasures(measure.build());
+    }
+  }
+
+  static void addMeasureIncludingRenamedMetric(Collection<String> requestedMetrics, Measures.Component.Builder componentBuilder,
+    Measures.Measure.Builder measureBuilder) {
+    if (measureBuilder.getMetric().equals(DEPRECATED_METRIC_REPLACEMENT)) {
+      if (requestedMetrics.contains(DEPRECATED_METRIC_REPLACEMENT)) {
+        componentBuilder.addMeasures(measureBuilder.build());
+      }
+      if (requestedMetrics.contains(REMOVED_METRIC)) {
+        componentBuilder.addMeasures(measureBuilder.setMetric(REMOVED_METRIC).build());
+      }
+    } else {
+      componentBuilder.addMeasures(measureBuilder.build());
+    }
+  }
+}
index 3e089a836a9a279be715b25bd29a79e85e57ef03..d5006a14c02672e3327a1ebbf238da9ae97a2fd1 100644 (file)
@@ -76,11 +76,14 @@ import static com.google.common.base.Preconditions.checkState;
 import static java.lang.String.format;
 import static java.util.Collections.emptyList;
 import static java.util.Collections.emptyMap;
+import static java.util.Optional.ofNullable;
 import static org.sonar.api.measures.Metric.ValueType.DATA;
 import static org.sonar.api.measures.Metric.ValueType.DISTRIB;
 import static org.sonar.api.utils.Paging.offset;
 import static org.sonar.db.component.ComponentTreeQuery.Strategy.CHILDREN;
 import static org.sonar.db.component.ComponentTreeQuery.Strategy.LEAVES;
+import static org.sonar.db.metric.RemovedMetricConverter.includeRenamedMetrics;
+import static org.sonar.db.metric.RemovedMetricConverter.withRemovedMetricAlias;
 import static org.sonar.server.component.ws.MeasuresWsParameters.ACTION_COMPONENT_TREE;
 import static org.sonar.server.component.ws.MeasuresWsParameters.ADDITIONAL_METRICS;
 import static org.sonar.server.component.ws.MeasuresWsParameters.ADDITIONAL_PERIOD;
@@ -96,16 +99,17 @@ import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_QUALIFIER
 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_STRATEGY;
 import static org.sonar.server.exceptions.BadRequestException.checkRequest;
 import static org.sonar.server.measure.ws.ComponentDtoToWsComponent.componentDtoToWsComponent;
+import static org.sonar.server.measure.ws.ComponentResponseCommon.addMeasureIncludingRenamedMetric;
+import static org.sonar.server.measure.ws.ComponentResponseCommon.addMetricToResponseIncludingRenamedMetric;
 import static org.sonar.server.measure.ws.MeasureDtoToWsMeasure.updateMeasureBuilder;
 import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createAdditionalFieldsParameter;
 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.SnapshotDtoToWsPeriod.snapshotToWsPeriods;
 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.KeyExamples.KEY_PULL_REQUEST_EXAMPLE_001;
-import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext;
 import static org.sonar.server.ws.WsParameterBuilder.createQualifiersParameter;
+import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
 
 /**
@@ -177,13 +181,16 @@ public class ComponentTreeAction implements MeasuresWsAction {
       .setHandler(this)
       .addPagingParams(100, MAX_SIZE)
       .setChangelog(
+        new Change("10.3", "The metric 'wont_fix_issues' is now deprecated in the response. Consume 'accepted_issues' instead."),
+        new Change("10.3", "The use of 'wont_fix_issues' value in 'metricKeys' and 'metricSort' params is now deprecated. Use 'accepted_issues' instead."),
+        new Change("10.3", "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.0", format("The use of the following metrics in 'metricKeys' parameter is not deprecated anymore: %s",
-          MeasuresWsModule.getDeprecatedMetrics())),
+          MeasuresWsModule.getDeprecatedMetricsInSonarQube93())),
         new Change("10.0", "the response field periods under measures field is removed."),
         new Change("10.0", "the option `periods` of 'additionalFields' request field is removed."),
         new Change("9.3", format("The use of the following metrics in 'metricKeys' parameter is deprecated: %s",
-          MeasuresWsModule.getDeprecatedMetrics())),
+          MeasuresWsModule.getDeprecatedMetricsInSonarQube93())),
         new Change("8.8", "parameter 'component' is now required"),
         new Change("8.8", "deprecated parameter 'baseComponentId' has been removed"),
         new Change("8.8", "deprecated parameter 'baseComponentKey' has been removed."),
@@ -279,10 +286,12 @@ public class ComponentTreeAction implements MeasuresWsAction {
       Paging.forPageIndex(
         request.getPage())
         .withPageSize(request.getPageSize())
-        .andTotal(data.getComponentCount()));
+        .andTotal(data.getComponentCount()),
+      request.getMetricKeys());
   }
 
-  private static ComponentTreeWsResponse buildResponse(ComponentTreeRequest request, ComponentTreeData data, Paging paging) {
+  private static ComponentTreeWsResponse buildResponse(ComponentTreeRequest request, ComponentTreeData data, Paging paging,
+    List<String> requestedMetrics) {
     ComponentTreeWsResponse.Builder response = ComponentTreeWsResponse.newBuilder();
     response.getPagingBuilder()
       .setPageIndex(paging.pageIndex())
@@ -295,7 +304,7 @@ public class ComponentTreeAction implements MeasuresWsAction {
       toWsComponent(
         data.getBaseComponent(),
         data.getMeasuresByComponentUuidAndMetric().row(data.getBaseComponent().uuid()),
-        data.getReferenceComponentsByUuid(), isMainBranch ? null : request.getBranch(), request.getPullRequest()));
+        data.getReferenceComponentsByUuid(), isMainBranch ? null : request.getBranch(), request.getPullRequest(), requestedMetrics));
 
     for (ComponentDto componentDto : data.getComponents()) {
       if (componentDto.getCopyComponentUuid() != null) {
@@ -303,23 +312,22 @@ public class ComponentTreeAction implements MeasuresWsAction {
         response.addComponents(toWsComponent(
           componentDto,
           data.getMeasuresByComponentUuidAndMetric().row(componentDto.uuid()),
-          data.getReferenceComponentsByUuid(), refBranch, null));
+          data.getReferenceComponentsByUuid(), refBranch, null, requestedMetrics));
       } else {
         response.addComponents(toWsComponent(
           componentDto,
           data.getMeasuresByComponentUuidAndMetric().row(componentDto.uuid()),
-          data.getReferenceComponentsByUuid(), isMainBranch ? null : request.getBranch(), request.getPullRequest()));
+          data.getReferenceComponentsByUuid(), isMainBranch ? null : request.getBranch(), request.getPullRequest(), requestedMetrics));
       }
     }
 
     if (areMetricsInResponse(request)) {
-      Measures.Metrics.Builder metricsBuilder = response.getMetricsBuilder();
       for (MetricDto metricDto : data.getMetrics()) {
-        metricsBuilder.addMetrics(metricDtoToWsMetric(metricDto));
+        addMetricToResponseIncludingRenamedMetric(metric -> response.getMetricsBuilder().addMetrics(metric), requestedMetrics, metricDto);
       }
     }
 
-    List<String> additionalFields = Optional.ofNullable(request.getAdditionalFields()).orElse(Collections.emptyList());
+    List<String> additionalFields = ofNullable(request.getAdditionalFields()).orElse(Collections.emptyList());
 
     if (additionalFields.contains(ADDITIONAL_PERIOD) && data.getPeriod() != null) {
       response.setPeriod(data.getPeriod());
@@ -359,7 +367,7 @@ public class ComponentTreeAction implements MeasuresWsAction {
       .setAdditionalFields(request.paramAsStrings(PARAM_ADDITIONAL_FIELDS))
       .setSort(request.paramAsStrings(Param.SORT))
       .setAsc(request.paramAsBoolean(Param.ASCENDING))
-      .setMetricSort(request.param(PARAM_METRIC_SORT))
+      .setMetricSort(includeRenamedMetrics(request.param(PARAM_METRIC_SORT)))
       .setMetricSortFilter(request.mandatoryParam(PARAM_METRIC_SORT_FILTER))
       .setMetricPeriodSort(request.paramAsInt(PARAM_METRIC_PERIOD_SORT))
       .setPage(request.mandatoryParamAsInt(Param.PAGE))
@@ -367,7 +375,7 @@ public class ComponentTreeAction implements MeasuresWsAction {
       .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);
-    List<String> sorts = Optional.ofNullable(componentTreeRequest.getSort()).orElse(emptyList());
+    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",
       Param.SORT, METRIC_SORT, METRIC_PERIOD_SORT, PARAM_METRIC_SORT);
@@ -382,7 +390,7 @@ 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) {
+    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) {
@@ -395,7 +403,7 @@ public class ComponentTreeAction implements MeasuresWsAction {
       ComponentTreeData.Measure measure = entry.getValue();
       boolean onNewCode = entry.getKey().getKey().startsWith("new_");
       updateMeasureBuilder(measureBuilder, entry.getKey(), measure.getValue(), measure.getData(), onNewCode);
-      wsComponent.addMeasures(measureBuilder);
+      addMeasureIncludingRenamedMetric(requestedMetrics, wsComponent, measureBuilder);
       measureBuilder.clear();
     }
     return wsComponent;
@@ -429,9 +437,9 @@ public class ComponentTreeAction implements MeasuresWsAction {
       ComponentTreeQuery componentTreeQuery = toComponentTreeQuery(wsRequest, baseComponent);
       List<ComponentDto> components = searchComponents(dbSession, componentTreeQuery);
 
-      List<MetricDto> metrics = searchMetrics(dbSession, new HashSet<>(wsRequest.getMetricKeys()));
-      Table<String, MetricDto, ComponentTreeData.Measure> measuresByComponentUuidAndMetric =
-        searchMeasuresByComponentUuidAndMetric(dbSession, baseComponent, componentTreeQuery, components, metrics);
+      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);
       components = filterAuthorizedComponents(components);
index 7ddd4bafb9f16a6573142cb22a80f53448c8c8f9..36ee695d4565d12fd35e3a9d0dfef5f8a0def26d 100644 (file)
@@ -75,7 +75,6 @@ class ComponentTreeData {
     return components;
   }
 
-  @CheckForNull
   int getComponentCount() {
     return componentCount;
   }
index 0e0e4e0d50fbcef7df88d791b93839936f3d9ba5..992968529b64e520da716790515da23b3037553e 100644 (file)
@@ -36,7 +36,7 @@ class ComponentTreeRequest {
   private String metricSort;
   private Integer metricPeriodSort;
   private String metricSortFilter;
-  private List<String> metricKeys;
+  private List<String> metricKeys = List.of();
   private Integer page;
   private Integer pageSize;
 
@@ -139,7 +139,6 @@ class ComponentTreeRequest {
     return this;
   }
 
-  @CheckForNull
   public List<String> getMetricKeys() {
     return metricKeys;
   }
index 747b40797398b533a1dd75256697b8fd7287f205..3c5e643e350970694f006198a5b272f037938024 100644 (file)
@@ -33,7 +33,7 @@ public class MeasuresWsModule extends Module {
   }
 
 
-  public static String getDeprecatedMetrics() {
+  public static String getDeprecatedMetricsInSonarQube93() {
     return String.join(", ", "releasability_effort", "security_rating_effort", "reliability_rating_effort", "security_review_rating_effort",
       "maintainability_rating_effort", "last_change_on_maintainability_rating", "last_change_on_releasability_rating", "last_change_on_reliability_rating",
       "last_change_on_security_rating", "last_change_on_security_review_rating");
index 1511b81a6e1a151369e1ed407da752f6504beb3d..9fafb5306a7f57f5dec88d706f82c4c34d991ded 100644 (file)
@@ -23,6 +23,9 @@ import org.sonar.db.metric.MetricDto;
 import org.sonarqube.ws.Common.Metric;
 
 import static java.util.Optional.ofNullable;
+import static org.sonar.db.metric.RemovedMetricConverter.REMOVED_METRIC;
+import static org.sonar.db.metric.RemovedMetricConverter.REMOVED_METRIC_DESCRIPTION;
+import static org.sonar.db.metric.RemovedMetricConverter.REMOVED_METRIC_SHORT_NAME;
 import static org.sonar.server.measure.ws.MeasureValueFormatter.formatNumericalValue;
 
 class MetricDtoToWsMetric {
@@ -48,4 +51,13 @@ class MetricDtoToWsMetric {
 
     return metric.build();
   }
+
+  static Metric wontFixToAcceptedWsMetric(MetricDto metricDto) {
+    return metricDtoToWsMetric(metricDto)
+      .toBuilder()
+      .setKey(REMOVED_METRIC)
+      .setDescription(REMOVED_METRIC_DESCRIPTION)
+      .setName(REMOVED_METRIC_SHORT_NAME)
+      .build();
+  }
 }
index 740c38ef822a40e85a1878ff113276edbde33616..23ac6a65ce23ec45c2667f9b94c9d96864234ce2 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.server.measure.ws;
 
 import com.google.common.collect.ImmutableSet;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
@@ -37,6 +38,7 @@ import org.sonar.db.DbSession;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.measure.LiveMeasureDto;
 import org.sonar.db.metric.MetricDto;
+import org.sonar.db.metric.RemovedMetricConverter;
 import org.sonar.server.user.UserSession;
 import org.sonarqube.ws.Measures.Measure;
 import org.sonarqube.ws.Measures.SearchWsResponse;
@@ -50,6 +52,8 @@ import static org.sonar.api.resources.Qualifiers.APP;
 import static org.sonar.api.resources.Qualifiers.PROJECT;
 import static org.sonar.api.resources.Qualifiers.SUBVIEW;
 import static org.sonar.api.resources.Qualifiers.VIEW;
+import static org.sonar.db.metric.RemovedMetricConverter.REMOVED_METRIC;
+import static org.sonar.db.metric.RemovedMetricConverter.DEPRECATED_METRIC_REPLACEMENT;
 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRIC_KEYS;
 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_PROJECT_KEYS;
 import static org.sonar.server.exceptions.BadRequestException.checkRequest;
@@ -77,17 +81,20 @@ public class SearchAction implements MeasuresWsAction {
     WebService.NewAction action = context.createAction("search")
       .setInternal(true)
       .setDescription("Search for project measures ordered by project names.<br>" +
-          "At most %d projects can be provided.<br>" +
-          "Returns the projects with the 'Browse' permission.",
+        "At most %d projects can be provided.<br>" +
+        "Returns the projects with the 'Browse' permission.",
         MAX_NB_PROJECTS)
       .setSince("6.2")
       .setResponseExample(getClass().getResource("search-example.json"))
       .setHandler(this)
       .setChangelog(
+        new Change("10.3", "The metric 'wont_fix_issues' is now deprecated in the response. Consume 'accepted_issues' instead."),
+        new Change("10.3", "The use of 'wont_fix_issues' value in 'metricKeys' param is now deprecated. Use 'accepted_issues' instead."),
+        new Change("10.3", "Added new accepted value for the 'metricKeys' param: 'accepted_issues'."),
         new Change("10.0", format("The use of the following metrics in 'metricKeys' parameter is not deprecated anymore: %s",
-          MeasuresWsModule.getDeprecatedMetrics())),
+          MeasuresWsModule.getDeprecatedMetricsInSonarQube93())),
         new Change("9.3", format("The use of the following metrics in 'metricKeys' parameter is deprecated: %s",
-        MeasuresWsModule.getDeprecatedMetrics())));
+          MeasuresWsModule.getDeprecatedMetricsInSonarQube93())));
 
     createMetricKeysParameter(action);
 
@@ -151,10 +158,11 @@ public class SearchAction implements MeasuresWsAction {
     }
 
     private List<MetricDto> searchMetrics() {
-      List<MetricDto> dbMetrics = dbClient.metricDao().selectByKeys(dbSession, request.getMetricKeys());
+      Collection<String> metricKeysParamValue = RemovedMetricConverter.withRemovedMetricAlias(request.getMetricKeys());
+      List<MetricDto> dbMetrics = dbClient.metricDao().selectByKeys(dbSession, metricKeysParamValue);
       List<String> metricKeys = dbMetrics.stream().map(MetricDto::getKey).toList();
-      checkRequest(request.getMetricKeys().size() == dbMetrics.size(), "The following metrics are not found: %s",
-        String.join(", ", difference(request.getMetricKeys(), metricKeys)));
+      checkRequest(metricKeysParamValue.size() == dbMetrics.size(), "The following metrics are not found: %s",
+        String.join(", ", difference(metricKeysParamValue, metricKeys)));
       return dbMetrics;
     }
 
@@ -190,17 +198,32 @@ public class SearchAction implements MeasuresWsAction {
       Function<Measure, String> byComponentName = wsMeasure -> componentNamesByKey.get(wsMeasure.getComponent());
 
       Measure.Builder measureBuilder = Measure.newBuilder();
-      return measures.stream()
-        .map(dbMeasure -> {
-          updateMeasureBuilder(measureBuilder, dbMeasureToDbMetric.apply(dbMeasure), dbMeasure);
-          measureBuilder.setComponent(componentsByUuid.get(dbMeasure.getComponentUuid()).getKey());
-          Measure measure = measureBuilder.build();
-          measureBuilder.clear();
-          return measure;
-        })
+      List<Measure> allMeasures = new ArrayList<>();
+      for (LiveMeasureDto measure : measures) {
+        updateMeasureBuilder(measureBuilder, dbMeasureToDbMetric.apply(measure), measure);
+        measureBuilder.setComponent(componentsByUuid.get(measure.getComponentUuid()).getKey());
+        Measure measureMsg = measureBuilder.build();
+        addMeasureIncludingRenamedMetric(measureMsg, allMeasures, measureBuilder);
+
+        measureBuilder.clear();
+      }
+      return allMeasures.stream()
         .sorted(comparing(byMetricKey).thenComparing(byComponentName))
         .toList();
     }
+
+    private void addMeasureIncludingRenamedMetric(Measure measureMsg, List<Measure> allMeasures, Measure.Builder measureBuilder) {
+      if (measureBuilder.getMetric().equals(DEPRECATED_METRIC_REPLACEMENT)) {
+        if (request.getMetricKeys().contains(DEPRECATED_METRIC_REPLACEMENT)) {
+          allMeasures.add(measureMsg);
+        }
+        if (request.getMetricKeys().contains(REMOVED_METRIC)) {
+          allMeasures.add(measureBuilder.setMetric(REMOVED_METRIC).build());
+        }
+      } else {
+        allMeasures.add(measureMsg);
+      }
+    }
   }
 
   private static class SearchRequest {
index c3adcaf99b8befabdd39efff38579799a31b04cc..197430a0d964fc6ec97429da69e203e5ba5b12fc 100644 (file)
@@ -21,6 +21,7 @@ package org.sonar.server.measure.ws;
 
 import com.google.common.collect.Sets;
 import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
@@ -46,6 +47,7 @@ import org.sonar.db.component.SnapshotQuery.SORT_ORDER;
 import org.sonar.db.measure.MeasureDto;
 import org.sonar.db.measure.PastMeasureQuery;
 import org.sonar.db.metric.MetricDto;
+import org.sonar.db.metric.RemovedMetricConverter;
 import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.user.UserSession;
 import org.sonar.server.ws.KeyExamples;
@@ -93,10 +95,13 @@ public class SearchHistoryAction implements MeasuresWsAction {
       .setResponseExample(getClass().getResource("search_history-example.json"))
       .setSince("6.3")
       .setChangelog(
+        new Change("10.3", "The metric 'wont_fix_issues' is now deprecated in the response. Consume 'accepted_issues' instead."),
+        new Change("10.3", "The use of 'wont_fix_issues' value in 'metricKeys' param is now deprecated. Use 'accepted_issues' instead."),
+        new Change("10.3", "Added new accepted value for the 'metricKeys' param: 'accepted_issues'."),
         new Change("10.0", format("The use of the following metrics in 'metricKeys' parameter is not deprecated anymore: %s",
-          MeasuresWsModule.getDeprecatedMetrics())),
+          MeasuresWsModule.getDeprecatedMetricsInSonarQube93())),
         new Change("9.3", format("The use of the following metrics in 'metrics' parameter is deprecated: %s",
-          MeasuresWsModule.getDeprecatedMetrics())),
+          MeasuresWsModule.getDeprecatedMetricsInSonarQube93())),
         new Change("7.6", format("The use of module keys in parameter '%s' is deprecated", PARAM_COMPONENT)))
       .setHandler(this);
 
@@ -165,7 +170,8 @@ public class SearchHistoryAction implements MeasuresWsAction {
         SearchHistoryResult result = new SearchHistoryResult(request.page, request.pageSize)
           .setComponent(component)
           .setAnalyses(searchAnalyses(dbSession, request, component))
-          .setMetrics(searchMetrics(dbSession, request));
+          .setMetrics(searchMetrics(dbSession, request))
+          .setRequestedMetrics(request.getMetrics());
         return result.setMeasures(searchMeasures(dbSession, request, result));
       }
     };
@@ -203,9 +209,10 @@ public class SearchHistoryAction implements MeasuresWsAction {
   }
 
   private List<MetricDto> searchMetrics(DbSession dbSession, SearchHistoryRequest request) {
-    List<MetricDto> metrics = dbClient.metricDao().selectByKeys(dbSession, request.getMetrics());
-    if (request.getMetrics().size() > metrics.size()) {
-      Set<String> requestedMetrics = request.getMetrics().stream().collect(Collectors.toSet());
+    List<String> upToDateRequestedMetrics = RemovedMetricConverter.withRemovedMetricAlias(request.getMetrics());
+    List<MetricDto> metrics = dbClient.metricDao().selectByKeys(dbSession, upToDateRequestedMetrics);
+    if (upToDateRequestedMetrics.size() > metrics.size()) {
+      Set<String> requestedMetrics = new HashSet<>(upToDateRequestedMetrics);
       Set<String> foundMetrics = metrics.stream().map(MetricDto::getKey).collect(Collectors.toSet());
 
       Set<String> unfoundMetrics = Sets.difference(requestedMetrics, foundMetrics).immutableCopy();
index a5764f6459e40e0cd568e673ea609f9ef0a24e96..02454a865377980c7fd624086d4d6124a668869b 100644 (file)
@@ -35,6 +35,7 @@ import org.sonarqube.ws.Measures.SearchHistoryResponse.HistoryMeasure;
 import org.sonarqube.ws.Measures.SearchHistoryResponse.HistoryValue;
 
 import static org.sonar.api.utils.DateUtils.formatDateTime;
+import static org.sonar.server.measure.ws.ComponentResponseCommon.addMetricToSearchHistoryResponseIncludingRenamedMetric;
 import static org.sonar.server.measure.ws.MeasureValueFormatter.formatMeasureValue;
 
 class SearchHistoryResponseFactory {
@@ -67,23 +68,17 @@ class SearchHistoryResponseFactory {
     result.getMeasures().forEach(m -> measuresByMetricByAnalysis.put(metricsByUuid.get(m.getMetricUuid()), analysesByUuid.get(m.getAnalysisUuid()), m));
 
     return response -> {
-      result.getMetrics().stream()
-        .map(clearMetric())
-        .map(addMetric())
-        .map(metric -> addValues(measuresByMetricByAnalysis.row(metric)).apply(metric))
-        .forEach(metric -> response.addMeasures(measure));
+      for (MetricDto metric : result.getMetrics()) {
+        measure.setMetric(metric.getKey());
+        addValues(measuresByMetricByAnalysis.row(metric)).apply(metric);
+        addMetricToSearchHistoryResponseIncludingRenamedMetric(response, result.getRequestedMetrics(), measure);
+        measure.clear();
+      }
 
       return response;
     };
   }
 
-  private UnaryOperator<MetricDto> addMetric() {
-    return metric -> {
-      measure.setMetric(metric.getKey());
-      return metric;
-    };
-  }
-
   private UnaryOperator<MetricDto> addValues(Map<SnapshotDto, MeasureDto> measuresByAnalysis) {
     return metric -> {
       result.getAnalyses().stream()
index bc42f1d947798359388333150924f5190e535f0f..8d5f99cdde33b4ac3107dd8026782ddb52b5a44f 100644 (file)
@@ -46,6 +46,7 @@ public class SearchHistoryResult {
   private List<MeasureDto> measures;
   private Common.Paging paging;
   private ComponentDto component;
+  private List<String> requestedMetrics;
 
   public SearchHistoryResult(int page, int pageSize) {
     this.page = page;
@@ -138,4 +139,13 @@ public class SearchHistoryResult {
   Common.Paging getPaging() {
     return requireNonNull(paging);
   }
+
+  public SearchHistoryResult setRequestedMetrics(List<String> requestedMetrics) {
+    this.requestedMetrics = requestedMetrics;
+    return this;
+  }
+
+  public List<String> getRequestedMetrics() {
+    return requestedMetrics;
+  }
 }
index 72d1c1669f8d87a0e57a9e6dbdb2b6750762aad3..6eaba1b4eb250514fc3c987fcd1866559bc1ec69 100644 (file)
           "value": "255"
         }
       },
+      {
+        "metric": "accepted_issues",
+        "value": "10"
+      },
       {
         "metric": "complexity",
         "value": "42"
           "metric": "complexity",
           "value": "12"
         },
+        {
+          "metric": "accepted_issues",
+          "value": "10"
+        },
         {
           "metric": "ncloc",
           "value": "114"
           "metric": "complexity",
           "value": "35"
         },
+        {
+          "metric": "accepted_issues",
+          "value": "10"
+        },
         {
           "metric": "ncloc",
           "value": "217"
       "qualitative": true,
       "hidden": false,
       "bestValue": "0"
+    },
+    {
+      "key": "accepted_issues",
+      "name": "Accepted Issues",
+      "description": "Accepted issues",
+      "domain": "Issues",
+      "type": "INT",
+      "higherValuesAreBetter": false,
+      "qualitative": false,
+      "hidden": false
     }
   ],
   "period": {
index 6b40a6a72f401e2508b6566cff139de7abd1bc83..38494be3b38acea186e7194775c920855d0ef143 100644 (file)
@@ -282,7 +282,7 @@ public class MeasureUpdateFormulaFactoryImplTest {
   public void count_resolved() {
     withNoIssues()
       .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 0)
-      .assertThatValueIs(CoreMetrics.WONT_FIX_ISSUES, 0);
+      .assertThatValueIs(CoreMetrics.ACCEPTED_ISSUES, 0);
 
     with(
       newResolvedGroup(Issue.RESOLUTION_FIXED, Issue.STATUS_RESOLVED).setCount(3),
@@ -296,7 +296,7 @@ public class MeasureUpdateFormulaFactoryImplTest {
       newGroup(RuleType.VULNERABILITY).setCount(17),
       newGroup(RuleType.BUG).setCount(19))
       .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 5)
-      .assertThatValueIs(CoreMetrics.WONT_FIX_ISSUES, 7 + 11);
+      .assertThatValueIs(CoreMetrics.ACCEPTED_ISSUES, 7 + 11);
   }
 
   @Test
index f22fa3713967fa4c9803ba9c9d521bcbea829c7d..86084892ad53b10a89e3ceb872e4917d6a19ad16 100644 (file)
@@ -3212,7 +3212,8 @@ metric.vulnerabilities.description=Vulnerabilities
 metric.vulnerabilities.name=Vulnerabilities
 metric.wont_fix_issues.description=Won't fix issues
 metric.wont_fix_issues.name=Won't Fix Issues
-
+metric.accepted_issues.description=Accepted issues
+metric.accepted_issues.name=Accepted Issues
 
 #------------------------------------------------------------------------------
 #