}
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)
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
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;
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;
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) {
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);
reopened += counter.reopened;
confirmed += counter.confirmed;
falsePositives += counter.falsePositives;
- wontFix += counter.wontFix;
+ accepted += counter.accepted;
severityBag.addAll(counter.severityBag);
typeBag.addAll(counter.typeBag);
}
} 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:
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;
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;
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;
.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)
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
--- /dev/null
+/*
+ * 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;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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
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) {
}
@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
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;
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 {
@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
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;
.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();
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)
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();
.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();
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")
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();
private MetricDto nclocMetric;
private MetricDto newViolationMetric;
private MetricDto stringMetric;
+ private MetricDto acceptedIssuesMetric;
@Before
public void setUp() {
complexityMetric = insertComplexityMetric();
newViolationMetric = insertNewViolationMetric();
stringMetric = insertStringMetric();
+ acceptedIssuesMetric = insertAcceptedIssuesMetric();
}
@Test
@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
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;
+ }
}
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(),
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;
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;
.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."),
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());
}
}
}
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);
}
}
*/
package org.sonar.server.measure.ws;
+import java.util.Collection;
import java.util.Map;
import javax.annotation.Nullable;
import org.sonar.db.component.ComponentDto;
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() {
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());
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();
}
--- /dev/null
+/*
+ * 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());
+ }
+ }
+}
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;
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;
/**
.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."),
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())
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) {
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());
.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))
.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);
}
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) {
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;
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);
return components;
}
- @CheckForNull
int getComponentCount() {
return componentCount;
}
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;
return this;
}
- @CheckForNull
public List<String> getMetricKeys() {
return metricKeys;
}
}
- 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");
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 {
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();
+ }
}
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;
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;
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;
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);
}
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;
}
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 {
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;
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;
.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);
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));
}
};
}
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();
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 {
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()
private List<MeasureDto> measures;
private Common.Paging paging;
private ComponentDto component;
+ private List<String> requestedMetrics;
public SearchHistoryResult(int page, int pageSize) {
this.page = page;
Common.Paging getPaging() {
return requireNonNull(paging);
}
+
+ public SearchHistoryResult setRequestedMetrics(List<String> requestedMetrics) {
+ this.requestedMetrics = requestedMetrics;
+ return this;
+ }
+
+ public List<String> getRequestedMetrics() {
+ return requestedMetrics;
+ }
}
"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": {
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),
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
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
#------------------------------------------------------------------------------
#