# 30 months from the release date for LTA versions
# No change required for patch versions
versionEOL=2025-03-27
-pluginApiVersion=10.10.0.2391
+pluginApiVersion=10.11.0.2468
description=Open source platform for continuous inspection of code quality
projectTitle=SonarQube
org.gradle.jvmargs=-Xmx2048m
return null;
}
switch (severity) {
- case CRITICAL:
case BLOCKER:
+ return org.sonar.api.issue.impact.Severity.BLOCKER;
+ case CRITICAL:
return org.sonar.api.issue.impact.Severity.HIGH;
case MAJOR:
return org.sonar.api.issue.impact.Severity.MEDIUM;
case MINOR:
- case INFO:
return org.sonar.api.issue.impact.Severity.LOW;
+ case INFO:
+ return org.sonar.api.issue.impact.Severity.INFO;
default:
return null;
}
NewRule oneIssuePerLine = repo.createRule(OneIssuePerLineSensor.RULE_KEY).setName("One Issue Per Line")
.setCleanCodeAttribute(CleanCodeAttribute.COMPLETE)
- .addDefaultImpact(SoftwareQuality.MAINTAINABILITY, Severity.MEDIUM)
+ .addDefaultImpact(SoftwareQuality.MAINTAINABILITY, Severity.INFO)
.setTags("line");
addDescriptionSectionsWithoutContexts(oneIssuePerLine, "Generate an issue on each line of a file. It requires the metric \"lines\".");
addHowToFixSectionsWithContexts(oneIssuePerLine);
NewRule oneQuickFixPerLine = repo.createRule(OneQuickFixPerLineSensor.RULE_KEY).setName("One Quick Fix Per Line")
.setCleanCodeAttribute(CleanCodeAttribute.DISTINCT)
- .addDefaultImpact(SoftwareQuality.MAINTAINABILITY, Severity.MEDIUM)
+ .addDefaultImpact(SoftwareQuality.MAINTAINABILITY, Severity.BLOCKER)
.setTags("line");
addAllDescriptionSections(oneQuickFixPerLine,
"Generate an issue with quick fix available on each line of a file. It requires the metric \"lines\".");
.setIssueCreationTime(963L)
.setIssueUpdateTime(852L)
.addImpact(new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.HIGH))
+ .addImpact(new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(Severity.BLOCKER))
.setIssueCloseTime(741L)
.setCodeVariants(List.of("v1", "v2"));
assertThat(issue.getIssueClosedAt()).isEqualTo(issueDto.getIssueCloseTime());
assertThat(issue.getLocations()).isNotEmpty();
assertThat(issue.getImpactsList()).extracting(ProjectDump.Impact::getSoftwareQuality, ProjectDump.Impact::getSeverity)
- .containsOnly(tuple(ProjectDump.SoftwareQuality.MAINTAINABILITY, ProjectDump.Severity.HIGH));
+ .containsOnly(tuple(ProjectDump.SoftwareQuality.MAINTAINABILITY, ProjectDump.Severity.HIGH), tuple(ProjectDump.SoftwareQuality.SECURITY, ProjectDump.Severity.BLOCKER));
assertThat(issue.getMessageFormattingsList())
.isEqualTo(ExportIssuesStep.dbToDumpMessageFormatting(messageFormattings.getMessageFormattingList()));
assertThat(issue.getCodeVariants()).isEqualTo(issueDto.getCodeVariantsString());
.setIsAdHoc(true)
.setCleanCodeAttribute(CleanCodeAttribute.CONVENTIONAL)
.addDefaultImpact(new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(org.sonar.api.issue.impact.Severity.MEDIUM))
- .addDefaultImpact(new ImpactDto().setSoftwareQuality(SoftwareQuality.RELIABILITY).setSeverity(org.sonar.api.issue.impact.Severity.HIGH))
+ .addDefaultImpact(new ImpactDto().setSoftwareQuality(SoftwareQuality.RELIABILITY).setSeverity(org.sonar.api.issue.impact.Severity.BLOCKER))
.setRuleKey(ruleKey)
.setScope(RuleDto.Scope.ALL)
.setStatus(RuleStatus.READY);
}
private void addSoftwareQualityMaintainabilityRatingMeasure(Component component, double density) {
- Rating rating = ratingSettings.getDebtRatingGrid().getAToDRatingForDensity(density);
+ Rating rating = ratingSettings.getDebtRatingGrid().getRatingForDensity(density);
measureRepository.add(component, softwareQualityMaintainabilityRatingMetric, RatingMeasures.get(rating));
}
double densityBasedOnSoftwareQuality = computeDensity(path.current().getNewSoftwareQualityDebt(), path.current().getDevCost());
double newSoftwareQualityDebtRatio = 100.0 * densityBasedOnSoftwareQuality;
- int newSoftwareQualityMaintainabilityRating = ratingSettings.getDebtRatingGrid().getAToDRatingForDensity(densityBasedOnSoftwareQuality).getIndex();
+ int newSoftwareQualityMaintainabilityRating = ratingSettings.getDebtRatingGrid().getRatingForDensity(densityBasedOnSoftwareQuality).getIndex();
measureRepository.add(component, this.newSoftwareQualityMaintainabilityDebtRatioMetric, newMeasureBuilder().create(newSoftwareQualityDebtRatio));
measureRepository.add(component, this.newSoftwareQualityMaintainabilityRatingMetric, newMeasureBuilder().create(newSoftwareQualityMaintainabilityRating));
}
import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT;
import static org.sonar.ce.task.projectanalysis.component.ComponentVisitor.Order.POST_ORDER;
import static org.sonar.ce.task.projectanalysis.component.CrawlerDepthLimit.FILE;
-import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY;
-import static org.sonar.server.security.SecurityReviewRating.computeAToDRating;
import static org.sonar.server.security.SecurityReviewRating.computePercent;
import static org.sonar.server.security.SecurityReviewRating.computeRating;
private final ComponentIssuesRepository componentIssuesRepository;
private final MeasureRepository measureRepository;
private final Metric newSecurityReviewRatingMetric;
- private final Metric newSoftwareQualitySecurityReviewRatingMetric;
private final Metric newSecurityHotspotsReviewedMetric;
private final Metric newSecurityHotspotsReviewedStatusMetric;
private final Metric newSecurityHotspotsToReviewStatusMetric;
this.componentIssuesRepository = componentIssuesRepository;
this.measureRepository = measureRepository;
this.newSecurityReviewRatingMetric = metricRepository.getByKey(NEW_SECURITY_REVIEW_RATING_KEY);
- this.newSoftwareQualitySecurityReviewRatingMetric = metricRepository.getByKey(NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY);
this.newSecurityHotspotsReviewedMetric = metricRepository.getByKey(NEW_SECURITY_HOTSPOTS_REVIEWED_KEY);
this.newSecurityHotspotsReviewedStatusMetric = metricRepository.getByKey(NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY);
this.newSecurityHotspotsToReviewStatusMetric = metricRepository.getByKey(NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY);
Optional<Double> percent = computePercent(path.current().getHotspotsToReview(), path.current().getHotspotsReviewed());
measureRepository.add(component, newSecurityReviewRatingMetric, Measure.newMeasureBuilder().create(computeRating(percent.orElse(null)).getIndex()));
- measureRepository.add(component, newSoftwareQualitySecurityReviewRatingMetric,
- Measure.newMeasureBuilder().create(computeAToDRating(percent.orElse(null)).getIndex()));
percent.ifPresent(p -> measureRepository.add(component, newSecurityHotspotsReviewedMetric, Measure.newMeasureBuilder().create(p)));
if (!path.isRoot()) {
import static org.sonar.ce.task.projectanalysis.component.ComponentVisitor.Order.POST_ORDER;
import static org.sonar.ce.task.projectanalysis.component.CrawlerDepthLimit.FILE;
import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder;
-import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY;
-import static org.sonar.server.security.SecurityReviewRating.computeAToDRating;
import static org.sonar.server.security.SecurityReviewRating.computePercent;
import static org.sonar.server.security.SecurityReviewRating.computeRating;
private final ComponentIssuesRepository componentIssuesRepository;
private final MeasureRepository measureRepository;
private final Metric securityReviewRatingMetric;
- private final Metric softwareQualitySecurityReviewRatingMetric;
private final Metric securityHotspotsReviewedMetric;
private final Metric securityHotspotsReviewedStatusMetric;
private final Metric securityHotspotsToReviewStatusMetric;
this.componentIssuesRepository = componentIssuesRepository;
this.measureRepository = measureRepository;
this.securityReviewRatingMetric = metricRepository.getByKey(SECURITY_REVIEW_RATING_KEY);
- this.softwareQualitySecurityReviewRatingMetric = metricRepository.getByKey(SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY);
this.securityHotspotsReviewedMetric = metricRepository.getByKey(SECURITY_HOTSPOTS_REVIEWED_KEY);
this.securityHotspotsReviewedStatusMetric = metricRepository.getByKey(SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY);
this.securityHotspotsToReviewStatusMetric = metricRepository.getByKey(SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY);
measureRepository.add(component, securityHotspotsToReviewStatusMetric, newMeasureBuilder().create(path.current().getHotspotsToReview()));
Optional<Double> percent = computePercent(path.current().getHotspotsToReview(), path.current().getHotspotsReviewed());
measureRepository.add(component, securityReviewRatingMetric, RatingMeasures.get(computeRating(percent.orElse(null))));
- measureRepository.add(component, softwareQualitySecurityReviewRatingMetric,
- RatingMeasures.get(computeAToDRating(percent.orElse(null))));
percent.ifPresent(p -> measureRepository.add(component, securityHotspotsReviewedMetric, newMeasureBuilder().create(p, securityHotspotsReviewedMetric.getDecimalScale())));
if (!path.isRoot()) {
SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY,
SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING_KEY,
SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING_KEY,
- SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY,
SoftwareQualitiesMetrics.EFFORT_TO_REACH_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_A_KEY,
SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT_KEY,
SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT_KEY,
LOW = 0;
MEDIUM = 1;
HIGH = 2;
+ INFO = 3;
+ BLOCKER = 4;
}
import static org.sonar.ce.task.projectanalysis.issue.IssueCounter.IMPACT_TO_NEW_METRIC_KEY;
import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder;
import static org.sonar.ce.task.projectanalysis.measure.MeasureRepoEntry.entryOf;
+import static org.sonar.test.JsonAssert.assertJson;
class IssueCounterTest {
underTest.beforeComponent(PROJECT);
underTest.afterComponent(PROJECT);
- assertIntValue(FILE1, entry(NEW_VIOLATIONS_KEY, 2), entry(NEW_CRITICAL_VIOLATIONS_KEY, 2), entry(NEW_BLOCKER_VIOLATIONS_KEY, 0), entry(NEW_MAJOR_VIOLATIONS_KEY, 0),
+ assertIntValue(FILE1, entry(NEW_VIOLATIONS_KEY, 2), entry(NEW_CRITICAL_VIOLATIONS_KEY, 2), entry(NEW_BLOCKER_VIOLATIONS_KEY, 0),
+ entry(NEW_MAJOR_VIOLATIONS_KEY, 0),
entry(NEW_CODE_SMELLS_KEY, 1), entry(NEW_BUGS_KEY, 1), entry(NEW_VULNERABILITIES_KEY, 0), entry(NEW_SECURITY_HOTSPOTS_KEY, 1));
- assertIntValue(PROJECT, entry(NEW_VIOLATIONS_KEY, 2), entry(NEW_CRITICAL_VIOLATIONS_KEY, 2), entry(NEW_BLOCKER_VIOLATIONS_KEY, 0), entry(NEW_MAJOR_VIOLATIONS_KEY, 0),
+ assertIntValue(PROJECT, entry(NEW_VIOLATIONS_KEY, 2), entry(NEW_CRITICAL_VIOLATIONS_KEY, 2), entry(NEW_BLOCKER_VIOLATIONS_KEY, 0),
+ entry(NEW_MAJOR_VIOLATIONS_KEY, 0),
entry(NEW_CODE_SMELLS_KEY, 1), entry(NEW_BUGS_KEY, 1), entry(NEW_VULNERABILITIES_KEY, 0), entry(NEW_SECURITY_HOTSPOTS_KEY, 1));
}
when(newIssueClassifier.isEnabled()).thenReturn(true);
underTest.beforeComponent(FILE1);
- underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, HIGH));
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, HIGH));
underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, MEDIUM));
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, HIGH));
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, SoftwareQuality.MAINTAINABILITY, HIGH));
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, MEDIUM));
- underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, HIGH));
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, HIGH));
underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, MEDIUM));
underTest.onIssue(FILE1, createNewSecurityHotspot());
Set<Map.Entry<String, Measure>> entries = measureRepository.getRawMeasures(FILE1).entrySet();
- assertOverallSoftwareQualityMeasures(SoftwareQuality.MAINTAINABILITY, getImpactMeasure(4, 2, 2, 0), entries);
- assertOverallSoftwareQualityMeasures(SoftwareQuality.SECURITY, getImpactMeasure(2, 1, 1, 0), entries);
- assertOverallSoftwareQualityMeasures(SoftwareQuality.RELIABILITY, getImpactMeasure(0, 0, 0, 0), entries);
+ assertOverallSoftwareQualityMeasures(SoftwareQuality.MAINTAINABILITY, getImpactMeasure(4, 2, 2, 0, 0, 0), entries);
+ assertOverallSoftwareQualityMeasures(SoftwareQuality.SECURITY, getImpactMeasure(2, 1, 1, 0, 0, 0), entries);
+ assertOverallSoftwareQualityMeasures(SoftwareQuality.RELIABILITY, getImpactMeasure(0, 0, 0, 0, 0, 0), entries);
}
@Test
when(newIssueClassifier.isEnabled()).thenReturn(true);
underTest.beforeComponent(FILE1);
- underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, HIGH));
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, HIGH));
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, HIGH));
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, SoftwareQuality.MAINTAINABILITY, HIGH));
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, MEDIUM));
- underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.RELIABILITY, HIGH));
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.RELIABILITY, HIGH));
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.RELIABILITY, LOW));
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, SoftwareQuality.RELIABILITY, HIGH));
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.RELIABILITY, MEDIUM));
- underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, MEDIUM));
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, MEDIUM));
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, LOW));
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, HIGH));
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, HIGH));
Set<Map.Entry<String, Measure>> entries = measureRepository.getRawMeasures(FILE1).entrySet();
- assertNewSoftwareQualityMeasures(SoftwareQuality.MAINTAINABILITY, getImpactMeasure(2, 1, 1, 0), entries);
- assertNewSoftwareQualityMeasures(SoftwareQuality.RELIABILITY, getImpactMeasure(2, 0, 1, 1), entries);
- assertNewSoftwareQualityMeasures(SoftwareQuality.SECURITY, getImpactMeasure(4, 2, 1, 1), entries);
+ assertNewSoftwareQualityMeasures(SoftwareQuality.MAINTAINABILITY, getImpactMeasure(2, 1, 1, 0, 0, 0), entries);
+ assertNewSoftwareQualityMeasures(SoftwareQuality.RELIABILITY, getImpactMeasure(2, 0, 1, 1, 0, 0), entries);
+ assertNewSoftwareQualityMeasures(SoftwareQuality.SECURITY, getImpactMeasure(4, 2, 1, 1, 0, 0), entries);
}
private static Map<String, Long> getImpactMeasure(long total, long high, long medium, long low) {
return map;
}
+ private static Map<String, Long> getImpactMeasure(long total, long high, long medium, long low, long info, long blocker) {
+ Map<String, Long> map = getImpactMeasure(total, high, medium, low);
+ map.put(Severity.INFO.name(), info);
+ map.put(Severity.BLOCKER.name(), blocker);
+ return map;
+ }
+
private void assertOverallSoftwareQualityMeasures(SoftwareQuality softwareQuality, Map<? extends String, Long> expectedMap,
Set<Map.Entry<String, Measure>> actualRaw) {
assertSoftwareQualityMeasures(softwareQuality, expectedMap, actualRaw, IMPACT_TO_METRIC_KEY);
.findFirst()
.get();
- assertThat(softwareQualityMap.getValue().getData()).isEqualTo(new Gson().toJson(expectedMap));
+ assertJson(softwareQualityMap.getValue().getData()).isSimilarTo(new Gson().toJson(expectedMap));
}
@Test
underTest.beforeComponent(PROJECT);
underTest.afterComponent(PROJECT);
- assertIntValue(FILE1, entry(NEW_VIOLATIONS_KEY, 0), entry(NEW_CRITICAL_VIOLATIONS_KEY, 0), entry(NEW_BLOCKER_VIOLATIONS_KEY, 0), entry(NEW_MAJOR_VIOLATIONS_KEY, 0),
+ assertIntValue(FILE1, entry(NEW_VIOLATIONS_KEY, 0), entry(NEW_CRITICAL_VIOLATIONS_KEY, 0), entry(NEW_BLOCKER_VIOLATIONS_KEY, 0),
+ entry(NEW_MAJOR_VIOLATIONS_KEY, 0),
entry(NEW_VULNERABILITIES_KEY, 0));
- assertIntValue(PROJECT, entry(NEW_VIOLATIONS_KEY, 0), entry(NEW_CRITICAL_VIOLATIONS_KEY, 0), entry(NEW_BLOCKER_VIOLATIONS_KEY, 0), entry(NEW_MAJOR_VIOLATIONS_KEY, 0),
+ assertIntValue(PROJECT, entry(NEW_VIOLATIONS_KEY, 0), entry(NEW_CRITICAL_VIOLATIONS_KEY, 0), entry(NEW_BLOCKER_VIOLATIONS_KEY, 0),
+ entry(NEW_MAJOR_VIOLATIONS_KEY, 0),
entry(NEW_VULNERABILITIES_KEY, 0));
}
return createNewIssue(resolution, status, SoftwareQuality.MAINTAINABILITY, impactSeverity);
}
- private DefaultIssue createNewIssue(@Nullable String resolution, String status, SoftwareQuality softwareQuality, Severity impactSeverity) {
+ private DefaultIssue createNewIssue(@Nullable String resolution, String status, SoftwareQuality softwareQuality,
+ Severity impactSeverity) {
DefaultIssue issue = createNewIssue(resolution, status, MAJOR, CODE_SMELL);
issue.addImpact(softwareQuality, impactSeverity);
return issue;
return createIssue(resolution, status, SoftwareQuality.MAINTAINABILITY, impactSeverity);
}
- private static DefaultIssue createIssue(@Nullable String resolution, String status, SoftwareQuality softwareQuality, Severity impactSeverity) {
+ private static DefaultIssue createIssue(@Nullable String resolution, String status, SoftwareQuality softwareQuality,
+ Severity impactSeverity) {
DefaultIssue issue = createIssue(resolution, status, MAJOR, CODE_SMELL);
issue.addImpact(softwareQuality, impactSeverity);
return issue;
verifyAddedRawMeasure(FILE_1_REF, SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY, C);
verifyAddedRawMeasure(FILE_2_REF, SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY, A);
verifyAddedRawMeasure(DIRECTORY_REF, SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY, C);
- verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY, D);
+ verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY, E);
}
@ParameterizedTest
@ParameterizedTest
@MethodSource("metrics")
- void compute_new_maintainability_rating_map_to_D(String remediationEffortKey, String debtRatioKey, String ratingKey) {
+ void compute_new_maintainability_rating_map_to_E(String remediationEffortKey, String debtRatioKey, String ratingKey) {
ReportComponent file = builder(FILE, LANGUAGE_1_FILE_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_1_KEY, 1)).build();
treeRootHolder.setRoot(
builder(PROJECT, ROOT_REF)
setNewLines(file, 3, 4);
underTest.visit(treeRootHolder.getRoot());
-
- if (ratingKey.equals(NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY)) {
- assertNewRating(ratingKey, LANGUAGE_1_FILE_REF, D);
- } else if (ratingKey.equals(NEW_MAINTAINABILITY_RATING_KEY)) {
- assertNewRating(ratingKey, LANGUAGE_1_FILE_REF, E);
- }
+ assertNewRating(ratingKey, LANGUAGE_1_FILE_REF, E);
}
@Test
oldImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH));
fillComponentIssuesVisitorRule.setIssues(FILE_2_REF,
newImpactIssue(SoftwareQuality.SECURITY, Severity.LOW),
- newImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH),
+ newImpactIssue(SoftwareQuality.SECURITY, Severity.BLOCKER),
// Should not be taken into account
oldImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH));
fillComponentIssuesVisitorRule.setIssues(ROOT_DIR_REF, newImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH));
underTest.visit(ROOT_PROJECT);
verifyAddedRawMeasureOnLeakPeriod(FILE_1_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, C);
- verifyAddedRawMeasureOnLeakPeriod(FILE_2_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, D);
- verifyAddedRawMeasureOnLeakPeriod(DIRECTORY_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, D);
- verifyAddedRawMeasureOnLeakPeriod(ROOT_DIR_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, D);
- verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, D);
+ verifyAddedRawMeasureOnLeakPeriod(FILE_2_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, E);
+ verifyAddedRawMeasureOnLeakPeriod(DIRECTORY_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, E);
+ verifyAddedRawMeasureOnLeakPeriod(ROOT_DIR_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, E);
+ verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, E);
}
@Test
// Should not be taken into account
oldImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH));
fillComponentIssuesVisitorRule.setIssues(FILE_2_REF,
- newImpactIssue(SoftwareQuality.RELIABILITY, Severity.LOW),
+ newImpactIssue(SoftwareQuality.RELIABILITY, Severity.INFO),
newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH),
// Should not be taken into account
oldImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH));
verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, E);
}
+ @Test
+ void compute_E_software_quality_reliability_and_security_rating_on_blocker_severity_issue() {
+ treeRootHolder.setRoot(ROOT_PROJECT);
+ fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
+ newImpactIssue(SoftwareQuality.RELIABILITY, Severity.BLOCKER),
+ newImpactIssue(SoftwareQuality.SECURITY, Severity.BLOCKER),
+ // Should not be taken into account
+ newCodeSmellIssue(1L, MAJOR));
+
+ underTest.visit(ROOT_PROJECT);
+
+ verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, E);
+ verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, E);
+ }
+
@Test
void compute_D_reliability_and_security_rating_on_critical_issue() {
treeRootHolder.setRoot(ROOT_PROJECT);
verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, A);
}
+ @Test
+ void compute_A_software_quality_reliability_and_security_rating_on_info_severity_issue() {
+ treeRootHolder.setRoot(ROOT_PROJECT);
+ fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
+ newImpactIssue(SoftwareQuality.RELIABILITY, Severity.INFO),
+ newImpactIssue(SoftwareQuality.SECURITY, Severity.INFO),
+ // Should not be taken into account
+ newCodeSmellIssue(1L, MAJOR));
+
+ underTest.visit(ROOT_PROJECT);
+
+ verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A);
+ verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, A);
+ }
+
@Test
void compute_A_software_quality_reliability_and_security_rating_when_no_issue() {
treeRootHolder.setRoot(ROOT_PROJECT);
import static org.sonar.server.measure.Rating.C;
import static org.sonar.server.measure.Rating.D;
import static org.sonar.server.measure.Rating.E;
-import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING;
-import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY;
class NewSecurityReviewMeasuresVisitorTest {
private static final Offset<Double> VALUE_COMPARISON_OFFSET = Offset.offset(0.01);
@RegisterExtension
private final MetricRepositoryRule metricRepository = new MetricRepositoryRule()
.add(NEW_SECURITY_REVIEW_RATING)
- .add(NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING)
.add(NEW_SECURITY_HOTSPOTS_REVIEWED)
.add(NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS)
.add(NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS);
underTest.visit(ROOT_PROJECT);
- verifyRatingAndReviewedMeasures(FILE_1_REF, A, A, 100.0);
- verifyRatingAndReviewedMeasures(FILE_2_REF, A, A, 100.0);
- verifyRatingAndReviewedMeasures(DIRECTORY_REF, A, A, 100.0);
- verifyRatingAndReviewedMeasures(ROOT_DIR_REF, A, A, 100.0);
- verifyRatingAndReviewedMeasures(PROJECT_REF, A, A, 100.0);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, A, 100.0);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyRatingAndReviewedMeasures(FILE_1_REF, A, A, 100.0);
- verifyRatingAndReviewedMeasures(FILE_2_REF, A, B, 80.0);
- verifyRatingAndReviewedMeasures(DIRECTORY_REF, A, B, 87.5);
- verifyRatingAndReviewedMeasures(ROOT_DIR_REF, A, B, 87.5);
- verifyRatingAndReviewedMeasures(PROJECT_REF, A, B, 87.5);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, A, 80.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, A, 87.5);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, A, 87.5);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, A, 87.5);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyRatingAndReviewedMeasures(FILE_1_REF, A, A, 100.0);
- verifyRatingAndReviewedMeasures(FILE_2_REF, B, B, 71.42);
- verifyRatingAndReviewedMeasures(DIRECTORY_REF, B, B, 75.0);
- verifyRatingAndReviewedMeasures(ROOT_DIR_REF, B, B, 75.0);
- verifyRatingAndReviewedMeasures(PROJECT_REF, B, B, 75.0);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, B, 71.42);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, B, 75.0);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, B, 75.0);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, B, 75.0);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyRatingAndReviewedMeasures(FILE_1_REF, C, C, 50.0);
- verifyRatingAndReviewedMeasures(FILE_2_REF, C, C, 60.0);
- verifyRatingAndReviewedMeasures(DIRECTORY_REF, C, C, 57.14);
- verifyRatingAndReviewedMeasures(ROOT_DIR_REF, C, C, 57.14);
- verifyRatingAndReviewedMeasures(PROJECT_REF, C, C, 57.14);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, C, 50.0);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, C, 60.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, C, 57.14);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, C, 57.14);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, C, 57.14);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyRatingAndReviewedMeasures(FILE_1_REF, D, D, 33.33);
- verifyRatingAndReviewedMeasures(FILE_2_REF, D, D, 40.0);
- verifyRatingAndReviewedMeasures(DIRECTORY_REF, D, D, 37.5);
- verifyRatingAndReviewedMeasures(ROOT_DIR_REF, D, D, 37.5);
- verifyRatingAndReviewedMeasures(PROJECT_REF, D, D, 37.5);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, D, 33.33);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, D, 40.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, D, 37.5);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, D, 37.5);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, D, 37.5);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyRatingAndReviewedMeasures(FILE_1_REF, D, D, 33.33);
- verifyRatingAndReviewedMeasures(FILE_2_REF, E, D, 0.0);
- verifyRatingAndReviewedMeasures(DIRECTORY_REF, E, D, 16.66);
- verifyRatingAndReviewedMeasures(ROOT_DIR_REF, E, D, 16.66);
- verifyRatingAndReviewedMeasures(PROJECT_REF, E, D, 16.66);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, D, 33.33);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, E, 0.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, E, 16.66);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, E, 16.66);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, E, 16.66);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyRatingAndReviewedMeasures(PROJECT_REF, A, A, null);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, A, null);
}
@Test
assertThat(measureRepository.getAddedRawMeasures(PROJECT_REF).values()).isEmpty();
}
- private void verifyRatingAndReviewedMeasures(int componentRef, Rating expectedReviewRating,
- Rating expectedSoftwareQualitySecurityReviewRating, @Nullable Double expectedHotspotsReviewed) {
+ private void verifyRatingAndReviewedMeasures(int componentRef, Rating expectedReviewRating, @Nullable Double expectedHotspotsReviewed) {
assertThat(measureRepository.getAddedRawMeasure(componentRef, NEW_SECURITY_REVIEW_RATING_KEY)).hasValue(expectedReviewRating.getIndex());
- assertThat(measureRepository.getAddedRawMeasure(componentRef, NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY)).hasValue(expectedSoftwareQualitySecurityReviewRating.getIndex());
if (expectedHotspotsReviewed != null) {
assertThat(measureRepository.getAddedRawMeasure(componentRef, NEW_SECURITY_HOTSPOTS_REVIEWED_KEY)).hasValue(expectedHotspotsReviewed,
VALUE_COMPARISON_OFFSET);
// Should not be taken into account
newImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH));
- fillComponentIssuesVisitorRule.setIssues(PROJECT_REF, newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH));
+ fillComponentIssuesVisitorRule.setIssues(PROJECT_REF, newImpactIssue(SoftwareQuality.RELIABILITY, Severity.BLOCKER));
underTest.visit(ROOT_PROJECT);
verifyAddedRawMeasure(FILE_2_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, C);
verifyAddedRawMeasure(FILE_3_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A);
verifyAddedRawMeasure(DIRECTORY_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, C);
- verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, D);
+ verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, E);
}
@Test
void compute_software_quality_security_rating() {
treeRootHolder.setRoot(ROOT_PROJECT);
fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
- newImpactIssue(SoftwareQuality.SECURITY, Severity.LOW),
+ newImpactIssue(SoftwareQuality.SECURITY, Severity.INFO),
// Should not be taken into account
newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH));
fillComponentIssuesVisitorRule.setIssues(FILE_2_REF,
newImpactIssue(SoftwareQuality.SECURITY, Severity.MEDIUM),
// Should not be taken into account
- newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH));
+ newImpactIssue(SoftwareQuality.RELIABILITY, Severity.BLOCKER));
fillComponentIssuesVisitorRule.setIssues(FILE_3_REF,
// Should not be taken into account
newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH));
underTest.visit(ROOT_PROJECT);
- verifyAddedRawMeasure(FILE_1_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, B);
+ verifyAddedRawMeasure(FILE_1_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, A);
verifyAddedRawMeasure(FILE_2_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, C);
verifyAddedRawMeasure(FILE_3_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, A);
verifyAddedRawMeasure(DIRECTORY_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, C);
verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, E);
}
+ @Test
+ void compute_E_software_quality_reliability_and_security_rating_on_blocker_issue() {
+ treeRootHolder.setRoot(ROOT_PROJECT);
+ fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newImpactIssue(SoftwareQuality.RELIABILITY, Severity.BLOCKER), newImpactIssue(SoftwareQuality.SECURITY, Severity.BLOCKER),
+ // Should not be taken into account
+ newImpactIssue(SoftwareQuality.MAINTAINABILITY, Severity.HIGH));
+
+ underTest.visit(ROOT_PROJECT);
+
+ verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, E);
+ verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, E);
+ }
+
@Test
void compute_D_reliability_and_security_rating_on_critical_issue() {
treeRootHolder.setRoot(ROOT_PROJECT);
verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, A);
}
+ @Test
+ void compute_A_software_quality_reliability_and_security_rating_on_info_issue() {
+ treeRootHolder.setRoot(ROOT_PROJECT);
+ fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newImpactIssue(SoftwareQuality.RELIABILITY, Severity.INFO), newImpactIssue(SoftwareQuality.SECURITY, Severity.INFO),
+ // Should not be taken into account
+ newImpactIssue(SoftwareQuality.MAINTAINABILITY, Severity.HIGH));
+
+ underTest.visit(ROOT_PROJECT);
+
+ verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A);
+ verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, A);
+ }
+
@Test
void compute_A_software_quality_reliability_and_security_rating_when_no_issue() {
treeRootHolder.setRoot(ROOT_PROJECT);
import static org.sonar.server.measure.Rating.C;
import static org.sonar.server.measure.Rating.D;
import static org.sonar.server.measure.Rating.E;
-import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING;
-import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY;
class SecurityReviewMeasuresVisitorTest {
@RegisterExtension
private final MetricRepositoryRule metricRepository = new MetricRepositoryRule()
.add(SECURITY_REVIEW_RATING)
- .add(SOFTWARE_QUALITY_SECURITY_REVIEW_RATING)
.add(SECURITY_HOTSPOTS_REVIEWED)
.add(SECURITY_HOTSPOTS_REVIEWED_STATUS)
.add(SECURITY_HOTSPOTS_TO_REVIEW_STATUS);
underTest.visit(ROOT_PROJECT);
- verifyRatingAndReviewedMeasures(FILE_1_REF, A, A, 100.0);
- verifyRatingAndReviewedMeasures(FILE_2_REF, A, A, 100.0);
- verifyRatingAndReviewedMeasures(DIRECTORY_REF, A, A, 100.0);
- verifyRatingAndReviewedMeasures(ROOT_DIR_REF, A, A, 100.0);
- verifyRatingAndReviewedMeasures(PROJECT_REF, A, A, 100.0);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, A, 100.0);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyRatingAndReviewedMeasures(FILE_1_REF, A, A, 100.0);
- verifyRatingAndReviewedMeasures(FILE_2_REF, A, B, 80.0);
- verifyRatingAndReviewedMeasures(DIRECTORY_REF, A, B, 87.5);
- verifyRatingAndReviewedMeasures(ROOT_DIR_REF, A, B, 87.5);
- verifyRatingAndReviewedMeasures(PROJECT_REF, A, B, 87.5);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, A, 80.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, A, 87.5);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, A, 87.5);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, A, 87.5);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyRatingAndReviewedMeasures(FILE_1_REF, A, A, 100.0);
- verifyRatingAndReviewedMeasures(FILE_2_REF, B, B, 71.4);
- verifyRatingAndReviewedMeasures(DIRECTORY_REF, B, B, 75.0);
- verifyRatingAndReviewedMeasures(ROOT_DIR_REF, B, B, 75.0);
- verifyRatingAndReviewedMeasures(PROJECT_REF, B, B, 75.0);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, B, 71.4);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, B, 75.0);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, B, 75.0);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, B, 75.0);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyRatingAndReviewedMeasures(FILE_1_REF, C, C,50.0);
- verifyRatingAndReviewedMeasures(FILE_2_REF, C, C,60.0);
- verifyRatingAndReviewedMeasures(DIRECTORY_REF, C,C, 57.1);
- verifyRatingAndReviewedMeasures(ROOT_DIR_REF, C, C,57.1);
- verifyRatingAndReviewedMeasures(PROJECT_REF, C, C,57.1);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, C, 50.0);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, C, 60.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, C, 57.1);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, C, 57.1);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, C, 57.1);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyRatingAndReviewedMeasures(FILE_1_REF, D, D,33.3);
- verifyRatingAndReviewedMeasures(FILE_2_REF, D, D,40.0);
- verifyRatingAndReviewedMeasures(DIRECTORY_REF, D,D, 37.5);
- verifyRatingAndReviewedMeasures(ROOT_DIR_REF, D, D,37.5);
- verifyRatingAndReviewedMeasures(PROJECT_REF, D, D,37.5);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, D, 33.3);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, D, 40.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, D, 37.5);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, D, 37.5);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, D, 37.5);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyRatingAndReviewedMeasures(FILE_1_REF, D, D,33.3);
- verifyRatingAndReviewedMeasures(FILE_2_REF, E, D,0.0);
- verifyRatingAndReviewedMeasures(DIRECTORY_REF, E,D, 16.7);
- verifyRatingAndReviewedMeasures(ROOT_DIR_REF, E, D,16.7);
- verifyRatingAndReviewedMeasures(PROJECT_REF, E, D,16.7);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, D, 33.3);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, E, 0.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, E, 16.7);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, E, 16.7);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, E, 16.7);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyRatingAndReviewedMeasures(PROJECT_REF, A, A,null);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, A, null);
}
@Test
verifyHotspotStatusMeasures(PROJECT_REF, 0, 0);
}
- private void verifyRatingAndReviewedMeasures(int componentRef, Rating expectedReviewRating, Rating expectedSoftwareQualityReviewRating,
- @Nullable Double expectedHotspotsReviewed) {
- verifySecurityReviewRating(componentRef, expectedReviewRating, expectedSoftwareQualityReviewRating);
+ private void verifyRatingAndReviewedMeasures(int componentRef, Rating expectedReviewRating, @Nullable Double expectedHotspotsReviewed) {
+ verifySecurityReviewRating(componentRef, expectedReviewRating);
if (expectedHotspotsReviewed != null) {
verifySecurityHotspotsReviewed(componentRef, expectedHotspotsReviewed);
} else {
}
}
- private void verifySecurityReviewRating(int componentRef, Rating rating, Rating softwareQualityRating) {
+ private void verifySecurityReviewRating(int componentRef, Rating rating) {
Measure measure = measureRepository.getAddedRawMeasure(componentRef, SECURITY_REVIEW_RATING_KEY).get();
- Measure softwareQualityMeasure = measureRepository.getAddedRawMeasure(componentRef, SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY).get();
assertThat(measure.getIntValue()).isEqualTo(rating.getIndex());
assertThat(measure.getData()).isEqualTo(rating.name());
- assertThat(softwareQualityMeasure.getIntValue()).isEqualTo(softwareQualityRating.getIndex());
- assertThat(softwareQualityMeasure.getData()).isEqualTo(softwareQualityRating.name());
}
private void verifySecurityHotspotsReviewed(int componentRef, double percent) {
SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY,
SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING_KEY,
SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING_KEY,
- SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY,
SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY,
- SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY,
SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY,
SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY
);
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.component.ProjectData;
import org.sonar.db.es.EsQueueDto;
+import org.sonar.db.issue.ImpactDto;
import org.sonar.db.issue.IssueDto;
import org.sonar.db.issue.IssueTesting;
import org.sonar.db.project.ProjectDto;
ComponentDto project = projectData.getMainBranchComponent();
ComponentDto dir = db.components().insertComponent(ComponentTesting.newDirectory(project, "src/main/java/foo"));
ComponentDto file = db.components().insertComponent(newFileDto(project, dir, "F1"));
- IssueDto issue = db.issues().insert(rule, project, file);
+ IssueDto issue = db.issues().insert(rule, project, file,
+ i -> i.replaceAllImpacts(List.of(new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.HIGH),
+ new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(Severity.INFO))));
underTest.indexAllIssues();
assertThat(doc.impacts())
.containsExactlyInAnyOrder(Map.of(
SUB_FIELD_SOFTWARE_QUALITY, SoftwareQuality.MAINTAINABILITY.name(),
- SUB_FIELD_SEVERITY, Severity.HIGH.name()));
+ SUB_FIELD_SEVERITY, Severity.HIGH.name()),
+ Map.of(
+ SUB_FIELD_SOFTWARE_QUALITY, SoftwareQuality.SECURITY.name(),
+ SUB_FIELD_SEVERITY, Severity.INFO.name()));
assertThat(doc.issueStatus()).isEqualTo(issue.getIssueStatus().name());
}
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
import org.sonar.server.security.SecurityStandards;
-import static com.google.common.collect.ImmutableSet.of;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
import static java.util.Collections.singletonList;
+import static java.util.Set.of;
import static java.util.stream.IntStream.rangeClosed;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
RuleDto rule1 = insertJavaRule("My great rule CWE-123 which makes your code 1000 times better!", "123", "rule 123");
RuleDto rule2 = insertJavaRule("Another great and shiny rule CWE-124", "124", "rule 124");
RuleDto rule3 = insertJavaRule("Another great rule CWE-1000", "1000", "rule 1000");
- RuleDto rule4 = insertJavaRule("<h1>HTML-Geeks</h1><p style=\"color:blue\">special formatting!</p><table><tr><td>inside</td><td>tables</td></tr></table>", "404", "rule 404");
+ RuleDto rule4 = insertJavaRule("<h1>HTML-Geeks</h1><p style=\"color:blue\">special " +
+ "formatting!</p><table><tr><td>inside</td><td>tables</td></tr></table>", "404", "rule 404");
RuleDto rule5 = insertJavaRule("internationalization missunderstandings alsdkjfnadklsjfnadkdfnsksdjfn", "405", "rule 405");
index();
@Test
public void tags_facet_supports_selected_value_with_regexp_special_characters() {
- createRule(r -> r.setTags(Set.of("misra++")));
+ createRule(r -> r.setTags(of("misra++")));
index();
RuleQuery query = new RuleQuery()
@Test
public void search_by_security_owaspTop10_2021_return_vulnerabilities_and_hotspots_only() {
- RuleDto rule1 = createRule(setSecurityStandards(of("owaspTop10-2021:a1", "owaspTop10-2021:a10", "cwe:543")), r -> r.setType(VULNERABILITY));
+ RuleDto rule1 = createRule(setSecurityStandards(of("owaspTop10-2021:a1", "owaspTop10-2021:a10", "cwe:543")),
+ r -> r.setType(VULNERABILITY));
RuleDto rule2 = createRule(setSecurityStandards(of("owaspTop10-2021:a10", "cwe:543")), r -> r.setType(SECURITY_HOTSPOT));
createRule(setSecurityStandards(of("cwe:543")), r -> r.setType(CODE_SMELL));
index();
// Creation of one rule for each standard security category defined (except other)
for (Map.Entry<SecurityStandards.SQCategory, Set<String>> sqCategorySetEntry : SecurityStandards.CWES_BY_SQ_CATEGORY.entrySet()) {
- rules.add(createRule(setSecurityStandards(of("cwe:" + sqCategorySetEntry.getValue().iterator().next())), r -> r.setType(SECURITY_HOTSPOT)));
+ rules.add(createRule(setSecurityStandards(of("cwe:" + sqCategorySetEntry.getValue().iterator().next())),
+ r -> r.setType(SECURITY_HOTSPOT)));
}
index();
db.qualityProfiles().activateRule(anotherProfile, anotherProfileRule2);
index();
- verifySearch(newRuleQuery().setActivation(false).setQProfile(profile).setCompareToQProfile(anotherProfile), anotherProfileRule1, anotherProfileRule2);
+ verifySearch(newRuleQuery().setActivation(false).setQProfile(profile).setCompareToQProfile(anotherProfile), anotherProfileRule1,
+ anotherProfileRule2);
verifySearch(newRuleQuery().setActivation(true).setQProfile(profile).setCompareToQProfile(anotherProfile), commonRule);
- verifySearch(newRuleQuery().setActivation(true).setQProfile(profile).setCompareToQProfile(profile), commonRule, profileRule1, profileRule2, profileRule3);
+ verifySearch(newRuleQuery().setActivation(true).setQProfile(profile).setCompareToQProfile(profile), commonRule, profileRule1,
+ profileRule2, profileRule3);
verifySearch(newRuleQuery().setActivation(false).setQProfile(profile).setCompareToQProfile(profile));
}
verifyEmptySearch(newRuleQuery().setActivation(true).setQProfile(parent).setInheritance(of(INHERITED.name(), OVERRIDES.name())));
// inherited AND overridden on child
- verifySearch(newRuleQuery().setActivation(true).setQProfile(child).setInheritance(of(INHERITED.name(), OVERRIDES.name())), rule1, rule2, rule3);
+ verifySearch(newRuleQuery().setActivation(true).setQProfile(child).setInheritance(of(INHERITED.name(), OVERRIDES.name())), rule1,
+ rule2, rule3);
}
@Test
index();
RuleQuery query = new RuleQuery();
- SearchIdResult result1 = underTest.search(query.setImpactSoftwareQualities(List.of(SoftwareQuality.MAINTAINABILITY.name())), new SearchOptions());
+ SearchIdResult result1 = underTest.search(query.setImpactSoftwareQualities(List.of(SoftwareQuality.MAINTAINABILITY.name())),
+ new SearchOptions());
assertThat(result1.getUuids()).isEmpty();
query = new RuleQuery();
- SearchIdResult result2 = underTest.search(query.setImpactSoftwareQualities(List.of(SoftwareQuality.SECURITY.name())), new SearchOptions());
+ SearchIdResult result2 = underTest.search(query.setImpactSoftwareQualities(List.of(SoftwareQuality.SECURITY.name())),
+ new SearchOptions());
assertThat(result2.getUuids()).containsOnly(phpRule.getUuid());
}
@Test
public void search_by_severity() {
- ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(Severity.HIGH);
+ ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(Severity.BLOCKER);
RuleDto phpRule = createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto)));
index();
assertThat(result1.getUuids()).isEmpty();
query = new RuleQuery();
- SearchIdResult result2 = underTest.search(query.setImpactSeverities(List.of(Severity.HIGH.name())), new SearchOptions());
+ SearchIdResult result2 = underTest.search(query.setImpactSeverities(List.of(Severity.BLOCKER.name())), new SearchOptions());
assertThat(result2.getUuids()).containsOnly(phpRule.getUuid());
}
SearchIdResult result2 = underTest.search(query, new SearchOptions().addFacets(singletonList("cleanCodeAttributeCategories")));
assertThat(result2.getFacets().getAll()).hasSize(1);
- assertThat(result2.getFacets().getAll().get("cleanCodeAttributeCategories")).containsOnly(entry("ADAPTABLE", 1L), entry("INTENTIONAL", 1L));
+ assertThat(result2.getFacets().getAll().get("cleanCodeAttributeCategories")).containsOnly(entry("ADAPTABLE", 1L), entry("INTENTIONAL"
+ , 1L));
}
@Test
RuleQuery query = new RuleQuery();
SearchIdResult result = underTest.search(
- query.setCleanCodeAttributesCategories(List.of(CleanCodeAttributeCategory.CONSISTENT.name(), CleanCodeAttributeCategory.ADAPTABLE.name())),
+ query.setCleanCodeAttributesCategories(List.of(CleanCodeAttributeCategory.CONSISTENT.name(),
+ CleanCodeAttributeCategory.ADAPTABLE.name())),
new SearchOptions().addFacets(singletonList("cleanCodeAttributeCategories")));
assertThat(result.getUuids()).containsExactlyInAnyOrder(php.getUuid(), java.getUuid());
RuleQuery query = new RuleQuery();
- SearchIdResult result2 = underTest.search(query.setImpactSeverities(Set.of(Severity.HIGH.name())), new SearchOptions().addFacets(singletonList("impactSoftwareQualities")));
+ SearchIdResult result2 = underTest.search(query.setImpactSeverities(of(Severity.HIGH.name())),
+ new SearchOptions().addFacets(singletonList("impactSoftwareQualities")));
assertThat(result2.getFacets().getAll()).hasSize(1);
assertThat(result2.getFacets().getAll().get("impactSoftwareQualities"))
ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.HIGH);
ImpactDto impactDto2 = new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.LOW);
ImpactDto impactDto3 = new ImpactDto().setSoftwareQuality(SoftwareQuality.RELIABILITY).setSeverity(Severity.LOW);
+ ImpactDto impactDto4 = new ImpactDto().setSoftwareQuality(SoftwareQuality.RELIABILITY).setSeverity(Severity.BLOCKER);
+ ImpactDto impactDto5 = new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.BLOCKER);
+ ImpactDto impactDto6 = new ImpactDto().setSoftwareQuality(SoftwareQuality.RELIABILITY).setSeverity(Severity.INFO);
createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto)));
- createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto2, impactDto3)));
+ createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto2)));
+ createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto3)));
+ createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto4)));
+ createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto5)));
+ createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto6)));
index();
RuleQuery query = new RuleQuery();
SearchIdResult result = underTest.search(
- query.setImpactSeverities(Set.of(Severity.LOW.name())).setImpactSoftwareQualities(List.of(SoftwareQuality.MAINTAINABILITY.name())),
+ query.setImpactSeverities(of(Severity.LOW.name())).setImpactSoftwareQualities(List.of(SoftwareQuality.MAINTAINABILITY.name())),
new SearchOptions().addFacets(List.of("impactSoftwareQualities", "impactSeverities")));
assertThat(result.getFacets().getAll()).hasSize(2);
.containsOnly(
entry("HIGH", 1L),
entry("MEDIUM", 0L),
- entry("LOW", 1L));
+ entry("LOW", 1L),
+ entry("INFO", 0L),
+ entry("BLOCKER", 1L));
}
@Test
public void search_should_support_severity_facet() {
ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(Severity.HIGH);
ImpactDto impactDto2 = new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.LOW);
+ ImpactDto impactDto3 = new ImpactDto().setSoftwareQuality(SoftwareQuality.RELIABILITY).setSeverity(Severity.BLOCKER);
createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto)));
- createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto2)));
+ createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto2, impactDto3)));
index();
RuleQuery query = new RuleQuery();
SearchIdResult result2 = underTest.search(query, new SearchOptions().addFacets(singletonList("impactSeverities")));
assertThat(result2.getFacets().getAll()).hasSize(1);
- assertThat(result2.getFacets().getAll().get("impactSeverities")).containsOnly(entry("LOW", 1L), entry("MEDIUM", 0L), entry("HIGH", 1L));
+ assertThat(result2.getFacets().getAll().get("impactSeverities"))
+ .containsOnly(
+ entry("LOW", 1L),
+ entry("MEDIUM", 0L),
+ entry("HIGH", 1L),
+ entry("INFO", 0L),
+ entry("BLOCKER", 1L));
}
@Test
public void search_should_support_severity_facet_with_filters() {
ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(Severity.HIGH);
ImpactDto impactDto2 = new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.LOW);
+ ImpactDto impactDto3 = new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(Severity.INFO);
+ ImpactDto impactDto4 = new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.INFO);
+ ImpactDto impactDto5 = new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(Severity.BLOCKER);
createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto)));
- createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto2)));
+ createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto2, impactDto3)));
+ createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto4, impactDto5)));
index();
RuleQuery query = new RuleQuery();
- SearchIdResult result2 = underTest.search(query.setImpactSeverities(Set.of("LOW")), new SearchOptions().addFacets(singletonList("impactSeverities")));
+ SearchIdResult result2 = underTest.search(query.setImpactSeverities(of("LOW")), new SearchOptions().addFacets(singletonList(
+ "impactSeverities")));
assertThat(result2.getFacets().getAll()).hasSize(1);
- assertThat(result2.getFacets().getAll().get("impactSeverities")).containsOnly(entry("LOW", 1L), entry("MEDIUM", 0L), entry("HIGH", 1L));
+ assertThat(result2.getFacets().getAll().get("impactSeverities"))
+ .containsOnly(
+ entry("LOW", 1L),
+ entry("MEDIUM", 0L),
+ entry("HIGH", 1L),
+ entry("INFO", 2L),
+ entry("BLOCKER", 1L));
}
@Test
public void search_should_support_software_quality_and_severity_facets_with_filtering() {
ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(Severity.HIGH);
ImpactDto impactDto2 = new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.LOW);
+ ImpactDto impactDto3 = new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.BLOCKER);
createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto)));
createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto2)));
+ createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto3)));
index();
- RuleQuery query = new RuleQuery().setImpactSeverities(Set.of("LOW"))
- .setImpactSoftwareQualities(Set.of(SoftwareQuality.MAINTAINABILITY.name()));
+ RuleQuery query = new RuleQuery().setImpactSeverities(of("LOW"))
+ .setImpactSoftwareQualities(of(SoftwareQuality.MAINTAINABILITY.name()));
SearchOptions searchOptions = new SearchOptions().addFacets(List.of("impactSeverities", "impactSoftwareQualities"));
SearchIdResult result2 = underTest.search(query, searchOptions);
assertThat(result2.getFacets().getAll()).hasSize(2);
- assertThat(result2.getFacets().getAll().get("impactSeverities")).containsOnly(entry("LOW", 1L), entry("MEDIUM", 0L), entry("HIGH", 0L));
+ assertThat(result2.getFacets().getAll().get("impactSeverities"))
+ .containsOnly(
+ entry("LOW", 1L),
+ entry("MEDIUM", 0L),
+ entry("HIGH", 0L),
+ entry("INFO", 0L),
+ entry("BLOCKER", 1L));
assertThat(result2.getFacets().getAll().get("impactSoftwareQualities")).containsOnly(
entry(SoftwareQuality.SECURITY.name(), 0L),
entry(SoftwareQuality.MAINTAINABILITY.name(), 1L),
assertThat(result1.getFacets().getAll()).isEmpty();
// should not have any facet on non matching query!
- SearchIdResult result2 = underTest.search(new RuleQuery().setQueryText("aeiou"), new SearchOptions().addFacets(singletonList("repositories")));
+ SearchIdResult result2 = underTest.search(new RuleQuery().setQueryText("aeiou"), new SearchOptions().addFacets(singletonList(
+ "repositories")));
assertThat(result2.getFacets().getAll()).hasSize(1);
assertThat(result2.getFacets().getAll().get("repositories")).isEmpty();
setupStickyFacets();
RuleQuery query = new RuleQuery().setLanguages(ImmutableList.of("cpp"));
- SearchIdResult<String> result = underTest.search(query, new SearchOptions().addFacets(asList(FACET_LANGUAGES, FACET_REPOSITORIES, FACET_TAGS)));
+ SearchIdResult<String> result = underTest.search(query, new SearchOptions().addFacets(asList(FACET_LANGUAGES, FACET_REPOSITORIES,
+ FACET_TAGS)));
assertThat(result.getUuids()).hasSize(3);
assertThat(result.getFacets().getAll()).hasSize(3);
assertThat(result.getFacets().get(FACET_LANGUAGES)).containsOnlyKeys("cpp", "java", "cobol");
.setTags(ImmutableList.of("T2"))
.setTypes(asList(BUG, CODE_SMELL));
- SearchIdResult<String> result = underTest.search(query, new SearchOptions().addFacets(asList(FACET_LANGUAGES, FACET_REPOSITORIES, FACET_TAGS,
+ SearchIdResult<String> result = underTest.search(query, new SearchOptions().addFacets(asList(FACET_LANGUAGES, FACET_REPOSITORIES,
+ FACET_TAGS,
FACET_TYPES)));
assertThat(result.getUuids()).hasSize(2);
assertThat(result.getFacets().getAll()).hasSize(4);
.orElseThrow(() -> new IllegalArgumentException(format("Invalid value '%s'", value)));
}
- /**
- * Computes a rating from A to D, where E is converted to D.
- */
- public Rating getAToDRatingForDensity(double value) {
- return ratingBounds.entrySet().stream()
- .filter(e -> e.getValue().match(value))
- .map(e -> e.getKey() == E ? D : e.getKey())
- .findFirst()
- .orElseThrow(() -> new IllegalArgumentException(format("Invalid value '%s'", value)));
- }
-
public double getGradeLowerBound(Rating rating) {
if (rating.getIndex() > 1) {
return gridValues[rating.getIndex() - 2];
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
-import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.annotation.CheckForNull;
import static org.sonar.api.utils.Preconditions.checkArgument;
/**
- * Builder class to help build measures based on impacts with payload such as @{link {@link org.sonar.api.measures.CoreMetrics#RELIABILITY_ISSUES}}.
+ * Builder class to help build measures based on impacts with payload such as @{link
+ * {@link org.sonar.api.measures.CoreMetrics#RELIABILITY_ISSUES}}.
*/
public class ImpactMeasureBuilder {
return new ImpactMeasureBuilder(map);
}
- private static void checkImpactMap(Map<String, Long> map) {
- checkArgument(map.containsKey(TOTAL_KEY), "Map must contain a total key");
- Arrays.stream(Severity.values()).forEach(severity -> checkArgument(map.containsKey(severity.name()), "Map must contain a key for severity " + severity.name()));
+ /**
+ * As we moved from 3 to 5 severities, we need to be able to handle measures saved with missing severities.
+ */
+ private static void checkImpactMap(Map<String, Long> impactMap) {
+ checkArgument(impactMap.containsKey(TOTAL_KEY), "Map must contain a total key");
+ for (Severity severity : Severity.values()) {
+ if (!impactMap.containsKey(severity.name())) {
+ impactMap.put(severity.name(), 0L);
+ }
+ }
}
public static ImpactMeasureBuilder fromString(String value) {
INFO, A);
public static final Map<Severity, Rating> RATING_BY_SOFTWARE_QUALITY_SEVERITY = Map.of(
+ Severity.BLOCKER, Rating.E,
Severity.HIGH, Rating.D,
Severity.MEDIUM, Rating.C,
- Severity.LOW, Rating.B);
+ Severity.LOW, Rating.B,
+ Severity.INFO, Rating.A);
private final int index;
/**
* This class defines "default" measures values for the "Software Quality Rating Metrics" when they do not exist.
- * The "default" value is the same as the equivalent "Rule Type Rating Metric", except for E Rating that is converted to D Rating
+ * The "default" value is the same as the equivalent "Rule Type Rating Metric"
* If the "Software Quality Rating Metrics" exists, then no changes are made
*/
public class ProjectMeasuresSoftwareQualityRatingsInitializer {
CoreMetrics.SQALE_RATING_KEY, SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY,
CoreMetrics.RELIABILITY_RATING_KEY, SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING_KEY,
CoreMetrics.SECURITY_RATING_KEY, SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING_KEY,
- CoreMetrics.SECURITY_REVIEW_RATING_KEY, SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY,
CoreMetrics.NEW_SECURITY_RATING_KEY, SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY,
- CoreMetrics.NEW_SECURITY_REVIEW_RATING_KEY, SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY,
CoreMetrics.NEW_MAINTAINABILITY_RATING_KEY, SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY,
CoreMetrics.NEW_RELIABILITY_RATING_KEY, SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY
);
Double value = measures.get(ruleTypeMetric);
if (value != null) {
- measures.put(softwareQualityMetric, value > Rating.D.getIndex() ? Double.valueOf(Rating.D.getIndex()) : value);
+ measures.put(softwareQualityMetric, value);
}
}
}
return E;
}
- public static Rating computeAToDRating(@Nullable Double percent) {
- if (percent == null || Math.abs(percent - 100.0D) < 10e-6) {
- return A;
- } else if (percent >= 70.0D) {
- return B;
- } else if (percent >= 50.0D) {
- return C;
- }
- return D;
- }
}
assertThat(ratingGrid.getRatingForDensity(1.01)).isEqualTo(E);
}
- @Test
- public void getAToDRatingForDensity_returnsValueBetweenAAndD() {
- assertThat(ratingGrid.getAToDRatingForDensity(0)).isEqualTo(A);
- assertThat(ratingGrid.getAToDRatingForDensity(0.05)).isEqualTo(A);
- assertThat(ratingGrid.getAToDRatingForDensity(0.09999999)).isEqualTo(A);
- assertThat(ratingGrid.getAToDRatingForDensity(0.1)).isEqualTo(A);
- assertThat(ratingGrid.getAToDRatingForDensity(0.15)).isEqualTo(B);
- assertThat(ratingGrid.getAToDRatingForDensity(0.2)).isEqualTo(B);
- assertThat(ratingGrid.getAToDRatingForDensity(0.25)).isEqualTo(C);
- assertThat(ratingGrid.getAToDRatingForDensity(0.5)).isEqualTo(C);
- assertThat(ratingGrid.getAToDRatingForDensity(0.65)).isEqualTo(D);
- assertThat(ratingGrid.getAToDRatingForDensity(1)).isEqualTo(D);
- assertThat(ratingGrid.getAToDRatingForDensity(1.01)).isEqualTo(D);
- }
-
@Test
public void density_matching_exact_grid_values() {
assertThat(ratingGrid.getRatingForDensity(0.1)).isEqualTo(A);
*/
package org.sonar.server.measure;
+import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.Test;
-import org.sonar.api.issue.impact.Severity;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.sonar.api.issue.impact.Severity.BLOCKER;
+import static org.sonar.api.issue.impact.Severity.HIGH;
+import static org.sonar.api.issue.impact.Severity.INFO;
+import static org.sonar.api.issue.impact.Severity.LOW;
+import static org.sonar.api.issue.impact.Severity.MEDIUM;
class ImpactMeasureBuilderTest {
void createEmptyMeasure_shouldReturnMeasureWithAllFields() {
ImpactMeasureBuilder builder = ImpactMeasureBuilder.createEmpty();
assertThat(builder.buildAsMap())
- .containsAllEntriesOf(getImpactMap(0L, 0L, 0L, 0L));
- }
-
- private static Map<String, Long> getImpactMap(Long total, Long high, Long medium, Long low) {
- return Map.of("total", total, Severity.HIGH.name(), high, Severity.MEDIUM.name(), medium, Severity.LOW.name(), low);
+ .containsAllEntriesOf(getImpactMap(0L, 0L, 0L, 0L, 0L, 0L));
}
@Test
void fromMap_shouldInitializeCorrectlyTheBuilder() {
Map<String, Long> map = getImpactMap(6L, 3L, 2L, 1L);
ImpactMeasureBuilder builder = ImpactMeasureBuilder.fromMap(map);
+
+ map.put(INFO.name(), 0L);
+ map.put(BLOCKER.name(), 0L);
+
assertThat(builder.buildAsMap())
.isEqualTo(map);
}
LOW: 1
}
""");
+ Map<String, Long> expectedMap = getImpactMap(6L, 3L, 2L, 1L, 0L, 0L);
assertThat(builder.buildAsMap())
- .isEqualTo(getImpactMap(6L, 3L, 2L, 1L));
+ .isEqualTo(expectedMap);
}
@Test
.hasMessage("Map must contain a total key");
}
- @Test
- void buildAsMap_whenMissingSeverity_shouldThrowException() {
- ImpactMeasureBuilder impactMeasureBuilder = ImpactMeasureBuilder.newInstance()
- .setTotal(1L)
- .setSeverity(Severity.HIGH, 1L)
- .setSeverity(Severity.MEDIUM, 1L);
- assertThatThrownBy(impactMeasureBuilder::buildAsMap)
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessage("Map must contain a key for severity LOW");
- }
-
- @Test
- void buildAsString_whenMissingSeverity_shouldThrowException() {
- ImpactMeasureBuilder impactMeasureBuilder = ImpactMeasureBuilder.newInstance()
- .setTotal(1L)
- .setSeverity(Severity.HIGH, 1L)
- .setSeverity(Severity.MEDIUM, 1L);
- assertThatThrownBy(impactMeasureBuilder::buildAsString)
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessage("Map must contain a key for severity LOW");
- }
-
@Test
void setSeverity_shouldInitializeSeverityValues() {
ImpactMeasureBuilder builder = ImpactMeasureBuilder.newInstance()
- .setSeverity(Severity.HIGH, 3L)
- .setSeverity(Severity.MEDIUM, 2L)
- .setSeverity(Severity.LOW, 1L)
- .setTotal(6L);
+ .setSeverity(HIGH, 3L)
+ .setSeverity(MEDIUM, 2L)
+ .setSeverity(LOW, 1L)
+ .setSeverity(INFO, 4L)
+ .setSeverity(BLOCKER, 5L)
+ .setTotal(15L);
assertThat(builder.buildAsMap())
- .isEqualTo(getImpactMap(6L, 3L, 2L, 1L));
+ .isEqualTo(getImpactMap(15L, 3L, 2L, 1L, 4L, 5L));
}
@Test
void add_shouldSumImpactsAndTotal() {
- ImpactMeasureBuilder builder = ImpactMeasureBuilder.fromMap(getImpactMap(6L, 3L, 2L, 1L))
- .add(ImpactMeasureBuilder.newInstance().setTotal(6L).setSeverity(Severity.HIGH, 3L).setSeverity(Severity.MEDIUM, 2L).setSeverity(Severity.LOW, 1L));
+ ImpactMeasureBuilder builder = ImpactMeasureBuilder.fromMap(getImpactMap(11L, 3L, 2L, 1L, 1L, 4L))
+ .add(ImpactMeasureBuilder.newInstance()
+ .setTotal(14L)
+ .setSeverity(HIGH, 3L)
+ .setSeverity(MEDIUM, 2L)
+ .setSeverity(LOW, 1L)
+ .setSeverity(INFO, 5L)
+ .setSeverity(BLOCKER, 3L));
assertThat(builder.buildAsMap())
- .isEqualTo(getImpactMap(12L, 6L, 4L, 2L));
+ .isEqualTo(getImpactMap(25L, 6L, 4L, 2L, 6L, 7L));
}
@Test
}
@Test
- void getTotal_shoudReturnExpectedTotal() {
+ void getTotal_shouldReturnExpectedTotal() {
ImpactMeasureBuilder builder = ImpactMeasureBuilder.fromMap(getImpactMap(6L, 3L, 2L, 1L));
assertThat(builder.getTotal()).isEqualTo(6L);
}
+ private static Map<String, Long> getImpactMap(Long total, Long high, Long medium, Long low) {
+ return new HashMap<>() {
+ {
+ put("total", total);
+ put(HIGH.name(), high);
+ put(MEDIUM.name(), medium);
+ put(LOW.name(), low);
+ }
+ };
+ }
+
+ private static Map<String, Long> getImpactMap(Long total, Long high, Long medium, Long low, Long info, Long blocker) {
+ Map<String, Long> impactMap = getImpactMap(total, high, medium, low);
+ impactMap.put(INFO.name(), info);
+ impactMap.put(BLOCKER.name(), blocker);
+ return impactMap;
+ }
+
}
initialMeasures.put(CoreMetrics.SQALE_RATING_KEY, 1.0);
initialMeasures.put(CoreMetrics.RELIABILITY_RATING_KEY, 2.0);
initialMeasures.put(CoreMetrics.SECURITY_RATING_KEY, 3.0);
- initialMeasures.put(CoreMetrics.SECURITY_REVIEW_RATING_KEY, 4.0);
initialMeasures.put(CoreMetrics.NEW_SECURITY_RATING_KEY, 4.0);
- initialMeasures.put(CoreMetrics.NEW_SECURITY_REVIEW_RATING_KEY, 3.0);
- initialMeasures.put(CoreMetrics.NEW_MAINTAINABILITY_RATING_KEY, 2.0);
+ initialMeasures.put(CoreMetrics.NEW_MAINTAINABILITY_RATING_KEY, 5.0);
initialMeasures.put(CoreMetrics.NEW_RELIABILITY_RATING_KEY, 1.0);
Map<String, Double> measures = new HashMap<>(initialMeasures);
.containsEntry(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY, 1.0)
.containsEntry(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, 2.0)
.containsEntry(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING_KEY, 3.0)
- .containsEntry(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY, 4.0)
.containsEntry(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, 4.0)
- .containsEntry(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY, 3.0)
- .containsEntry(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY, 2.0)
+ .containsEntry(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY, 5.0)
.containsEntry(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, 1.0);
}
-
- @Test
- void initializeSoftwareQualityRatings_whenERating_thenSoftwareQualityRatingCreatedWithD() {
- Map<String, Double> initialMeasures = new HashMap<>();
- initialMeasures.put(CoreMetrics.SQALE_RATING_KEY, (double) Rating.E.getIndex());
- initialMeasures.put(CoreMetrics.RELIABILITY_RATING_KEY, (double) Rating.E.getIndex());
- initialMeasures.put(CoreMetrics.SECURITY_RATING_KEY, (double) Rating.E.getIndex());
- initialMeasures.put(CoreMetrics.SECURITY_REVIEW_RATING_KEY, (double) Rating.E.getIndex());
- initialMeasures.put(CoreMetrics.NEW_SECURITY_RATING_KEY, (double) Rating.E.getIndex());
- initialMeasures.put(CoreMetrics.NEW_SECURITY_REVIEW_RATING_KEY, (double) Rating.E.getIndex());
- initialMeasures.put(CoreMetrics.NEW_MAINTAINABILITY_RATING_KEY, (double) Rating.E.getIndex());
- initialMeasures.put(CoreMetrics.NEW_RELIABILITY_RATING_KEY, (double) Rating.E.getIndex());
-
- Map<String, Double> measures = new HashMap<>(initialMeasures);
-
- ProjectMeasuresSoftwareQualityRatingsInitializer.initializeSoftwareQualityRatings(measures);
-
- assertThat(measures).hasSize(initialMeasures.size() * 2)
- .containsAllEntriesOf(initialMeasures)
- .containsEntry(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY, (double) Rating.D.getIndex())
- .containsEntry(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, (double) Rating.D.getIndex())
- .containsEntry(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING_KEY, (double) Rating.D.getIndex())
- .containsEntry(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY, (double) Rating.D.getIndex())
- .containsEntry(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, (double) Rating.D.getIndex())
- .containsEntry(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY, (double) Rating.D.getIndex())
- .containsEntry(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY, (double) Rating.D.getIndex())
- .containsEntry(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, (double) Rating.D.getIndex());
- }
}
import static org.sonar.server.measure.Rating.C;
import static org.sonar.server.measure.Rating.D;
import static org.sonar.server.measure.Rating.E;
-import static org.sonar.server.security.SecurityReviewRating.computeAToDRating;
import static org.sonar.server.security.SecurityReviewRating.computePercent;
import static org.sonar.server.security.SecurityReviewRating.computeRating;
return res.toArray(new Object[res.size()][2]);
}
- private static Object[][] valuesForSoftwareQualityRatings() {
- List<Object[]> res = new ArrayList<>();
- res.add(new Object[] {100.0, A});
- res.add(new Object[] {99.999999, A});
- res.add(new Object[] {99.99999, B});
- res.add(new Object[] {99.9, B});
- res.add(new Object[] {90.0, B});
- res.add(new Object[] {80.0, B});
- res.add(new Object[] {75.0, B});
- res.add(new Object[] {70.0, B});
- res.add(new Object[] {60, C});
- res.add(new Object[] {50.0, C});
- res.add(new Object[] {40.0, D});
- res.add(new Object[] {30.0, D});
- res.add(new Object[] {29.9, D});
- return res.toArray(new Object[res.size()][2]);
- }
-
@ParameterizedTest
@MethodSource("values")
void compute_rating(double percent, Rating expectedRating) {
assertThat(computeRating(percent)).isEqualTo(expectedRating);
}
- @ParameterizedTest
- @MethodSource("valuesForSoftwareQualityRatings")
- void compute_ratingForSoftwareQuality(double percent, Rating expectedRating) {
- assertThat(computeAToDRating(percent)).isEqualTo(expectedRating);
- }
-
@Test
void compute_percent() {
assertThat(computePercent(0, 0)).isEmpty();
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
});
+ return result;
+ },
+ async toHaveAPopoverWithContent(received: any, content: string) {
+ const user = userEvent.setup({ pointerEventsCheck: PointerEventsCheckLevel.Never });
+
+ if (!(received instanceof Element)) {
+ return {
+ pass: false,
+ message: () => `Received object is not an HTMLElement, and cannot have a tooltip`,
+ };
+ }
+
+ await user.click(received);
+
+ const popover = await screen.findByRole('dialog');
+
+ const result = popover.textContent?.includes(content)
+ ? {
+ pass: true,
+ message: () => `Tooltip content "${popover.textContent}" contains expected "${content}"`,
+ }
+ : {
+ pass: false,
+ message: () =>
+ `Tooltip content "${popover.textContent}" does not contain expected "${content}"`,
+ };
+
+ await user.keyboard('{Escape}');
+
+ await waitFor(() => {
+ expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
+ });
+
return result;
},
});
? {
backgroundColor:
color.backgroundColor ??
- themeColor(`bubble.legacy.${(idx + 1) as BubbleColorVal}`)({
+ themeColor(`bubble.${(idx + 1) as BubbleColorVal}`)({
theme,
}),
borderColor:
color.borderColor ??
- themeContrast(`bubble.legacy.${(idx + 1) as BubbleColorVal}`)({
+ themeContrast(`bubble.${(idx + 1) as BubbleColorVal}`)({
theme,
}),
}
inner={inner}
>
<Header>
- <ChevronAndTitle
- aria-controls={`${id}-panel`}
- aria-disabled={!expandable}
- aria-expanded={open}
- aria-label={ariaLabel ?? name}
- expandable={expandable}
- id={`${id}-header`}
- onClick={() => {
- if (!disabled) {
- onClick?.(!open);
- }
- }}
- >
- {expandable && <OpenCloseIndicator aria-hidden open={open} />}
-
- {disabled ? (
- <Tooltip content={disabledHelper}>
- <HeaderTitle
- aria-disabled
- aria-label={`${name}, ${disabledHelper ?? ''}`}
- disabled={disabled}
- >
- {name}
- </HeaderTitle>
- </Tooltip>
- ) : (
- <HeaderTitle>{name}</HeaderTitle>
- )}
-
+ <TitleWithHelp>
+ <ChevronAndTitle
+ aria-controls={`${id}-panel`}
+ aria-disabled={!expandable}
+ aria-expanded={open}
+ aria-label={ariaLabel ?? name}
+ expandable={expandable}
+ id={`${id}-header`}
+ onClick={() => {
+ if (!disabled) {
+ onClick?.(!open);
+ }
+ }}
+ >
+ {expandable && <OpenCloseIndicator aria-hidden open={open} />}
+
+ {disabled ? (
+ <Tooltip content={disabledHelper}>
+ <HeaderTitle
+ aria-disabled
+ aria-label={`${name}, ${disabledHelper ?? ''}`}
+ disabled={disabled}
+ >
+ {name}
+ </HeaderTitle>
+ </Tooltip>
+ ) : (
+ <HeaderTitle>{name}</HeaderTitle>
+ )}
+ </ChevronAndTitle>
{help && <span className="sw-ml-1">{help}</span>}
- </ChevronAndTitle>
+ </TitleWithHelp>
{<Spinner loading={loading} />}
${tw`sw-gap-2`};
`;
+const TitleWithHelp = styled.div`
+ ${tw`sw-flex`};
+ ${tw`sw-items-center`};
+`;
+
const ChevronAndTitle = styled(BareButton)<{
expandable?: boolean;
}>`
import { themeColor, themeContrast } from '../helpers/theme';
import { ThemeColors } from '../types/theme';
-type PillVariant = 'danger' | 'warning' | 'info' | 'accent';
+export enum PillVariant {
+ Critical = 'critical',
+ Danger = 'danger',
+ Warning = 'warning',
+ Caution = 'caution',
+ Info = 'info',
+ Accent = 'accent',
+}
const variantThemeColors: Record<PillVariant, ThemeColors> = {
- danger: 'pillDanger',
- warning: 'pillWarning',
- info: 'pillInfo',
- accent: 'pillAccent',
+ [PillVariant.Critical]: 'pillCritical',
+ [PillVariant.Danger]: 'pillDanger',
+ [PillVariant.Warning]: 'pillWarning',
+ [PillVariant.Caution]: 'pillCaution',
+ [PillVariant.Info]: 'pillInfo',
+ [PillVariant.Accent]: 'pillAccent',
};
const variantThemeBorderColors: Record<PillVariant, ThemeColors> = {
- danger: 'pillDangerBorder',
- warning: 'pillWarningBorder',
- info: 'pillInfoBorder',
- accent: 'pillAccentBorder',
+ [PillVariant.Critical]: 'pillCriticalBorder',
+ [PillVariant.Danger]: 'pillDangerBorder',
+ [PillVariant.Warning]: 'pillWarningBorder',
+ [PillVariant.Caution]: 'pillCautionBorder',
+ [PillVariant.Info]: 'pillInfoBorder',
+ [PillVariant.Accent]: 'pillAccentBorder',
};
interface PillProps {
background-color: ${({ variant }) => themeColor(variantThemeColors[variant])};
color: ${({ variant }) => themeContrast(variantThemeColors[variant])};
- border-style: ${({ variant }) => (variant === 'accent' ? 'hidden' : 'solid')};
+ border-style: ${({ variant }) => (variant === PillVariant.Accent ? 'hidden' : 'solid')};
border-color: ${({ variant }) => themeColor(variantThemeBorderColors[variant])};
`;
background-color: ${({ variant }) => themeColor(variantThemeColors[variant])};
color: ${({ variant }) => themeContrast(variantThemeColors[variant])};
- border-style: ${({ variant }) => (variant === 'accent' ? 'hidden' : 'solid')};
+ border-style: ${({ variant }) => (variant === PillVariant.Accent ? 'hidden' : 'solid')};
border-color: ${({ variant }) => themeColor(variantThemeBorderColors[variant])};
cursor: pointer;
*/
import { screen } from '@testing-library/react';
import { render } from '../../helpers/testUtils';
-import { Pill } from '../Pill';
+import { Pill, PillVariant } from '../Pill';
it('should render correctly', () => {
- render(<Pill variant="accent">23</Pill>);
+ render(<Pill variant={PillVariant.Accent}>23</Pill>);
expect(screen.getByText('23')).toBeInTheDocument();
});
<circle
cx="8"
cy="8"
- fill="rgb(254,205,202)"
+ fill="rgb(255,214,175)"
r="7"
/>
<path
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 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.
+ */
+import { useTheme } from '@emotion/react';
+import { themeColor } from '../../helpers';
+import { CustomIcon, IconProps } from './Icon';
+
+export function SoftwareImpactSeverityBlockerIcon({
+ disabled,
+ ...iconProps
+}: IconProps & { disabled?: boolean }) {
+ const theme = useTheme();
+ const color = disabled
+ ? 'iconSoftwareImpactSeverityDisabled'
+ : 'iconSoftwareImpactSeverityBlocker';
+
+ return (
+ <CustomIcon viewBox="0 0 14 14" {...iconProps}>
+ <path
+ clipRule="evenodd"
+ d="M7 13.375C10.5208 13.375 13.375 10.5208 13.375 7C13.375 3.47918 10.5208 0.625 7 0.625C3.47918 0.625 0.625 3.47918 0.625 7C0.625 10.5208 3.47918 13.375 7 13.375ZM4 6C3.44772 6 3 6.44772 3 7C3 7.55228 3.44772 8 4 8H10C10.5523 8 11 7.55228 11 7C11 6.44772 10.5523 6 10 6H4Z"
+ fill={themeColor(color)({ theme })}
+ fillRule="evenodd"
+ />
+ </CustomIcon>
+ );
+}
const color = disabled ? 'iconSoftwareImpactSeverityDisabled' : 'iconSoftwareImpactSeverityHigh';
return (
- <CustomIcon {...iconProps}>
+ <CustomIcon viewBox="0 0 14 14" {...iconProps}>
<path
clipRule="evenodd"
- d="M7 14C10.866 14 14 10.866 14 7C14 3.13401 10.866 0 7 0C3.13401 0 0 3.13401 0 7C0 10.866 3.13401 14 7 14ZM4.14421 5.43198C4.05583 5.47727 4 5.56986 4 5.67113V9.73238C4 9.91906 4.18192 10.0483 4.35247 9.98273L6.9084 9.00033C6.96746 8.97763 7.03254 8.97763 7.0916 9.00033L9.64753 9.98273C9.81808 10.0483 10 9.91906 10 9.73238V5.67113C10 5.56986 9.94417 5.47727 9.85579 5.43198L7.11666 4.02823C7.04322 3.99059 6.95678 3.99059 6.88334 4.02823L4.14421 5.43198Z"
+ d="M7 13.375C10.5208 13.375 13.375 10.5208 13.375 7C13.375 3.47918 10.5208 0.625 7 0.625C3.47918 0.625 0.625 3.47918 0.625 7C0.625 10.5208 3.47918 13.375 7 13.375ZM4.3983 5.57213C4.31781 5.61338 4.26697 5.6977 4.26697 5.78993V9.48856C4.26697 9.65858 4.43265 9.77626 4.58796 9.71657L6.91569 8.82188C6.96948 8.80121 7.02875 8.80121 7.08253 8.82188L9.41026 9.71657C9.56557 9.77626 9.73125 9.65858 9.73125 9.48856V5.78993C9.73125 5.6977 9.68041 5.61338 9.59992 5.57213L7.10536 4.29371C7.03847 4.25944 6.95975 4.25944 6.89286 4.29371L4.3983 5.57213Z"
fill={themeColor(color)({ theme })}
fillRule="evenodd"
/>
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 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.
+ */
+import styled from '@emotion/styled';
+import { IconInfo } from '@sonarsource/echoes-react';
+import { IconProps } from './Icon';
+
+const defaultIconSize = 15;
+
+export function SoftwareImpactSeverityInfoIcon({
+ disabled,
+ ...iconProps
+}: IconProps & { disabled?: boolean }) {
+ const color = disabled ? 'echoes-color-icon-disabled' : 'echoes-color-icon-info';
+
+ return <StyledIconInfo color={color} {...iconProps} />;
+}
+
+// Info icon is the only one that is imported from echoes, so we need to adjust its size
+const StyledIconInfo = styled(IconInfo)`
+ ${(props: IconProps & { disabled?: boolean }) => {
+ let size = props.width ?? props.height;
+ size = size ? size + 1 : defaultIconSize;
+
+ return `
+ font-size: ${size}px;
+ margin-left: -0.5px;
+ `;
+ }};
+`;
const color = disabled ? 'iconSoftwareImpactSeverityDisabled' : 'iconSoftwareImpactSeverityLow';
return (
- <CustomIcon {...iconProps}>
+ <CustomIcon viewBox="0 0 14 14" {...iconProps}>
<path
clipRule="evenodd"
- d="M7 14C10.866 14 14 10.866 14 7C14 3.13401 10.866 0 7 0C3.13401 0 0 3.13401 0 7C0 10.866 3.13401 14 7 14ZM3.7019 6.46256L6.46967 9.23033C6.76256 9.52322 7.23744 9.52322 7.53033 9.23033L10.2981 6.46256C10.591 6.16967 10.591 5.6948 10.2981 5.4019C10.0052 5.10901 9.53033 5.10901 9.23744 5.4019L7 7.63934L4.76256 5.4019C4.46967 5.10901 3.9948 5.10901 3.7019 5.4019C3.40901 5.6948 3.40901 6.16967 3.7019 6.46256Z"
+ d="M7 13.375C10.5208 13.375 13.375 10.5208 13.375 7C13.375 3.47918 10.5208 0.625 7 0.625C3.47918 0.625 0.625 3.47918 0.625 7C0.625 10.5208 3.47918 13.375 7 13.375ZM3.94899 6.55761L6.46964 9.07825C6.76253 9.37115 7.2374 9.37115 7.5303 9.07825L10.0509 6.55761C10.3438 6.26472 10.3438 5.78984 10.0509 5.49695C9.75805 5.20406 9.28317 5.20406 8.99028 5.49695L6.99997 7.48727L5.00965 5.49695C4.71676 5.20406 4.24188 5.20406 3.94899 5.49695C3.6561 5.78984 3.6561 6.26472 3.94899 6.55761Z"
fill={themeColor(color)({ theme })}
fillRule="evenodd"
/>
: 'iconSoftwareImpactSeverityMedium';
return (
- <CustomIcon {...iconProps}>
+ <CustomIcon viewBox="0 0 14 14" {...iconProps}>
<path
clipRule="evenodd"
- d="M7 14C10.866 14 14 10.866 14 7C14 3.13401 10.866 0 7 0C3.13401 0 0 3.13401 0 7C0 10.866 3.13401 14 7 14ZM10.2981 7.96967L7.53033 5.2019C7.23744 4.90901 6.76256 4.90901 6.46967 5.2019L3.7019 7.96967C3.40901 8.26256 3.40901 8.73744 3.7019 9.03033C3.9948 9.32322 4.46967 9.32322 4.76256 9.03033L7 6.79289L9.23744 9.03033C9.53033 9.32322 10.0052 9.32322 10.2981 9.03033C10.591 8.73744 10.591 8.26256 10.2981 7.96967Z"
+ d="M7 13.375C10.5208 13.375 13.375 10.5208 13.375 7C13.375 3.47918 10.5208 0.625 7 0.625C3.47918 0.625 0.625 3.47918 0.625 7C0.625 10.5208 3.47918 13.375 7 13.375ZM10.051 7.83547L7.53033 5.31482C7.23744 5.02193 6.76256 5.02193 6.46967 5.31482L3.94903 7.83547C3.65613 8.12836 3.65613 8.60324 3.94903 8.89613C4.24192 9.18902 4.71679 9.18902 5.00969 8.89613L7 6.90581L8.99031 8.89613C9.28321 9.18902 9.75808 9.18902 10.051 8.89613C10.3439 8.60324 10.3439 8.12836 10.051 7.83547Z"
fill={themeColor(color)({ theme })}
fillRule="evenodd"
/>
export { SeverityMajorIcon } from './SeverityMajorIcon';
export { SeverityMinorIcon } from './SeverityMinorIcon';
export { SnoozeCircleIcon } from './SnoozeCircleIcon';
+export { SoftwareImpactSeverityBlockerIcon } from './SoftwareImpactSeverityBlockerIcon';
export { SoftwareImpactSeverityHighIcon } from './SoftwareImpactSeverityHighIcon';
+export { SoftwareImpactSeverityInfoIcon } from './SoftwareImpactSeverityInfoIcon';
export { SoftwareImpactSeverityLowIcon } from './SoftwareImpactSeverityLowIcon';
export { SoftwareImpactSeverityMediumIcon } from './SoftwareImpactSeverityMediumIcon';
export { SortAscendIcon } from './SortAscendIcon';
export * from './NavBarTabs';
export * from './NewCodeLegend';
export * from './OutsideClickHandler';
-export { Pill } from './Pill';
+export * from './Pill';
export * from './popups';
export { QualityGateIndicator } from './QualityGateIndicator';
export * from './SearchHighlighter';
type sizeType = keyof typeof SIZE_MAPPING;
interface Props extends React.AriaAttributes {
className?: string;
- isLegacy?: boolean;
label?: string;
rating?: RatingLabel;
size?: sizeType;
};
export const MetricsRatingBadge = forwardRef<HTMLDivElement, Props>(
- (
- { className, size = 'sm', isLegacy = true, label, rating, ...ariaAttrs }: Readonly<Props>,
- ref,
- ) => {
+ ({ className, size = 'sm', label, rating, ...ariaAttrs }: Readonly<Props>, ref) => {
if (!rating) {
return (
<StyledNoRatingBadge
<MetricsRatingBadgeStyled
aria-label={label}
className={className}
- isLegacy={isLegacy}
rating={rating}
ref={ref}
size={SIZE_MAPPING[size]}
};
const MetricsRatingBadgeStyled = styled.div<{
- isLegacy: boolean;
rating: RatingLabel;
size: string;
}>`
height: ${getProp('size')};
color: ${({ rating }) => themeContrast(`rating.${rating}`)};
font-size: ${({ size }) => getFontSize(size)};
- background-color: ${({ rating, isLegacy }) =>
- themeColor(`rating.${isLegacy ? 'legacy.' : ''}${rating}`)};
+ background-color: ${({ rating }) => themeColor(`rating.${rating}`)};
user-select: none;
display: inline-flex;
badgeCounterFailedBorder: COLORS.red[200],
// pills
+ pillCritical: COLORS.red[100],
+ pillCriticalBorder: COLORS.red[800],
pillDanger: COLORS.red[50],
- pillDangerBorder: COLORS.red[300],
- pillWarning: COLORS.yellow[50],
- pillWarningBorder: COLORS.yellow[300],
+ pillDangerBorder: COLORS.red[600],
+ pillWarning: COLORS.orange[50],
+ pillWarningBorder: COLORS.orange[300],
+ pillCaution: COLORS.yellow[50],
+ pillCautionBorder: COLORS.yellow[300],
pillInfo: COLORS.blue[50],
pillInfoBorder: COLORS.blue[300],
pillAccent: COLORS.indigo[50],
destructiveIconFocus: danger.default,
// icons
- iconSoftwareImpactSeverityHigh: COLORS.red[500],
- iconSoftwareImpactSeverityMedium: COLORS.yellow[700],
- iconSoftwareImpactSeverityLow: COLORS.blue[700],
+ iconSoftwareImpactSeverityBlocker: COLORS.red[800],
+ iconSoftwareImpactSeverityHigh: COLORS.red[600],
+ iconSoftwareImpactSeverityMedium: COLORS.orange[400],
+ iconSoftwareImpactSeverityLow: COLORS.yellow[500],
+ iconSoftwareImpactSeverityInfo: COLORS.blue[600],
iconSoftwareImpactSeverityDisabled: COLORS.blueGrey[300],
iconSeverityMajor: danger.light,
iconSeverityMinor: COLORS.yellowGreen[400],
// size indicators
sizeIndicator: COLORS.blue[500],
- // rating colors
- 'rating.legacy.A': COLORS.green[200],
- 'rating.legacy.B': COLORS.yellowGreen[200],
- 'rating.legacy.C': COLORS.yellow[200],
- 'rating.legacy.D': COLORS.orange[200],
- 'rating.legacy.E': COLORS.red[200],
-
// rating colors
'rating.A': COLORS.green[200],
'rating.B': COLORS.yellowGreen[200],
'rating.C': COLORS.yellow[200],
- 'rating.D': COLORS.red[200],
+ 'rating.D': COLORS.orange[200],
'rating.E': COLORS.red[200],
'portfolio.rating.A.text': COLORS.green[900],
'portfolio.rating.C.text': COLORS.yellow[900],
'portfolio.rating.C.background': COLORS.yellow[100],
'portfolio.rating.C.border': COLORS.yellow[500],
- 'portfolio.rating.D.text': COLORS.red[900],
- 'portfolio.rating.D.background': COLORS.red[100],
- 'portfolio.rating.D.border': COLORS.red[400],
+ 'portfolio.rating.D.text': COLORS.orange[900],
+ 'portfolio.rating.D.background': COLORS.orange[100],
+ 'portfolio.rating.D.border': COLORS.orange[300],
'portfolio.rating.E.text': COLORS.red[900],
'portfolio.rating.E.background': COLORS.red[100],
'portfolio.rating.E.border': COLORS.red[400],
'portfolio.rating.NONE.background': COLORS.blueGrey[50],
'portfolio.rating.NONE.border': COLORS.blueGrey[200],
- 'portfolio.rating.legacy.A.text': COLORS.green[900],
- 'portfolio.rating.legacy.A.background': COLORS.green[100],
- 'portfolio.rating.legacy.A.border': COLORS.green[400],
- 'portfolio.rating.legacy.B.text': COLORS.yellowGreen[900],
- 'portfolio.rating.legacy.B.background': COLORS.yellowGreen[100],
- 'portfolio.rating.legacy.B.border': COLORS.yellowGreen[400],
- 'portfolio.rating.legacy.C.text': COLORS.yellow[900],
- 'portfolio.rating.legacy.C.background': COLORS.yellow[100],
- 'portfolio.rating.legacy.C.border': COLORS.yellow[500],
- 'portfolio.rating.legacy.D.text': COLORS.orange[900],
- 'portfolio.rating.legacy.D.background': COLORS.orange[100],
- 'portfolio.rating.legacy.D.border': COLORS.orange[300],
- 'portfolio.rating.legacy.E.text': COLORS.red[900],
- 'portfolio.rating.legacy.E.background': COLORS.red[100],
- 'portfolio.rating.legacy.E.border': COLORS.red[400],
- 'portfolio.rating.legacy.NONE.text': COLORS.blueGrey[300],
- 'portfolio.rating.legacy.NONE.background': COLORS.blueGrey[50],
- 'portfolio.rating.legacy.NONE.border': COLORS.blueGrey[200],
-
// rating donut outside circle indicators
'ratingDonut.A': COLORS.green[400],
'ratingDonut.B': COLORS.yellowGreen[400],
// bubble charts
bubbleChartLine: COLORS.grey[50],
bubbleDefault: [...COLORS.blue[500], 0.3],
- 'bubble.legacy.1': [...COLORS.green[500], 0.3],
- 'bubble.legacy.2': [...COLORS.yellowGreen[500], 0.3],
- 'bubble.legacy.3': [...COLORS.yellow[500], 0.3],
- 'bubble.legacy.4': [...COLORS.orange[500], 0.3],
- 'bubble.legacy.5': [...COLORS.red[500], 0.3],
'bubble.1': [...COLORS.green[500], 0.3],
'bubble.2': [...COLORS.yellowGreen[500], 0.3],
'bubble.3': [...COLORS.yellow[500], 0.3],
- 'bubble.4': [...COLORS.red[500], 0.3],
+ 'bubble.4': [...COLORS.orange[500], 0.3],
'bubble.5': [...COLORS.red[500], 0.3],
// TreeMap Colors
- 'treeMap.legacy.A': COLORS.green[500],
- 'treeMap.legacy.B': COLORS.yellowGreen[500],
- 'treeMap.legacy.C': COLORS.yellow[500],
- 'treeMap.legacy.D': COLORS.orange[500],
- 'treeMap.legacy.E': COLORS.red[500],
-
'treeMap.A': COLORS.green[500],
'treeMap.B': COLORS.yellowGreen[500],
'treeMap.C': COLORS.yellow[500],
- 'treeMap.D': COLORS.red[500],
+ 'treeMap.D': COLORS.orange[500],
'treeMap.E': COLORS.red[500],
'treeMap.NA1': COLORS.blueGrey[300],
badgeCounterFailed: danger.dark,
// pills
- pillDanger: COLORS.red[800],
- pillDangerIcon: COLORS.red[700],
- pillWarning: COLORS.yellow[800],
- pillWarningIcon: COLORS.yellow[700],
+ pillCritical: COLORS.red[800],
+ pillDanger: COLORS.red[700],
+ pillWarning: COLORS.orange[800],
+ pillCaution: COLORS.yellow[800],
pillInfo: COLORS.blue[800],
- pillInfoIcon: COLORS.blue[700],
pillAccent: COLORS.indigo[500],
// project cards
// page
pageBlock: secondary.darker,
- // overview software impact breakdown
- overviewSoftwareImpactSeverityNeutral: COLORS.blueGrey[500],
- overviewSoftwareImpactSeverityHigh: COLORS.red[700],
- overviewSoftwareImpactSeverityMedium: COLORS.yellow[800],
- overviewSoftwareImpactSeverityLow: COLORS.blue[800],
-
// graph - chart
graphZoomHandleColor: COLORS.white,
// bubble charts
bubbleDefault: COLORS.blue[500],
- 'bubble.legacy.1': COLORS.green[500],
- 'bubble.legacy.2': COLORS.yellowGreen[500],
- 'bubble.legacy.3': COLORS.yellow[500],
- 'bubble.legacy.4': COLORS.orange[500],
- 'bubble.legacy.5': COLORS.red[500],
'bubble.1': COLORS.green[500],
'bubble.2': COLORS.yellowGreen[500],
'bubble.3': COLORS.yellow[500],
- 'bubble.4': COLORS.red[500],
+ 'bubble.4': COLORS.orange[500],
'bubble.5': COLORS.red[500],
// news bar
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { Popover } from '@sonarsource/echoes-react';
-import { Pill } from 'design-system';
+import { Pill, PillVariant } from 'design-system';
import * as React from 'react';
import DocumentationLink from '../../components/common/DocumentationLink';
import { DocLink } from '../../helpers/doc-links';
</DocumentationLink>
}
>
- <Pill variant="info" className="sw-ml-2" onClick={() => setIsPopoverOpen(!isPopoverOpen)}>
+ <Pill
+ variant={PillVariant.Accent}
+ className="sw-ml-2"
+ onClick={() => setIsPopoverOpen(!isPopoverOpen)}
+ >
{translate('projects.awaiting_scan')}
</Pill>
</Popover>
const useGetMetricKeyForRating = (ratingMetric: RatingMetricKeys): MetricKey | null => {
const { data: isLegacy, isLoading } = useIsLegacyCCTMode();
+ const hasSoftwareQualityRating = !!SOFTWARE_QUALITY_RATING_METRICS_MAP[ratingMetric];
+
if (isNewRatingMetric(ratingMetric)) {
return ratingMetric;
}
if (isLoading) {
return null;
}
- return isLegacy ? ratingMetric : SOFTWARE_QUALITY_RATING_METRICS_MAP[ratingMetric];
+ return isLegacy || !hasSoftwareQualityRating
+ ? ratingMetric
+ : SOFTWARE_QUALITY_RATING_METRICS_MAP[ratingMetric];
};
export default function RatingComponent(props: Readonly<Props>) {
const badge = (
<MetricsRatingBadge
label={getLabel ? getLabel(rating) : (value ?? '—')}
- isLegacy={measure?.metric ? !isNewRatingMetric(measure.metric as MetricKey) : false}
rating={rating}
size={size}
className={className}
exports[`getCodeMetrics should return the right metrics for portfolios 1`] = `
[
"releasability_rating",
- "software_quality_releasability_rating",
"new_security_rating",
"new_software_quality_security_rating",
"new_reliability_rating",
"new_maintainability_rating",
"new_software_quality_maintainability_rating",
"new_security_review_rating",
- "new_software_quality_security_review_rating",
"new_lines",
"releasability_rating",
- "software_quality_releasability_rating",
"security_rating",
"software_quality_security_rating",
"reliability_rating",
"sqale_rating",
"software_quality_maintainability_rating",
"security_review_rating",
- "software_quality_security_review_rating",
"ncloc",
]
`;
exports[`getCodeMetrics should return the right metrics for portfolios 2`] = `
[
"releasability_rating",
- "software_quality_releasability_rating",
"new_security_rating",
"new_software_quality_security_rating",
"new_reliability_rating",
"new_maintainability_rating",
"new_software_quality_maintainability_rating",
"new_security_review_rating",
- "new_software_quality_security_review_rating",
"new_lines",
"releasability_rating",
- "software_quality_releasability_rating",
"security_rating",
"software_quality_security_rating",
"reliability_rating",
"sqale_rating",
"software_quality_maintainability_rating",
"security_review_rating",
- "software_quality_security_review_rating",
"ncloc",
"alert_status",
]
exports[`getCodeMetrics should return the right metrics for portfolios 3`] = `
[
"releasability_rating",
- "software_quality_releasability_rating",
"new_security_rating",
"new_software_quality_security_rating",
"new_reliability_rating",
"new_maintainability_rating",
"new_software_quality_maintainability_rating",
"new_security_review_rating",
- "new_software_quality_security_review_rating",
"new_lines",
"alert_status",
]
exports[`getCodeMetrics should return the right metrics for portfolios 4`] = `
[
"releasability_rating",
- "software_quality_releasability_rating",
"security_rating",
"software_quality_security_rating",
"reliability_rating",
"sqale_rating",
"software_quality_maintainability_rating",
"security_review_rating",
- "software_quality_security_review_rating",
"ncloc",
"alert_status",
]
areCCTMeasuresComputed,
areSoftwareQualityRatingsComputed,
} from '../../../helpers/measures';
+import { useIsLegacyCCTMode } from '../../../queries/settings';
import { BranchLike } from '../../../types/branch-like';
import { isApplication } from '../../../types/component';
import { Component, ComponentMeasure, Dict, Metric } from '../../../types/types';
const showComponentList = sourceViewer === undefined && components.length > 0 && !showSearch;
+ const { data: isLegacy, isLoading: isLoadingLegacy } = useIsLegacyCCTMode();
+
const metricKeys = intersection(
getCodeMetrics(component.qualifier, branchLike, { newCode: newCodeSelected }),
Object.keys(metrics),
);
const filteredMetrics = difference(metricKeys, [
- ...(allComponentsHaveSoftwareQualityMeasures
+ ...(allComponentsHaveSoftwareQualityMeasures && !isLegacy
? OLD_TAXONOMY_METRICS
: CCT_SOFTWARE_QUALITY_METRICS),
- ...(allComponentsHaveRatings
+ ...(allComponentsHaveRatings && !isLegacy
? [...OLD_TAXONOMY_RATINGS, ...LEAK_OLD_TAXONOMY_RATINGS]
: SOFTWARE_QUALITY_RATING_METRICS),
]).map((key) => metrics[key]);
</FlagMessage>
)}
- <Spinner isLoading={loading}>
+ <Spinner isLoading={loading || isLoadingLegacy}>
{!allComponentsHaveSoftwareQualityMeasures && (
<AnalysisMissingInfoMessage
qualifier={component.qualifier}
const PORTFOLIO_METRICS = [
MetricKey.releasability_rating,
- MetricKey.software_quality_releasability_rating,
MetricKey.security_rating,
MetricKey.software_quality_security_rating,
MetricKey.reliability_rating,
MetricKey.sqale_rating,
MetricKey.software_quality_maintainability_rating,
MetricKey.security_review_rating,
- MetricKey.software_quality_security_review_rating,
MetricKey.ncloc,
];
const NEW_PORTFOLIO_METRICS = [
MetricKey.releasability_rating,
- MetricKey.software_quality_releasability_rating,
MetricKey.new_security_rating,
MetricKey.new_software_quality_security_rating,
MetricKey.new_reliability_rating,
MetricKey.new_maintainability_rating,
MetricKey.new_software_quality_maintainability_rating,
MetricKey.new_security_review_rating,
- MetricKey.new_software_quality_security_review_rating,
MetricKey.new_lines,
];
// Filter by severity
await user.click(ui.severetiesFacet.get());
- await user.click(ui.facetItem(/severity.HIGH/).get());
+ await user.click(ui.facetItem(/severity_impact.HIGH/).get());
expect(ui.getAllRuleListItems()).toHaveLength(8);
});
await user.click(ui.cleanCodeQualityCheckbox(SoftwareQuality.Reliability).get());
await user.click(ui.cleanCodeSeveritySelect(SoftwareQuality.Reliability).get());
- await user.click(byRole('option', { name: 'severity.MEDIUM severity.MEDIUM' }).get());
+ await user.click(
+ byRole('option', { name: 'severity_impact.MEDIUM severity_impact.MEDIUM' }).get(),
+ );
- expect(ui.createCustomRuleDialog.byText('severity.MEDIUM').get()).toBeInTheDocument();
+ expect(ui.createCustomRuleDialog.byText('severity_impact.MEDIUM').get()).toBeInTheDocument();
await user.click(ui.statusSelect.get());
await user.click(byRole('option', { name: 'rules.status.BETA' }).get());
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import Facet, { BasicProps } from '../../../components/facets/Facet';
import { CLEAN_CODE_CATEGORIES } from '../../../helpers/constants';
import { translate } from '../../../helpers/l10n';
-import Facet, { BasicProps } from './Facet';
export default function AttributeCategoryFacet(props: BasicProps) {
const renderName = React.useCallback(
() =>
IMPACT_SEVERITIES.map((severity) => ({
value: severity,
- label: intl.formatMessage({ id: `severity.${severity}` }),
+ label: intl.formatMessage({ id: `severity_impact.${severity}` }),
Icon: <SoftwareImpactSeverityIcon severity={severity} />,
})),
[intl],
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2024 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.
- */
-import classNames from 'classnames';
-import { FacetBox, FacetItem } from 'design-system';
-import { orderBy, sortBy, without } from 'lodash';
-import * as React from 'react';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { MetricType } from '~sonar-aligned/types/metrics';
-import Tooltip from '../../../components/controls/Tooltip';
-import { translate } from '../../../helpers/l10n';
-import { Dict } from '../../../types/types';
-import { FacetItemsList } from '../../issues/sidebar/FacetItemsList';
-import { MultipleSelectionHint } from '../../issues/sidebar/MultipleSelectionHint';
-import { FacetKey } from '../query';
-
-export interface BasicProps {
- help?: React.ReactNode;
- onChange: (changes: Dict<string | string[] | undefined>) => void;
- onToggle: (facet: FacetKey) => void;
- open: boolean;
- stats?: Dict<number>;
- values: string[];
-}
-
-interface Props extends BasicProps {
- disabled?: boolean;
- disabledHelper?: string;
- options?: string[];
- property: FacetKey;
- renderFooter?: () => React.ReactNode;
- renderName?: (value: string, disabled: boolean) => React.ReactNode;
- renderTextName?: (value: string) => string;
- singleSelection?: boolean;
-}
-
-export default class Facet extends React.PureComponent<Props> {
- handleItemClick = (itemValue: string, multiple: boolean) => {
- const { values } = this.props;
- let newValue;
- if (this.props.singleSelection) {
- const value = values.length ? values[0] : undefined;
- newValue = itemValue === value ? undefined : itemValue;
- } else if (multiple) {
- newValue = orderBy(
- values.includes(itemValue) ? without(values, itemValue) : [...values, itemValue],
- );
- } else {
- newValue = values.includes(itemValue) && values.length < 2 ? [] : [itemValue];
- }
- this.props.onChange({ [this.props.property]: newValue });
- };
-
- handleHeaderClick = () => this.props.onToggle(this.props.property);
-
- handleClear = () => this.props.onChange({ [this.props.property]: [] });
-
- getStat = (value: string) => this.props.stats && this.props.stats[value];
-
- renderItem = (value: string) => {
- const active = this.props.values.includes(value);
- const stat = this.getStat(value);
- const disabled = stat === 0 || typeof stat === 'undefined';
- const { renderName = defaultRenderName, renderTextName = defaultRenderName } = this.props;
-
- return (
- <FacetItem
- className="it__search-navigator-facet"
- active={active}
- key={value}
- name={renderName(value, disabled)}
- onClick={this.handleItemClick}
- stat={stat && formatMeasure(stat, MetricType.ShortInteger)}
- value={value}
- tooltip={renderTextName(value)}
- />
- );
- };
-
- render() {
- const {
- disabled,
- disabledHelper,
- open,
- property,
- renderTextName = defaultRenderName,
- stats,
- help,
- values,
- } = this.props;
- const items =
- this.props.options ||
- (stats &&
- sortBy(
- Object.keys(stats),
- (key) => -stats[key],
- (key) => renderTextName(key).toLowerCase(),
- ));
- const headerId = `facet_${property}`;
- const nbSelectableItems =
- items?.filter((item) => (stats ? stats[item] : undefined)).length ?? 0;
- const nbSelectedItems = values.length;
-
- return (
- <FacetBox
- className={classNames('it__search-navigator-facet-box', {
- 'it__search-navigator-facet-box-forbidden': disabled,
- })}
- data-property={property}
- clearIconLabel={translate('clear')}
- count={values.length}
- id={headerId}
- name={translate('coding_rules.facet', property)}
- onClear={this.handleClear}
- onClick={disabled ? undefined : this.handleHeaderClick}
- open={open && !disabled}
- disabled={disabled}
- disabledHelper={disabledHelper}
- tooltipComponent={Tooltip}
- help={help}
- >
- {open && items !== undefined && (
- <FacetItemsList labelledby={headerId}>{items.map(this.renderItem)}</FacetItemsList>
- )}
-
- {open && this.props.renderFooter !== undefined && this.props.renderFooter()}
-
- <MultipleSelectionHint
- nbSelectableItems={nbSelectableItems}
- nbSelectedItems={nbSelectedItems}
- />
- </FacetBox>
- );
- }
-}
-
-function defaultRenderName(value: string) {
- return value;
-}
import * as React from 'react';
import { Profile } from '../../../api/quality-profiles';
import { useAvailableFeatures } from '../../../app/components/available-features/withAvailableFeatures';
+import SeverityFacet from '../../../components/facets/SeverityFacet';
import { translate } from '../../../helpers/l10n';
import { Feature } from '../../../types/features';
import { Dict } from '../../../types/types';
import PrioritizedRulesFacet from './PrioritizedRulesFacet';
import ProfileFacet from './ProfileFacet';
import RepositoryFacet from './RepositoryFacet';
-import SeverityFacet from './SeverityFacet';
import SoftwareQualityFacet from './SoftwareQualityFacet';
import StatusFacet from './StatusFacet';
import TagFacet from './TagFacet';
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import Facet, { BasicProps } from '../../../components/facets/Facet';
import { translate } from '../../../helpers/l10n';
import { RuleInheritance } from '../../../types/types';
-import Facet, { BasicProps } from './Facet';
interface Props extends Omit<BasicProps, 'values'> {
disabled: boolean;
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import Facet, { BasicProps } from '../../../components/facets/Facet';
import { translate } from '../../../helpers/l10n';
-import Facet, { BasicProps } from './Facet';
interface Props extends Omit<BasicProps, 'onChange' | 'values'> {
disabled: boolean;
import * as React from 'react';
import { getRuleRepositories } from '../../../api/rules';
import withLanguagesContext from '../../../app/components/languages/withLanguagesContext';
+import { BasicProps } from '../../../components/facets/Facet';
import { translate } from '../../../helpers/l10n';
import { highlightTerm } from '../../../helpers/search';
import { Languages } from '../../../types/languages';
import { Dict } from '../../../types/types';
import { ListStyleFacet } from '../../issues/sidebar/ListStyleFacet';
-import { BasicProps } from './Facet';
interface StateProps {
languages: Languages;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2024 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.
- */
-
-import { HelperHintIcon } from 'design-system';
-import * as React from 'react';
-import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip';
-import SoftwareImpactSeverityIcon from '../../../components/icon-mappers/SoftwareImpactSeverityIcon';
-import { IMPACT_SEVERITIES } from '../../../helpers/constants';
-import { DocLink } from '../../../helpers/doc-links';
-import { translate } from '../../../helpers/l10n';
-import Facet, { BasicProps } from './Facet';
-
-export default function SeverityFacet(props: BasicProps) {
- const renderName = React.useCallback(
- (severity: string, disabled: boolean) => (
- <div className="sw-flex sw-items-center">
- <SoftwareImpactSeverityIcon severity={severity} disabled={disabled} />
- <span className="sw-ml-1">{translate('severity', severity)}</span>
- </div>
- ),
- [],
- );
-
- const renderTextName = React.useCallback(
- (severity: string) => translate('severity', severity),
- [],
- );
-
- return (
- <Facet
- {...props}
- options={IMPACT_SEVERITIES}
- property="impactSeverities"
- renderName={renderName}
- renderTextName={renderTextName}
- help={
- <DocHelpTooltip
- placement="right"
- content={
- <>
- <p>{translate('issues.facet.impactSeverities.help.line1')}</p>
- <p className="sw-mt-2">{translate('issues.facet.impactSeverities.help.line2')}</p>
- </>
- }
- links={[
- {
- href: DocLink.CleanCodeIntroduction,
- label: translate('learn_more'),
- },
- ]}
- >
- <HelperHintIcon />
- </DocHelpTooltip>
- }
- />
- );
-}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import Facet, { BasicProps } from '../../../components/facets/Facet';
import { SOFTWARE_QUALITIES } from '../../../helpers/constants';
import { translate } from '../../../helpers/l10n';
-import Facet, { BasicProps } from './Facet';
export default function SoftwareQualityFacet(props: BasicProps) {
const renderName = React.useCallback(
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import Facet, { BasicProps } from '../../../components/facets/Facet';
import { RULE_STATUSES } from '../../../helpers/constants';
import { translate } from '../../../helpers/l10n';
-import Facet, { BasicProps } from './Facet';
export default class StatusFacet extends React.PureComponent<BasicProps> {
renderName = (status: string) => translate('rules.status', status.toLowerCase());
import { uniq } from 'lodash';
import * as React from 'react';
import { getRuleTags } from '../../../api/rules';
+import { BasicProps } from '../../../components/facets/Facet';
import { translate } from '../../../helpers/l10n';
import { highlightTerm } from '../../../helpers/search';
import { ListStyleFacet } from '../../issues/sidebar/ListStyleFacet';
-import { BasicProps } from './Facet';
export default class TagFacet extends React.PureComponent<BasicProps> {
handleSearch = (query: string) => {
import { HelperHintIcon } from 'design-system';
import * as React from 'react';
import HelpTooltip from '~sonar-aligned/components/controls/HelpTooltip';
+import Facet, { BasicProps } from '../../../components/facets/Facet';
import { translate } from '../../../helpers/l10n';
-import Facet, { BasicProps } from './Facet';
interface Props extends Omit<BasicProps, 'onChange' | 'values'> {
onChange: (changes: { template: boolean | undefined }) => void;
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import Facet, { BasicProps } from '../../../components/facets/Facet';
import IssueTypeIcon from '../../../components/icon-mappers/IssueTypeIcon';
import { RULE_TYPES } from '../../../helpers/constants';
import { translate } from '../../../helpers/l10n';
-import Facet, { BasicProps } from './Facet';
export default class TypeFacet extends React.PureComponent<BasicProps> {
renderName = (type: string) => (
import { getProjectUrl } from '../../../helpers/urls';
import { useCurrentBranchQuery } from '../../../queries/branch';
import { useComponentTreeQuery, useMeasuresComponentQuery } from '../../../queries/measures';
-import { useIsLegacyCCTMode } from '../../../queries/settings';
import { useLocation, useRouter } from '../../../sonar-aligned/components/hoc/withRouter';
import { BranchLike } from '../../../types/branch-like';
import { isApplication, isFile, isView } from '../../../types/component';
const { data: branchLike } = useCurrentBranchQuery(rootComponent);
const router = useRouter();
const query = parseQuery(rawQuery);
- const { data: isLegacy } = useIsLegacyCCTMode();
const { selected, asc, view } = query;
const containerRef = React.useRef<HTMLDivElement>(null);
);
}
- return (
- <TreeMapView
- isLegacyMode={Boolean(isLegacy)}
- components={components}
- handleSelect={onOpenComponent}
- metric={metric}
- />
- );
+ return <TreeMapView components={components} handleSelect={onOpenComponent} metric={metric} />;
};
return (
import HelpTooltip from '~sonar-aligned/components/controls/HelpTooltip';
import { formatMeasure } from '~sonar-aligned/helpers/measures';
import { MetricKey } from '~sonar-aligned/types/metrics';
-import { SOFTWARE_QUALITY_RATING_METRICS } from '../../../helpers/constants';
import {
getLocalizedMetricDomain,
getLocalizedMetricName,
import { getCCTMeasureValue, isDiffMetric } from '../../../helpers/measures';
import { isDefined } from '../../../helpers/types';
import { getComponentDrilldownUrl } from '../../../helpers/urls';
-import { useIsLegacyCCTMode } from '../../../queries/settings';
import { BranchLike } from '../../../types/branch-like';
import { isProject, isView } from '../../../types/component';
import {
bubblesByDomain,
} = props;
const theme = useTheme();
- const { data: isLegacy } = useIsLegacyCCTMode();
const bubbleMetrics = getBubbleMetrics(bubblesByDomain, domain, metrics);
const [ratingFilters, setRatingFilters] = React.useState<{ [rating: number]: boolean }>({});
return undefined;
}
- const bubbleColor =
- `bubble.${isLegacy ? 'legacy.' : ''}${(colorRating ?? 1) as BubbleColorVal}` as const;
+ const bubbleColor = `bubble.${(colorRating ?? 1) as BubbleColorVal}` as const;
return {
x,
</div>
{bubbleMetrics.colors && (
<ColorRatingsLegend
- isLegacy={
- isLegacy ||
- bubbleMetrics.colors.every(
- (m) => !SOFTWARE_QUALITY_RATING_METRICS.includes(m.key as MetricKey),
- )
- }
className="sw-mt-2"
filters={ratingFilters}
onRatingClick={handleRatingFilterClick}
export interface ColorRatingsLegendProps {
className?: string;
filters: { [rating: number]: boolean };
- isLegacy?: boolean;
onRatingClick: (selection: number) => void;
}
export default function ColorRatingsLegend(props: ColorRatingsLegendProps) {
- const { className, filters, isLegacy } = props;
+ const { className, filters } = props;
const theme = useTheme();
- const RATINGS = isLegacy ? [1, 2, 3, 4, 5] : [1, 2, 3, 4];
+ const RATINGS = [1, 2, 3, 4, 5];
const ratingsColors = RATINGS.map((rating: BubbleColorVal) => {
const formattedMeasure = formatMeasure(rating, MetricType.Rating);
label: formattedMeasure,
value: rating,
selected: !filters[rating],
- backgroundColor: themeColor(isLegacy ? `bubble.legacy.${rating}` : `bubble.${rating}`)({
+ backgroundColor: themeColor(`bubble.${rating}`)({
theme,
}),
- borderColor: themeContrast(isLegacy ? `bubble.legacy.${rating}` : `bubble.${rating}`)({
+ borderColor: themeContrast(`bubble.${rating}`)({
theme,
}),
};
interface TreeMapViewProps {
components: ComponentMeasureEnhanced[];
handleSelect: (component: ComponentMeasureIntern) => void;
- isLegacyMode: boolean;
metric: Metric;
}
}
const PERCENT_SCALE_DOMAIN = [0, 25, 50, 75, 100];
-const RATING_SCALE_DOMAIN = [1, 2, 3, 4];
-const LEGACY_RATING_SCALE_DOMAIN = [1, 2, 3, 4, 5];
+const RATING_SCALE_DOMAIN = [1, 2, 3, 4, 5];
const HEIGHT = 500;
const NA_COLORS: [ThemeColors, ThemeColors] = ['treeMap.NA1', 'treeMap.NA2'];
'treeMap.D',
'treeMap.E',
];
-const TREEMAP_LEGACY_COLORS: ThemeColors[] = [
- 'treeMap.legacy.A',
- 'treeMap.legacy.B',
- 'treeMap.legacy.C',
- 'treeMap.legacy.D',
- 'treeMap.legacy.E',
-];
export class TreeMapView extends React.PureComponent<Props, State> {
state: State;
};
getMappedThemeColors = (): string[] => {
- const { theme, isLegacyMode } = this.props;
- return (isLegacyMode ? TREEMAP_LEGACY_COLORS : TREEMAP_COLORS).map((c) =>
- themeColor(c)({ theme }),
- );
+ const { theme } = this.props;
+ return TREEMAP_COLORS.map((c) => themeColor(c)({ theme }));
};
getLevelColorScale = () =>
};
getRatingColorScale = () => {
- const { isLegacyMode } = this.props;
return scaleLinear<string, string>()
- .domain(isLegacyMode ? LEGACY_RATING_SCALE_DOMAIN : RATING_SCALE_DOMAIN)
+ .domain(RATING_SCALE_DOMAIN)
.range(this.getMappedThemeColors());
};
bannedMetrics.push(MetricKey.alert_status);
}
if (qualifier === ComponentQualifier.Application) {
- bannedMetrics.push(
- MetricKey.releasability_rating,
- MetricKey.releasability_effort,
- MetricKey.software_quality_releasability_rating,
- );
+ bannedMetrics.push(MetricKey.releasability_rating, MetricKey.releasability_effort);
}
return measures.filter((measure) => !bannedMetrics.includes(measure.metric));
}
`issue.clean_code_attribute_category.${issue.cleanCodeAttributeCategory}`,
).get();
expect(cctBadge).toBeInTheDocument();
- await expect(cctBadge).toHaveATooltipWithContent(
+ await expect(cctBadge).toHaveAPopoverWithContent(
`issue.clean_code_attribute.${issue.cleanCodeAttribute}`,
);
// Software Qualities
const qualityBadge = byText(`software_quality.${issue.impacts[0].softwareQuality}`).get();
expect(qualityBadge).toBeInTheDocument();
- await expect(qualityBadge).toHaveATooltipWithContent('software_quality');
+ await expect(qualityBadge).toHaveAPopoverWithContent('software_quality');
// Deprecated type
const type = byText(`issue.type.${issue.type}`).get();
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2024 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.
- */
-
-import { HelperHintIcon } from 'design-system';
-import * as React from 'react';
-import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip';
-import SoftwareImpactSeverityIcon from '../../../components/icon-mappers/SoftwareImpactSeverityIcon';
-import { IMPACT_SEVERITIES } from '../../../helpers/constants';
-import { DocLink } from '../../../helpers/doc-links';
-import { translate } from '../../../helpers/l10n';
-import { SoftwareImpactSeverity } from '../../../types/clean-code-taxonomy';
-import { CommonProps, SimpleListStyleFacet } from './SimpleListStyleFacet';
-
-interface Props extends CommonProps {
- severities: SoftwareImpactSeverity[];
-}
-
-export function SeverityFacet(props: Props) {
- const { severities = [], ...rest } = props;
-
- return (
- <SimpleListStyleFacet
- property="impactSeverities"
- itemNamePrefix="severity"
- listItems={IMPACT_SEVERITIES}
- selectedItems={severities}
- renderIcon={(severity: string, disabled: boolean) => (
- <SoftwareImpactSeverityIcon severity={severity} disabled={disabled} />
- )}
- help={
- <DocHelpTooltip
- placement="right"
- content={
- <>
- <p>{translate('issues.facet.impactSeverities.help.line1')}</p>
- <p className="sw-mt-2">{translate('issues.facet.impactSeverities.help.line2')}</p>
- </>
- }
- links={[
- {
- href: DocLink.CleanCodeIntroduction,
- label: translate('learn_more'),
- },
- ]}
- >
- <HelperHintIcon />
- </DocHelpTooltip>
- }
- {...rest}
- />
- );
-}
import { ComponentQualifier } from '~sonar-aligned/types/component';
import { useAppState } from '../../../app/components/app-state/withAppStateContext';
import { useAvailableFeatures } from '../../../app/components/available-features/withAvailableFeatures';
+import SeverityFacet from '../../../components/facets/SeverityFacet';
import { translate } from '../../../helpers/l10n';
import { BranchLike } from '../../../types/branch-like';
import { isApplication, isProject, isView } from '../../../types/component';
import { ProjectFacet } from './ProjectFacet';
import { RuleFacet } from './RuleFacet';
import { ScopeFacet } from './ScopeFacet';
-import { SeverityFacet } from './SeverityFacet';
import { SoftwareQualityFacet } from './SoftwareQualityFacet';
import { StandardFacet } from './StandardFacet';
import { TagFacet } from './TagFacet';
onChange={props.onFilterChange}
onToggle={props.onFacetToggle}
open={!!openFacets.impactSeverities}
- severities={query.impactSeverities}
stats={facets.impactSeverities}
+ values={query.impactSeverities}
/>
<BasicSeparator className="sw-my-4" />
expect(screen.getAllByRole('button').map((button) => button.textContent)).toStrictEqual([
'issues.facet.cleanCodeAttributeCategories',
'issues.facet.impactSoftwareQualities',
- 'issues.facet.impactSeverities',
+ 'coding_rules.facet.impactSeverities',
+ // help icon
+ '',
'issues.facet.types',
'issues.facet.scopes',
'issues.facet.issueStatuses',
expect(screen.getAllByRole('button').map((button) => button.textContent)).toStrictEqual([
'issues.facet.cleanCodeAttributeCategories',
'issues.facet.impactSoftwareQualities',
- 'issues.facet.impactSeverities',
+ 'coding_rules.facet.impactSeverities',
+ // help icon
+ '',
'issues.facet.types',
'issues.facet.scopes',
'issues.facet.issueStatuses',
expect(screen.getAllByRole('button').map((button) => button.textContent)).toStrictEqual([
'issues.facet.cleanCodeAttributeCategories',
'issues.facet.impactSoftwareQualities',
- 'issues.facet.impactSeverities',
+ 'coding_rules.facet.impactSeverities',
+ // help icon
+ '',
'issues.facet.types',
'issues.facet.scopes',
'issues.facet.issueStatuses',
expect(screen.getAllByRole('button').map((button) => button.textContent)).toStrictEqual([
'issues.facet.cleanCodeAttributeCategories',
'issues.facet.impactSoftwareQualities',
- 'issues.facet.impactSeverities',
+ 'coding_rules.facet.impactSeverities',
+ // help icon
+ '',
'issues.facet.types',
'issues.facet.scopes',
'issues.facet.issueStatuses',
softwareQualityFacet: byRole('button', {
name: 'issues.facet.impactSoftwareQualities',
}),
- severityFacet: byRole('button', { name: 'issues.facet.impactSeverities' }),
+ severityFacet: byRole('button', { name: 'coding_rules.facet.impactSeverities' }),
prioritizedRuleFacet: byRole('button', { name: 'issues.facet.prioritized_rule.category' }),
clearCodeCategoryFacet: byTestId('clear-issues.facet.cleanCodeAttributeCategories'),
clearResolutionFacet: byTestId('clear-issues.facet.resolutions'),
clearRuleFacet: byTestId('clear-issues.facet.rules'),
clearScopeFacet: byTestId('clear-issues.facet.scopes'),
- clearSeverityFacet: byTestId('clear-issues.facet.impactSeverities'),
+ clearSeverityFacet: byTestId('clear-coding_rules.facet.impactSeverities'),
clearIssueStatusFacet: byTestId('clear-issues.facet.issueStatuses'),
clearTagFacet: byTestId('clear-issues.facet.tags'),
clearPrioritizedRuleFacet: byTestId('clear-issues.facet.prioritized_rule.category'),
confirmedStatusFilter: byRole('checkbox', { name: 'issue.issue_status.CONFIRMED' }),
fixedResolutionFilter: byRole('checkbox', { name: 'issue.resolution.FIXED' }),
mainScopeFilter: byRole('checkbox', { name: 'issue.scope.MAIN' }),
- mediumSeverityFilter: byRole('checkbox', { name: `severity.${SoftwareImpactSeverity.Medium}` }),
+ mediumSeverityFilter: byRole('checkbox', {
+ name: `severity_impact.${SoftwareImpactSeverity.Medium}`,
+ }),
openStatusFilter: byRole('checkbox', { name: 'issue.issue_status.OPEN' }),
vulnerabilityIssueTypeFilter: byRole('checkbox', { name: 'issue.type.VULNERABILITY' }),
prioritizedRuleFilter: byRole('checkbox', { name: 'issues.facet.prioritized_rule' }),
<RatingComponent
branchLike={branch}
componentKey={component.key}
+ getTooltip={(rating) =>
+ intl.formatMessage({ id: `metric.security_review_rating.tooltip.${rating}` })
+ }
+ getLabel={(rating) =>
+ intl.formatMessage({ id: 'metric.has_rating_X' }, { 0: rating })
+ }
ratingMetric={MetricKey.security_review_rating}
size="md"
/>
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2024 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.
- */
-import styled from '@emotion/styled';
-import { Tooltip } from '@sonarsource/echoes-react';
-import classNames from 'classnames';
-import { DiscreetLinkBox, themeColor, themeContrast } from 'design-system';
-import * as React from 'react';
-import { useIntl } from 'react-intl';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { getComponentIssuesUrl } from '~sonar-aligned/helpers/urls';
-import { MetricType } from '~sonar-aligned/types/metrics';
-import { DEFAULT_ISSUES_QUERY } from '../../../components/shared/utils';
-import { Branch } from '../../../types/branch-like';
-import { SoftwareImpactSeverity, SoftwareQuality } from '../../../types/clean-code-taxonomy';
-import { Component } from '../../../types/types';
-
-export interface SoftwareImpactMeasureBreakdownCardProps {
- active?: boolean;
- branch?: Branch;
- component: Component;
- severity: SoftwareImpactSeverity;
- softwareQuality: SoftwareQuality;
- value?: string;
-}
-
-export function SoftwareImpactMeasureBreakdownCard(
- props: Readonly<SoftwareImpactMeasureBreakdownCardProps>,
-) {
- const { softwareQuality, component, value, severity, active, branch } = props;
-
- const intl = useIntl();
-
- const url = getComponentIssuesUrl(component.key, {
- ...DEFAULT_ISSUES_QUERY,
- impactSoftwareQualities: softwareQuality,
- impactSeverities: severity,
- branch: branch?.name,
- });
-
- const testId = `overview__software-impact-${softwareQuality}-severity-${severity}`;
- const cardClasses =
- 'sw-w-1/3 sw-px-2 sw-py-1 sw-rounded-1 sw-text-xs sw-font-semibold sw-select-none sw-flex sw-gap-1 sw-justify-center sw-items-center';
-
- if (!value) {
- return (
- <StyledBreakdownCard
- data-testid={testId}
- className={classNames(cardClasses, severity, {
- active,
- })}
- >
- -
- </StyledBreakdownCard>
- );
- }
-
- return (
- <Tooltip
- content={intl.formatMessage({
- id: `overview.measures.software_impact.severity.${severity}.tooltip`,
- })}
- >
- <StyledBreakdownLinkCard
- data-testid={testId}
- className={classNames(cardClasses, severity, {
- active,
- })}
- aria-label={intl.formatMessage(
- {
- id: 'overview.measures.software_impact.severity.see_x_open_issues',
- },
- {
- count: formatMeasure(value, MetricType.ShortInteger),
- softwareQuality: intl.formatMessage({
- id: `software_quality.${softwareQuality}`,
- }),
- severity: intl.formatMessage({
- id: `overview.measures.software_impact.severity.${severity}.tooltip`,
- }),
- },
- )}
- disabled={component.needIssueSync}
- to={url}
- >
- <span>{formatMeasure(value, MetricType.ShortInteger)}</span>
- <span>
- {intl.formatMessage({
- id: `overview.measures.software_impact.severity.${severity}`,
- })}
- </span>
- </StyledBreakdownLinkCard>
- </Tooltip>
- );
-}
-
-const StyledBreakdownCard = styled.div`
- background-color: ${themeColor('overviewSoftwareImpactSeverityNeutral')};
-
- &.active.HIGH {
- background-color: ${themeColor('overviewSoftwareImpactSeverityHigh')};
- color: ${themeContrast('overviewSoftwareImpactSeverityHigh')};
- }
- &.active.MEDIUM {
- background-color: ${themeColor('overviewSoftwareImpactSeverityMedium')};
- color: ${themeContrast('overviewSoftwareImpactSeverityMedium')};
- }
- &.active.LOW {
- background-color: ${themeColor('overviewSoftwareImpactSeverityLow')};
- color: ${themeContrast('overviewSoftwareImpactSeverityLow')};
- }
-`;
-const StyledBreakdownLinkCard = StyledBreakdownCard.withComponent(DiscreetLinkBox);
-
-export default SoftwareImpactMeasureBreakdownCard;
import { isDefined } from '../../../helpers/types';
import { useIsLegacyCCTMode } from '../../../queries/settings';
import { Branch } from '../../../types/branch-like';
-import {
- SoftwareImpactMeasureData,
- SoftwareImpactSeverity,
- SoftwareQuality,
-} from '../../../types/clean-code-taxonomy';
+import { SoftwareImpactMeasureData, SoftwareQuality } from '../../../types/clean-code-taxonomy';
import { QualityGateStatusConditionEnhanced } from '../../../types/quality-gates';
import { Component, MeasureEnhanced } from '../../../types/types';
import { Status, softwareQualityToMeasure } from '../utils';
-import SoftwareImpactMeasureBreakdownCard from './SoftwareImpactMeasureBreakdownCard';
import SoftwareImpactMeasureRating from './SoftwareImpactMeasureRating';
export interface SoftwareImpactBreakdownCardProps {
branch: branch?.name,
});
- // We highlight the highest severity breakdown card with non-zero count
- const highlightedSeverity =
- measure &&
- [SoftwareImpactSeverity.High, SoftwareImpactSeverity.Medium, SoftwareImpactSeverity.Low].find(
- (severity) => measure[severity] > 0,
- );
-
const countTooltipOverlay = intl.formatMessage({
id: 'overview.measures.software_impact.count_tooltip',
});
/>
</div>
</div>
- {measure && (
- <div className="sw-flex sw-gap-2">
- {[
- SoftwareImpactSeverity.High,
- SoftwareImpactSeverity.Medium,
- SoftwareImpactSeverity.Low,
- ].map((severity) => (
- <SoftwareImpactMeasureBreakdownCard
- branch={branch}
- key={severity}
- component={component}
- softwareQuality={softwareQuality}
- value={measure?.[severity]?.toString()}
- severity={severity}
- active={highlightedSeverity === severity}
- />
- ))}
- </div>
- )}
</div>
</div>
);
import { mockLoggedInUser, mockMeasure, mockPaging } from '../../../../helpers/testMocks';
import { renderComponent } from '../../../../helpers/testReactTestingUtils';
import { ComponentPropsType } from '../../../../helpers/testUtils';
-import { SoftwareImpactSeverity, SoftwareQuality } from '../../../../types/clean-code-taxonomy';
+import { SoftwareQuality } from '../../../../types/clean-code-taxonomy';
import { ProjectAnalysisEventCategory } from '../../../../types/project-activity';
import { SettingsKey } from '../../../../types/settings';
import { CaycStatus } from '../../../../types/types';
await user.click(await ui.overallCodeButton.find());
- ui.expectSoftwareImpactMeasureCard(
- SoftwareQuality.Security,
- 'B',
- {
- total: 1,
- [SoftwareImpactSeverity.High]: 0,
- [SoftwareImpactSeverity.Medium]: 1,
- [SoftwareImpactSeverity.Low]: 0,
- },
- [false, true, false],
- );
+ ui.expectSoftwareImpactMeasureCard(SoftwareQuality.Security, 'B', 1);
await ui.expectSoftwareImpactMeasureCardRatingTooltip(
SoftwareQuality.Security,
'B',
'overview.measures.software_impact.improve_rating_tooltip.software_quality.SECURITY.software_quality.security.B.overview.measures.software_impact.severity.LOW.improve_tooltip',
);
- ui.expectSoftwareImpactMeasureCard(
- SoftwareQuality.Reliability,
- 'A',
- {
- total: 3,
- [SoftwareImpactSeverity.High]: 0,
- [SoftwareImpactSeverity.Medium]: 2,
- [SoftwareImpactSeverity.Low]: 1,
- },
- [false, true, false],
- undefined,
- true,
- );
+ ui.expectSoftwareImpactMeasureCard(SoftwareQuality.Reliability, 'A', 3, undefined, true);
await ui.expectSoftwareImpactMeasureCardRatingTooltip(
SoftwareQuality.Reliability,
'A',
'overview.measures.software_impact.improve_rating_tooltip.A.software_quality.RELIABILITY.software_quality.reliability.A.overview.measures.software_impact.severity.LOW.improve_tooltip',
);
- ui.expectSoftwareImpactMeasureCard(
- SoftwareQuality.Maintainability,
- 'D',
- {
- total: 2,
- [SoftwareImpactSeverity.High]: 0,
- [SoftwareImpactSeverity.Medium]: 0,
- [SoftwareImpactSeverity.Low]: 1,
- },
- [false, false, true],
- );
+ ui.expectSoftwareImpactMeasureCard(SoftwareQuality.Maintainability, 'D', 2);
await ui.expectSoftwareImpactMeasureCardRatingTooltip(
SoftwareQuality.Maintainability,
'D',
await user.click(await ui.overallCodeButton.find());
- ui.expectSoftwareImpactMeasureCard(
- SoftwareQuality.Maintainability,
- 'D',
- {
- total: 2,
- [SoftwareImpactSeverity.High]: 0,
- [SoftwareImpactSeverity.Medium]: 0,
- [SoftwareImpactSeverity.Low]: 1,
- },
- [false, false, true],
- '',
- );
+ ui.expectSoftwareImpactMeasureCard(SoftwareQuality.Maintainability, 'D', 2, '');
});
it('should render old measures if software impact are missing', async () => {
*/
import userEvent from '@testing-library/user-event';
import { byLabelText, byRole, byTestId, byText } from '~sonar-aligned/helpers/testSelector';
-import {
- SoftwareImpactMeasureData,
- SoftwareImpactSeverity,
- SoftwareQuality,
-} from '../../../types/clean-code-taxonomy';
+import { SoftwareImpactSeverity, SoftwareQuality } from '../../../types/clean-code-taxonomy';
export const getPageObjects = () => {
const user = userEvent.setup();
expectSoftwareImpactMeasureCard: (
softwareQuality: SoftwareQuality,
rating?: string,
- data?: SoftwareImpactMeasureData,
- severitiesActiveState?: boolean[],
+ total?: number,
branch = 'master',
failed = false,
) => {
byText(rating, { exact: true }).get(ui.softwareImpactMeasureCard(softwareQuality).get()),
).toBeInTheDocument();
}
- if (data) {
+ if (total !== undefined) {
const branchQuery = branch ? `&branch=${branch}` : '';
expect(
byRole('link', {
- name: `overview.measures.software_impact.see_list_of_x_open_issues.${data.total}.software_quality.${softwareQuality}`,
+ name: `overview.measures.software_impact.see_list_of_x_open_issues.${total}.software_quality.${softwareQuality}`,
}).get(),
).toHaveAttribute(
'href',
`/project/issues?issueStatuses=OPEN%2CCONFIRMED&impactSoftwareQualities=${softwareQuality}${branchQuery}&id=foo`,
);
- expect(
- byRole('link', {
- name: `overview.measures.software_impact.severity.see_x_open_issues.${
- data[SoftwareImpactSeverity.High]
- }.software_quality.${softwareQuality}.overview.measures.software_impact.severity.HIGH.tooltip`,
- }).get(),
- ).toHaveAttribute(
- 'href',
- `/project/issues?issueStatuses=OPEN%2CCONFIRMED&impactSoftwareQualities=${softwareQuality}&impactSeverities=${SoftwareImpactSeverity.High}${branchQuery}&id=foo`,
- );
- expect(
- byRole('link', {
- name: `overview.measures.software_impact.severity.see_x_open_issues.${
- data[SoftwareImpactSeverity.Medium]
- }.software_quality.${softwareQuality}.overview.measures.software_impact.severity.MEDIUM.tooltip`,
- }).get(),
- ).toBeInTheDocument();
- expect(
- byRole('link', {
- name: `overview.measures.software_impact.severity.see_x_open_issues.${
- data[SoftwareImpactSeverity.Low]
- }.software_quality.${softwareQuality}.overview.measures.software_impact.severity.LOW.tooltip`,
- }).get(),
- ).toBeInTheDocument();
- }
- if (severitiesActiveState) {
- ui.expectSoftwareImpactMeasureBreakdownCard(
- softwareQuality,
- SoftwareImpactSeverity.High,
- severitiesActiveState[0],
- );
- ui.expectSoftwareImpactMeasureBreakdownCard(
- softwareQuality,
- SoftwareImpactSeverity.Medium,
- severitiesActiveState[1],
- );
- ui.expectSoftwareImpactMeasureBreakdownCard(
- softwareQuality,
- SoftwareImpactSeverity.Low,
- severitiesActiveState[2],
- );
}
},
expectSoftwareImpactMeasureCardToHaveOldMeasures: (
MetricKey.security_hotspots_reviewed,
MetricKey.new_security_hotspots_reviewed,
MetricKey.security_review_rating,
- MetricKey.software_quality_security_review_rating,
MetricKey.new_security_review_rating,
- MetricKey.new_software_quality_security_review_rating,
// code smells
MetricKey.code_smells,
};
render() {
- const { analyses, leakPeriodDate, loading, measuresHistory, metrics, query, isLegacy } =
- this.props;
+ const { analyses, leakPeriodDate, loading, measuresHistory, metrics, query } = this.props;
const { graphEndDate, graphStartDate, series } = this.state;
return (
graphs={this.state.graphs}
leakPeriodDate={leakPeriodDate}
loading={loading}
- isLegacy={isLegacy}
measuresHistory={measuresHistory}
removeCustomMetric={this.handleRemoveCustomMetric}
selectedDate={query.selectedDate}
expect(await ui.graphs.findAll()).toHaveLength(1);
expect(ui.metricChangedInfoBtn.get()).toBeInTheDocument();
expect(ui.gapInfoMessage.get()).toBeInTheDocument();
- expect(byText('E').query()).not.toBeInTheDocument();
});
it('should not show old rating if new one was always there', async () => {
expect(await ui.graphs.findAll()).toHaveLength(1);
expect(ui.metricChangedInfoBtn.query()).not.toBeInTheDocument();
expect(ui.gapInfoMessage.query()).not.toBeInTheDocument();
- expect(byText('E').query()).not.toBeInTheDocument();
});
- it('should show E if no new metrics', async () => {
+ it('should not show change info button if no new metrics', async () => {
timeMachineHandler.setMeasureHistory([
mockMeasureHistory({
metric: MetricKey.reliability_rating,
expect(await ui.graphs.findAll()).toHaveLength(1);
expect(ui.metricChangedInfoBtn.query()).not.toBeInTheDocument();
expect(ui.gapInfoMessage.query()).not.toBeInTheDocument();
- expect(byText('E').get()).toBeInTheDocument();
});
- it('should not show gaps message and metric change button, but should show E in legacy mode', async () => {
+ it('should not show gaps message and metric change button in legacy mode', async () => {
settingsHandler.set(SettingsKey.LegacyMode, 'true');
timeMachineHandler.setMeasureHistory([
mockMeasureHistory({
expect(await ui.graphs.findAll()).toHaveLength(1);
expect(ui.metricChangedInfoBtn.query()).not.toBeInTheDocument();
expect(ui.gapInfoMessage.query()).not.toBeInTheDocument();
- expect(byText('E').get()).toBeInTheDocument();
});
});
settingsHandler.set(SettingsKey.LegacyMode, 'true');
renderPageSidebar();
- expect(await screen.findAllByText('E')).toHaveLength(4);
- expect(screen.queryByText(/projects.facets.rating_option/)).not.toBeInTheDocument();
- expect(screen.queryByText('projects.facets.maintainability.description')).not.toBeInTheDocument();
- expect(screen.queryByText('projects.facets.security_review.description')).not.toBeInTheDocument();
+ expect(await screen.findAllByText(/projects.facets.rating_option/)).toHaveLength(20);
+ expect(screen.getByText('projects.facets.rating_option.security.legacy.1')).toBeInTheDocument();
+ expect(
+ screen.getByText('projects.facets.rating_option.reliability.legacy.1'),
+ ).toBeInTheDocument();
});
it('should show non legacy filters', async () => {
settingsHandler.set(SettingsKey.LegacyMode, 'false');
renderPageSidebar();
- expect(await screen.findAllByText(/projects.facets.rating_option/)).toHaveLength(16);
- expect(screen.queryAllByText('E')).toHaveLength(0);
- expect(screen.getByText('projects.facets.maintainability.description')).toBeInTheDocument();
- expect(screen.getByText('projects.facets.security_review.description')).toBeInTheDocument();
+ expect(await screen.findAllByText(/projects.facets.rating_option/)).toHaveLength(20);
+ expect(screen.getByText('projects.facets.rating_option.security.1')).toBeInTheDocument();
+ expect(screen.getByText('projects.facets.rating_option.reliability.1')).toBeInTheDocument();
});
function renderPageSidebar(overrides: Partial<PageSidebarProps> = {}, currentUser?: CurrentUser) {
[MetricKey.reliability_rating]: '1.0',
[MetricKey.security_rating]: '1.0',
[MetricKey.sqale_rating]: '1.0',
- [MetricKey.security_review_rating]: '1.0',
+ [MetricKey.security_review_rating]: '3.0',
[MetricKey.new_bugs]: '12',
};
}),
[MetricKey.security_review_rating]: mockMeasure({
metric: MetricKey.security_review_rating,
- value: '1',
+ value: '3',
}),
};
metric: MetricKey.software_quality_security_rating,
value: '2',
}),
- [MetricKey.software_quality_security_review_rating]: mockMeasure({
- metric: MetricKey.software_quality_security_review_rating,
- value: '2',
+ [MetricKey.security_review_rating]: mockMeasure({
+ metric: MetricKey.security_review_rating,
+ value: '3',
}),
};
beforeEach(() => {
[MetricKey.software_quality_maintainability_rating]: '2',
[MetricKey.software_quality_reliability_rating]: '2',
[MetricKey.software_quality_security_rating]: '2',
- [MetricKey.software_quality_security_review_rating]: '2',
[MetricKey.code_smells]: '4',
[MetricKey.bugs]: '5',
[MetricKey.vulnerabilities]: '6',
expect(screen.getByText('1')).toBeInTheDocument();
expect(screen.getByText('2')).toBeInTheDocument();
expect(screen.getByText('3')).toBeInTheDocument();
- await waitFor(() => expect(screen.getAllByText('B')).toHaveLength(4));
+ await waitFor(() => expect(screen.getAllByText('B')).toHaveLength(3));
+ await waitFor(() => expect(screen.getAllByText('C')).toHaveLength(1));
expect(screen.queryByText('projects.awaiting_scan')).not.toBeInTheDocument();
expect(screen.queryByText('4')).not.toBeInTheDocument();
expect(screen.queryByText('5')).not.toBeInTheDocument();
expect(screen.getByText('4')).toBeInTheDocument();
expect(screen.getByText('5')).toBeInTheDocument();
expect(screen.getByText('6')).toBeInTheDocument();
- expect(screen.getAllByText('A')).toHaveLength(4);
+ expect(screen.getAllByText('A')).toHaveLength(3);
+ expect(screen.getAllByText('C')).toHaveLength(1);
});
it('should display awaiting analysis badge, show new software qualities, but old ratings', async () => {
expect(screen.queryByText('4')).not.toBeInTheDocument();
expect(screen.queryByText('5')).not.toBeInTheDocument();
expect(screen.queryByText('6')).not.toBeInTheDocument();
- await waitFor(() => expect(screen.getAllByText('A')).toHaveLength(4));
+ await waitFor(() => expect(screen.getAllByText('A')).toHaveLength(3));
+ expect(screen.getAllByText('C')).toHaveLength(1);
});
it('should display awaiting analysis badge and show the old measures for Application', async () => {
expect(screen.getByText('4')).toBeInTheDocument();
expect(screen.getByText('5')).toBeInTheDocument();
expect(screen.getByText('6')).toBeInTheDocument();
- await waitFor(() => expect(screen.getAllByText('A')).toHaveLength(4));
+ await waitFor(() => expect(screen.getAllByText('A')).toHaveLength(3));
+ expect(screen.getAllByText('C')).toHaveLength(1);
expect(screen.queryByText('projects.awaiting_scan')).not.toBeInTheDocument();
});
[MetricKey.software_quality_maintainability_rating]: '2',
[MetricKey.software_quality_reliability_rating]: '2',
[MetricKey.software_quality_security_rating]: '2',
- [MetricKey.software_quality_security_review_rating]: '2',
[MetricKey.code_smells]: '4',
[MetricKey.bugs]: '5',
[MetricKey.vulnerabilities]: '6',
expect(screen.queryByText('1')).not.toBeInTheDocument();
expect(screen.queryByText('2')).not.toBeInTheDocument();
expect(screen.queryByText('3')).not.toBeInTheDocument();
- await waitFor(() => expect(screen.getAllByText('A')).toHaveLength(4));
+ await waitFor(() => expect(screen.getAllByText('A')).toHaveLength(3));
+ expect(screen.getAllByText('C')).toHaveLength(1);
expect(screen.queryByText('B')).not.toBeInTheDocument();
expect(screen.queryByText('projects.awaiting_scan')).not.toBeInTheDocument();
});
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { Spinner } from '@sonarsource/echoes-react';
import { MetricsRatingBadge, RatingEnum } from 'design-system';
import * as React from 'react';
import { useIntl } from 'react-intl';
value?: any;
}
-export default function RatingFacet(props: Props) {
+export default function RatingFacet(props: Readonly<Props>) {
const { facet, maxFacetValue, name, property, value } = props;
- const { data: isLegacy } = useIsLegacyCCTMode();
const renderAccessibleLabel = React.useCallback(
(option: number) => {
facet={facet}
header={translate('metric_domain', name)}
description={
- !isLegacy && hasDescription(property)
+ hasDescription(property)
? translate(`projects.facets.${property.replace('new_', '')}.description`)
: undefined
}
highlightUnder={1}
maxFacetValue={maxFacetValue}
onQueryChange={props.onQueryChange}
- options={isLegacy ? [1, 2, 3, 4, 5] : [1, 2, 3, 4]}
+ options={[1, 2, 3, 4, 5]}
property={property}
renderAccessibleLabel={renderAccessibleLabel}
renderOption={(option) => renderOption(option, property)}
option,
property,
}: Readonly<{ option: string | number; property: string }>) {
- const { data: isLegacy } = useIsLegacyCCTMode();
+ const { data: isLegacy, isLoading } = useIsLegacyCCTMode();
const intl = useIntl();
const ratingFormatted = formatMeasure(option, MetricType.Rating);
+ const propertyWithoutPrefix = property.replace('new_', '');
+ const isSecurityOrReliability = ['security', 'reliability'].includes(propertyWithoutPrefix);
return (
- <>
+ <Spinner isLoading={isLoading}>
<MetricsRatingBadge
label={ratingFormatted}
rating={ratingFormatted as RatingEnum}
- isLegacy={isLegacy}
size="xs"
/>
- {!isLegacy && (
- <span className="sw-ml-2">
- {intl.formatMessage({
- id: `projects.facets.rating_option.${property.replace('new_', '')}.${option}`,
- })}
- </span>
- )}
- </>
+ <span className="sw-ml-2">
+ {intl.formatMessage({
+ id: `projects.facets.rating_option.${propertyWithoutPrefix}${isLegacy && isSecurityOrReliability ? '.legacy' : ''}.${option}`,
+ })}
+ </span>
+ </Spinner>
);
}
MetricKey.software_quality_maintainability_rating,
MetricKey.security_hotspots_reviewed,
MetricKey.security_review_rating,
- MetricKey.software_quality_security_review_rating,
MetricKey.duplicated_lines_density,
MetricKey.coverage,
MetricKey.ncloc,
export const FACETS = [
MetricKey.software_quality_reliability_rating,
MetricKey.software_quality_security_rating,
- MetricKey.software_quality_security_review_rating,
MetricKey.software_quality_maintainability_rating,
+ MetricKey.security_review_rating,
MetricKey.coverage,
MetricKey.duplicated_lines_density,
MetricKey.ncloc,
export const LEAK_FACETS = [
MetricKey.new_software_quality_reliability_rating,
MetricKey.new_software_quality_security_rating,
- MetricKey.new_software_quality_security_review_rating,
MetricKey.new_software_quality_maintainability_rating,
+ MetricKey.new_security_review_rating,
MetricKey.new_coverage,
MetricKey.new_duplicated_lines_density,
MetricKey.new_lines,
new_reliability: 'new_software_quality_reliability_rating',
security: 'software_quality_security_rating',
new_security: 'new_software_quality_security_rating',
- security_review: 'software_quality_security_review_rating',
- new_security_review: 'new_software_quality_security_review_rating',
maintainability: 'software_quality_maintainability_rating',
new_maintainability: 'new_software_quality_maintainability_rating',
};
MetricKey.new_software_quality_reliability_rating,
MetricKey.software_quality_security_rating,
MetricKey.new_software_quality_security_rating,
- MetricKey.software_quality_security_review_rating,
- MetricKey.new_software_quality_security_review_rating,
MetricKey.effort_to_reach_software_quality_maintainability_rating_a,
MetricKey.software_quality_maintainability_remediation_effort,
MetricKey.new_software_quality_maintainability_remediation_effort,
graphEndDate?: Date;
graphStartDate?: Date;
isCustom?: boolean;
- isLegacy?: boolean;
leakPeriodDate?: Date;
measuresHistory: MeasureHistory[];
metricsType: string;
series,
showAreas,
graphDescription,
- isLegacy,
} = props;
const [tooltipIdx, setTooltipIdx] = React.useState<number | undefined>(undefined);
const [tooltipXPos, setTooltipXPos] = React.useState<number | undefined>(undefined);
splitPointDate={measuresHistory.find((m) => m.splitPointDate)?.splitPointDate}
metricType={metricsType}
selectedDate={selectedDate}
- isLegacy={isLegacy}
series={series}
showAreas={showAreas}
startDate={graphStartDate}
graphEndDate?: Date;
graphStartDate?: Date;
graphs: Serie[][];
- isLegacy?: boolean;
leakPeriodDate?: Date;
loading: boolean;
measuresHistory: MeasureHistory[];
};
render() {
- const { analyses, graph, loading, series, ariaLabel, canShowDataAsTable, isLegacy } =
- this.props;
+ const { analyses, graph, loading, series, ariaLabel, canShowDataAsTable } = this.props;
const isCustom = isCustomGraph(graph);
if (loading) {
graphStartDate={this.props.graphStartDate}
isCustom={isCustom}
key={idx}
- isLegacy={isLegacy}
leakPeriodDate={this.props.leakPeriodDate}
measuresHistory={this.props.measuresHistory}
metricsType={getSeriesMetricType(graphSeries)}
height: number;
hideGrid?: boolean;
hideXAxis?: boolean;
- isLegacy?: boolean;
leakPeriodDate?: Date;
// used to avoid same y ticks labels
maxYTicksCount?: number;
}
getRatingScale = (availableHeight: number) => {
- const { isLegacy } = this.props;
- return scalePoint<number>()
- .domain(isLegacy ? [5, 4, 3, 2, 1] : [4, 3, 2, 1])
- .range([availableHeight, 0]);
+ return scalePoint<number>().domain([5, 4, 3, 2, 1]).range([availableHeight, 0]);
};
getLevelScale = (availableHeight: number) => {
checkSnapShot({ zoomSpeed: 2 }, 'zoomSpeed');
checkSnapShot({ leakPeriodDate: new Date('2019-10-02T00:00:00.000Z') }, 'leakPeriodDate');
checkSnapShot({ basisCurve: true }, 'basisCurve');
- checkSnapShot({ isLegacy: false }, 'not legacy');
checkSnapShot(
- { isLegacy: false, splitPointDate: new Date('2019-10-02T00:00:00.000Z') },
- 'not legacy + split point, but not Rating',
- );
- checkSnapShot(
- {
- isLegacy: false,
- splitPointDate: new Date('2019-10-02T00:00:00.000Z'),
- metricType: MetricType.Rating,
- },
- 'not legacy + split point',
+ { splitPointDate: new Date('2019-10-02T00:00:00.000Z') },
+ 'split point, but not Rating',
);
});
]}
width={100}
zoomSpeed={1}
- isLegacy
{...props}
/>
</TooltipProvider>,
exports[`should render correctly: no width 1`] = `null`;
-exports[`should render correctly: not legacy + split point 1`] = `
-<svg
- class="line-chart"
- height="100"
- width="100"
->
- <g
- transform="translate(50, 26)"
- >
- <g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="24"
- y2="24"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="16"
- y2="16"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="8"
- y2="8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="0"
- y2="0"
- />
- </g>
- </g>
- <g
- transform="translate(0, 20)"
- >
- <text
- class="line-chart-tick sw-body-sm"
- text-anchor="end"
- transform="rotate(-35, 15, 24)"
- x="15"
- y="24"
- >
- October
- </text>
- <text
- class="line-chart-tick sw-body-sm"
- text-anchor="end"
- transform="rotate(-35, 20, 24)"
- x="20"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-body-sm"
- text-anchor="end"
- transform="rotate(-35, 25, 24)"
- x="25"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-body-sm"
- text-anchor="end"
- transform="rotate(-35, 30, 24)"
- x="30"
- y="24"
- >
- 06 PM
- </text>
- <text
- class="line-chart-tick sw-body-sm"
- text-anchor="end"
- transform="rotate(-35, 35, 24)"
- x="35"
- y="24"
- >
- Wed 02
- </text>
- <text
- class="line-chart-tick sw-body-sm"
- text-anchor="end"
- transform="rotate(-35, 40, 24)"
- x="40"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-body-sm"
- text-anchor="end"
- transform="rotate(-35, 45, 24)"
- x="45"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-body-sm"
- text-anchor="end"
- transform="rotate(-35, 50, 24)"
- x="50"
- y="24"
- >
- 06 PM
- </text>
- </g>
- <g>
- <path
- class="line-chart-path line-chart-path-0"
- d="M0,0L20,8"
- stroke="rgb(85,170,223)"
- stroke-dasharray="0"
- />
- <path
- class="line-chart-path line-chart-path-1"
- d="M40,16Z"
- stroke="rgb(58,127,173)"
- stroke-dasharray="3"
- />
- </g>
- <g>
- <circle
- cx="40"
- cy="16"
- fill="rgb(58,127,173)"
- r="2"
- stroke="white"
- stroke-width="1"
- />
- </g>
- <rect
- class="chart-mouse-events-overlay"
- height="24"
- width="40"
- />
- <line
- class="line-tooltip"
- stroke-dasharray="2"
- x1="20"
- x2="20"
- y1="24"
- y2="-10"
- />
- </g>
-</svg>
-`;
-
-exports[`should render correctly: not legacy + split point, but not Rating 1`] = `
+exports[`should render correctly: rating metric 1`] = `
<svg
class="line-chart"
height="100"
class="line-chart-grid"
x1="0"
x2="40"
- y1="22.4"
- y2="22.4"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="20.8"
- y2="20.8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="19.200000000000003"
- y2="19.200000000000003"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="17.6"
- y2="17.6"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="16"
- y2="16"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="14.400000000000002"
- y2="14.400000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="12.800000000000002"
- y2="12.800000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="11.2"
- y2="11.2"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="9.600000000000001"
- y2="9.600000000000001"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="8"
- y2="8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="6.399999999999999"
- y2="6.399999999999999"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="4.800000000000002"
- y2="4.800000000000002"
+ y1="18"
+ y2="18"
/>
</g>
<g>
class="line-chart-grid"
x1="0"
x2="40"
- y1="3.1999999999999993"
- y2="3.1999999999999993"
+ y1="12"
+ y2="12"
/>
</g>
<g>
class="line-chart-grid"
x1="0"
x2="40"
- y1="1.6000000000000023"
- y2="1.6000000000000023"
+ y1="6"
+ y2="6"
/>
</g>
<g>
<g>
<path
class="line-chart-path line-chart-path-0"
- d="M0,16L20,8"
+ d="M0,0L20,6"
stroke="rgb(85,170,223)"
stroke-dasharray="0"
/>
<path
class="line-chart-path line-chart-path-1"
- d="M40,0Z"
+ d="M40,12Z"
stroke="rgb(58,127,173)"
stroke-dasharray="3"
/>
<g>
<circle
cx="40"
- cy="0"
+ cy="12"
fill="rgb(58,127,173)"
r="2"
stroke="white"
height="24"
width="40"
/>
- <line
- class="line-tooltip"
- stroke-dasharray="2"
- x1="20"
- x2="20"
- y1="24"
- y2="-10"
- />
</g>
</svg>
`;
-exports[`should render correctly: not legacy 1`] = `
+exports[`should render correctly: selected date 1`] = `
<svg
class="line-chart"
height="100"
stroke-width="1"
/>
</g>
- <rect
- class="chart-mouse-events-overlay"
- height="24"
- width="40"
- />
- </g>
-</svg>
-`;
-
-exports[`should render correctly: rating metric 1`] = `
-<svg
- class="line-chart"
- height="100"
- width="100"
->
- <g
- transform="translate(50, 26)"
- >
<g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="24"
- y2="24"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="18"
- y2="18"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="12"
- y2="12"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="6"
- y2="6"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="0"
- y2="0"
- />
- </g>
- </g>
- <g
- transform="translate(0, 20)"
- >
- <text
- class="line-chart-tick sw-body-sm"
- text-anchor="end"
- transform="rotate(-35, 15, 24)"
- x="15"
- y="24"
- >
- October
- </text>
- <text
- class="line-chart-tick sw-body-sm"
- text-anchor="end"
- transform="rotate(-35, 20, 24)"
- x="20"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-body-sm"
- text-anchor="end"
- transform="rotate(-35, 25, 24)"
- x="25"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-body-sm"
- text-anchor="end"
- transform="rotate(-35, 30, 24)"
- x="30"
- y="24"
- >
- 06 PM
- </text>
- <text
- class="line-chart-tick sw-body-sm"
- text-anchor="end"
- transform="rotate(-35, 35, 24)"
- x="35"
- y="24"
- >
- Wed 02
- </text>
- <text
- class="line-chart-tick sw-body-sm"
- text-anchor="end"
- transform="rotate(-35, 40, 24)"
- x="40"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-body-sm"
- text-anchor="end"
- transform="rotate(-35, 45, 24)"
- x="45"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-body-sm"
- text-anchor="end"
- transform="rotate(-35, 50, 24)"
- x="50"
- y="24"
- >
- 06 PM
- </text>
- </g>
- <g>
- <path
- class="line-chart-path line-chart-path-0"
- d="M0,0L20,6"
- stroke="rgb(85,170,223)"
- stroke-dasharray="0"
+ <line
+ class="line-tooltip"
+ x1="0"
+ x2="0"
+ y1="24"
+ y2="0"
/>
- <path
- class="line-chart-path line-chart-path-1"
- d="M40,12Z"
- stroke="rgb(58,127,173)"
- stroke-dasharray="3"
+ <circle
+ cx="0"
+ cy="16"
+ fill="rgb(85,170,223)"
+ r="4"
+ stroke="white"
+ stroke-width="1"
/>
- </g>
- <g>
<circle
- cx="40"
- cy="12"
+ cx="0"
+ cy="0"
fill="rgb(58,127,173)"
- r="2"
+ r="4"
stroke="white"
stroke-width="1"
/>
</svg>
`;
-exports[`should render correctly: selected date 1`] = `
+exports[`should render correctly: split point, but not Rating 1`] = `
<svg
class="line-chart"
height="100"
stroke-width="1"
/>
</g>
- <g>
- <line
- class="line-tooltip"
- x1="0"
- x2="0"
- y1="24"
- y2="0"
- />
- <circle
- cx="0"
- cy="16"
- fill="rgb(85,170,223)"
- r="4"
- stroke="white"
- stroke-width="1"
- />
- <circle
- cx="0"
- cy="0"
- fill="rgb(58,127,173)"
- r="4"
- stroke="white"
- stroke-width="1"
- />
- </g>
<rect
class="chart-mouse-events-overlay"
height="24"
width="40"
/>
+ <line
+ class="line-tooltip"
+ stroke-dasharray="2"
+ x1="20"
+ x2="20"
+ y1="24"
+ y2="-10"
+ />
</g>
</svg>
`;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 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.
+ */
+import classNames from 'classnames';
+import { FacetBox, FacetItem } from 'design-system';
+import { orderBy, sortBy, without } from 'lodash';
+import * as React from 'react';
+import { formatMeasure } from '~sonar-aligned/helpers/measures';
+import { MetricType } from '~sonar-aligned/types/metrics';
+import { FacetKey } from '../../apps/coding-rules/query';
+import { FacetItemsList } from '../../apps/issues/sidebar/FacetItemsList';
+import { MultipleSelectionHint } from '../../apps/issues/sidebar/MultipleSelectionHint';
+import { translate } from '../../helpers/l10n';
+import { Dict } from '../../types/types';
+import Tooltip from '../controls/Tooltip';
+
+export interface BasicProps {
+ fetching?: boolean;
+ help?: React.ReactNode;
+ onChange: (changes: Dict<string | string[] | undefined>) => void;
+ onToggle: (facet: FacetKey) => void;
+ open: boolean;
+ stats?: Dict<number>;
+ values: string[];
+}
+
+interface Props extends BasicProps {
+ disabled?: boolean;
+ disabledHelper?: string;
+ options?: string[];
+ property: FacetKey;
+ renderFooter?: () => React.ReactNode;
+ renderName?: (value: string, disabled: boolean) => React.ReactNode;
+ renderTextName?: (value: string) => string;
+ singleSelection?: boolean;
+}
+
+export default class Facet extends React.PureComponent<Props> {
+ handleItemClick = (itemValue: string, multiple: boolean) => {
+ const { values } = this.props;
+ let newValue;
+ if (this.props.singleSelection) {
+ const value = values.length ? values[0] : undefined;
+ newValue = itemValue === value ? undefined : itemValue;
+ } else if (multiple) {
+ newValue = orderBy(
+ values.includes(itemValue) ? without(values, itemValue) : [...values, itemValue],
+ );
+ } else {
+ newValue = values.includes(itemValue) && values.length < 2 ? [] : [itemValue];
+ }
+ this.props.onChange({ [this.props.property]: newValue });
+ };
+
+ handleHeaderClick = () => this.props.onToggle(this.props.property);
+
+ handleClear = () => this.props.onChange({ [this.props.property]: [] });
+
+ getStat = (value: string) => this.props.stats && this.props.stats[value];
+
+ renderItem = (value: string) => {
+ const active = this.props.values.includes(value);
+ const stat = this.getStat(value);
+ const disabled = stat === 0 || typeof stat === 'undefined';
+ const { renderName = defaultRenderName, renderTextName = defaultRenderName } = this.props;
+
+ return (
+ <FacetItem
+ className="it__search-navigator-facet"
+ active={active}
+ key={value}
+ name={renderName(value, disabled)}
+ onClick={this.handleItemClick}
+ stat={stat && formatMeasure(stat, MetricType.ShortInteger)}
+ value={value}
+ tooltip={renderTextName(value)}
+ />
+ );
+ };
+
+ render() {
+ const {
+ disabled,
+ disabledHelper,
+ open,
+ property,
+ renderTextName = defaultRenderName,
+ stats,
+ help,
+ values,
+ fetching,
+ } = this.props;
+ const items =
+ this.props.options ||
+ (stats &&
+ sortBy(
+ Object.keys(stats),
+ (key) => -stats[key],
+ (key) => renderTextName(key).toLowerCase(),
+ ));
+ const headerId = `facet_${property}`;
+ const nbSelectableItems =
+ items?.filter((item) => (stats ? stats[item] : undefined)).length ?? 0;
+ const nbSelectedItems = values.length;
+
+ return (
+ <FacetBox
+ className={classNames('it__search-navigator-facet-box it__search-navigator-facet-header', {
+ 'it__search-navigator-facet-box-forbidden': disabled,
+ })}
+ data-property={property}
+ loading={fetching}
+ clearIconLabel={translate('clear')}
+ count={values.length}
+ id={headerId}
+ name={translate('coding_rules.facet', property)}
+ onClear={this.handleClear}
+ onClick={disabled ? undefined : this.handleHeaderClick}
+ open={open && !disabled}
+ disabled={disabled}
+ disabledHelper={disabledHelper}
+ tooltipComponent={Tooltip}
+ help={help}
+ >
+ {open && items !== undefined && (
+ <FacetItemsList labelledby={headerId}>{items.map(this.renderItem)}</FacetItemsList>
+ )}
+
+ {open && this.props.renderFooter !== undefined && this.props.renderFooter()}
+
+ <MultipleSelectionHint
+ nbSelectableItems={nbSelectableItems}
+ nbSelectedItems={nbSelectedItems}
+ />
+ </FacetBox>
+ );
+ }
+}
+
+function defaultRenderName(value: string) {
+ return value;
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 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.
+ */
+
+import { Popover } from '@sonarsource/echoes-react';
+import { BareButton, HelperHintIcon } from 'design-system';
+import * as React from 'react';
+import { useIntl } from 'react-intl';
+import { IMPACT_SEVERITIES } from '../../helpers/constants';
+import { DocLink } from '../../helpers/doc-links';
+import { translate } from '../../helpers/l10n';
+import DocumentationLink from '../common/DocumentationLink';
+import SoftwareImpactSeverityIcon from '../icon-mappers/SoftwareImpactSeverityIcon';
+import Facet, { BasicProps } from './Facet';
+
+export default function SeverityFacet(props: Readonly<BasicProps>) {
+ const intl = useIntl();
+ const renderName = React.useCallback(
+ (severity: string, disabled: boolean) => (
+ <div className="sw-flex sw-items-center">
+ <SoftwareImpactSeverityIcon severity={severity} disabled={disabled} />
+ <span className="sw-ml-1">{translate('severity_impact', severity)}</span>
+ </div>
+ ),
+ [],
+ );
+
+ const renderTextName = React.useCallback(
+ (severity: string) => translate('severity_impact', severity),
+ [],
+ );
+
+ return (
+ <Facet
+ {...props}
+ options={IMPACT_SEVERITIES}
+ property="impactSeverities"
+ renderName={renderName}
+ renderTextName={renderTextName}
+ help={
+ <Popover
+ title={intl.formatMessage({ id: 'severity_impact.levels' })}
+ description={
+ <>
+ <p>{intl.formatMessage({ id: 'severity_impact.help.line1' })}</p>
+ <p className="sw-mt-2">{intl.formatMessage({ id: 'severity_impact.help.line2' })}</p>
+ </>
+ }
+ footer={
+ <DocumentationLink to={DocLink.CleanCodeIntroduction}>
+ {intl.formatMessage({ id: 'learn_more' })}
+ </DocumentationLink>
+ }
+ >
+ <BareButton aria-label={intl.formatMessage({ id: 'more_information' })}>
+ <HelperHintIcon />
+ </BareButton>
+ </Popover>
+ }
+ />
+ );
+}
*/
import {
IconProps,
+ SoftwareImpactSeverityBlockerIcon,
SoftwareImpactSeverityHighIcon,
+ SoftwareImpactSeverityInfoIcon,
SoftwareImpactSeverityLowIcon,
SoftwareImpactSeverityMediumIcon,
} from 'design-system';
severity: string | null | undefined;
}
+const defaultIconSize = 14;
+
const severityIcons: Dict<(props: IconProps) => React.ReactElement> = {
+ [SoftwareImpactSeverity.Blocker]: SoftwareImpactSeverityBlockerIcon,
[SoftwareImpactSeverity.High]: SoftwareImpactSeverityHighIcon,
[SoftwareImpactSeverity.Medium]: SoftwareImpactSeverityMediumIcon,
[SoftwareImpactSeverity.Low]: SoftwareImpactSeverityLowIcon,
+ [SoftwareImpactSeverity.Info]: SoftwareImpactSeverityInfoIcon,
};
export default function SoftwareImpactSeverityIcon({ severity, ...iconProps }: Readonly<Props>) {
}
const DesiredIcon = severityIcons[severity];
- return <DesiredIcon {...iconProps} aria-label={translate('severity', severity)} />;
+ return (
+ <DesiredIcon
+ {...iconProps}
+ width={iconProps?.width ?? defaultIconSize}
+ height={iconProps?.height ?? defaultIconSize}
+ aria-label={translate('severity_impact', severity)}
+ />
+ );
}
MetricKey.software_quality_maintainability_rating,
MetricKey.software_quality_reliability_rating,
MetricKey.software_quality_security_rating,
- MetricKey.software_quality_security_review_rating,
'maintainability_rating', // Needed to provide the label for "new_maintainability_rating"
];
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { Pill } from 'design-system';
+import { Popover } from '@sonarsource/echoes-react';
+import { Pill, PillVariant } from 'design-system';
import React from 'react';
-import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip';
import { DocLink } from '../../helpers/doc-links';
import { translate } from '../../helpers/l10n';
import { CleanCodeAttribute, CleanCodeAttributeCategory } from '../../types/clean-code-taxonomy';
+import DocumentationLink from '../common/DocumentationLink';
export interface Props {
className?: string;
const { className, cleanCodeAttributeCategory, cleanCodeAttribute, type = 'issue' } = props;
return (
- <DocHelpTooltip
- content={
- <>
- <p className="sw-mb-4">
- {translate(
- type,
- cleanCodeAttribute ? 'clean_code_attribute' : 'clean_code_attribute_category',
- cleanCodeAttribute ?? cleanCodeAttributeCategory,
- 'title',
- )}
- </p>
- <p>
- {translate(
- 'issue',
- cleanCodeAttribute ? 'clean_code_attribute' : 'clean_code_attribute_category',
- cleanCodeAttribute ?? cleanCodeAttributeCategory,
- 'advice',
- )}
- </p>
- </>
+ <Popover
+ title={translate(
+ type,
+ cleanCodeAttribute ? 'clean_code_attribute' : 'clean_code_attribute_category',
+ cleanCodeAttribute ?? cleanCodeAttributeCategory,
+ 'title',
+ )}
+ description={translate(
+ 'issue',
+ cleanCodeAttribute ? 'clean_code_attribute' : 'clean_code_attribute_category',
+ cleanCodeAttribute ?? cleanCodeAttributeCategory,
+ 'advice',
+ )}
+ footer={
+ <DocumentationLink to={DocLink.CleanCodeIntroduction}>
+ {translate('learn_more')}
+ </DocumentationLink>
}
- links={[
- {
- href: DocLink.CleanCodeIntroduction,
- label: translate('learn_more'),
- },
- ]}
>
- <Pill variant="accent" data-guiding-id="issue-1" className={className}>
+ <Pill variant={PillVariant.Accent} data-guiding-id="issue-1" className={className}>
<span className="sw-font-semibold">
{translate(type, 'clean_code_attribute_category', cleanCodeAttributeCategory)}
</span>
<span> | {translate(type, 'clean_code_attribute', cleanCodeAttribute)}</span>
)}
</Pill>
- </DocHelpTooltip>
+ </Popover>
);
}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { Popover } from '@sonarsource/echoes-react';
import classNames from 'classnames';
-import { Pill } from 'design-system';
+import { Pill, PillVariant } from 'design-system';
+import { noop } from 'lodash';
import React from 'react';
import { FormattedMessage } from 'react-intl';
-import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip';
import { DocLink } from '../../helpers/doc-links';
import { translate } from '../../helpers/l10n';
import { SoftwareImpactSeverity } from '../../types/clean-code-taxonomy';
+import DocumentationLink from '../common/DocumentationLink';
import SoftwareImpactSeverityIcon from '../icon-mappers/SoftwareImpactSeverityIcon';
export interface Props {
const { className, severity, quality, type = 'issue' } = props;
const variant = {
- [SoftwareImpactSeverity.High]: 'danger',
- [SoftwareImpactSeverity.Medium]: 'warning',
- [SoftwareImpactSeverity.Low]: 'info',
- }[severity] as 'danger' | 'warning' | 'info';
+ [SoftwareImpactSeverity.Blocker]: PillVariant.Critical,
+ [SoftwareImpactSeverity.High]: PillVariant.Danger,
+ [SoftwareImpactSeverity.Medium]: PillVariant.Warning,
+ [SoftwareImpactSeverity.Low]: PillVariant.Caution,
+ [SoftwareImpactSeverity.Info]: PillVariant.Info,
+ }[severity];
return (
- <DocHelpTooltip
- content={
- <FormattedMessage
- id={`${type}.impact.severity.tooltip`}
- defaultMessage={translate(`${type}.impact.severity.tooltip`)}
- values={{
- severity: translate('severity', severity).toLowerCase(),
- quality: quality.toLowerCase(),
- }}
- />
+ <Popover
+ title={translate('severity_impact.title')}
+ description={
+ <>
+ <FormattedMessage
+ id={`${type}.impact.severity.tooltip`}
+ values={{
+ severity: translate('severity_impact', severity).toLowerCase(),
+ quality: quality.toLowerCase(),
+ }}
+ />
+ <p className="sw-mt-2">
+ <span className="sw-mr-1">{translate('severity_impact.help.line1')}</span>
+ {translate('severity_impact.help.line2')}
+ </p>
+ </>
+ }
+ footer={
+ <DocumentationLink to={DocLink.CleanCodeIntroduction}>
+ {translate('learn_more')}
+ </DocumentationLink>
}
- links={[
- {
- href: DocLink.CleanCodeIntroduction,
- label: translate('learn_more'),
- },
- ]}
>
- <Pill className={classNames('sw-flex sw-gap-1 sw-items-center', className)} variant={variant}>
+ <Pill
+ className={classNames('sw-flex sw-gap-1 sw-items-center', className)}
+ onClick={noop}
+ variant={variant}
+ >
{quality}
- <SoftwareImpactSeverityIcon severity={severity} data-guiding-id="issue-3" />
+ <SoftwareImpactSeverityIcon
+ width={14}
+ height={14}
+ severity={severity}
+ data-guiding-id="issue-3"
+ />
</Pill>
- </DocHelpTooltip>
+ </Popover>
);
}
}
const severityMap = {
- [SoftwareImpactSeverity.High]: 2,
- [SoftwareImpactSeverity.Medium]: 1,
- [SoftwareImpactSeverity.Low]: 0,
+ [SoftwareImpactSeverity.Blocker]: 4,
+ [SoftwareImpactSeverity.High]: 3,
+ [SoftwareImpactSeverity.Medium]: 2,
+ [SoftwareImpactSeverity.Low]: 1,
+ [SoftwareImpactSeverity.Info]: 0,
};
export default function SoftwareImpactPillList({
const historyMapper = (historyItem: { date: string; value?: string }) => ({
date: parseDateFn(historyItem.date),
- value:
- softwareQualityMeasuresMap.size > 0 && historyItem.value === '5.0'
- ? '4.0'
- : historyItem.value,
+ value: historyItem.value,
});
return historyDataFiltered.map((measure) => {
];
export const OLD_TAXONOMY_RATINGS = [
- MetricKey.releasability_rating,
MetricKey.sqale_rating,
MetricKey.security_rating,
MetricKey.reliability_rating,
- MetricKey.security_review_rating,
MetricKey.sqale_index,
MetricKey.reliability_remediation_effort,
MetricKey.security_remediation_effort,
MetricKey.new_maintainability_rating,
MetricKey.new_security_rating,
MetricKey.new_reliability_rating,
- MetricKey.new_security_review_rating,
MetricKey.new_technical_debt,
MetricKey.new_security_remediation_effort,
MetricKey.new_reliability_remediation_effort,
];
export const SOFTWARE_QUALITY_RATING_METRICS_MAP: Record<string, MetricKey> = {
- [MetricKey.releasability_rating]: MetricKey.software_quality_releasability_rating,
- [MetricKey.releasability_rating_distribution]:
- MetricKey.software_quality_releasability_rating_distribution,
[MetricKey.sqale_rating]: MetricKey.software_quality_maintainability_rating,
[MetricKey.maintainability_rating_distribution]:
MetricKey.software_quality_maintainability_rating_distribution,
[MetricKey.reliability_rating]: MetricKey.software_quality_reliability_rating,
[MetricKey.reliability_rating_distribution]:
MetricKey.software_quality_reliability_rating_distribution,
- [MetricKey.security_review_rating]: MetricKey.software_quality_security_review_rating,
- [MetricKey.security_review_rating_distribution]:
- MetricKey.software_quality_security_review_rating_distribution,
[MetricKey.reliability_remediation_effort]:
MetricKey.software_quality_reliability_remediation_effort,
[MetricKey.security_remediation_effort]: MetricKey.software_quality_security_remediation_effort,
MetricKey.effort_to_reach_software_quality_maintainability_rating_a,
[MetricKey.last_change_on_maintainability_rating]:
MetricKey.last_change_on_software_quality_maintainability_rating,
- [MetricKey.last_change_on_releasability_rating]:
- MetricKey.last_change_on_software_quality_releasability_rating,
[MetricKey.last_change_on_reliability_rating]:
MetricKey.last_change_on_software_quality_reliability_rating,
[MetricKey.last_change_on_security_rating]:
MetricKey.last_change_on_software_quality_security_rating,
- [MetricKey.last_change_on_security_review_rating]:
- MetricKey.last_change_on_software_quality_security_review_rating,
[MetricKey.maintainability_rating_effort]:
MetricKey.software_quality_maintainability_rating_effort,
[MetricKey.reliability_rating_effort]: MetricKey.software_quality_reliability_rating_effort,
[MetricKey.security_rating_effort]: MetricKey.software_quality_security_rating_effort,
- [MetricKey.security_review_rating_effort]:
- MetricKey.software_quality_security_review_rating_effort,
[MetricKey.new_maintainability_rating]: MetricKey.new_software_quality_maintainability_rating,
[MetricKey.new_maintainability_rating_distribution]:
MetricKey.new_software_quality_maintainability_rating_distribution,
[MetricKey.new_reliability_rating]: MetricKey.new_software_quality_reliability_rating,
[MetricKey.new_reliability_rating_distribution]:
MetricKey.new_software_quality_reliability_rating_distribution,
- [MetricKey.new_security_review_rating]: MetricKey.new_software_quality_security_review_rating,
- [MetricKey.new_security_review_rating_distribution]:
- MetricKey.new_software_quality_security_review_rating_distribution,
[MetricKey.new_technical_debt]: MetricKey.new_software_quality_maintainability_remediation_effort,
[MetricKey.new_reliability_remediation_effort]:
MetricKey.new_software_quality_reliability_remediation_effort,
};
export const SOFTWARE_QUALITY_RATING_METRICS = [
- MetricKey.software_quality_releasability_rating,
MetricKey.software_quality_maintainability_rating,
MetricKey.software_quality_security_rating,
MetricKey.software_quality_reliability_rating,
- MetricKey.software_quality_security_review_rating,
MetricKey.software_quality_maintainability_remediation_effort,
MetricKey.software_quality_reliability_remediation_effort,
MetricKey.software_quality_security_remediation_effort,
MetricKey.new_software_quality_maintainability_rating,
MetricKey.new_software_quality_security_rating,
MetricKey.new_software_quality_reliability_rating,
- MetricKey.new_software_quality_security_review_rating,
MetricKey.new_software_quality_maintainability_remediation_effort,
MetricKey.new_software_quality_reliability_remediation_effort,
MetricKey.new_software_quality_security_remediation_effort,
last_change_on_security_rating = 'last_change_on_security_rating',
last_change_on_security_review_rating = 'last_change_on_security_review_rating',
last_change_on_software_quality_maintainability_rating = 'last_change_on_software_quality_maintainability_rating',
- last_change_on_software_quality_releasability_rating = 'last_change_on_software_quality_releasability_rating',
last_change_on_software_quality_reliability_rating = 'last_change_on_software_quality_reliability_rating',
last_change_on_software_quality_security_rating = 'last_change_on_software_quality_security_rating',
- last_change_on_software_quality_security_review_rating = 'last_change_on_software_quality_security_review_rating',
last_commit_date = 'last_commit_date',
leak_projects = 'leak_projects',
line_coverage = 'line_coverage',
new_security_remediation_effort = 'new_security_remediation_effort',
new_software_quality_security_remediation_effort = 'new_software_quality_security_remediation_effort',
new_security_review_rating = 'new_security_review_rating',
- new_software_quality_security_review_rating = 'new_software_quality_security_review_rating',
new_security_review_rating_distribution = 'new_security_review_rating_distribution',
- new_software_quality_security_review_rating_distribution = 'new_software_quality_security_review_rating_distribution',
new_sqale_debt_ratio = 'new_sqale_debt_ratio',
new_software_quality_maintainability_debt_ratio = 'new_software_quality_maintainability_debt_ratio',
new_technical_debt = 'new_technical_debt',
quality_profiles = 'quality_profiles',
releasability_effort = 'releasability_effort',
releasability_rating = 'releasability_rating',
- software_quality_releasability_rating = 'software_quality_releasability_rating',
releasability_rating_distribution = 'releasability_rating_distribution',
- software_quality_releasability_rating_distribution = 'software_quality_releasability_rating_distribution',
reliability_issues = 'reliability_issues',
reliability_rating = 'reliability_rating',
software_quality_reliability_rating = 'software_quality_reliability_rating',
security_remediation_effort = 'security_remediation_effort',
software_quality_security_remediation_effort = 'software_quality_security_remediation_effort',
security_review_rating = 'security_review_rating',
- software_quality_security_review_rating = 'software_quality_security_review_rating',
security_review_rating_distribution = 'security_review_rating_distribution',
- software_quality_security_review_rating_distribution = 'software_quality_security_review_rating_distribution',
security_review_rating_effort = 'security_review_rating_effort',
- software_quality_security_review_rating_effort = 'software_quality_security_review_rating_effort',
skipped_tests = 'skipped_tests',
sonarjava_feedback = 'sonarjava_feedback',
sqale_debt_ratio = 'sqale_debt_ratio',
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
export enum SoftwareImpactSeverity {
+ Blocker = 'BLOCKER',
High = 'HIGH',
Medium = 'MEDIUM',
Low = 'LOW',
+ Info = 'INFO',
}
export enum CleanCodeAttributeCategory {
export interface SoftwareImpactMeasureData {
total: number;
+ [SoftwareImpactSeverity.Blocker]: number;
[SoftwareImpactSeverity.High]: number;
[SoftwareImpactSeverity.Medium]: number;
[SoftwareImpactSeverity.Low]: number;
+ [SoftwareImpactSeverity.Info]: number;
}
*/
declare namespace jest {
interface Matchers<R> {
+ toHaveAPopoverWithContent(content: string): Promise<CustomMatcherResult>;
toHaveATooltipWithContent(content: string): Promise<CustomMatcherResult>;
toHaveNoA11yViolations(): Promise<CustomMatcherResult>;
}
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY;
-import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING_KEY;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING_KEY;
-import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY;
import static org.sonar.server.es.EsUtils.escapeSpecialRegexChars;
import static org.sonar.server.es.EsUtils.termsToMap;
import static org.sonar.server.es.IndexType.FIELD_INDEX_TYPE;
NEW_SECURITY_REVIEW_RATING(new RatingMeasureFacet(NEW_SECURITY_REVIEW_RATING_KEY)),
//Software quality ratings
- SOFTWARE_QUALITY_MAINTAINABILITY_RATING(new RatingMeasureFacet(SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY, 4)),
- NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING(new RatingMeasureFacet(NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY, 4)),
- SOFTWARE_QUALITY_RELIABILITY_RATING(new RatingMeasureFacet(SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, 4)),
- NEW_SOFTWARE_QUALITY_RELIABILITY_RATING(new RatingMeasureFacet(NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, 4)),
- SOFTWARE_QUALITY_SECURITY_RATING(new RatingMeasureFacet(SOFTWARE_QUALITY_SECURITY_RATING_KEY, 4)),
- NEW_SOFTWARE_QUALITY_SECURITY_RATING(new RatingMeasureFacet(NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, 4)),
- SOFTWARE_QUALITY_SECURITY_REVIEW_RATING(new RatingMeasureFacet(SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY, 4)),
- NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING(new RatingMeasureFacet(NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY, 4)),
+ SOFTWARE_QUALITY_MAINTAINABILITY_RATING(new RatingMeasureFacet(SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY)),
+ NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING(new RatingMeasureFacet(NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY)),
+ SOFTWARE_QUALITY_RELIABILITY_RATING(new RatingMeasureFacet(SOFTWARE_QUALITY_RELIABILITY_RATING_KEY)),
+ NEW_SOFTWARE_QUALITY_RELIABILITY_RATING(new RatingMeasureFacet(NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY)),
+ SOFTWARE_QUALITY_SECURITY_RATING(new RatingMeasureFacet(SOFTWARE_QUALITY_SECURITY_RATING_KEY)),
+ NEW_SOFTWARE_QUALITY_SECURITY_RATING(new RatingMeasureFacet(NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY)),
SECURITY_HOTSPOTS_REVIEWED(new RangeMeasureFacet(SECURITY_HOTSPOTS_REVIEWED_KEY, SECURITY_REVIEW_RATING_THRESHOLDS)),
NEW_SECURITY_HOTSPOTS_REVIEWED(new RangeMeasureFacet(NEW_SECURITY_HOTSPOTS_REVIEWED_KEY, SECURITY_REVIEW_RATING_THRESHOLDS)),
private static class RatingMeasureFacet extends MeasureFacet {
private RatingMeasureFacet(String metricKey) {
- super(metricKey, new MetricRatingFacetBuilder(metricKey, 5));
- }
-
- private RatingMeasureFacet(String metricKey, int maxRating) {
- super(metricKey, new MetricRatingFacetBuilder(metricKey, maxRating));
+ super(metricKey, new MetricRatingFacetBuilder(metricKey));
}
private static class MetricRatingFacetBuilder implements FacetBuilder {
private final String metricKey;
- private final int maxRating;
- private MetricRatingFacetBuilder(String metricKey, int maxRating) {
+ private MetricRatingFacetBuilder(String metricKey) {
this.metricKey = metricKey;
- this.maxRating = maxRating;
}
@Override
return topAggregationHelper.buildTopAggregation(
facet.getName(), facet.getTopAggregationDef(),
NO_EXTRA_FILTER,
- t -> t.subAggregation(createMeasureRatingFacet(metricKey, maxRating)));
+ t -> t.subAggregation(createMeasureRatingFacet(metricKey)));
}
- private static AbstractAggregationBuilder<?> createMeasureRatingFacet(String metricKey, int maxRating) {
- List<KeyedFilter> filter = new ArrayList<>();
- for (int i = 1; i <= maxRating; i++) {
- filter.add(new KeyedFilter(String.valueOf(i), termQuery(FIELD_MEASURES_MEASURE_VALUE, Double.valueOf(i))));
- }
-
+ private static AbstractAggregationBuilder<?> createMeasureRatingFacet(String metricKey) {
return AggregationBuilders.nested("nested_" + metricKey, FIELD_MEASURES)
.subAggregation(
AggregationBuilders.filter("filter_" + metricKey, termsQuery(FIELD_MEASURES_MEASURE_KEY, metricKey))
- .subAggregation(filters(metricKey, filter.toArray(new KeyedFilter[0])
- )));
+ .subAggregation(filters(metricKey,
+ new KeyedFilter("1", termQuery(FIELD_MEASURES_MEASURE_VALUE, 1D)),
+ new KeyedFilter("2", termQuery(FIELD_MEASURES_MEASURE_VALUE, 2D)),
+ new KeyedFilter("3", termQuery(FIELD_MEASURES_MEASURE_VALUE, 3D)),
+ new KeyedFilter("4", termQuery(FIELD_MEASURES_MEASURE_VALUE, 4D)),
+ new KeyedFilter("5", termQuery(FIELD_MEASURES_MEASURE_VALUE, 5D)))));
}
}
}
import static org.sonar.api.issue.Issue.STATUS_RESOLVED;
import static org.sonar.api.issue.impact.SoftwareQuality.MAINTAINABILITY;
import static org.sonar.api.issue.impact.SoftwareQuality.RELIABILITY;
+import static org.sonar.api.issue.impact.SoftwareQuality.SECURITY;
import static org.sonar.api.rule.Severity.BLOCKER;
import static org.sonar.api.rule.Severity.CRITICAL;
import static org.sonar.api.rule.Severity.INFO;
newDoc("I4", project.uuid(), file2),
newDoc("I5", project.uuid(), file3));
- assertThatFacetHasOnly(IssueQuery.builder(), "files", entry("src/NAME_ABCD", 1L), entry("src/NAME_BCDE", 2L), entry("src/NAME_CDEF", 1L));
+ assertThatFacetHasOnly(IssueQuery.builder(), "files", entry("src/NAME_ABCD", 1L), entry("src/NAME_BCDE", 2L), entry("src/NAME_CDEF",
+ 1L));
}
@Test
void facet_on_directories_return_100_entries_plus_selected_values() {
ComponentDto project = newPrivateProjectDto();
indexIssues(
- rangeClosed(1, 110).mapToObj(i -> newDoc(newFileDto(project, newDirectory(project, "dir" + i)), project.uuid()).setDirectoryPath("a" + i)).toArray(IssueDoc[]::new));
+ rangeClosed(1, 110).mapToObj(i -> newDoc(newFileDto(project, newDirectory(project, "dir" + i)), project.uuid()).setDirectoryPath("a"
+ + i)).toArray(IssueDoc[]::new));
IssueDoc issue1 = newDoc(newFileDto(project, newDirectory(project, "path1")), project.uuid()).setDirectoryPath("directory1");
IssueDoc issue2 = newDoc(newFileDto(project, newDirectory(project, "path2")), project.uuid()).setDirectoryPath("directory2");
indexIssues(issue1, issue2);
assertThatFacetHasSize(IssueQuery.builder().build(), "directories", 100);
- assertThatFacetHasSize(IssueQuery.builder().directories(asList(issue1.directoryPath(), issue2.directoryPath())).build(), "directories", 102);
+ assertThatFacetHasSize(IssueQuery.builder().directories(asList(issue1.directoryPath(), issue2.directoryPath())).build(), "directories"
+ , 102);
}
@Test
ComponentDto file = newFileDto(project);
indexIssues(
- newDoc("I1", project.uuid(), file).setType(RuleType.VULNERABILITY).setSansTop25(asList("porous-defenses", "risky-resource", "insecure-interaction")),
+ newDoc("I1", project.uuid(), file).setType(RuleType.VULNERABILITY).setSansTop25(asList("porous-defenses", "risky-resource",
+ "insecure-interaction")),
newDoc("I2", project.uuid(), file).setType(RuleType.VULNERABILITY).setSansTop25(singletonList("porous-defenses")),
newDoc("I3", project.uuid(), file));
indexIssues(issue1, issue2);
assertThatFacetHasSize(IssueQuery.builder().build(), "assignees", 100);
- assertThatFacetHasSize(IssueQuery.builder().assigneeUuids(asList(issue1.assigneeUuid(), issue2.assigneeUuid())).build(), "assignees", 102);
+ assertThatFacetHasSize(IssueQuery.builder().assigneeUuids(asList(issue1.assigneeUuid(), issue2.assigneeUuid())).build(), "assignees",
+ 102);
}
@Test
SearchOptions options = fixtureForCreatedAtFacet();
SearchResponse result = underTest.search(IssueQuery.builder()
- .createdAfter(parseDateTime("2014-09-01T00:00:00+0100"))
- .createdBefore(parseDateTime("2014-09-21T00:00:00+0100")).build(),
+ .createdAfter(parseDateTime("2014-09-01T00:00:00+0100"))
+ .createdBefore(parseDateTime("2014-09-21T00:00:00+0100")).build(),
options);
Map<String, Long> createdAt = new Facets(result, system2.getDefaultTimeZone().toZoneId()).get("createdAt");
assertThat(createdAt).containsOnly(
SearchOptions options = fixtureForCreatedAtFacet();
SearchResponse result = underTest.search(IssueQuery.builder()
- .createdAfter(parseDateTime("2014-09-01T00:00:00+0100"))
- .createdBefore(parseDateTime("2015-01-19T00:00:00+0100")).build(),
+ .createdAfter(parseDateTime("2014-09-01T00:00:00+0100"))
+ .createdBefore(parseDateTime("2015-01-19T00:00:00+0100")).build(),
options);
Map<String, Long> createdAt = new Facets(result, system2.getDefaultTimeZone().toZoneId()).get("createdAt");
assertThat(createdAt).containsOnly(
SearchOptions options = fixtureForCreatedAtFacet();
SearchResponse result = underTest.search(IssueQuery.builder()
- .createdAfter(parseDateTime("2011-01-01T00:00:00+0100"))
- .createdBefore(parseDateTime("2016-01-01T00:00:00+0100")).build(),
+ .createdAfter(parseDateTime("2011-01-01T00:00:00+0100"))
+ .createdBefore(parseDateTime("2016-01-01T00:00:00+0100")).build(),
options);
Map<String, Long> createdAt = new Facets(result, system2.getDefaultTimeZone().toZoneId()).get("createdAt");
assertThat(createdAt).containsOnly(
SearchOptions options = fixtureForCreatedAtFacet();
SearchResponse result = underTest.search(IssueQuery.builder()
- .createdAfter(parseDateTime("2014-09-01T00:00:00-0100"))
- .createdBefore(parseDateTime("2014-09-02T00:00:00-0100")).build(),
+ .createdAfter(parseDateTime("2014-09-01T00:00:00-0100"))
+ .createdBefore(parseDateTime("2014-09-02T00:00:00-0100")).build(),
options);
Map<String, Long> createdAt = new Facets(result, system2.getDefaultTimeZone().toZoneId()).get("createdAt");
assertThat(createdAt).containsOnly(
SearchOptions searchOptions = fixtureForCreatedAtFacet();
SearchResponse result = underTest.search(IssueQuery.builder()
- .createdBefore(parseDateTime("2016-01-01T00:00:00+0100")).build(),
+ .createdBefore(parseDateTime("2016-01-01T00:00:00+0100")).build(),
searchOptions);
Map<String, Long> createdAt = new Facets(result, system2.getDefaultTimeZone().toZoneId()).get("createdAt");
assertThat(createdAt).containsOnly(
indexIssues(
newDoc("I1", project.uuid(), file).setImpacts(Map.of(
- MAINTAINABILITY, org.sonar.api.issue.impact.Severity.HIGH,
- RELIABILITY, org.sonar.api.issue.impact.Severity.MEDIUM))
+ MAINTAINABILITY, org.sonar.api.issue.impact.Severity.HIGH,
+ RELIABILITY, org.sonar.api.issue.impact.Severity.MEDIUM))
.setTags(singletonList("my-tag")),
newDoc("I2", project.uuid(), file).setImpacts(Map.of(
MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW)),
entry("RELIABILITY", 1L),
entry("SECURITY", 0L));
- assertThatFacetHasOnly(IssueQuery.builder().impactSeverities(Set.of(org.sonar.api.issue.impact.Severity.HIGH.name())), "impactSoftwareQualities",
+ assertThatFacetHasOnly(IssueQuery.builder().impactSeverities(Set.of(org.sonar.api.issue.impact.Severity.HIGH.name())),
+ "impactSoftwareQualities",
entry("MAINTAINABILITY", 1L),
entry("RELIABILITY", 1L),
entry("SECURITY", 0L));
assertThatFacetHasOnly(IssueQuery.builder()
- .tags(singletonList("my-tag"))
- .impactSeverities(Set.of(org.sonar.api.issue.impact.Severity.HIGH.name())), "impactSoftwareQualities",
+ .tags(singletonList("my-tag"))
+ .impactSeverities(Set.of(org.sonar.api.issue.impact.Severity.HIGH.name())), "impactSoftwareQualities",
entry("MAINTAINABILITY", 1L),
entry("RELIABILITY", 0L),
entry("SECURITY", 0L));
indexIssues(
newDoc("I1", project.uuid(), file).setImpacts(Map.of(
MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW,
- RELIABILITY, org.sonar.api.issue.impact.Severity.LOW)));
+ RELIABILITY, org.sonar.api.issue.impact.Severity.LOW,
+ SECURITY, org.sonar.api.issue.impact.Severity.BLOCKER)));
assertThatFacetHasOnly(IssueQuery.builder()
- .impactSoftwareQualities(Set.of(MAINTAINABILITY.name()))
- .impactSeverities(Set.of(org.sonar.api.issue.impact.Severity.LOW.name())),
+ .impactSoftwareQualities(Set.of(MAINTAINABILITY.name()))
+ .impactSeverities(Set.of(org.sonar.api.issue.impact.Severity.LOW.name())),
"impactSoftwareQualities",
entry("MAINTAINABILITY", 1L),
entry("RELIABILITY", 1L),
entry("SECURITY", 0L));
assertThatFacetHasOnly(IssueQuery.builder()
- .impactSoftwareQualities(Set.of(MAINTAINABILITY.name()))
- .impactSeverities(Set.of(org.sonar.api.issue.impact.Severity.LOW.name())),
+ .impactSoftwareQualities(Set.of(MAINTAINABILITY.name()))
+ .impactSeverities(Set.of(org.sonar.api.issue.impact.Severity.LOW.name())),
"impactSeverities",
entry("HIGH", 0L),
entry("MEDIUM", 0L),
- entry("LOW", 1L));
+ entry("LOW", 1L),
+ entry("INFO", 0L),
+ entry("BLOCKER", 0L));
}
@Test
newDoc("I2", project.uuid(), file).setImpacts(Map.of(
MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW)),
newDoc("I3", project.uuid(), file).setImpacts(Map.of(
- RELIABILITY, org.sonar.api.issue.impact.Severity.HIGH)),
+ RELIABILITY, org.sonar.api.issue.impact.Severity.HIGH,
+ SECURITY, org.sonar.api.issue.impact.Severity.BLOCKER)),
newDoc("I4", project.uuid(), file).setImpacts(Map.of(
- MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW)));
+ MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW,
+ RELIABILITY, org.sonar.api.issue.impact.Severity.INFO)));
assertThatFacetHasOnly(IssueQuery.builder(), "impactSeverities",
entry("HIGH", 2L),
entry("MEDIUM", 1L),
- entry("LOW", 2L));
+ entry("LOW", 2L),
+ entry("BLOCKER", 1L),
+ entry("INFO", 1L));
}
@Test
assertThatFacetHasOnly(IssueQuery.builder().impactSoftwareQualities(Set.of(MAINTAINABILITY.name())), "impactSeverities",
entry("HIGH", 1L),
entry("MEDIUM", 0L),
- entry("LOW", 2L));
+ entry("LOW", 2L),
+ entry("BLOCKER", 0L),
+ entry("INFO", 0L));
}
@Test
private static final String NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY = "new_software_quality_reliability_rating";
private static final String SOFTWARE_QUALITY_SECURITY_RATING_KEY = "software_quality_security_rating";
private static final String NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY = "new_software_quality_security_rating";
- private static final String SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY = "software_quality_security_review_rating";
- private static final String NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY = "new_software_quality_security_review_rating";
private static final String SECURITY_HOTSPOTS_REVIEWED = "security_hotspots_reviewed";
private static final String NEW_SECURITY_HOTSPOTS_REVIEWED = "new_security_hotspots_reviewed";
return new String[]{
SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY, NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY,
SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY,
- SOFTWARE_QUALITY_SECURITY_RATING_KEY, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY,
- SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY, NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY
+ SOFTWARE_QUALITY_SECURITY_RATING_KEY, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY
};
}
newDoc(metricKey, 3d),
// 2 docs with rating D
newDoc(metricKey, 4d),
- newDoc(metricKey, 4d));
+ newDoc(metricKey, 4d),
+ // 1 doc with rating E
+ newDoc(metricKey, 5d));
+
Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(metricKey)).getFacets();
entry("1", 3L),
entry("2", 2L),
entry("3", 4L),
- entry("4", 2L));
+ entry("4", 2L),
+ entry("5", 1L));
}
@ParameterizedTest
newDoc(metricKey, 3d, NCLOC, 40000d, COVERAGE, 0d),
newDoc(metricKey, 3d, NCLOC, 50000d, COVERAGE, 0d),
// docs with rating D
- newDoc(metricKey, 4d, NCLOC, 120000d, COVERAGE, 0d));
+ newDoc(metricKey, 4d, NCLOC, 120000d, COVERAGE, 0d),
+ // docs with rating E
+ newDoc(metricKey, 5d, NCLOC, 120000d, COVERAGE, 0d));
Facets facets = underTest.search(new ProjectMeasuresQuery()
.addMetricCriterion(MetricCriterion.create(metricKey, Operator.LT, 3d))
entry("1", 3L),
entry("2", 2L),
entry("3", 4L),
- entry("4", 1L));
+ entry("4", 1L),
+ entry("5", 1L));
// But facet on ncloc does well take into into filters
assertThat(facets.get(NCLOC)).containsExactly(
entry("*-1000.0", 3L),
// docs with rating C
newDoc(metricKey, 3d),
// docs with rating D
- newDoc(metricKey, 4d));
+ newDoc(metricKey, 4d),
+ // docs with rating E
+ newDoc(metricKey, 5d));
userSession.logIn(USER1);
Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(metricKey)).getFacets();
entry("1", 3L),
entry("2", 2L),
entry("3", 0L),
- entry("4", 0L));
+ entry("4", 0L),
+ entry("5", 0L));
}
@Test
import org.sonar.api.issue.impact.Severity;
public enum ImpactSeverityRestEnum {
+ INFO(Severity.INFO),
LOW(Severity.LOW),
MEDIUM(Severity.MEDIUM),
- HIGH(Severity.HIGH);
+ HIGH(Severity.HIGH),
+ BLOCKER(Severity.BLOCKER);
private final Severity severity;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY;
-import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING_KEY;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING_KEY;
-import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_002;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_003;
@DataProvider
public static Object[][] software_quality_rating_metric_keys() {
return new Object[][]{{SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY}, {SOFTWARE_QUALITY_RELIABILITY_RATING_KEY},
- {SOFTWARE_QUALITY_SECURITY_RATING_KEY}, {SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY}};
+ {SOFTWARE_QUALITY_SECURITY_RATING_KEY}};
}
@DataProvider
@DataProvider
public static Object[][] new_software_quality_rating_metric_keys() {
return new Object[][]{{NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY}, {NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY},
- {NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY}, {NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY}};
+ {NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY}};
}
@DataProvider
"new_software_quality_maintainability_rating",
"new_software_quality_reliability_rating",
"new_software_quality_security_rating",
- "new_software_quality_security_review_rating",
"software_quality_maintainability_rating",
"software_quality_reliability_rating",
- "software_quality_security_rating",
- "software_quality_security_review_rating");
+ "software_quality_security_rating");
Param asc = def.param("asc");
assertThat(asc.defaultValue()).isEqualTo("true");
"new_software_quality_maintainability_rating",
"new_software_quality_reliability_rating",
"new_software_quality_security_rating",
- "new_software_quality_security_review_rating",
"software_quality_maintainability_rating",
"software_quality_reliability_rating",
- "software_quality_security_rating",
- "software_quality_security_review_rating");
+ "software_quality_security_rating");
}
@Test
insertProject(new Measure(ratingMetric, c -> c.setValue(1d)));
insertProject(new Measure(ratingMetric, c -> c.setValue(1d)));
insertProject(new Measure(ratingMetric, c -> c.setValue(3d)));
+ insertProject(new Measure(ratingMetric, c -> c.setValue(5d)));
+ insertProject(new Measure(ratingMetric, c -> c.setValue(5d)));
index();
SearchProjectsWsResponse result = call(request.setFacets(singletonList(ratingMetricKey)));
tuple("1", 2L),
tuple("2", 0L),
tuple("3", 1L),
- tuple("4", 0L));
+ tuple("4", 0L),
+ tuple("5", 2L));
}
@Test
tuple("1", 2L),
tuple("2", 0L),
tuple("3", 1L),
- tuple("4", 0L));
+ tuple("4", 0L),
+ tuple("5", 0L));
}
@Test
import org.sonar.db.component.BranchType;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ProjectData;
+import org.sonar.db.issue.ImpactDto;
import org.sonar.db.issue.IssueDto;
import org.sonar.db.metric.MetricDto;
import org.sonar.db.protobuf.DbIssues;
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.issue.impact.SoftwareQuality.MAINTAINABILITY;
import static org.sonar.api.measures.CoreMetrics.ANALYSIS_FROM_SONARQUBE_9_4_KEY;
import static org.sonar.api.utils.DateUtils.formatDateTime;
import static org.sonar.api.utils.DateUtils.parseDate;
import static org.sonar.db.rule.RuleTesting.XOO_X2;
import static org.sonar.db.rule.RuleTesting.newRule;
import static org.sonar.server.tester.UserSessionRule.standalone;
+import static org.sonarqube.ws.Common.Impact.newBuilder;
@RunWith(DataProviderRunner.class)
public class ListActionIT {
.setMessageFormattings(DbIssues.MessageFormattings.newBuilder().addMessageFormatting(MESSAGE_FORMATTING).build())
.setStatus(STATUS_OPEN)
.setResolution(null)
- .setSeverity("MAJOR")
+ .setSeverity("BLOCKER")
+ .replaceAllImpacts(List.of(new ImpactDto().setSoftwareQuality(MAINTAINABILITY).setSeverity(org.sonar.api.issue.impact.Severity.BLOCKER)))
.setAuthorLogin("John")
.setAssigneeUuid(simon.getUuid())
.setTags(asList("bug", "owasp"))
.extracting(
Issue::getKey, Issue::getRule, Issue::getSeverity, Issue::getComponent, Issue::getResolution, Issue::getStatus, Issue::getMessage, Issue::getMessageFormattingsList,
Issue::getEffort, Issue::getAssignee, Issue::getAuthor, Issue::getLine, Issue::getHash, Issue::getTagsList, Issue::getCreationDate, Issue::getUpdateDate,
- Issue::getQuickFixAvailable, Issue::getCodeVariantsList)
+ Issue::getQuickFixAvailable, Issue::getCodeVariantsList, Issue::getImpactsList)
.containsExactlyInAnyOrder(
- tuple(issue.getKey(), rule.getKey().toString(), Severity.MAJOR, file.getKey(), "", STATUS_OPEN, "the message",
+ tuple(issue.getKey(), rule.getKey().toString(), Severity.BLOCKER, file.getKey(), "", STATUS_OPEN, "the message",
MessageFormattingUtils.dbMessageFormattingListToWs(List.of(MESSAGE_FORMATTING)), "10min",
simon.getLogin(), "John", 42, "a227e508d6646b55a086ee11d63b21e9", asList("bug", "owasp"), formatDateTime(issue.getIssueCreationDate()),
- formatDateTime(issue.getIssueUpdateDate()), false, List.of("variant1", "variant2")));
+ formatDateTime(issue.getIssueUpdateDate()), false, List.of("variant1", "variant2"),
+ List.of(newBuilder().setSoftwareQuality(Common.SoftwareQuality.MAINTAINABILITY).setSeverity(Common.ImpactSeverity.ImpactSeverity_BLOCKER).build())));
assertThat(response.getComponentsList())
.extracting(
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.impact.Severity;
+import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ProjectData;
import org.sonar.db.component.ResourceTypesRule;
+import org.sonar.db.issue.ImpactDto;
import org.sonar.db.issue.IssueDbTester;
import org.sonar.db.issue.IssueDto;
import org.sonar.db.project.ProjectDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.issue.ImpactFormatter;
import org.sonar.server.issue.TaintChecker;
import org.sonar.server.issue.ws.pull.PullTaintActionProtobufObjectGenerator;
import org.sonar.server.tester.UserSessionRule;
.setManualSeverity(true)
.setMessage("message")
.setMessageFormattings(DbIssues.MessageFormattings.newBuilder().addMessageFormatting(MESSAGE_FORMATTING).build())
+ .replaceAllImpacts(List.of(new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.BLOCKER),
+ new ImpactDto().setSoftwareQuality(SoftwareQuality.RELIABILITY).setSeverity(Severity.HIGH)))
.setIssueCreationTime(NOW)
.setStatus(Issue.STATUS_OPEN)
.setLocations(mainLocation.build())
.containsExactlyInAnyOrderElementsOf(issueDto.getEffectiveImpacts()
.entrySet()
.stream()
- .map(entry -> tuple(Common.SoftwareQuality.valueOf(entry.getKey().name()), Common.ImpactSeverity.valueOf(entry.getValue().name())))
+ .map(entry -> tuple(Common.SoftwareQuality.valueOf(entry.getKey().name()), ImpactFormatter.mapImpactSeverity(entry.getValue())))
.collect(toList()));
Issues.Location location = taintLite.getMainLocation();
private final DbClient dbClient = db.getDbClient();
private final DbSession session = db.getSession();
- private final IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSession, new WebAuthorizationTypeSupport(userSession));
+ private final IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSession,
+ new WebAuthorizationTypeSupport(userSession));
private final IssueIndexer issueIndexer = new IssueIndexer(es.client(), dbClient, new IssueIteratorFactory(dbClient), null);
private final IssueQueryFactory issueQueryFactory = new IssueQueryFactory(dbClient, Clock.systemUTC(), userSession);
private final IssueFieldsSetter issueFieldsSetter = new IssueFieldsSetter();
private final IssueWorkflow issueWorkflow = new IssueWorkflow(new FunctionExecutor(issueFieldsSetter), issueFieldsSetter);
- private final SearchResponseLoader searchResponseLoader = new SearchResponseLoader(userSession, dbClient, new TransitionService(userSession, issueWorkflow));
+ private final SearchResponseLoader searchResponseLoader = new SearchResponseLoader(userSession, dbClient,
+ new TransitionService(userSession, issueWorkflow));
private final Languages languages = new Languages();
private final UserResponseFormatter userFormatter = new UserResponseFormatter(new AvatarResolverImpl());
- private final SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), languages, new TextRangeResponseFormatter(), userFormatter);
+ private final SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), languages,
+ new TextRangeResponseFormatter(), userFormatter);
private final IssueIndexSyncProgressChecker issueIndexSyncProgressChecker = new IssueIndexSyncProgressChecker(dbClient);
private final WsActionTester ws = new WsActionTester(
- new SearchAction(userSession, issueIndex, issueQueryFactory, issueIndexSyncProgressChecker, searchResponseLoader, searchResponseFormat, System2.INSTANCE, dbClient));
+ new SearchAction(userSession, issueIndex, issueQueryFactory, issueIndexSyncProgressChecker, searchResponseLoader,
+ searchResponseFormat, System2.INSTANCE, dbClient));
private final PermissionIndexer permissionIndexer = new PermissionIndexer(dbClient, es.client(), issueIndexer);
@Before
assertThat(response.getIssuesList())
.extracting(
- Issue::getKey, Issue::getRule, Issue::getSeverity, Issue::getComponent, Issue::getResolution, Issue::getStatus, Issue::getMessage, Issue::getMessageFormattingsList,
- Issue::getEffort, Issue::getAssignee, Issue::getAuthor, Issue::getLine, Issue::getHash, Issue::getTagsList, Issue::getCreationDate, Issue::getUpdateDate,
+ Issue::getKey, Issue::getRule, Issue::getSeverity, Issue::getComponent, Issue::getResolution, Issue::getStatus, Issue::getMessage
+ , Issue::getMessageFormattingsList,
+ Issue::getEffort, Issue::getAssignee, Issue::getAuthor, Issue::getLine, Issue::getHash, Issue::getTagsList,
+ Issue::getCreationDate, Issue::getUpdateDate,
Issue::getQuickFixAvailable, Issue::getCodeVariantsList)
.containsExactlyInAnyOrder(
tuple(issue.getKey(), rule.getKey().toString(), Severity.MAJOR, file.getKey(), RESOLUTION_FIXED, STATUS_RESOLVED, "the message",
MessageFormattingUtils.dbMessageFormattingListToWs(List.of(MESSAGE_FORMATTING)), "10min",
- simon.getLogin(), "John", 42, "a227e508d6646b55a086ee11d63b21e9", asList("bug", "owasp"), formatDateTime(issue.getIssueCreationDate()),
+ simon.getLogin(), "John", 42, "a227e508d6646b55a086ee11d63b21e9", asList("bug", "owasp"),
+ formatDateTime(issue.getIssueCreationDate()),
formatDateTime(issue.getIssueUpdateDate()), false, List.of("variant1", "variant2")));
}
.get(0)
.getActions()
.getActionsList())
- .isEqualTo(asList(ACTION_SET_TAGS, COMMENT_KEY, ACTION_ASSIGN));
+ .isEqualTo(asList(ACTION_SET_TAGS, COMMENT_KEY, ACTION_ASSIGN));
response = ws.newRequest()
.setParam(PARAM_ADDITIONAL_FIELDS, "actions")
.get(0)
.getActions()
.getActionsList())
- .isEqualTo(asList(ACTION_SET_TAGS, COMMENT_KEY));
+ .isEqualTo(asList(ACTION_SET_TAGS, COMMENT_KEY));
}
@Test
SearchWsResponse result = ws.newRequest().executeProtobuf(SearchWsResponse.class);
assertThat(result.getIssuesCount()).isOne();
- assertThat(result.getIssues(0).getFlows(0).getLocationsList()).extracting(Common.Location::getComponent, Common.Location::getMsg, Common.Location::getMsgFormattingsList)
+ assertThat(result.getIssues(0).getFlows(0).getLocationsList()).extracting(Common.Location::getComponent, Common.Location::getMsg,
+ Common.Location::getMsgFormattingsList)
.containsExactlyInAnyOrder(
tuple(file.getKey(), "FLOW MESSAGE", List.of()),
tuple(anotherFile.getKey(), "ANOTHER FLOW MESSAGE", List.of(Common.MessageFormatting.newBuilder()
c -> c.setKey("PROJECT_KEY").setName("NAME_PROJECT_ID").setLongName("LONG_NAME_PROJECT_ID").setLanguage("java"));
grantPermissionToAnyone(project.getProjectDto(), ISSUE_ADMIN);
indexPermissions();
- ComponentDto file = db.components().insertComponent(newFileDto(project.getMainBranchComponent(), null, "FILE_ID").setKey("FILE_KEY").setLanguage("js"));
+ ComponentDto file =
+ db.components().insertComponent(newFileDto(project.getMainBranchComponent(), null, "FILE_ID").setKey("FILE_KEY").setLanguage("js"));
IssueDto issue = newIssue(newIssueRule(), project.getMainBranchComponent(), file)
.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2")
c -> c.setKey("PROJECT_KEY").setName("NAME_PROJECT_ID").setLongName("LONG_NAME_PROJECT_ID").setLanguage("java")).getMainBranchComponent();
ComponentDto file = db.components().insertComponent(newFileDto(project, null, "FILE_ID").setKey("FILE_KEY").setLanguage("java"));
db.issues().insertIssue(rule, project, file, i -> i.setStatus(STATUS_OPEN));
- IssueDto expectedIssue = db.issues().insertIssue(rule, project, file, i -> i.setStatus(STATUS_RESOLVED).setResolution(RESOLUTION_WONT_FIX));
+ IssueDto expectedIssue = db.issues().insertIssue(rule, project, file,
+ i -> i.setStatus(STATUS_RESOLVED).setResolution(RESOLUTION_WONT_FIX));
db.issues().insertIssue(rule, project, file, i -> i.setStatus(STATUS_RESOLVED).setResolution(RESOLUTION_FALSE_POSITIVE));
db.issues().insertIssue(rule, project, file, i -> i.setStatus(STATUS_RESOLVED).setResolution(RESOLUTION_FIXED));
db.issues().insertIssue(rule, project, file, i -> i.setStatus(STATUS_CLOSED).setResolution(RESOLUTION_WONT_FIX));
.addImpact(new ImpactDto().setSoftwareQuality(SoftwareQuality.RELIABILITY).setSeverity(org.sonar.api.issue.impact.Severity.HIGH)));
IssueDto issue3 = db.issues().insertIssue(rule, project, file, i -> i
.addImpact(new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(org.sonar.api.issue.impact.Severity.MEDIUM))
- .addImpact(new ImpactDto().setSoftwareQuality(SoftwareQuality.RELIABILITY).setSeverity(org.sonar.api.issue.impact.Severity.LOW)));
+ .addImpact(new ImpactDto().setSoftwareQuality(SoftwareQuality.RELIABILITY).setSeverity(org.sonar.api.issue.impact.Severity.INFO)));
indexPermissionsAndIssues();
- Map<Common.SoftwareQuality, Common.ImpactSeverity> expectedImpacts = Map.of(Common.SoftwareQuality.SECURITY, Common.ImpactSeverity.MEDIUM,
- Common.SoftwareQuality.RELIABILITY, Common.ImpactSeverity.LOW,
+ Map<Common.SoftwareQuality, Common.ImpactSeverity> expectedImpacts = Map.of(Common.SoftwareQuality.SECURITY,
+ Common.ImpactSeverity.MEDIUM,
+ Common.SoftwareQuality.RELIABILITY, Common.ImpactSeverity.ImpactSeverity_INFO,
Common.SoftwareQuality.MAINTAINABILITY, Common.ImpactSeverity.HIGH);
SearchWsResponse response = ws.newRequest()
- .setParam(PARAM_IMPACT_SEVERITIES, org.sonar.api.issue.impact.Severity.LOW.name())
+ .setParam(PARAM_IMPACT_SEVERITIES, org.sonar.api.issue.impact.Severity.INFO.name())
.setParam(FACETS, PARAM_IMPACT_SOFTWARE_QUALITIES)
.executeProtobuf(SearchWsResponse.class);
new ImpactDto(SoftwareQuality.MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW),
new ImpactDto(SoftwareQuality.SECURITY, org.sonar.api.issue.impact.Severity.MEDIUM),
new ImpactDto(SoftwareQuality.RELIABILITY, org.sonar.api.issue.impact.Severity.LOW))));
+ IssueDto issue4 = db.issues().insertIssue(rule, project, file, i -> i.replaceAllImpacts(List.of(
+ new ImpactDto(SoftwareQuality.MAINTAINABILITY, org.sonar.api.issue.impact.Severity.INFO),
+ new ImpactDto(SoftwareQuality.SECURITY, org.sonar.api.issue.impact.Severity.BLOCKER))));
indexPermissionsAndIssues();
SearchWsResponse response = ws.newRequest()
assertThat(response.getIssuesList())
.extracting(Issue::getKey)
- .containsExactlyInAnyOrder(issue1.getKey(), issue2.getKey(), issue3.getKey());
+ .containsExactlyInAnyOrder(issue1.getKey(), issue2.getKey(), issue3.getKey(), issue4.getKey());
Optional<Common.Facet> first = response.getFacets().getFacetsList()
.stream().filter(facet -> facet.getProperty().equals(PARAM_IMPACT_SEVERITIES))
assertThat(first.get().getValuesList())
.extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
.containsExactlyInAnyOrder(
+ tuple("BLOCKER", 1L),
tuple("HIGH", 2L),
tuple("MEDIUM", 1L),
- tuple("LOW", 1L));
+ tuple("LOW", 1L),
+ tuple("INFO", 1L));
}
@Test
new ImpactDto(SoftwareQuality.RELIABILITY, org.sonar.api.issue.impact.Severity.HIGH))));
db.issues().insertIssue(rule, project, file, i -> i.replaceAllImpacts(List.of(
new ImpactDto(SoftwareQuality.RELIABILITY, org.sonar.api.issue.impact.Severity.HIGH))));
+ IssueDto issue2 = db.issues().insertIssue(rule, project, file, i -> i.replaceAllImpacts(List.of(
+ new ImpactDto(SoftwareQuality.SECURITY, org.sonar.api.issue.impact.Severity.BLOCKER))));
IssueDto issue3 = db.issues().insertIssue(rule, project, file, i -> i.replaceAllImpacts(List.of(
+ new ImpactDto(SoftwareQuality.SECURITY, org.sonar.api.issue.impact.Severity.BLOCKER))));
+ IssueDto issue4 = db.issues().insertIssue(rule, project, file, i -> i.replaceAllImpacts(List.of(
+ new ImpactDto(SoftwareQuality.SECURITY, org.sonar.api.issue.impact.Severity.INFO))));
+ IssueDto issue5 = db.issues().insertIssue(rule, project, file, i -> i.replaceAllImpacts(List.of(
new ImpactDto(SoftwareQuality.MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW),
new ImpactDto(SoftwareQuality.SECURITY, org.sonar.api.issue.impact.Severity.MEDIUM),
new ImpactDto(SoftwareQuality.RELIABILITY, org.sonar.api.issue.impact.Severity.LOW))));
assertThat(response.getIssuesList())
.extracting(Issue::getKey)
- .containsExactlyInAnyOrder(issue1.getKey(), issue3.getKey());
+ .containsExactlyInAnyOrder(issue1.getKey(), issue2.getKey(), issue3.getKey(), issue4.getKey(), issue5.getKey());
Optional<Common.Facet> first = response.getFacets().getFacetsList()
.stream().filter(facet -> facet.getProperty().equals(PARAM_IMPACT_SEVERITIES))
.containsExactlyInAnyOrder(
tuple("HIGH", 1L),
tuple("MEDIUM", 1L),
- tuple("LOW", 0L));
+ tuple("LOW", 0L),
+ tuple("INFO", 1L),
+ tuple("BLOCKER", 2L));
}
@Test
@Test
public void issue_on_removed_file() {
RuleDto rule = newIssueRule();
- ComponentDto project = db.components().insertPublicProject("PROJECT_ID", c -> c.setKey("PROJECT_KEY").setKey("PROJECT_KEY")).getMainBranchComponent();
+ ComponentDto project =
+ db.components().insertPublicProject("PROJECT_ID", c -> c.setKey("PROJECT_KEY").setKey("PROJECT_KEY")).getMainBranchComponent();
indexPermissions();
ComponentDto removedFile = db.components().insertComponent(newFileDto(project).setUuid("REMOVED_FILE_ID")
.setKey("REMOVED_FILE_KEY")
@Test
public void apply_paging_with_one_component() {
RuleDto rule = newIssueRule();
- ComponentDto project = db.components().insertPublicProject("PROJECT_ID", c -> c.setKey("PROJECT_KEY").setKey("PROJECT_KEY")).getMainBranchComponent();
+ ComponentDto project =
+ db.components().insertPublicProject("PROJECT_ID", c -> c.setKey("PROJECT_KEY").setKey("PROJECT_KEY")).getMainBranchComponent();
indexPermissions();
ComponentDto file = db.components().insertComponent(newFileDto(project, null, "FILE_ID").setKey("FILE_KEY"));
for (int i = 0; i < SearchOptions.MAX_PAGE_SIZE + 1; i++) {
public void filter_by_assigned_to_me() {
UserDto alice = db.users().insertUser(u -> u.setLogin("alice").setName("Alice").setEmail("alice@email.com"));
UserDto john = db.users().insertUser(u -> u.setLogin("john").setName("John").setEmail("john@email.com"));
- ComponentDto project = db.components().insertPublicProject(c -> c.setUuid("PROJECT_ID").setKey("PROJECT_KEY").setBranchUuid("PROJECT_ID")).getMainBranchComponent();
+ ComponentDto project = db.components().insertPublicProject(c -> c.setUuid("PROJECT_ID").setKey("PROJECT_KEY").setBranchUuid(
+ "PROJECT_ID")).getMainBranchComponent();
indexPermissions();
ComponentDto file = db.components().insertComponent(newFileDto(project, null, "FILE_ID").setKey("FILE_KEY"));
RuleDto rule = newIssueRule();
UserDto alice = db.users().insertUser(u -> u.setLogin("alice").setName("Alice").setEmail("alice@email.com"));
ComponentDto project = db.components().insertPublicProject("PROJECT_ID",
c -> c.setKey("PROJECT_KEY").setName("NAME_PROJECT_ID").setLongName("LONG_NAME_PROJECT_ID")).getMainBranchComponent();
- SnapshotDto snapshotDto = db.components().insertSnapshot(project, s -> s.setLast(true).setPeriodDate(parseDateTime("2014-09-05T00:00:00+0100").getTime()));
+ db.components().insertSnapshot(project, s -> s.setLast(true).setPeriodDate(parseDateTime("2014-09-05T00:00:00+0100").getTime()));
indexPermissions();
ComponentDto file = db.components().insertComponent(newFileDto(project, null, "FILE_ID").setKey("FILE_KEY"));
assertThat(ws.newRequest()
.setMultiParam("author", singletonList("unknown"))
.executeProtobuf(SearchWsResponse.class).getIssuesList())
- .isEmpty();
+ .isEmpty();
}
@Test
assertThat(parse.getAsJsonObject().get("issues").getAsJsonArray())
.extracting(o -> o.getAsJsonObject().get("key").getAsString())
- .containsExactly("82fd47d4-b650-4037-80bc-7b112bd4eac3", "82fd47d4-b650-4037-80bc-7b112bd4eac1", "82fd47d4-b650-4037-80bc-7b112bd4eac2");
+ .containsExactly("82fd47d4-b650-4037-80bc-7b112bd4eac3", "82fd47d4-b650-4037-80bc-7b112bd4eac1", "82fd47d4-b650-4037-80bc" +
+ "-7b112bd4eac2");
}
@Test
Consumer<RuleDto> ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
.setSecurityStandards(Sets.newHashSet("cwe:20", "owaspTop10:a1", "pciDss-3.2:6.5.3", "owaspAsvs-4.0:12.3.1"))
.setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
- Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25" +
+ "-insecure", "sql"));
RuleDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
RuleDto issueRule = db.rules().insertIssueRule(ruleConsumer);
- IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL));
indexPermissionsAndIssues();
public void only_vulnerabilities_are_returned_by_owaspAsvs40_with_level() {
ComponentDto project = db.components().insertPublicProject().getMainBranchComponent();
ComponentDto file = db.components().insertComponent(newFileDto(project));
- Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25" +
+ "-insecure", "sql"));
RuleDto issueRule1 = db.rules().insertIssueRule(r -> r.setSecurityStandards(Set.of("owaspAsvs-4.0:1.7.2", "owaspAsvs-4.0:12.3.1")));
RuleDto issueRule2 = db.rules().insertIssueRule(r -> r.setSecurityStandards(Set.of("owaspAsvs-4.0:2.2.5")));
RuleDto issueRule3 = db.rules().insertIssueRule(r -> r.setSecurityStandards(Set.of("owaspAsvs-4.0:2.2.5", "owaspAsvs-4.0:12.1.3")));
- IssueDto issueDto1 = db.issues().insertIssue(issueRule1, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto2 = db.issues().insertIssue(issueRule2, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto3 = db.issues().insertIssue(issueRule3, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule1, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto3 = db.issues().insertIssue(issueRule3, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
indexPermissionsAndIssues();
SearchWsResponse result = ws.newRequest()
Consumer<RuleDto> ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
.setSecurityStandards(Sets.newHashSet("cwe:20", "owaspTop10:a1", "pciDss-3.2:6.5.3", "pciDss-3.2:10.1"))
.setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
- Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25" +
+ "-insecure", "sql"));
RuleDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
RuleDto issueRule = db.rules().insertIssueRule(ruleConsumer);
- IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL));
indexPermissionsAndIssues();
Consumer<RuleDto> ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
.setSecurityStandards(Sets.newHashSet("cwe:20", "owaspTop10:a1", "pciDss-3.2:6.5.3", "pciDss-3.2:10.1"))
.setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
- Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25" +
+ "-insecure", "sql"));
RuleDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
RuleDto issueRule = db.rules().insertIssueRule(ruleConsumer);
- IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
// Rule 2
ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
issueRule = db.rules().insertIssueRule(ruleConsumer);
- IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto4 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto4 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
// Rule 3
ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
issueRule = db.rules().insertIssueRule(ruleConsumer);
- IssueDto issueDto5 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto6 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto5 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto6 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
indexPermissionsAndIssues();
assertThat(result.getIssuesList())
.extracting(Issue::getKey)
- .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey(), issueDto3.getKey(), issueDto4.getKey(), issueDto5.getKey(), issueDto6.getKey());
+ .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey(), issueDto3.getKey(), issueDto4.getKey(), issueDto5.getKey(),
+ issueDto6.getKey());
result = ws.newRequest()
.setParam("pciDss-3.2", "1")
assertThat(result.getIssuesList())
.extracting(Issue::getKey)
- .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey(), issueDto3.getKey(), issueDto4.getKey(), issueDto5.getKey(), issueDto6.getKey());
+ .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey(), issueDto3.getKey(), issueDto4.getKey(), issueDto5.getKey(),
+ issueDto6.getKey());
result = ws.newRequest()
.setParam("pciDss-3.2", "4")
Consumer<RuleDto> ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
.setSecurityStandards(Sets.newHashSet("cwe:20", "owaspTop10:a1", "pciDss-4.0:6.5.3", "pciDss-4.0:10.1"))
.setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
- Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25" +
+ "-insecure", "sql"));
RuleDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
RuleDto issueRule = db.rules().insertIssueRule(ruleConsumer);
- IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL));
indexPermissionsAndIssues();
Consumer<RuleDto> ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
.setSecurityStandards(Sets.newHashSet("cwe:20", "owaspTop10:a1", "pciDss-4.0:6.5.3", "pciDss-4.0:10.1"))
.setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
- Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25" +
+ "-insecure", "sql"));
RuleDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
RuleDto issueRule = db.rules().insertIssueRule(ruleConsumer);
- IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
// Rule 2
ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
issueRule = db.rules().insertIssueRule(ruleConsumer);
- IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto4 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto4 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
// Rule 3
ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
issueRule = db.rules().insertIssueRule(ruleConsumer);
- IssueDto issueDto5 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto6 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
indexPermissionsAndIssues();
Consumer<RuleDto> ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
.setSecurityStandards(Sets.newHashSet("cwe:20", "cwe:564", "cwe:89", "cwe:943", "owaspTop10:a1"))
.setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
- Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25" +
+ "-insecure", "sql"));
RuleDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
RuleDto issueRule = db.rules().insertIssueRule(ruleConsumer);
- IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL));
indexPermissionsAndIssues();
Consumer<RuleDto> ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
.setSecurityStandards(Sets.newHashSet("cwe:20", "cwe:564", "cwe:89", "cwe:943", "owaspTop10:a1", "owaspTop10-2021:a2"))
.setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
- Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25" +
+ "-insecure", "sql"));
RuleDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
RuleDto issueRule = db.rules().insertIssueRule(ruleConsumer);
- IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL));
indexPermissionsAndIssues();
Consumer<RuleDto> ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
.setSecurityStandards(Sets.newHashSet("cwe:20", "cwe:564", "cwe:89", "cwe:943", "owaspTop10:a1", "owaspTop10-2021:a2"))
.setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
- Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25" +
+ "-insecure", "sql"));
RuleDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
RuleDto issueRule = db.rules().insertIssueRule(ruleConsumer);
- IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL));
indexPermissionsAndIssues();
ComponentDto project = db.components().insertPublicProject().getMainBranchComponent();
ComponentDto file = db.components().insertComponent(newFileDto(project));
Consumer<RuleDto> ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
- .setSecurityStandards(Sets.newHashSet("cwe:20", "cwe:564", "stig-ASD_V5R3:V-222402", "stig-ASD_V5R3:V-222403", "stig-ASD_V5R3:V-222404", "ostig-ASD_V5R3:V-222405"))
+ .setSecurityStandards(Sets.newHashSet("cwe:20", "cwe:564", "stig-ASD_V5R3:V-222402", "stig-ASD_V5R3:V-222403", "stig-ASD_V5R3:V" +
+ "-222404", "ostig-ASD_V5R3:V-222405"))
.setSystemTags(Sets.newHashSet("bad-practice", "cwe", "stig", "sans-top25-insecure", "sql"));
- Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "stig", "sans-top25-insecure", "sql"));
+ Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "stig", "sans-top25-insecure",
+ "sql"));
RuleDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
RuleDto issueRule = db.rules().insertIssueRule(ruleConsumer);
- IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL));
indexPermissionsAndIssues();
RuleDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
RuleDto issueRule = db.rules().insertIssueRule(ruleConsumer);
- IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL));
indexPermissionsAndIssues();
RuleDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
RuleDto issueRule = db.rules().insertIssueRule(ruleConsumer);
- IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL));
indexPermissionsAndIssues();
RuleDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
RuleDto issueRule = db.rules().insertIssueRule(ruleConsumer);
- IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL));
indexPermissionsAndIssues();
indexPermissionsAndIssues();
SearchWsResponse result = ws.newRequest()
- .setParam("issues", Stream.of(bugIssue, vulnerabilityIssue, codeSmellIssue, hotspot).map(IssueDto::getKey).collect(Collectors.joining(",")))
+ .setParam("issues",
+ Stream.of(bugIssue, vulnerabilityIssue, codeSmellIssue, hotspot).map(IssueDto::getKey).collect(Collectors.joining(",")))
.executeProtobuf(SearchWsResponse.class);
assertThat(result.getIssuesList())
Consumer<RuleDto> ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
.setSecurityStandards(Sets.newHashSet("cwe:20", "cwe:564", "cwe:89", "cwe:943", "owaspTop10:a1"))
.setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
- Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25" +
+ "-insecure", "sql"));
RuleDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
RuleDto issueRule = db.rules().insertIssueRule(ruleConsumer);
- IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
- IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer,
+ issueDto -> issueDto.setType(RuleType.VULNERABILITY));
indexPermissions();
indexIssues();
ComponentDto file = db.components().insertComponent(newFileDto(project));
RuleDto issueRule = db.rules().insertIssueRule();
IssueDto bugIssue = db.issues().insertIssue(issueRule, project, file, i -> i.setType(RuleType.BUG).setSeverity(Severity.MAJOR.name()));
- IssueDto vulnerabilityIssue = db.issues().insertIssue(issueRule, project, file, i -> i.setType(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR.name()));
- IssueDto codeSmellIssue = db.issues().insertIssue(issueRule, project, file, i -> i.setType(CODE_SMELL).setSeverity(Severity.MAJOR.name()));
+ IssueDto vulnerabilityIssue = db.issues().insertIssue(issueRule, project, file,
+ i -> i.setType(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR.name()));
+ IssueDto codeSmellIssue = db.issues().insertIssue(issueRule, project, file,
+ i -> i.setType(CODE_SMELL).setSeverity(Severity.MAJOR.name()));
RuleDto hotspotRule = db.rules().insertHotspotRule();
db.issues().insertHotspot(hotspotRule, project, file, i -> i.setSeverity(Severity.MAJOR.name()));
indexPermissions();
assertThat(def.params()).extracting("key").containsExactlyInAnyOrder(
"additionalFields", "asc", "assigned", "assignees", "author", "components", "branch", "pullRequest", "createdAfter", "createdAt",
"createdBefore", "createdInLast", "directories", "facets", "files", "issues", "scopes", "languages", "onComponentOnly",
- "p", "projects", "ps", "resolutions", "resolved", "rules", "s", "severities", "statuses", "tags", "types", "pciDss-3.2", "pciDss-4.0", "owaspAsvs-4.0",
- "owaspAsvsLevel", "owaspTop10", "owaspTop10-2021", "stig-ASD_V5R3", "casa", "sansTop25", "cwe", "sonarsourceSecurity", "timeZone", "inNewCodePeriod", "codeVariants",
+ "p", "projects", "ps", "resolutions", "resolved", "rules", "s", "severities", "statuses", "tags", "types", "pciDss-3.2", "pciDss-4" +
+ ".0", "owaspAsvs-4.0",
+ "owaspAsvsLevel", "owaspTop10", "owaspTop10-2021", "stig-ASD_V5R3", "casa", "sansTop25", "cwe", "sonarsourceSecurity", "timeZone",
+ "inNewCodePeriod", "codeVariants",
"cleanCodeAttributeCategories", "impactSeverities", "impactSoftwareQualities", "issueStatuses", "fixedInPullRequest",
"prioritizedRule");
assertThat(branch.since()).isEqualTo("6.6");
WebService.Param projectUuids = def.param("projects");
- assertThat(projectUuids.description()).isEqualTo("To retrieve issues associated to a specific list of projects (comma-separated list of project keys). " +
- "This parameter is mostly used by the Issues page, please prefer usage of the componentKeys parameter. If this parameter is set, projectUuids must not be set.");
+ assertThat(projectUuids.description()).isEqualTo("To retrieve issues associated to a specific list of projects (comma-separated list " +
+ "of project keys). " +
+ "This parameter is mostly used by the Issues page, please prefer usage of the componentKeys parameter. If this parameter is set, " +
+ "projectUuids must not be set.");
}
@Test
private RuleDto newIssueRule(String ruleKey, Consumer<RuleDto> consumer) {
RuleDto rule = newRule(RuleKey.of("xoo", ruleKey),
createDefaultRuleDescriptionSection(uuidFactory.create(), "Rule desc"))
- .setLanguage("xoo")
- .setName("Rule name")
- .setStatus(RuleStatus.READY);
+ .setLanguage("xoo")
+ .setName("Rule name")
+ .setStatus(RuleStatus.READY);
consumer.accept(rule);
db.rules().insert(rule);
return rule;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbTester;
import org.sonar.db.rule.RuleDto;
+import org.sonar.server.common.rule.RuleCreator;
import org.sonar.server.common.rule.service.RuleService;
import org.sonar.server.common.text.MacroInterpreter;
import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.UnauthorizedException;
-import org.sonar.server.common.rule.RuleCreator;
import org.sonar.server.rule.RuleDescriptionFormatter;
import org.sonar.server.rule.index.RuleIndexer;
import org.sonar.server.tester.UserSessionRule;
.setParam("markdownDescription", "Description")
.setParam("status", "BETA")
.setParam("cleanCodeAttribute", "MODULAR")
- .setParam("impacts", "RELIABILITY=HIGH;SECURITY=LOW")
+ .setParam("impacts", "RELIABILITY=BLOCKER;SECURITY=INFO")
.execute().getInput();
String expectedResult = """
"repo": "java",
"name": "My custom rule",
"htmlDesc": "Description",
- "severity": "MINOR",
+ "severity": "INFO",
"status": "BETA",
"type": "VULNERABILITY",
"internalKey": "configKey_S001",
"impacts": [
{
"softwareQuality": "RELIABILITY",
- "severity": "HIGH"
+ "severity": "BLOCKER"
},
{
"softwareQuality": "SECURITY",
- "severity": "LOW"
+ "severity": "INFO"
}
]
}
db.rules().insert(
r -> r.replaceAllDefaultImpacts(List.of(new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.HIGH))));
db.rules().insert(
- r -> r.replaceAllDefaultImpacts(List.of(new ImpactDto().setSoftwareQuality(SoftwareQuality.RELIABILITY).setSeverity(Severity.MEDIUM))));
+ r -> r.replaceAllDefaultImpacts(List.of(new ImpactDto().setSoftwareQuality(SoftwareQuality.RELIABILITY).setSeverity(Severity.MEDIUM),
+ new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.INFO))));
indexRules();
SearchResponse result = ws.newRequest()
.setParam("impactSoftwareQualities", SoftwareQuality.MAINTAINABILITY.name())
.executeProtobuf(SearchResponse.class);
assertThat(result.getFacets().getFacets(0).getValuesList()).extracting(v -> entry(v.getVal(), v.getCount()))
- .contains(entry(Severity.HIGH.name(), 1L), entry(Severity.MEDIUM.name(), 0L), entry(Severity.LOW.name(), 0L));
+ .contains(entry(Severity.HIGH.name(), 1L), entry(Severity.MEDIUM.name(), 0L), entry(Severity.LOW.name(), 0L), entry(Severity.INFO.name(), 1L));
}
@Test
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 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.issue;
+
+import org.sonar.api.issue.impact.Severity;
+import org.sonarqube.ws.Common;
+
+public class ImpactFormatter {
+ private ImpactFormatter() {
+ }
+
+ public static Common.ImpactSeverity mapImpactSeverity(Severity severity) {
+ return switch (severity) {
+ case BLOCKER -> Common.ImpactSeverity.ImpactSeverity_BLOCKER;
+ case HIGH -> Common.ImpactSeverity.HIGH;
+ case MEDIUM -> Common.ImpactSeverity.MEDIUM;
+ case LOW -> Common.ImpactSeverity.LOW;
+ case INFO -> Common.ImpactSeverity.ImpactSeverity_INFO;
+ };
+ }
+}
import org.sonar.db.user.UserDto;
import org.sonar.markdown.Markdown;
import org.sonar.server.es.Facets;
+import org.sonar.server.issue.ImpactFormatter;
import org.sonar.server.issue.TextRangeResponseFormatter;
import org.sonar.server.issue.index.IssueScope;
import org.sonar.server.issue.workflow.Transition;
.stream()
.map(entry -> Common.Impact.newBuilder()
.setSoftwareQuality(Common.SoftwareQuality.valueOf(entry.getKey().name()))
- .setSeverity(Common.ImpactSeverity.valueOf(entry.getValue().name()))
+ .setSeverity(ImpactFormatter.mapImpactSeverity(entry.getValue()))
.build())
.toList());
import org.sonar.db.issue.IssueDto;
import org.sonar.db.protobuf.DbIssues;
import org.sonar.db.rule.RuleDto;
+import org.sonar.server.issue.ImpactFormatter;
import org.sonar.server.user.UserSession;
import org.sonar.server.ws.MessageFormattingUtils;
import org.sonarqube.ws.Common;
taintBuilder.addAllImpacts(issueDto.getEffectiveImpacts().entrySet()
.stream().map(entry -> Common.Impact.newBuilder()
.setSoftwareQuality(Common.SoftwareQuality.valueOf(entry.getKey().name()))
- .setSeverity(Common.ImpactSeverity.valueOf(entry.getValue().name()))
+ .setSeverity(ImpactFormatter.mapImpactSeverity(entry.getValue()))
.build())
.toList());
import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT;
-import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_DEBT_RATIO;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING;
import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT;
-import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING;
import static org.sonar.server.measure.Rating.RATING_BY_SEVERITY;
import static org.sonar.server.measure.Rating.RATING_BY_SOFTWARE_QUALITY_SEVERITY;
import static org.sonar.server.metric.IssueCountMetrics.PRIORITIZED_RULE_ISSUES;
-import static org.sonar.server.security.SecurityReviewRating.computeAToDRating;
import static org.sonar.server.security.SecurityReviewRating.computePercent;
import static org.sonar.server.security.SecurityReviewRating.computeRating;
asList(NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, CoreMetrics.NEW_DEVELOPMENT_COST)),
new MeasureUpdateFormula(SOFTWARE_QUALITY_MAINTAINABILITY_RATING, false, true,
- (context, issues) -> context.setValue(context.getDebtRatingGrid().getAToDRatingForDensity(debtDensity(SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, context))),
- (context, issues) -> context.setValue(context.getDebtRatingGrid().getAToDRatingForDensity(debtDensity(SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, context))),
+ (context, issues) -> context.setValue(context.getDebtRatingGrid().getRatingForDensity(debtDensity(SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, context))),
+ (context, issues) -> context.setValue(context.getDebtRatingGrid().getRatingForDensity(debtDensity(SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, context))),
asList(SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, CoreMetrics.DEVELOPMENT_COST)),
new MeasureUpdateFormula(NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING, true, true,
- (context, formula) -> context.setValue(context.getDebtRatingGrid().getAToDRatingForDensity(newDebtDensity(NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, context))),
- (context, issues) -> context.setValue(context.getDebtRatingGrid().getAToDRatingForDensity(newDebtDensity(NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, context))),
+ (context, formula) -> context.setValue(context.getDebtRatingGrid().getRatingForDensity(newDebtDensity(NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, context))),
+ (context, issues) -> context.setValue(context.getDebtRatingGrid().getRatingForDensity(newDebtDensity(NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, context))),
asList(NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, CoreMetrics.NEW_DEVELOPMENT_COST)),
new MeasureUpdateFormula(EFFORT_TO_REACH_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_A, false, true,
.map(RATING_BY_SOFTWARE_QUALITY_SEVERITY::get)
.orElse(Rating.A);
context.setValue(rating);
- }),
-
- new MeasureUpdateFormula(SOFTWARE_QUALITY_SECURITY_REVIEW_RATING, false, true,
- (context, formula) -> context.setValue(computeAToDRating(context.getValue(SECURITY_HOTSPOTS_REVIEWED).orElse(null))),
- (context, issues) -> {
- Optional<Double> percent = computePercent(issues.countHotspotsByStatus(Issue.STATUS_TO_REVIEW, false), issues.countHotspotsByStatus(Issue.STATUS_REVIEWED, false));
- context.setValue(computeAToDRating(percent.orElse(null)));
- }),
-
- new MeasureUpdateFormula(NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING, true, true,
- (context, formula) -> context.setValue(computeAToDRating(context.getValue(NEW_SECURITY_HOTSPOTS_REVIEWED).orElse(null))),
- (context, issues) -> {
- Optional<Double> percent = computePercent(issues.countHotspotsByStatus(Issue.STATUS_TO_REVIEW, true), issues.countHotspotsByStatus(Issue.STATUS_REVIEWED, true));
- context.setValue(computeAToDRating(percent.orElse(null)));
}));
private static final Set<Metric> FORMULA_METRICS = MeasureUpdateFormulaFactory.extractMetrics(FORMULAS);
SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING,
SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING,
SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING,
- SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING,
SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT,
SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT,
SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING,
SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING,
SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING,
- SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING,
SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT,
SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT)
import org.sonar.db.user.UserDto;
import org.sonar.markdown.Markdown;
import org.sonar.server.common.text.MacroInterpreter;
+import org.sonar.server.issue.ImpactFormatter;
import org.sonar.server.rule.RuleDescriptionFormatter;
import org.sonar.server.rule.ws.RulesResponseFormatter.SearchResult;
import org.sonarqube.ws.Common;
}
private static Common.Impact toImpact(ImpactDto impactDto) {
- Common.ImpactSeverity severity = Common.ImpactSeverity.valueOf(impactDto.getSeverity().name());
+ Common.ImpactSeverity severity = ImpactFormatter.mapImpactSeverity(impactDto.getSeverity());
Common.SoftwareQuality softwareQuality = Common.SoftwareQuality.valueOf(impactDto.getSoftwareQuality().name());
return Common.Impact.newBuilder().setSeverity(severity).setSoftwareQuality(softwareQuality).build();
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 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.issue;
+
+import org.junit.jupiter.api.Test;
+import org.sonar.api.issue.impact.Severity;
+import org.sonarqube.ws.Common;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class ImpactFormatterTest {
+
+ @Test
+ void mapImpactSeverity_shouldReturnExpectedValue() {
+ assertEquals(Common.ImpactSeverity.ImpactSeverity_BLOCKER, ImpactFormatter.mapImpactSeverity(Severity.BLOCKER));
+ assertEquals(Common.ImpactSeverity.HIGH, ImpactFormatter.mapImpactSeverity(Severity.HIGH));
+ assertEquals(Common.ImpactSeverity.MEDIUM, ImpactFormatter.mapImpactSeverity(Severity.MEDIUM));
+ assertEquals(Common.ImpactSeverity.LOW, ImpactFormatter.mapImpactSeverity(Severity.LOW));
+ assertEquals(Common.ImpactSeverity.ImpactSeverity_INFO, ImpactFormatter.mapImpactSeverity(Severity.INFO));
+ }
+}
import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.params.provider.Arguments.arguments;
+import static org.sonar.api.issue.impact.Severity.BLOCKER;
import static org.sonar.api.issue.impact.Severity.HIGH;
+import static org.sonar.api.issue.impact.Severity.INFO;
import static org.sonar.api.issue.impact.Severity.LOW;
import static org.sonar.api.issue.impact.Severity.MEDIUM;
import static org.sonar.api.issue.impact.SoftwareQuality.MAINTAINABILITY;
@Test
void computeHierarchy_shouldRecomputeSoftwareQualityMetricsCombiningOtherMetrics() {
- new HierarchyTester(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING)
- .withValue(SECURITY_HOTSPOTS_REVIEWED, 0d)
- .expectedRating(Rating.D);
- new HierarchyTester(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING)
- .withValue(NEW_SECURITY_HOTSPOTS_REVIEWED, 0d)
- .expectedRating(Rating.D);
new HierarchyTester(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_DEBT_RATIO)
.withValue(SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 10d)
.withValue(CoreMetrics.DEVELOPMENT_COST, "40")
.withValue(CoreMetrics.DEVELOPMENT_COST, "40")
.expectedRating(Rating.D);
+ new HierarchyTester(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING)
+ .withValue(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 21d)
+ .withValue(CoreMetrics.DEVELOPMENT_COST, "40")
+ .expectedRating(Rating.E);
+
+ new HierarchyTester(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING)
+ .withValue(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 1d)
+ .withValue(CoreMetrics.NEW_DEVELOPMENT_COST, 40d)
+ .expectedRating(Rating.A);
+
new HierarchyTester(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING)
.withValue(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 10d)
.withValue(CoreMetrics.NEW_DEVELOPMENT_COST, 40d)
.expectedRating(Rating.D);
+ new HierarchyTester(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING)
+ .withValue(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 21d)
+ .withValue(CoreMetrics.NEW_DEVELOPMENT_COST, 40d)
+ .expectedRating(Rating.E);
+
new HierarchyTester(SoftwareQualitiesMetrics.EFFORT_TO_REACH_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_A)
.withValue(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 10d)
.withValue(CoreMetrics.DEVELOPMENT_COST, "40")
newResolvedGroup(RuleType.BUG).setCount(7),
// not bugs
newGroup(RuleType.CODE_SMELL).setCount(11))
- .assertThatValueIs(CoreMetrics.BUGS, 3 + 5);
+ .assertThatValueIs(CoreMetrics.BUGS, 3 + 5);
}
@Test
newResolvedGroup(RuleType.CODE_SMELL).setCount(7),
// not code smells
newGroup(RuleType.BUG).setCount(11))
- .assertThatValueIs(CoreMetrics.CODE_SMELLS, 3 + 5);
+ .assertThatValueIs(CoreMetrics.CODE_SMELLS, 3 + 5);
}
@Test
newResolvedGroup(RuleType.VULNERABILITY).setCount(7),
// not vulnerabilities
newGroup(RuleType.BUG).setCount(11))
- .assertThatValueIs(CoreMetrics.VULNERABILITIES, 3 + 5);
+ .assertThatValueIs(CoreMetrics.VULNERABILITIES, 3 + 5);
}
@Test
newResolvedGroup(RuleType.SECURITY_HOTSPOT).setCount(7),
// not hotspots
newGroup(RuleType.BUG).setCount(11))
- .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS, 3 + 5);
+ .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS, 3 + 5);
}
@Test
with(
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
- .assertThatValueIs(SECURITY_REVIEW_RATING, Rating.B)
- .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING, Rating.B);
+ .assertThatValueIs(SECURITY_REVIEW_RATING, Rating.B);
withNoIssues()
- .assertThatValueIs(SECURITY_REVIEW_RATING, Rating.A)
- .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING, Rating.A);
+ .assertThatValueIs(SECURITY_REVIEW_RATING, Rating.A);
with(
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(3).setInLeak(true),
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true))
- .assertThatValueIs(SECURITY_REVIEW_RATING, Rating.E)
- .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING, Rating.D);
+ .assertThatValueIs(SECURITY_REVIEW_RATING, Rating.E);
}
@Test
with(
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
- .assertThatValueIs(SECURITY_HOTSPOTS_REVIEWED, 75.0);
+ .assertThatValueIs(SECURITY_HOTSPOTS_REVIEWED, 75.0);
withNoIssues()
.assertNoValue(SECURITY_HOTSPOTS_REVIEWED);
with(
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
- .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS, 3.0);
+ .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS, 3.0);
withNoIssues()
.assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS, 0.0);
with(
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
- .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1.0);
+ .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1.0);
withNoIssues()
.assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 0.0);
newResolvedGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setCount(17),
newResolvedGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(19),
newResolvedGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.INFO).setCount(21))
- .assertThatValueIs(CoreMetrics.BLOCKER_VIOLATIONS, 11 + 13)
- .assertThatValueIs(CoreMetrics.CRITICAL_VIOLATIONS, 7)
- .assertThatValueIs(CoreMetrics.MAJOR_VIOLATIONS, 3 + 5)
- .assertThatValueIs(CoreMetrics.MINOR_VIOLATIONS, 0)
- .assertThatValueIs(CoreMetrics.INFO_VIOLATIONS, 0);
+ .assertThatValueIs(CoreMetrics.BLOCKER_VIOLATIONS, 11 + 13)
+ .assertThatValueIs(CoreMetrics.CRITICAL_VIOLATIONS, 7)
+ .assertThatValueIs(CoreMetrics.MAJOR_VIOLATIONS, 3 + 5)
+ .assertThatValueIs(CoreMetrics.MINOR_VIOLATIONS, 0)
+ .assertThatValueIs(CoreMetrics.INFO_VIOLATIONS, 0);
}
@Test
// exclude unresolved
newGroup(RuleType.VULNERABILITY).setCount(17),
newGroup(RuleType.BUG).setCount(19))
- .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 5)
- .assertThatValueIs(CoreMetrics.ACCEPTED_ISSUES, 7 + 11);
+ .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 5)
+ .assertThatValueIs(CoreMetrics.ACCEPTED_ISSUES, 7 + 11);
}
@Test
// exclude security hotspot
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_OPEN).setCount(12),
newResolvedGroup(Issue.RESOLUTION_FALSE_POSITIVE, Issue.STATUS_CLOSED).setCount(13))
- .assertThatValueIs(CoreMetrics.CONFIRMED_ISSUES, 3 + 5)
- .assertThatValueIs(CoreMetrics.OPEN_ISSUES, 9 + 11)
- .assertThatValueIs(CoreMetrics.REOPENED_ISSUES, 7);
+ .assertThatValueIs(CoreMetrics.CONFIRMED_ISSUES, 3 + 5)
+ .assertThatValueIs(CoreMetrics.OPEN_ISSUES, 9 + 11)
+ .assertThatValueIs(CoreMetrics.REOPENED_ISSUES, 7);
}
@Test
newGroup(RuleType.BUG).setEffort(7.0),
// exclude resolved
newResolvedGroup(RuleType.CODE_SMELL).setEffort(17.0))
- .assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 3.0 + 5.0);
+ .assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 3.0 + 5.0);
}
@Test
newGroup(RuleType.CODE_SMELL).setEffort(7.0),
// exclude resolved
newResolvedGroup(RuleType.BUG).setEffort(17.0))
- .assertThatValueIs(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, 3.0 + 5.0);
+ .assertThatValueIs(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, 3.0 + 5.0);
}
@Test
newGroup(RuleType.CODE_SMELL).setEffort(7.0),
// exclude resolved
newResolvedGroup(RuleType.VULNERABILITY).setEffort(17.0))
- .assertThatValueIs(CoreMetrics.SECURITY_REMEDIATION_EFFORT, 3.0 + 5.0);
+ .assertThatValueIs(CoreMetrics.SECURITY_REMEDIATION_EFFORT, 3.0 + 5.0);
}
private static Stream<Arguments> maintainabilityMetrics() {
return Stream.of(
arguments(TECHNICAL_DEBT, SQALE_DEBT_RATIO, SQALE_RATING),
- arguments(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_DEBT_RATIO,
+ arguments(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
+ SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_DEBT_RATIO,
SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING));
}
@ParameterizedTest
@MethodSource("maintainabilityMetrics")
- void test_sqale_debt_ratio_and_sqale_rating(Metric<?> maintainabilityRemediationEffortMetric, Metric<?> maintainabilityDebtRatioMetric, Metric<?> maintainabilityRatingMetric) {
+ void test_sqale_debt_ratio_and_sqale_rating(Metric<?> maintainabilityRemediationEffortMetric, Metric<?> maintainabilityDebtRatioMetric,
+ Metric<?> maintainabilityRatingMetric) {
withNoIssues()
.assertThatValueIs(maintainabilityDebtRatioMetric, 0)
.assertThatValueIs(maintainabilityRatingMetric, Rating.A);
.andText(CoreMetrics.DEVELOPMENT_COST, "10")
.assertThatValueIs(maintainabilityDebtRatioMetric, 200.0);
switch (maintainabilityRatingMetric.key()) {
- case SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY -> verifier.assertThatValueIs(maintainabilityRatingMetric, Rating.D);
- case SQALE_RATING_KEY -> verifier.assertThatValueIs(maintainabilityRatingMetric, Rating.E);
+ case SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY, SQALE_RATING_KEY ->
+ verifier.assertThatValueIs(maintainabilityRatingMetric, Rating.E);
default -> throw new IllegalArgumentException("Unexpected metric: " + maintainabilityRatingMetric.key());
}
newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setCount(5),
// excluded, not a bug
newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(3))
- // highest severity of bugs is CRITICAL --> D
- .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.D);
+ // highest severity of bugs is CRITICAL --> D
+ .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.D);
with(
newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(5))
- // no bugs --> A
- .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.A);
+ // no bugs --> A
+ .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.A);
}
@Test
withNoIssues()
.assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.A);
+ with(
+ newImpactGroup(RELIABILITY, BLOCKER, 1))
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.E);
+
+ with(
+ newImpactGroup(RELIABILITY, HIGH, 1))
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.D);
+
with(
newImpactGroup(MAINTAINABILITY, HIGH, 1),
newImpactGroup(RELIABILITY, MEDIUM, 1),
newImpactGroup(RELIABILITY, LOW, 1),
newImpactGroup(SECURITY, MEDIUM, 1))
- .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.C);
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.C);
with(
newImpactGroup(RELIABILITY, LOW, 1))
- .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.B);
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.B);
+
+ with(
+ newImpactGroup(RELIABILITY, INFO, 1))
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.A);
}
@Test
withNoIssues()
.assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.A);
+ with(
+ newImpactGroup(RELIABILITY, BLOCKER, 1, true))
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.E);
+
+ with(
+ newImpactGroup(RELIABILITY, HIGH, 1, true),
+ newImpactGroup(RELIABILITY, BLOCKER, 1, false))
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.D);
+
with(
newImpactGroup(MAINTAINABILITY, HIGH, 1, true),
newImpactGroup(RELIABILITY, MEDIUM, 1, true),
newImpactGroup(RELIABILITY, LOW, 1, true),
newImpactGroup(RELIABILITY, HIGH, 1, false),
newImpactGroup(SECURITY, HIGH, 1, true))
- .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.C);
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.C);
with(
newImpactGroup(RELIABILITY, LOW, 1, true),
newImpactGroup(RELIABILITY, MEDIUM, 1, false))
- .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.B);
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.B);
+
+ with(
+ newImpactGroup(RELIABILITY, INFO, 1, true),
+ newImpactGroup(RELIABILITY, MEDIUM, 1, false))
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.A);
}
@Test
newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setCount(5),
// excluded, not a vulnerability
newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(3))
- // highest severity of vulnerabilities is CRITICAL --> D
- .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.D);
+ // highest severity of vulnerabilities is CRITICAL --> D
+ .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.D);
with(
newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(5))
- // no vulnerabilities --> A
- .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.A);
+ // no vulnerabilities --> A
+ .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.A);
}
@Test
withNoIssues()
.assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.A);
+ with(
+ newImpactGroup(SECURITY, BLOCKER, 1))
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.E);
+
+ with(
+ newImpactGroup(SECURITY, HIGH, 1))
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.D);
+
with(
newImpactGroup(MAINTAINABILITY, HIGH, 1),
newImpactGroup(SECURITY, MEDIUM, 1),
newImpactGroup(SECURITY, LOW, 1),
newImpactGroup(RELIABILITY, MEDIUM, 1))
- .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.C);
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.C);
with(
newImpactGroup(SECURITY, LOW, 1))
- .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.B);
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.B);
+
+ with(
+ newImpactGroup(SECURITY, INFO, 2))
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.A);
}
@Test
withNoIssues()
.assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.A);
+ with(
+ newImpactGroup(SECURITY, BLOCKER, 1, true))
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.E);
+
+ with(
+ newImpactGroup(SECURITY, HIGH, 1, true),
+ newImpactGroup(SECURITY, BLOCKER, 1, false))
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.D);
+
with(
newImpactGroup(MAINTAINABILITY, HIGH, 1, true),
newImpactGroup(SECURITY, MEDIUM, 1, true),
newImpactGroup(SECURITY, LOW, 1, true),
newImpactGroup(SECURITY, HIGH, 1, false),
newImpactGroup(RELIABILITY, HIGH, 1, true))
- .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.C);
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.C);
with(
newImpactGroup(SECURITY, LOW, 1, true),
newImpactGroup(SECURITY, MEDIUM, 1, false))
- .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.B);
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.B);
+
+ with(
+ newImpactGroup(SECURITY, INFO, 1, true),
+ newImpactGroup(SECURITY, MEDIUM, 1, false))
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.A);
}
@Test
// not bugs
newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(9),
newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(11))
- .assertThatLeakValueIs(CoreMetrics.NEW_BUGS, 5 + 7);
+ .assertThatLeakValueIs(CoreMetrics.NEW_BUGS, 5 + 7);
}
// not code smells
newGroup(RuleType.BUG).setInLeak(true).setCount(9),
newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(11))
- .assertThatLeakValueIs(CoreMetrics.NEW_CODE_SMELLS, 5 + 7);
+ .assertThatLeakValueIs(CoreMetrics.NEW_CODE_SMELLS, 5 + 7);
}
@Test
// not vulnerabilities
newGroup(RuleType.BUG).setInLeak(true).setCount(9),
newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(11))
- .assertThatLeakValueIs(CoreMetrics.NEW_VULNERABILITIES, 5 + 7);
+ .assertThatLeakValueIs(CoreMetrics.NEW_VULNERABILITIES, 5 + 7);
}
@Test
// not hotspots
newGroup(RuleType.BUG).setInLeak(true).setCount(9),
newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(11))
- .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS, 5 + 7);
+ .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS, 5 + 7);
}
@Test
newGroup(RuleType.BUG).setInLeak(false).setCount(11),
newGroup(RuleType.CODE_SMELL).setInLeak(false).setCount(13),
newGroup(RuleType.VULNERABILITY).setInLeak(false).setCount(17))
- .assertThatLeakValueIs(CoreMetrics.NEW_VIOLATIONS, 5 + 7 + 9);
+ .assertThatLeakValueIs(CoreMetrics.NEW_VIOLATIONS, 5 + 7 + 9);
}
@Test
// not in leak
newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(false).setCount(11),
newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(false).setCount(13))
- .assertThatLeakValueIs(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 3 + 5 + 7);
+ .assertThatLeakValueIs(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 3 + 5 + 7);
}
@Test
// not in leak
newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(false).setCount(11),
newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setInLeak(false).setCount(13))
- .assertThatLeakValueIs(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 3 + 5 + 7);
+ .assertThatLeakValueIs(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 3 + 5 + 7);
}
@Test
// not in leak
newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(false).setCount(11),
newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setInLeak(false).setCount(13))
- .assertThatLeakValueIs(CoreMetrics.NEW_MAJOR_VIOLATIONS, 3 + 5 + 7);
+ .assertThatLeakValueIs(CoreMetrics.NEW_MAJOR_VIOLATIONS, 3 + 5 + 7);
}
@Test
// not in leak
newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MINOR).setInLeak(false).setCount(11),
newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setInLeak(false).setCount(13))
- .assertThatLeakValueIs(CoreMetrics.NEW_MINOR_VIOLATIONS, 3 + 5 + 7);
+ .assertThatLeakValueIs(CoreMetrics.NEW_MINOR_VIOLATIONS, 3 + 5 + 7);
}
@Test
// not in leak
newGroup(RuleType.CODE_SMELL).setSeverity(Severity.INFO).setInLeak(false).setCount(11),
newGroup(RuleType.BUG).setSeverity(Severity.INFO).setInLeak(false).setCount(13))
- .assertThatLeakValueIs(CoreMetrics.NEW_INFO_VIOLATIONS, 3 + 5 + 7);
+ .assertThatLeakValueIs(CoreMetrics.NEW_INFO_VIOLATIONS, 3 + 5 + 7);
}
@Test
// not in leak
newGroup(RuleType.CODE_SMELL).setResolution(Issue.RESOLUTION_WONT_FIX).setInLeak(false).setCount(5),
newGroup(RuleType.BUG).setResolution(Issue.RESOLUTION_WONT_FIX).setInLeak(false).setCount(50))
- .assertThatLeakValueIs(CoreMetrics.NEW_ACCEPTED_ISSUES, 4 + 40);
+ .assertThatLeakValueIs(CoreMetrics.NEW_ACCEPTED_ISSUES, 4 + 40);
}
@Test
newGroup(RuleType.BUG).setEffort(7.0).setInLeak(true),
// exclude resolved
newResolvedGroup(RuleType.CODE_SMELL).setEffort(17.0).setInLeak(true))
- .assertThatLeakValueIs(CoreMetrics.NEW_TECHNICAL_DEBT, 3.0);
+ .assertThatLeakValueIs(CoreMetrics.NEW_TECHNICAL_DEBT, 3.0);
}
@Test
newGroup(RuleType.CODE_SMELL).setEffort(7.0).setInLeak(true),
// exclude resolved
newResolvedGroup(RuleType.BUG).setEffort(17.0).setInLeak(true))
- .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, 3.0);
+ .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, 3.0);
}
@Test
newGroup(RuleType.CODE_SMELL).setEffort(7.0).setInLeak(true),
// exclude resolved
newResolvedGroup(RuleType.VULNERABILITY).setEffort(17.0).setInLeak(true))
- .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, 3.0);
+ .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, 3.0);
}
@Test
newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true),
// exclude resolved
newResolvedGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(true))
- // highest severity of bugs on leak period is minor -> B
- .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_RATING, Rating.B);
+ // highest severity of bugs on leak period is minor -> B
+ .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_RATING, Rating.B);
}
@Test
newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true),
// exclude resolved
newResolvedGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(true))
- // highest severity of bugs on leak period is minor -> B
- .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_RATING, Rating.B);
+ // highest severity of bugs on leak period is minor -> B
+ .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_RATING, Rating.B);
}
@Test
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
// not in leak
newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Issue.STATUS_TO_REVIEW).setInLeak(false))
- .assertThatLeakValueIs(NEW_SECURITY_REVIEW_RATING, Rating.B)
- .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING, Rating.B);
+ .assertThatLeakValueIs(NEW_SECURITY_REVIEW_RATING, Rating.B);
withNoIssues()
- .assertThatLeakValueIs(NEW_SECURITY_REVIEW_RATING, Rating.A)
- .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING, Rating.A);
+ .assertThatLeakValueIs(NEW_SECURITY_REVIEW_RATING, Rating.A);
with(
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(3).setInLeak(true),
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
// not in leak
newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Issue.STATUS_TO_REVIEW).setInLeak(false))
- .assertThatLeakValueIs(NEW_SECURITY_REVIEW_RATING, Rating.E)
- .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING, Rating.D);
+ .assertThatLeakValueIs(NEW_SECURITY_REVIEW_RATING, Rating.E);
}
@Test
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
// not in leak
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(5).setInLeak(false))
- .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED, 75.0);
+ .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED, 75.0);
withNoIssues()
.assertNoLeakValue(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED);
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
// not in leak
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(5).setInLeak(false))
- .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 3.0);
+ .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 3.0);
withNoIssues()
.assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 0.0);
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
// not in leak
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(5).setInLeak(false))
- .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1.0);
+ .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1.0);
withNoIssues()
.assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 0.0);
private static Stream<Arguments> newMaintainabilityMetrics() {
return Stream.of(
arguments(CoreMetrics.NEW_TECHNICAL_DEBT, CoreMetrics.NEW_SQALE_DEBT_RATIO, CoreMetrics.NEW_MAINTAINABILITY_RATING),
- arguments(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_DEBT_RATIO,
+ arguments(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
+ SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_DEBT_RATIO,
SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING));
}
@ParameterizedTest
@MethodSource("newMaintainabilityMetrics")
- void test_new_sqale_debt_ratio_and_new_maintainability_rating(Metric<?> newMaintainabilityRemediationEffortMetric, Metric<?> newMaintainabilityDebtRatioMetric,
+ void test_new_sqale_debt_ratio_and_new_maintainability_rating(Metric<?> newMaintainabilityRemediationEffortMetric,
+ Metric<?> newMaintainabilityDebtRatioMetric,
Metric<?> newMaintainabilityRatingMetric) {
withNoIssues()
.assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0)
.and(CoreMetrics.NEW_DEVELOPMENT_COST, 10.0D)
.assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 200.0);
switch (newMaintainabilityRatingMetric.key()) {
- case NEW_MAINTAINABILITY_RATING_KEY -> verifier.assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.E);
- case SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY -> verifier.assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.D);
+ case NEW_MAINTAINABILITY_RATING_KEY, SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY ->
+ verifier.assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.E);
default -> throw new IllegalArgumentException("Unexpected metric: " + newMaintainabilityRatingMetric.key());
}
newImpactGroup(SECURITY, LOW, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 6),
newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_FALSE_POSITIVE, 7),
newImpactGroup(RELIABILITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8))
- .assertThatValueIs(CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES, 4 + 8);
+ .assertThatValueIs(CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES, 4 + 8);
}
@Test
newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 4, 1d, false),
newImpactGroup(RELIABILITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8, 1d, false),
newImpactGroup(MAINTAINABILITY, MEDIUM, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8, 1d, false))
- .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 1d + 2d)
- .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT, 1d + 2d)
- .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT, 1d)
- .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 2d)
- .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT, 2d)
- .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT, 0d);
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 1d + 2d)
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT, 1d + 2d)
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT, 1d)
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 2d)
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT, 2d)
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT, 0d);
}
@Test
newImpactGroup(MAINTAINABILITY, MEDIUM, 10),
newImpactGroup(MAINTAINABILITY, LOW, 11),
newImpactGroup(SECURITY, HIGH, 3))
- .assertThatJsonValueIs(CoreMetrics.RELIABILITY_ISSUES, impactMeasureToJson(8, 3, 4, 1))
- .assertThatJsonValueIs(CoreMetrics.MAINTAINABILITY_ISSUES, impactMeasureToJson(21, 0, 10, 11))
- .assertThatJsonValueIs(CoreMetrics.SECURITY_ISSUES, impactMeasureToJson(3, 3, 0, 0));
+ .assertThatJsonValueIs(CoreMetrics.RELIABILITY_ISSUES, impactMeasureToJson(8, 3, 4, 1))
+ .assertThatJsonValueIs(CoreMetrics.MAINTAINABILITY_ISSUES, impactMeasureToJson(21, 0, 10, 11))
+ .assertThatJsonValueIs(CoreMetrics.SECURITY_ISSUES, impactMeasureToJson(3, 3, 0, 0));
}
@Test
return newImpactGroup(softwareQuality, severity, status, resolution, count, 0, false);
}
- private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity, long count) {
+ private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
+ long count) {
return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count, 0, false);
}
- private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity, long count, boolean inLeak) {
+ private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
+ long count, boolean inLeak) {
return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count, 0, inLeak);
}
- private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity, long count, double effort) {
+ private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
+ long count, double effort) {
return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count, effort, false);
}
- private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity, long count, double effort, boolean inLeak) {
+ private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
+ long count, double effort, boolean inLeak) {
return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count, effort, inLeak);
}
@Override
public DebtRatingGrid getDebtRatingGrid() {
- return new DebtRatingGrid(new double[] {0.05, 0.1, 0.2, 0.5});
+ return new DebtRatingGrid(new double[]{0.05, 0.1, 0.2, 0.5});
}
@Override
return this;
}
- public HierarchyTester withChildrenHotspotsCounts(long childrenHotspotsReviewed, long childrenNewHotspotsReviewed, long childrenHotspotsToReview,
+ public HierarchyTester withChildrenHotspotsCounts(long childrenHotspotsReviewed, long childrenNewHotspotsReviewed,
+ long childrenHotspotsToReview,
long childrenNewHotspotsToReview) {
this.initialValues.childrenHotspotsReviewed = childrenHotspotsReviewed;
this.initialValues.childrenNewHotspotsReviewed = childrenNewHotspotsReviewed;
public void getNewMetricsInSonarQube107_shouldReturnExactString() {
String actual = MeasuresWsModule.getNewMetricsInSonarQube107();
assertThat(actual).isEqualTo("'software_quality_maintainability_debt_ratio', 'software_quality_maintainability_rating', 'software_quality_reliability_rating', " +
- "'software_quality_security_rating', 'software_quality_security_review_rating', 'software_quality_maintainability_remediation_effort', " +
+ "'software_quality_security_rating', 'software_quality_maintainability_remediation_effort', " +
"'software_quality_reliability_remediation_effort', 'software_quality_security_remediation_effort', 'effort_to_reach_software_quality_maintainability_rating_a', " +
"'new_software_quality_maintainability_debt_ratio', 'new_software_quality_maintainability_rating', 'new_software_quality_reliability_rating', " +
- "'new_software_quality_security_rating', 'new_software_quality_security_review_rating', 'new_software_quality_maintainability_remediation_effort'," +
+ "'new_software_quality_security_rating', 'new_software_quality_maintainability_remediation_effort'," +
" 'new_software_quality_reliability_remediation_effort', 'new_software_quality_security_remediation_effort'");
}
}
import static org.sonar.api.measures.CoreMetrics.DOMAIN_MAINTAINABILITY;
import static org.sonar.api.measures.CoreMetrics.DOMAIN_RELIABILITY;
import static org.sonar.api.measures.CoreMetrics.DOMAIN_SECURITY;
-import static org.sonar.api.measures.CoreMetrics.DOMAIN_SECURITY_REVIEW;
public class SoftwareQualitiesMetrics implements Metrics {
.setDirection(Metric.DIRECTION_WORST)
.setQualitative(true)
.setBestValue(1.0)
- .setWorstValue(4.0)
+ .setWorstValue(5.0)
.create();
public static final String NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY = "new_software_quality_maintainability_rating";
.setOptimizedBestValue(true)
.setQualitative(true)
.setBestValue(1.0)
- .setWorstValue(4.0)
+ .setWorstValue(5.0)
.create();
public static final String SOFTWARE_QUALITY_RELIABILITY_RATING_KEY = "software_quality_reliability_rating";
.setDirection(Metric.DIRECTION_WORST)
.setQualitative(true)
.setBestValue(1.0)
- .setWorstValue(4.0)
+ .setWorstValue(5.0)
.create();
public static final String NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY = "new_software_quality_reliability_rating";
.setOptimizedBestValue(true)
.setQualitative(true)
.setBestValue(1.0)
- .setWorstValue(4.0)
+ .setWorstValue(5.0)
.create();
public static final String SOFTWARE_QUALITY_SECURITY_RATING_KEY = "software_quality_security_rating";
.setDirection(Metric.DIRECTION_WORST)
.setQualitative(true)
.setBestValue(1.0)
- .setWorstValue(4.0)
+ .setWorstValue(5.0)
.create();
public static final String NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY = "new_software_quality_security_rating";
.setOptimizedBestValue(true)
.setQualitative(true)
.setBestValue(1.0)
- .setWorstValue(4.0)
+ .setWorstValue(5.0)
.create();
- public static final String SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY = "software_quality_security_review_rating";
-
- public static final Metric<Integer> SOFTWARE_QUALITY_SECURITY_REVIEW_RATING =
- new Metric.Builder(SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY, "Software Quality Security Review Rating", Metric.ValueType.RATING)
- .setDescription("Software quality security review rating")
- .setDomain(DOMAIN_SECURITY_REVIEW)
- .setDirection(Metric.DIRECTION_WORST)
- .setQualitative(true)
- .setBestValue(1.0)
- .setWorstValue(4.0)
- .create();
-
- public static final String NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY = "new_software_quality_security_review_rating";
-
- public static final Metric<Integer> NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING =
- new Metric.Builder(NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING_KEY, "Software Quality Security Review Rating on New Code",
- Metric.ValueType.RATING)
- .setDescription("Software quality security review rating on new code")
- .setDomain(DOMAIN_SECURITY_REVIEW)
- .setDirection(Metric.DIRECTION_WORST)
- .setDeleteHistoricalData(true)
- .setOptimizedBestValue(true)
- .setQualitative(true)
- .setBestValue(1.0)
- .setWorstValue(4.0)
- .create();
-
public static final String EFFORT_TO_REACH_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_A_KEY =
"effort_to_reach_software_quality_maintainability_rating_a";
NEW_SOFTWARE_QUALITY_RELIABILITY_RATING,
SOFTWARE_QUALITY_SECURITY_RATING,
NEW_SOFTWARE_QUALITY_SECURITY_RATING,
- SOFTWARE_QUALITY_SECURITY_REVIEW_RATING,
- NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING,
EFFORT_TO_REACH_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_A,
SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
writer.value((String) value);
break;
case ENUM:
- writer.value(((Descriptors.EnumValueDescriptor) value).getName());
+ String enumValue = formatEnumValue(fieldDescriptor, (Descriptors.EnumValueDescriptor) value);
+ writer.value(enumValue);
break;
case MESSAGE:
writeMessageValue((Message) value, writer);
}
}
+ /**
+ * As a limitation from protobuf, there can't be the same enum value defined twice in proto, even if they belong to different enums.
+ * To remove this constraint, we let the possibility to have the enum name as the prefix of the enum value to make it unique.
+ * The class will make sure to remove it when converted to JSON.
+ * @see <a href="https://github.com/protocolbuffers/protobuf/issues/5425">https://github.com/protocolbuffers/protobuf/issues/5425</a>
+ */
+ private static String formatEnumValue(Descriptors.FieldDescriptor fieldDescriptor, Descriptors.EnumValueDescriptor value) {
+ String enumValue = value.getName();
+ if (enumValue.startsWith(fieldDescriptor.getEnumType().getName())) {
+ enumValue = enumValue.substring(fieldDescriptor.getEnumType().getName().length() + 1);
+ }
+ return enumValue;
+ }
+
private static void writeMessageValue(Message message, JsonWriter writer) {
MessageType messageType = MessageType.of(message);
if (messageType.doesWrapRepeated) {
issues.facet.createdAt.bar_description={0} issues from {1} to {2}
issues.facet.authors=Author
issues.facet.impactSeverities=Severity
-issues.facet.impactSeverities.help.line1=Severities are now directly tied to the software quality impacted. This means that one software quality impacted has one severity.
-issues.facet.impactSeverities.help.line2=There are only three levels: high, medium, and low.
issues.facet.issues=Issue Key
issues.facet.mode=Display Mode
issues.facet.mode.count=Issues
projects.facets.quality_gate=Quality Gate
projects.facets.quality_gate.warning_help=Warning status is deprecated. This filter will disappear when no Warning Quality Gate remains.
projects.facets.rating_x={0} rating
-projects.facets.rating_option.reliability.1=0 issues
+projects.facets.rating_option.reliability.legacy.1=≥ 0 info issues
+projects.facets.rating_option.reliability.legacy.2=≥ 1 minor issue
+projects.facets.rating_option.reliability.legacy.3=≥ 1 major issue
+projects.facets.rating_option.reliability.legacy.4=≥ 1 critical issue
+projects.facets.rating_option.reliability.legacy.5=≥ 1 blocker issue
+projects.facets.rating_option.reliability.1=≥ 0 info issues
projects.facets.rating_option.reliability.2=≥ 1 low issue
projects.facets.rating_option.reliability.3=≥ 1 medium issue
projects.facets.rating_option.reliability.4=≥ 1 high issue
-projects.facets.rating_option.security.1=0 issues
+projects.facets.rating_option.reliability.5=≥ 1 blocker issue
+projects.facets.rating_option.security.legacy.1=≥ 0 info issues
+projects.facets.rating_option.security.legacy.2=≥ 1 minor issue
+projects.facets.rating_option.security.legacy.3=≥ 1 major issue
+projects.facets.rating_option.security.legacy.4=≥ 1 critical issue
+projects.facets.rating_option.security.legacy.5=≥ 1 blocker issue
+projects.facets.rating_option.security.1=≥ 0 info issues
projects.facets.rating_option.security.2=≥ 1 low issue
projects.facets.rating_option.security.3=≥ 1 medium issue
projects.facets.rating_option.security.4=≥ 1 high issue
+projects.facets.rating_option.security.5=≥ 1 blocker issue
projects.facets.rating_option.maintainability.1=≤ 5% to 0%
projects.facets.rating_option.maintainability.2=≥ 5% to <10%
projects.facets.rating_option.maintainability.3=≥ 10% to <20%
-projects.facets.rating_option.maintainability.4=≥ 20%
-projects.facets.rating_option.security_review.1== 100%
-projects.facets.rating_option.security_review.2=≥ 70% to <100%
+projects.facets.rating_option.maintainability.4=≥ 20% to <50%
+projects.facets.rating_option.maintainability.5=≥ 50%
+projects.facets.rating_option.security_review.1=≥ 80%
+projects.facets.rating_option.security_review.2=≥ 70% to <80%
projects.facets.rating_option.security_review.3=≥ 50% to <70%
-projects.facets.rating_option.security_review.4=< 50%
+projects.facets.rating_option.security_review.4=≥ 30% to <50%
+projects.facets.rating_option.security_review.5=< 30%
projects.facets.security_review.description=The percentage of reviewed (fixed or safe) security hotspots
-projects.facets.maintainability.description=Ratio of the size of the project to the estimated time needed to fix all outstanding maintainability issues
+projects.facets.maintainability.description=Ratio of the estimated time needed to fix all outstanding maintainability issues to the size of the project
projects.facets.languages=Languages
projects.facets.search.languages=Search for languages
projects.facets.new_lines=New Lines
severity.INFO.description=Neither a bug nor a quality flaw. Just a finding.
# New severities
-severity.HIGH=High
-severity.HIGH.description=Must be fixed immediately.
-severity.MEDIUM=Medium
-severity.MEDIUM.description=High potential for significant to moderate impact.
-severity.LOW=Low
-severity.LOW.description=Potential for moderate to minor impact.
+severity_impact.title=Severity of impact
+severity_impact.levels=Severity levels
+severity_impact.BLOCKER=Blocker
+severity_impact.BLOCKER.description=Must be fixed immediately.
+severity_impact.HIGH=High
+severity_impact.HIGH.description=Must be reviewed immediately and fixed soon.
+severity_impact.MEDIUM=Medium
+severity_impact.MEDIUM.description=High potential for significant to moderate impact.
+severity_impact.LOW=Low
+severity_impact.LOW.description=Potential for moderate to minor impact.
+severity_impact.INFO=Info
+severity_impact.INFO.description=Neither a bug nor a quality flaw. Just a finding.
+severity_impact.help.line1=Severities are now directly tied to the software quality impacted. This means that one software quality impacted has one severity.
+severity_impact.help.line2=There are five levels of severity: blocker, high, medium, low and info.
#------------------------------------------------------------------------------
metric.new_security_review_rating.description=Security Review Rating on New Code
metric.new_security_review_rating.name=Security Review Rating on New Code
metric.new_security_review_rating.extra_short_name=Rating
-metric.new_software_quality_security_review_rating.description=Security Review Rating on New Code
-metric.new_software_quality_security_review_rating.name=Security Review Rating on New Code
-metric.new_software_quality_security_review_rating.extra_short_name=Rating
metric.new_sqale_debt_ratio.description=Technical Debt Ratio of new/changed code.
metric.new_sqale_debt_ratio.name=Technical Debt Ratio on New Code
metric.new_sqale_debt_ratio.short_name=Debt Ratio on new code
metric.software_quality_reliability_rating.description=Reliability rating
metric.software_quality_reliability_rating.name=Reliability Rating
metric.software_quality_reliability_rating.extra_short_name=Rating
-metric.software_quality_reliability_rating.tooltip.A=Reliability rating is A when there are no reliability issues.
+metric.software_quality_reliability_rating.tooltip.A=Reliability rating is A when there are no reliability issues above info severity.
metric.software_quality_reliability_rating.tooltip.B=Reliability rating is B when there is at least one low reliability issue.
metric.software_quality_reliability_rating.tooltip.C=Reliability rating is C when there is at least one medium reliability issue.
metric.software_quality_reliability_rating.tooltip.D=Reliability rating is D when there is at least one high reliability issue.
-metric.software_quality_reliability_rating.tooltip.E=Reliability rating is E when there is at least one high reliability issue.
+metric.software_quality_reliability_rating.tooltip.E=Reliability rating is E when there is at least one blocker reliability issue.
metric.reliability_remediation_effort.description=Reliability Remediation Effort
metric.reliability_remediation_effort.name=Reliability Remediation Effort
metric.reliability_remediation_effort.extra_short_name=Remediation Effort
metric.software_quality_security_rating.description=Security rating
metric.software_quality_security_rating.name=Security Rating
metric.software_quality_security_rating.extra_short_name=Rating
-metric.software_quality_security_rating.tooltip.A=Security rating is A when there are no security issues.
+metric.software_quality_security_rating.tooltip.A=Security rating is A when there are no security issues above info severity.
metric.software_quality_security_rating.tooltip.B=Security rating is B when there is at least one low security issue.
metric.software_quality_security_rating.tooltip.C=Security rating is C when there is at least one medium security issue.
metric.software_quality_security_rating.tooltip.D=Security rating is D when there is at least one high security issue.
-metric.software_quality_security_rating.tooltip.E=Security rating is E when there is at least one high security issue.
+metric.software_quality_security_rating.tooltip.E=Security rating is E when there is at least one blocker security issue.
metric.security_remediation_effort.description=Security remediation effort
metric.security_remediation_effort.name=Security Remediation Effort
metric.security_remediation_effort.extra_short_name=Remediation Effort
metric.security_review_rating.description=Security Review Rating
metric.security_review_rating.name=Security Review Rating
metric.security_review_rating.extra_short_name=Rating
-metric.software_quality_security_review_rating.description=Security Review Rating
-metric.software_quality_security_review_rating.name=Security Review Rating
-metric.software_quality_security_review_rating.extra_short_name=Rating
metric.security_review_rating.tooltip.A=Security Review rating is A when at least 80% of Security Hotspots are reviewed.
metric.security_review_rating.tooltip.B=Security Review rating is B when less than 80% of Security Hotspots are reviewed.
metric.security_review_rating.tooltip.C=Security Review rating is C when less than 70% of Security Hotspots are reviewed.
metric.security_review_rating.tooltip.D=Security Review rating is D when less than 50% of Security Hotspots are reviewed.
metric.security_review_rating.tooltip.E=Security Review rating is E when less than 30% of Security Hotspots are reviewed.
-metric.software_quality_security_review_rating.tooltip.A=Security Review rating is A when all Security Hotspots are reviewed.
-metric.software_quality_security_review_rating.tooltip.B=Security Review rating is B when less than 100% of Security Hotspots are reviewed.
-metric.software_quality_security_review_rating.tooltip.C=Security Review rating is C when less than 70% of Security Hotspots are reviewed.
-metric.software_quality_security_review_rating.tooltip.D=Security Review rating is D when less than 50% of Security Hotspots are reviewed.
-metric.software_quality_security_review_rating.tooltip.E=Security Review rating is E when less than 30% of Security Hotspots are reviewed.
metric.skipped_tests.description=Number of skipped unit tests
metric.skipped_tests.name=Skipped Unit Tests
metric.skipped_tests.short_name=Skipped
overview.measures.software_impact.severity.LOW.tooltip=Low Impact
overview.measures.software_impact.severity.LOW.improve_tooltip=low
overview.measures.software_impact.improve_rating_tooltip=The {softwareQuality} rating is {ratingLabel} when there is at least one issue with {severity} impact on the {_softwareQuality} of your software.
-overview.measures.software_impact.improve_rating_tooltip.A=The {softwareQuality} rating is {ratingLabel} when there are no issues with impact on the {_softwareQuality} of your software.
+overview.measures.software_impact.improve_rating_tooltip.A=The {softwareQuality} rating is {ratingLabel} when there are no issues above info severity with impact on the {_softwareQuality} of your software.
overview.measures.software_impact.improve_rating_tooltip.MAINTAINABILITY=The Maintainability rating is {ratingLabel} if the code has a relatively higher level of technical debt when compared to the size of the codebase.
overview.measures.software_impact.improve_rating_tooltip.MAINTAINABILITY.A=The Maintainability rating is A if the code has a relatively lower level of technical debt when compared to the size of the codebase.
SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING,
SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING,
SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING,
- SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING,
- SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING,
SoftwareQualitiesMetrics.EFFORT_TO_REACH_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_A,
SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
"{\"stringField\":\"foo\",\"intField\":10,\"longField\":100,\"doubleField\":3.14,\"booleanField\":true,\"enumField\":\"GREEN\"}");
}
+ @Test
+ public void toJson_whenPrefixedEnum_shouldConvertToExpectedEnumValue() {
+ PrimitiveTypeMsg protobuf = PrimitiveTypeMsg.newBuilder()
+ .setStringField("foo")
+ .setIntField(10)
+ .setLongField(100L)
+ .setDoubleField(3.14)
+ .setBooleanField(true)
+ .setEnumField(org.sonar.core.test.Test.FakeEnum.FakeEnum_YELLOW)
+ .build();
+
+ assertThat(toJson(protobuf)).isEqualTo(
+ "{\"stringField\":\"foo\",\"intField\":10,\"longField\":100,\"doubleField\":3.14,\"booleanField\":true,\"enumField\":\"YELLOW\"}");
+ }
+
@Test
public void bytes_field_can_not_be_converted() {
assertThatThrownBy(() -> {
BLUE = 0;
RED = 1;
GREEN = 2;
+ FakeEnum_YELLOW = 3;
}
message PrimitiveTypeMsg {
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.sonar.api.issue.impact.Severity.BLOCKER;
import static org.sonar.api.issue.impact.Severity.HIGH;
import static org.sonar.api.issue.impact.Severity.LOW;
import static org.sonar.api.issue.impact.SoftwareQuality.MAINTAINABILITY;
ExternalIssue output = context.allExternalIssues().iterator().next();
assertThat(output.engineId()).isEqualTo(RULE_ENGINE_ID);
assertThat(output.ruleId()).isEqualTo(RULE_ID);
- assertThat(output.severity()).isEqualTo(Severity.CRITICAL); //backmapped
+ assertThat(output.severity()).isEqualTo(Severity.BLOCKER); // backmapped
assertThat(output.type()).isEqualTo(RuleType.VULNERABILITY); //backmapped
assertThat(output.remediationEffort()).isNull();
assertThat(logs.logs(Level.INFO)).contains("Imported 1 issue in 1 file");
assertThat(output1.ruleId()).isEqualTo(RULE_ID);
assertThat(output1.name()).isEqualTo(RULE_NAME);
assertThat(output1.engineId()).isEqualTo(RULE_ENGINE_ID);
- assertThat(output1.severity()).isEqualTo(Severity.CRITICAL); //backmapped
+ assertThat(output1.severity()).isEqualTo(Severity.BLOCKER); // backmapped
assertThat(output1.type()).isEqualTo(RuleType.VULNERABILITY); //backmapped
assertThat(output1.cleanCodeAttribute()).isEqualTo(RULE_ATTRIBUTE);
- assertThat(output1.defaultImpacts()).containsExactlyInAnyOrderEntriesOf(Map.of(SECURITY, HIGH, MAINTAINABILITY, LOW));
+ assertThat(output1.defaultImpacts()).containsExactlyInAnyOrderEntriesOf(Map.of(SECURITY, BLOCKER, MAINTAINABILITY, LOW));
}
@Test
private static ExternalIssueReport.Rule createRule() {
- return createRule(RULE_ATTRIBUTE.name(), SECURITY.name(), HIGH.name());
+ return createRule(RULE_ATTRIBUTE.name(), SECURITY.name(), BLOCKER.name());
}
private static ExternalIssueReport.Rule createRule(String cleanCodeAttribute, String softwareQuality, String impactSeverity) {
LOW = 1;
MEDIUM = 2;
HIGH = 3;
+ // INFO and BLOCKER conflicts with Severity enum, so we use different values prefixed with enum name
+ ImpactSeverity_INFO = 4;
+ ImpactSeverity_BLOCKER = 5;
}
// Lines start at 1 and line offsets start at 0