@@ -33,6 +33,12 @@ public class ImpactDto implements Serializable { | |||
// nothing to do | |||
} | |||
public ImpactDto(String uuid, SoftwareQuality softwareQuality, Severity severity) { | |||
this.uuid = uuid; | |||
this.softwareQuality = softwareQuality; | |||
this.severity = severity; | |||
} | |||
public String getUuid() { | |||
return uuid; | |||
} |
@@ -801,10 +801,13 @@ | |||
i.component_uuid as component_uuid, | |||
i.assignee as assigneeUuid, | |||
u.login as assigneeLogin, | |||
i.rule_description_context_key as ruleDescriptionContextKey | |||
i.rule_description_context_key as ruleDescriptionContextKey, | |||
<include refid="issueImpactsColumns"/> | |||
<include refid="ruleDefaultImpactsColumns"/> | |||
r.clean_code_attribute as cleanCodeAttribute | |||
</sql> | |||
<select id="selectByBranch" parameterType="map" resultType="Issue"> | |||
<select id="selectByBranch" parameterType="map" resultMap="issueResultMap" resultOrdered="true"> | |||
select | |||
<include refid="selectByBranchColumns"/> | |||
, p.path as filePath | |||
@@ -812,6 +815,8 @@ | |||
inner join rules r on r.uuid = i.rule_uuid | |||
inner join components p on p.uuid=i.component_uuid | |||
left join users u on i.assignee = u.uuid | |||
left outer join issues_impacts ii on i.kee = ii.issue_key | |||
left outer join rules_default_impacts rdi on r.uuid = rdi.rule_uuid | |||
where | |||
<if test="keys.size() > 0"> | |||
i.kee IN | |||
@@ -822,6 +827,7 @@ | |||
<if test="changedSince != null"> | |||
AND i.issue_update_date >= #{changedSince,jdbcType=BIGINT} | |||
</if> | |||
order by i.kee | |||
</select> | |||
<select id="selectRecentlyClosedIssues" resultType="string"> |
@@ -24,15 +24,11 @@ import java.util.Collections; | |||
import java.util.Set; | |||
import java.util.TreeSet; | |||
import org.jetbrains.annotations.NotNull; | |||
import org.jetbrains.annotations.Nullable; | |||
import org.junit.Test; | |||
import org.sonar.api.issue.impact.Severity; | |||
import org.sonar.api.issue.impact.SoftwareQuality; | |||
import org.sonar.core.util.UuidFactoryFast; | |||
import org.sonar.api.rule.RuleScope; | |||
import org.sonar.api.rules.CleanCodeAttribute; | |||
import org.sonar.api.rules.RuleType; | |||
import org.sonar.api.server.rule.RulesDefinition; | |||
import org.sonar.core.util.Uuids; | |||
import org.sonar.db.issue.ImpactDto; | |||
@@ -41,8 +37,6 @@ import static org.apache.commons.lang.StringUtils.repeat; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.db.rule.RuleDto.ERROR_MESSAGE_SECTION_ALREADY_EXISTS; | |||
import static org.sonar.db.rule.RuleTesting.newRule; | |||
@@ -248,10 +242,6 @@ public class RuleDtoTest { | |||
} | |||
public static ImpactDto newImpactDto(SoftwareQuality softwareQuality, Severity severity) { | |||
return new ImpactDto() | |||
.setUuid(UuidFactoryFast.getInstance().create()) | |||
.setSoftwareQuality(softwareQuality) | |||
.setSeverity(severity); | |||
return new ImpactDto(UuidFactoryFast.getInstance().create(), softwareQuality, severity); | |||
} | |||
} |
@@ -38,6 +38,7 @@ import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation; | |||
import org.elasticsearch.search.aggregations.bucket.filter.Filter; | |||
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram; | |||
import org.elasticsearch.search.aggregations.bucket.missing.Missing; | |||
import org.elasticsearch.search.aggregations.bucket.nested.ReverseNested; | |||
import org.elasticsearch.search.aggregations.bucket.terms.Terms; | |||
import org.elasticsearch.search.aggregations.metrics.Sum; | |||
@@ -176,7 +177,16 @@ public class Facets { | |||
private void processMultiBucketAggregation(MultiBucketsAggregation aggregation) { | |||
LinkedHashMap<String, Long> facet = getOrCreateFacet(aggregation.getName()); | |||
aggregation.getBuckets().forEach(bucket -> facet.put(bucket.getKeyAsString(), bucket.getDocCount())); | |||
aggregation.getBuckets().forEach(bucket -> { | |||
if (!bucket.getAggregations().asList().isEmpty()) { | |||
Aggregation next = bucket.getAggregations().iterator().next(); | |||
if (next instanceof ReverseNested reverseNestedBucket) { | |||
facet.put(bucket.getKeyAsString(), reverseNestedBucket.getDocCount()); | |||
} | |||
} else { | |||
facet.put(bucket.getKeyAsString(), bucket.getDocCount()); | |||
} | |||
}); | |||
} | |||
public boolean contains(String facetName) { |
@@ -57,6 +57,9 @@ public class SearchRequest { | |||
private List<String> rules; | |||
private String sort; | |||
private List<String> severities; | |||
private List<String> impactSeverities; | |||
private List<String> impactSoftwareQualities; | |||
private List<String> cleanCodeAttributesCategories; | |||
private List<String> statuses; | |||
private List<String> tags; | |||
private Set<String> types; | |||
@@ -512,4 +515,31 @@ public class SearchRequest { | |||
this.codeVariants = codeVariants; | |||
return this; | |||
} | |||
public List<String> getImpactSeverities() { | |||
return impactSeverities; | |||
} | |||
public SearchRequest setImpactSeverities(@Nullable List<String> impactSeverities) { | |||
this.impactSeverities = impactSeverities; | |||
return this; | |||
} | |||
public List<String> getImpactSoftwareQualities() { | |||
return impactSoftwareQualities; | |||
} | |||
public SearchRequest setImpactSoftwareQualities(@Nullable List<String> impactSoftwareQualities) { | |||
this.impactSoftwareQualities = impactSoftwareQualities; | |||
return this; | |||
} | |||
public List<String> getCleanCodeAttributesCategories() { | |||
return cleanCodeAttributesCategories; | |||
} | |||
public SearchRequest setCleanCodeAttributesCategories(@Nullable List<String> cleanCodeAttributesCategories) { | |||
this.cleanCodeAttributesCategories = cleanCodeAttributesCategories; | |||
return this; | |||
} | |||
} |
@@ -19,6 +19,7 @@ | |||
*/ | |||
package org.sonar.server.issue; | |||
import java.util.List; | |||
import org.junit.Test; | |||
import static java.util.Arrays.asList; | |||
@@ -54,7 +55,10 @@ public class SearchRequestTest { | |||
.setOwaspAsvsLevel(2) | |||
.setPciDss32(asList("1", "4")) | |||
.setPciDss40(asList("3", "5")) | |||
.setCodeVariants(asList("variant1", "variant2")); | |||
.setCodeVariants(asList("variant1", "variant2")) | |||
.setCleanCodeAttributesCategories(singletonList("ADAPTABLE")) | |||
.setImpactSeverities(List.of("HIGH", "LOW")) | |||
.setImpactSoftwareQualities(List.of("RELIABILITY", "SECURITY")); | |||
assertThat(underTest.getIssues()).containsOnlyOnce("anIssueKey"); | |||
assertThat(underTest.getSeverities()).containsExactly("MAJOR", "MINOR"); | |||
@@ -81,6 +85,9 @@ public class SearchRequestTest { | |||
assertThat(underTest.getPciDss32()).containsExactly("1", "4"); | |||
assertThat(underTest.getPciDss40()).containsExactly("3", "5"); | |||
assertThat(underTest.getCodeVariants()).containsExactly("variant1", "variant2"); | |||
assertThat(underTest.getCleanCodeAttributesCategories()).containsExactly("ADAPTABLE"); | |||
assertThat(underTest.getImpactSeverities()).containsExactly("HIGH", "LOW"); | |||
assertThat(underTest.getImpactSoftwareQualities()).containsExactly("RELIABILITY", "SECURITY"); | |||
} | |||
@Test |
@@ -111,6 +111,7 @@ import static org.elasticsearch.index.query.QueryBuilders.rangeQuery; | |||
import static org.elasticsearch.index.query.QueryBuilders.termQuery; | |||
import static org.elasticsearch.index.query.QueryBuilders.termsQuery; | |||
import static org.elasticsearch.search.aggregations.AggregationBuilders.filters; | |||
import static org.elasticsearch.search.aggregations.AggregationBuilders.reverseNested; | |||
import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT; | |||
import static org.sonar.api.rules.RuleType.VULNERABILITY; | |||
import static org.sonar.server.es.EsUtils.escapeSpecialRegexChars; | |||
@@ -128,6 +129,8 @@ import static org.sonar.server.issue.index.IssueIndex.Facet.CREATED_AT; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.CWE; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.DIRECTORIES; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.FILES; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.IMPACT_SEVERITY; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.IMPACT_SOFTWARE_QUALITY; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.LANGUAGES; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.OWASP_ASVS_40; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.OWASP_TOP_10; | |||
@@ -140,8 +143,6 @@ import static org.sonar.server.issue.index.IssueIndex.Facet.RULES; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.SANS_TOP_25; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.SCOPES; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.SEVERITIES; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.IMPACT_SOFTWARE_QUALITY; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.IMPACT_SEVERITY; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.SONARSOURCE_SECURITY; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.STATUSES; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.TAGS; | |||
@@ -159,6 +160,9 @@ import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_FILE | |||
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_FUNC_CLOSED_AT; | |||
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_FUNC_CREATED_AT; | |||
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_FUNC_UPDATED_AT; | |||
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_IMPACTS; | |||
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_IMPACT_SEVERITY; | |||
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_IMPACT_SOFTWARE_QUALITY; | |||
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_IS_MAIN_BRANCH; | |||
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_KEY; | |||
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_LANGUAGE; | |||
@@ -176,9 +180,6 @@ import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_SANS | |||
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_SCOPE; | |||
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_SEVERITY; | |||
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_SEVERITY_VALUE; | |||
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_IMPACTS; | |||
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_IMPACT_SOFTWARE_QUALITY; | |||
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_IMPACT_SEVERITY; | |||
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_SQ_SECURITY_CATEGORY; | |||
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_STATUS; | |||
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_TAGS; | |||
@@ -199,6 +200,8 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_AT; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CWE; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_DIRECTORIES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_FILES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_IMPACT_SEVERITIES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_IMPACT_SOFTWARE_QUALITIES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_LANGUAGES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_OWASP_ASVS_40; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_OWASP_TOP_10; | |||
@@ -210,8 +213,6 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RULES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SANS_TOP_25; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SCOPES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SEVERITIES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SOFTWARE_QUALITIES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SOFTWARE_QUALITIES_SEVERTIIES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SONARSOURCE_SECURITY; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_STATUSES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_TAGS; | |||
@@ -255,8 +256,8 @@ public class IssueIndex { | |||
public enum Facet { | |||
SEVERITIES(PARAM_SEVERITIES, FIELD_ISSUE_SEVERITY, STICKY, Severity.ALL.size()), | |||
IMPACT_SOFTWARE_QUALITY(PARAM_SOFTWARE_QUALITIES, FIELD_ISSUE_IMPACT_SOFTWARE_QUALITY, STICKY, SoftwareQuality.values().length), | |||
IMPACT_SEVERITY(PARAM_SOFTWARE_QUALITIES_SEVERTIIES, FIELD_ISSUE_IMPACT_SEVERITY, STICKY, | |||
IMPACT_SOFTWARE_QUALITY(PARAM_IMPACT_SOFTWARE_QUALITIES, FIELD_ISSUE_IMPACT_SOFTWARE_QUALITY, STICKY, SoftwareQuality.values().length), | |||
IMPACT_SEVERITY(PARAM_IMPACT_SEVERITIES, FIELD_ISSUE_IMPACT_SEVERITY, STICKY, | |||
org.sonar.api.issue.impact.Severity.values().length), | |||
CLEAN_CODE_ATTRIBUTE_CATEGORY(PARAM_CLEAN_CODE_ATTRIBUTE_CATEGORIES, FIELD_ISSUE_CLEAN_CODE_ATTRIBUTE_CATEGORY, STICKY, CleanCodeAttributeCategory.values().length), | |||
STATUSES(PARAM_STATUSES, FIELD_ISSUE_STATUS, STICKY, Issue.STATUSES.size()), | |||
@@ -900,7 +901,7 @@ public class IssueIndex { | |||
} | |||
private static void addImpactSoftwareQualityFacetIfNeeded(SearchOptions options, IssueQuery query, TopAggregationHelper aggregationHelper, SearchSourceBuilder esRequest) { | |||
if (!options.getFacets().contains(PARAM_SOFTWARE_QUALITIES)) { | |||
if (!options.getFacets().contains(PARAM_IMPACT_SOFTWARE_QUALITIES)) { | |||
return; | |||
} | |||
@@ -924,7 +925,7 @@ public class IssueIndex { | |||
} | |||
private static void addImpactSeverityFacetIfNeeded(SearchOptions options, IssueQuery query, TopAggregationHelper aggregationHelper, SearchSourceBuilder esRequest) { | |||
if (!options.getFacets().contains(PARAM_SOFTWARE_QUALITIES_SEVERTIIES)) { | |||
if (!options.getFacets().contains(PARAM_IMPACT_SEVERITIES)) { | |||
return; | |||
} | |||
@@ -942,8 +943,9 @@ public class IssueIndex { | |||
IMPACT_SEVERITY.getName(), IMPACT_SEVERITY.getTopAggregationDef(), | |||
NO_EXTRA_FILTER, | |||
t -> t.subAggregation(AggregationBuilders.nested("nested_" + IMPACT_SEVERITY.getName(), FIELD_ISSUE_IMPACTS) | |||
.subAggregation(filters(IMPACT_SEVERITY.getName(), | |||
keyedFilters)))); | |||
.subAggregation(filters(IMPACT_SEVERITY.getName(), keyedFilters) | |||
// we want to count the number of issues for each severity, so we need to reverse the nested aggregation | |||
.subAggregation(reverseNested("reverse_nested_" + IMPACT_SOFTWARE_QUALITY.getName()))))); | |||
esRequest.aggregation(aggregation); | |||
} | |||
@@ -101,7 +101,7 @@ public class IssueQuery { | |||
private final Boolean newCodeOnReference; | |||
private final Collection<String> newCodeOnReferenceByProjectUuids; | |||
private final Collection<String> codeVariants; | |||
private Collection<String> cleanCodeAttributesCategories; | |||
private final Collection<String> cleanCodeAttributesCategories; | |||
private IssueQuery(Builder builder) { | |||
this.issueKeys = defaultCollection(builder.issueKeys); |
@@ -122,6 +122,9 @@ public class IssueQueryFactory { | |||
IssueQuery.Builder builder = IssueQuery.builder() | |||
.issueKeys(request.getIssues()) | |||
.severities(request.getSeverities()) | |||
.cleanCodeAttributesCategories(request.getCleanCodeAttributesCategories()) | |||
.impactSoftwareQualities(request.getImpactSoftwareQualities()) | |||
.impactSeverities(request.getImpactSeverities()) | |||
.statuses(request.getStatuses()) | |||
.resolutions(request.getResolutions()) | |||
.resolved(request.getResolved()) |
@@ -671,7 +671,7 @@ public class IssueIndexFacetsTest extends IssueIndexTestCommon { | |||
} | |||
@Test | |||
public void search_shouldReturnSoftwareQualityFacet() { | |||
public void search_shouldReturnImpactSoftwareQualitiesFacet() { | |||
ComponentDto project = newPrivateProjectDto(); | |||
ComponentDto file = newFileDto(project); | |||
@@ -686,14 +686,14 @@ public class IssueIndexFacetsTest extends IssueIndexTestCommon { | |||
newDoc("I4", project.uuid(), file).setImpacts(Map.of( | |||
MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW))); | |||
assertThatFacetHasOnly(IssueQuery.builder(), "softwareQualities", | |||
assertThatFacetHasOnly(IssueQuery.builder(), "impactSoftwareQualities", | |||
entry("MAINTAINABILITY", 3L), | |||
entry("RELIABILITY", 2L), | |||
entry("SECURITY", 0L)); | |||
} | |||
@Test | |||
public void search_whenFilteredOnSeverity_shouldReturnSoftwareQualityFacet() { | |||
public void search_whenFilteredOnSeverity_shouldReturnImpactSoftwareQualitiesFacet() { | |||
ComponentDto project = newPrivateProjectDto(); | |||
ComponentDto file = newFileDto(project); | |||
@@ -710,31 +710,31 @@ public class IssueIndexFacetsTest extends IssueIndexTestCommon { | |||
MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW))); | |||
assertThatFacetHasOnly(IssueQuery.builder().impactSoftwareQualities(Set.of(MAINTAINABILITY.name())).impactSeverities(Set.of(org.sonar.api.issue.impact.Severity.LOW.name())), | |||
"softwareQualities", | |||
"impactSoftwareQualities", | |||
entry("MAINTAINABILITY", 2L), | |||
entry("RELIABILITY", 0L), | |||
entry("SECURITY", 0L)); | |||
assertThatFacetHasOnly(IssueQuery.builder().impactSeverities(Set.of(Severity.MEDIUM.name())), "softwareQualities", | |||
assertThatFacetHasOnly(IssueQuery.builder().impactSeverities(Set.of(Severity.MEDIUM.name())), "impactSoftwareQualities", | |||
entry("MAINTAINABILITY", 0L), | |||
entry("RELIABILITY", 1L), | |||
entry("SECURITY", 0L)); | |||
assertThatFacetHasOnly(IssueQuery.builder().impactSeverities(Set.of(org.sonar.api.issue.impact.Severity.HIGH.name())), "softwareQualities", | |||
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())), "softwareQualities", | |||
.impactSeverities(Set.of(org.sonar.api.issue.impact.Severity.HIGH.name())), "impactSoftwareQualities", | |||
entry("MAINTAINABILITY", 1L), | |||
entry("RELIABILITY", 0L), | |||
entry("SECURITY", 0L)); | |||
} | |||
@Test | |||
public void search_shouldReturnSoftwareQualitySeverityFacet() { | |||
public void search_shouldReturnImpactSeverityFacet() { | |||
ComponentDto project = newPrivateProjectDto(); | |||
ComponentDto file = newFileDto(project); | |||
@@ -749,14 +749,14 @@ public class IssueIndexFacetsTest extends IssueIndexTestCommon { | |||
newDoc("I4", project.uuid(), file).setImpacts(Map.of( | |||
MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW))); | |||
assertThatFacetHasOnly(IssueQuery.builder(), "softwareQualitiesSeverities", | |||
assertThatFacetHasOnly(IssueQuery.builder(), "impactSeverities", | |||
entry("HIGH", 2L), | |||
entry("MEDIUM", 1L), | |||
entry("LOW", 2L)); | |||
} | |||
@Test | |||
public void search_whenFilteredOnSoftwareQuality_shouldReturnSoftwareQualitySeverityFacet() { | |||
public void search_whenFilteredOnSoftwareQuality_shouldReturnImpactSeverityFacet() { | |||
ComponentDto project = newPrivateProjectDto(); | |||
ComponentDto file = newFileDto(project); | |||
@@ -771,7 +771,7 @@ public class IssueIndexFacetsTest extends IssueIndexTestCommon { | |||
newDoc("I4", project.uuid(), file).setImpacts(Map.of( | |||
MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW))); | |||
assertThatFacetHasOnly(IssueQuery.builder().impactSoftwareQualities(Set.of(MAINTAINABILITY.name())), "softwareQualitiesSeverities", | |||
assertThatFacetHasOnly(IssueQuery.builder().impactSoftwareQualities(Set.of(MAINTAINABILITY.name())), "impactSeverities", | |||
entry("HIGH", 1L), | |||
entry("MEDIUM", 0L), | |||
entry("LOW", 2L)); |
@@ -56,9 +56,11 @@ import org.sonarqube.ws.Common; | |||
import org.sonarqube.ws.Issues; | |||
import static java.lang.String.format; | |||
import static java.util.stream.Collectors.toList; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.assertj.core.groups.Tuple.tuple; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.api.web.UserRole.USER; | |||
@@ -253,6 +255,18 @@ public class PullTaintActionIT { | |||
assertThat(taintLite.getRuleKey()).isEqualTo("javasecurity:S1000"); | |||
assertThat(taintLite.getType()).isEqualTo(Common.RuleType.forNumber(issueDto.getType())); | |||
assertThat(taintLite.getAssignedToSubscribedUser()).isTrue(); | |||
assertThat(taintLite.getCleanCodeAttribute()) | |||
.isEqualTo(Common.CleanCodeAttribute.valueOf(issueDto.getCleanCodeAttribute().name())); | |||
assertThat(taintLite.getCleanCodeAttributeCategory()) | |||
.isEqualTo(Common.CleanCodeAttributeCategory.valueOf(issueDto.getCleanCodeAttribute().getAttributeCategory().name())); | |||
assertThat(taintLite.getImpactsList()) | |||
.extracting(Common.Impact::getSoftwareQuality, Common.Impact::getSeverity) | |||
.containsExactlyInAnyOrderElementsOf(issueDto.getEffectiveImpacts() | |||
.entrySet() | |||
.stream() | |||
.map(entry -> tuple(Common.SoftwareQuality.valueOf(entry.getKey().name()), Common.ImpactSeverity.valueOf(entry.getValue().name()))) | |||
.collect(toList())); | |||
Issues.Location location = taintLite.getMainLocation(); | |||
assertThat(location.getMessage()).isEqualTo(issueDto.getMessage()); |
@@ -26,6 +26,7 @@ import java.time.Clock; | |||
import java.util.Arrays; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import java.util.Optional; | |||
import java.util.Random; | |||
import java.util.Set; | |||
import java.util.function.Consumer; | |||
@@ -35,6 +36,7 @@ import java.util.stream.Stream; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.issue.impact.SoftwareQuality; | |||
import org.sonar.api.resources.Languages; | |||
import org.sonar.api.rule.RuleStatus; | |||
import org.sonar.api.rules.RuleType; | |||
@@ -51,6 +53,7 @@ import org.sonar.db.component.BranchType; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ProjectData; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.issue.ImpactDto; | |||
import org.sonar.db.issue.IssueChangeDto; | |||
import org.sonar.db.issue.IssueDto; | |||
import org.sonar.db.permission.GroupPermissionDto; | |||
@@ -123,6 +126,8 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CODE_VARIAN | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENTS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_AFTER; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_HIDE_COMMENTS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_IMPACT_SEVERITIES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_IMPACT_SOFTWARE_QUALITIES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_IN_NEW_CODE_PERIOD; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PULL_REQUEST; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RULES; | |||
@@ -227,7 +232,8 @@ public class SearchActionIT { | |||
.getIssuesList() | |||
.get(0) | |||
.getActions() | |||
.getActionsList()).isEqualTo(asList(ACTION_SET_TAGS, COMMENT_KEY, ACTION_ASSIGN)); | |||
.getActionsList()) | |||
.isEqualTo(asList(ACTION_SET_TAGS, COMMENT_KEY, ACTION_ASSIGN)); | |||
response = ws.newRequest() | |||
.setParam(PARAM_ADDITIONAL_FIELDS, "actions") | |||
@@ -239,7 +245,8 @@ public class SearchActionIT { | |||
.getIssuesList() | |||
.get(0) | |||
.getActions() | |||
.getActionsList()).isEqualTo(asList(ACTION_SET_TAGS, COMMENT_KEY)); | |||
.getActionsList()) | |||
.isEqualTo(asList(ACTION_SET_TAGS, COMMENT_KEY)); | |||
} | |||
@Test | |||
@@ -582,6 +589,152 @@ public class SearchActionIT { | |||
.assertJson(this.getClass(), "search_by_variants_with_facets.json"); | |||
} | |||
@Test | |||
public void search_whenImpactSoftwareQualitiesFacetRequested_shouldReturnFacet() { | |||
RuleDto rule = newIssueRule(); | |||
ComponentDto project = db.components().insertPublicProject("PROJECT_ID", | |||
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")); | |||
IssueDto issue1 = db.issues().insertIssue(rule, project, file, i -> i | |||
.addImpact(new ImpactDto(uuidFactory.create(), SoftwareQuality.SECURITY, org.sonar.api.issue.impact.Severity.HIGH)) | |||
.addImpact(new ImpactDto(uuidFactory.create(), SoftwareQuality.RELIABILITY, org.sonar.api.issue.impact.Severity.HIGH))); | |||
IssueDto issue2 = db.issues().insertIssue(rule, project, file, i -> i | |||
.addImpact(new ImpactDto(uuidFactory.create(), SoftwareQuality.RELIABILITY, org.sonar.api.issue.impact.Severity.HIGH))); | |||
IssueDto issue3 = db.issues().insertIssue(rule, project, file, i -> i | |||
.addImpact(new ImpactDto(uuidFactory.create(), SoftwareQuality.SECURITY, org.sonar.api.issue.impact.Severity.MEDIUM)) | |||
.addImpact(new ImpactDto(uuidFactory.create(), SoftwareQuality.RELIABILITY, org.sonar.api.issue.impact.Severity.LOW))); | |||
indexPermissionsAndIssues(); | |||
SearchWsResponse response = ws.newRequest() | |||
.setParam(FACETS, PARAM_IMPACT_SOFTWARE_QUALITIES) | |||
.executeProtobuf(SearchWsResponse.class); | |||
assertThat(response.getIssuesList()) | |||
.extracting(Issue::getKey) | |||
.containsExactlyInAnyOrder(issue1.getKey(), issue2.getKey(), issue3.getKey()); | |||
Optional<Common.Facet> first = response.getFacets().getFacetsList() | |||
.stream().filter(facet -> facet.getProperty().equals(PARAM_IMPACT_SOFTWARE_QUALITIES)) | |||
.findFirst(); | |||
assertThat(first.get().getValuesList()) | |||
.extracting(Common.FacetValue::getVal, Common.FacetValue::getCount) | |||
.containsExactlyInAnyOrder( | |||
tuple("MAINTAINABILITY", 3L), | |||
tuple("RELIABILITY", 3L), | |||
tuple("SECURITY", 2L)); | |||
} | |||
@Test | |||
public void search_whenFilteredByImpactSeverities_shouldReturnImpactSoftwareQualitiesFacet() { | |||
RuleDto rule = newIssueRule(); | |||
ComponentDto project = db.components().insertPublicProject("PROJECT_ID", | |||
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")); | |||
IssueDto issue1 = db.issues().insertIssue(rule, project, file, i -> i | |||
.addImpact(new ImpactDto(uuidFactory.create(), SoftwareQuality.SECURITY, org.sonar.api.issue.impact.Severity.HIGH)) | |||
.addImpact(new ImpactDto(uuidFactory.create(), SoftwareQuality.RELIABILITY, org.sonar.api.issue.impact.Severity.HIGH))); | |||
IssueDto issue2 = db.issues().insertIssue(rule, project, file, i -> i | |||
.addImpact(new ImpactDto(uuidFactory.create(), SoftwareQuality.RELIABILITY, org.sonar.api.issue.impact.Severity.HIGH))); | |||
IssueDto issue3 = db.issues().insertIssue(rule, project, file, i -> i | |||
.addImpact(new ImpactDto(uuidFactory.create(), SoftwareQuality.SECURITY, org.sonar.api.issue.impact.Severity.MEDIUM)) | |||
.addImpact(new ImpactDto(uuidFactory.create(), SoftwareQuality.RELIABILITY, org.sonar.api.issue.impact.Severity.LOW))); | |||
indexPermissionsAndIssues(); | |||
SearchWsResponse response = ws.newRequest() | |||
.setParam(PARAM_IMPACT_SEVERITIES, org.sonar.api.issue.impact.Severity.LOW.name()) | |||
.setParam(FACETS, PARAM_IMPACT_SOFTWARE_QUALITIES) | |||
.executeProtobuf(SearchWsResponse.class); | |||
assertThat(response.getIssuesList()) | |||
.extracting(Issue::getKey) | |||
.containsExactlyInAnyOrder(issue3.getKey()) | |||
.doesNotContain(issue1.getKey(), issue2.getKey()); | |||
Optional<Common.Facet> first = response.getFacets().getFacetsList() | |||
.stream().filter(facet -> facet.getProperty().equals(PARAM_IMPACT_SOFTWARE_QUALITIES)) | |||
.findFirst(); | |||
assertThat(first.get().getValuesList()) | |||
.extracting(Common.FacetValue::getVal, Common.FacetValue::getCount) | |||
.containsExactlyInAnyOrder( | |||
tuple("MAINTAINABILITY", 0L), | |||
tuple("RELIABILITY", 1L), | |||
tuple("SECURITY", 0L)); | |||
} | |||
@Test | |||
public void search_whenImpactSeveritiesFacetRequested_shouldReturnFacet() { | |||
RuleDto rule = newIssueRule(); | |||
ComponentDto project = db.components().insertPublicProject("PROJECT_ID", | |||
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")); | |||
IssueDto issue1 = db.issues().insertIssue(rule, project, file, i -> i.replaceAllImpacts(List.of( | |||
new ImpactDto(uuidFactory.create(), SoftwareQuality.SECURITY, org.sonar.api.issue.impact.Severity.HIGH), | |||
new ImpactDto(uuidFactory.create(), SoftwareQuality.RELIABILITY, org.sonar.api.issue.impact.Severity.HIGH)))); | |||
IssueDto issue2 = db.issues().insertIssue(rule, project, file, i -> i.replaceAllImpacts(List.of( | |||
new ImpactDto(uuidFactory.create(), SoftwareQuality.RELIABILITY, org.sonar.api.issue.impact.Severity.HIGH)))); | |||
IssueDto issue3 = db.issues().insertIssue(rule, project, file, i -> i.replaceAllImpacts(List.of( | |||
new ImpactDto(uuidFactory.create(), SoftwareQuality.MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW), | |||
new ImpactDto(uuidFactory.create(), SoftwareQuality.SECURITY, org.sonar.api.issue.impact.Severity.MEDIUM), | |||
new ImpactDto(uuidFactory.create(), SoftwareQuality.RELIABILITY, org.sonar.api.issue.impact.Severity.LOW)))); | |||
indexPermissionsAndIssues(); | |||
SearchWsResponse response = ws.newRequest() | |||
.setParam(FACETS, PARAM_IMPACT_SEVERITIES) | |||
.executeProtobuf(SearchWsResponse.class); | |||
assertThat(response.getIssuesList()) | |||
.extracting(Issue::getKey) | |||
.containsExactlyInAnyOrder(issue1.getKey(), issue2.getKey(), issue3.getKey()); | |||
Optional<Common.Facet> first = response.getFacets().getFacetsList() | |||
.stream().filter(facet -> facet.getProperty().equals(PARAM_IMPACT_SEVERITIES)) | |||
.findFirst(); | |||
assertThat(first.get().getValuesList()) | |||
.extracting(Common.FacetValue::getVal, Common.FacetValue::getCount) | |||
.containsExactlyInAnyOrder( | |||
tuple("HIGH", 2L), | |||
tuple("MEDIUM", 1L), | |||
tuple("LOW", 1L)); | |||
} | |||
@Test | |||
public void search_whenFilteredByImpactSoftwareQualities_shouldReturnFacet() { | |||
RuleDto rule = newIssueRule(); | |||
ComponentDto project = db.components().insertPublicProject("PROJECT_ID", | |||
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")); | |||
IssueDto issue1 = db.issues().insertIssue(rule, project, file, i -> i.replaceAllImpacts(List.of( | |||
new ImpactDto(uuidFactory.create(), SoftwareQuality.SECURITY, org.sonar.api.issue.impact.Severity.HIGH), | |||
new ImpactDto(uuidFactory.create(), SoftwareQuality.RELIABILITY, org.sonar.api.issue.impact.Severity.HIGH)))); | |||
IssueDto issue2 = db.issues().insertIssue(rule, project, file, i -> i.replaceAllImpacts(List.of( | |||
new ImpactDto(uuidFactory.create(), SoftwareQuality.RELIABILITY, org.sonar.api.issue.impact.Severity.HIGH)))); | |||
IssueDto issue3 = db.issues().insertIssue(rule, project, file, i -> i.replaceAllImpacts(List.of( | |||
new ImpactDto(uuidFactory.create(), SoftwareQuality.MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW), | |||
new ImpactDto(uuidFactory.create(), SoftwareQuality.SECURITY, org.sonar.api.issue.impact.Severity.MEDIUM), | |||
new ImpactDto(uuidFactory.create(), SoftwareQuality.RELIABILITY, org.sonar.api.issue.impact.Severity.LOW)))); | |||
indexPermissionsAndIssues(); | |||
SearchWsResponse response = ws.newRequest() | |||
.setParam(PARAM_IMPACT_SOFTWARE_QUALITIES, SoftwareQuality.SECURITY.name()) | |||
.setParam(FACETS, PARAM_IMPACT_SEVERITIES) | |||
.executeProtobuf(SearchWsResponse.class); | |||
assertThat(response.getIssuesList()) | |||
.extracting(Issue::getKey) | |||
.containsExactlyInAnyOrder(issue1.getKey(), issue3.getKey()) | |||
.doesNotContain(issue2.getKey()); | |||
Optional<Common.Facet> first = response.getFacets().getFacetsList() | |||
.stream().filter(facet -> facet.getProperty().equals(PARAM_IMPACT_SEVERITIES)) | |||
.findFirst(); | |||
assertThat(first.get().getValuesList()) | |||
.extracting(Common.FacetValue::getVal, Common.FacetValue::getCount) | |||
.containsExactlyInAnyOrder( | |||
tuple("HIGH", 1L), | |||
tuple("MEDIUM", 1L), | |||
tuple("LOW", 0L)); | |||
} | |||
@Test | |||
public void issue_on_removed_file() { | |||
RuleDto rule = newIssueRule(); | |||
@@ -1790,8 +1943,8 @@ public class SearchActionIT { | |||
"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", "sansTop25", "cwe", "sonarsourceSecurity", "timeZone", "inNewCodePeriod", "codeVariants"); | |||
"owaspAsvsLevel", "owaspTop10", "owaspTop10-2021", "sansTop25", "cwe", "sonarsourceSecurity", "timeZone", "inNewCodePeriod", "codeVariants", | |||
"cleanCodeAttributeCategories", "impactSeverities", "impactSoftwareQualities"); | |||
WebService.Param branch = def.param(PARAM_BRANCH); | |||
assertThat(branch.isInternal()).isFalse(); |
@@ -72,6 +72,7 @@ public class AddCommentAction implements IssuesWsAction { | |||
"Requires authentication and the following permission: 'Browse' on the project of the specified issue.") | |||
.setSince("3.6") | |||
.setChangelog( | |||
new Change("10.2", "Add 'impacts', 'cleanCodeAttribute', 'cleanCodeAttributeCategory' fields to the response"), | |||
new Change("9.6", "Response field 'ruleDescriptionContextKey' added"), | |||
new Change("8.8", "The response field components.uuid is removed"), | |||
new Change("6.3", "the response returns the issue with all its details"), |
@@ -75,6 +75,7 @@ public class AssignAction implements IssuesWsAction { | |||
.setDescription("Assign/Unassign an issue. Requires authentication and Browse permission on project") | |||
.setSince("3.6") | |||
.setChangelog( | |||
new Change("10.2", "Add 'impacts', 'cleanCodeAttribute', 'cleanCodeAttributeCategory' fields to the response"), | |||
new Change("9.6", "Response field 'ruleDescriptionContextKey' added"), | |||
new Change("8.8", "The response field components.uuid is removed"), | |||
new Change("6.5", "the database ids of the components are removed from the response"), |
@@ -60,6 +60,7 @@ public class DeleteCommentAction implements IssuesWsAction { | |||
"Requires authentication and the following permission: 'Browse' on the project of the specified issue.") | |||
.setSince("3.6") | |||
.setChangelog( | |||
new Change("10.2", "Add 'impacts', 'cleanCodeAttribute', 'cleanCodeAttributeCategory' fields to the response"), | |||
new Change("9.6", "Response field 'ruleDescriptionContextKey' added"), | |||
new Change("8.8", "The response field components.uuid is removed"), | |||
new Change("6.5", "the response field components.uuid is deprecated. Use components.key instead."), |
@@ -82,6 +82,7 @@ public class DoTransitionAction implements IssuesWsAction { | |||
"The transitions involving security hotspots require the permission 'Administer Security Hotspot'.") | |||
.setSince("3.6") | |||
.setChangelog( | |||
new Change("10.2", "Add 'impacts', 'cleanCodeAttribute', 'cleanCodeAttributeCategory' fields to the response"), | |||
new Change("9.6", "Response field 'ruleDescriptionContextKey' added"), | |||
new Change("8.8", "The response field components.uuid is removed"), | |||
new Change("8.1", format("transitions '%s' and '%s' are no more supported", SET_AS_IN_REVIEW, OPEN_AS_VULNERABILITY)), |
@@ -66,6 +66,7 @@ public class EditCommentAction implements IssuesWsAction { | |||
"Requires authentication and the following permission: 'Browse' on the project of the specified issue.") | |||
.setSince("3.6") | |||
.setChangelog( | |||
new Change("10.2", "Add 'impacts', 'cleanCodeAttribute', 'cleanCodeAttributeCategory' fields to the response"), | |||
new Change("9.6", "Response field 'ruleDescriptionContextKey' added"), | |||
new Change("8.8", "The response field components.uuid is removed"), | |||
new Change("6.3", "the response returns the issue with all its details"), |
@@ -22,6 +22,7 @@ package org.sonar.server.issue.ws; | |||
import com.google.common.collect.Lists; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.Collection; | |||
import java.util.EnumSet; | |||
import java.util.List; | |||
import java.util.Map; | |||
@@ -32,7 +33,9 @@ import javax.annotation.Nullable; | |||
import org.apache.lucene.search.TotalHits; | |||
import org.elasticsearch.action.search.SearchResponse; | |||
import org.elasticsearch.search.SearchHit; | |||
import org.sonar.api.issue.impact.SoftwareQuality; | |||
import org.sonar.api.rule.Severity; | |||
import org.sonar.api.rules.CleanCodeAttributeCategory; | |||
import org.sonar.api.rules.RuleType; | |||
import org.sonar.api.server.ws.Change; | |||
import org.sonar.api.server.ws.Request; | |||
@@ -94,6 +97,7 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ASSIGNED; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ASSIGNEES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_AUTHOR; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_BRANCH; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CLEAN_CODE_ATTRIBUTE_CATEGORIES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CODE_VARIANTS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENTS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS; | |||
@@ -122,6 +126,8 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RULES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SANS_TOP_25; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SCOPES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SEVERITIES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_IMPACT_SOFTWARE_QUALITIES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_IMPACT_SEVERITIES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SONARSOURCE_SECURITY; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_STATUSES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_TAGS; | |||
@@ -157,10 +163,15 @@ public class SearchAction implements IssuesWsAction { | |||
PARAM_CWE, | |||
PARAM_CREATED_AT, | |||
PARAM_SONARSOURCE_SECURITY, | |||
PARAM_CODE_VARIANTS | |||
PARAM_CODE_VARIANTS, | |||
PARAM_CLEAN_CODE_ATTRIBUTE_CATEGORIES, | |||
PARAM_IMPACT_SOFTWARE_QUALITIES, | |||
PARAM_IMPACT_SEVERITIES | |||
); | |||
private static final String INTERNAL_PARAMETER_DISCLAIMER = "This parameter is mostly used by the Issues page, please prefer usage of the componentKeys parameter. "; | |||
private static final String NEW_FACET_ADDED_MESSAGE = "Facet '%s' has been added"; | |||
private static final String NEW_PARAM_ADDED_MESSAGE = "Param '%s' has been added"; | |||
private static final Set<String> FACETS_REQUIRING_PROJECT = newHashSet(PARAM_FILES, PARAM_DIRECTORIES); | |||
private final UserSession userSession; | |||
@@ -194,6 +205,13 @@ public class SearchAction implements IssuesWsAction { | |||
+ "<br/>When issue indexation is in progress returns 503 service unavailable HTTP code.") | |||
.setSince("3.6") | |||
.setChangelog( | |||
new Change("10.2", "Add 'impacts', 'cleanCodeAttribute', 'cleanCodeAttributeCategory' fields to the response"), | |||
new Change("10.2", format(NEW_PARAM_ADDED_MESSAGE, PARAM_IMPACT_SOFTWARE_QUALITIES)), | |||
new Change("10.2", format(NEW_PARAM_ADDED_MESSAGE, PARAM_IMPACT_SEVERITIES)), | |||
new Change("10.2", format(NEW_PARAM_ADDED_MESSAGE, PARAM_CLEAN_CODE_ATTRIBUTE_CATEGORIES)), | |||
new Change("10.2", format(NEW_FACET_ADDED_MESSAGE, PARAM_IMPACT_SOFTWARE_QUALITIES)), | |||
new Change("10.2", format(NEW_FACET_ADDED_MESSAGE, PARAM_IMPACT_SEVERITIES)), | |||
new Change("10.2", format(NEW_FACET_ADDED_MESSAGE, PARAM_CLEAN_CODE_ATTRIBUTE_CATEGORIES)), | |||
new Change("10.2", format("Parameter '%s' renamed to '%s'", PARAM_COMPONENT_KEYS, PARAM_COMPONENTS)), | |||
new Change("10.1", "Add the 'codeVariants' parameter, facet and response field"), | |||
new Change("10.0", "Parameter 'sansTop25' is deprecated"), | |||
@@ -256,6 +274,21 @@ public class SearchAction implements IssuesWsAction { | |||
.setDescription("Comma-separated list of severities") | |||
.setExampleValue(Severity.BLOCKER + "," + Severity.CRITICAL) | |||
.setPossibleValues(Severity.ALL); | |||
action.createParam(PARAM_IMPACT_SOFTWARE_QUALITIES) | |||
.setSince("10.2") | |||
.setDescription("Comma-separated list of Software Qualities") | |||
.setExampleValue(SoftwareQuality.MAINTAINABILITY + "," + SoftwareQuality.RELIABILITY) | |||
.setPossibleValues(SoftwareQuality.values()); | |||
action.createParam(PARAM_IMPACT_SEVERITIES) | |||
.setSince("10.2") | |||
.setDescription("Comma-separated list of Software Quality Severities") | |||
.setExampleValue(org.sonar.api.issue.impact.Severity.HIGH + "," + org.sonar.api.issue.impact.Severity.MEDIUM) | |||
.setPossibleValues(org.sonar.api.issue.impact.Severity.values()); | |||
action.createParam(PARAM_CLEAN_CODE_ATTRIBUTE_CATEGORIES) | |||
.setSince("10.2") | |||
.setDescription("Comma-separated list of Clean Code Attribute Categories") | |||
.setExampleValue(CleanCodeAttributeCategory.ADAPTABLE + "," + CleanCodeAttributeCategory.INTENTIONAL) | |||
.setPossibleValues(CleanCodeAttributeCategory.values()); | |||
action.createParam(PARAM_STATUSES) | |||
.setDescription("Comma-separated list of statuses") | |||
.setExampleValue(STATUS_OPEN + "," + STATUS_REOPENED) | |||
@@ -482,6 +515,10 @@ public class SearchAction implements IssuesWsAction { | |||
private void completeFacets(Facets facets, SearchRequest request, IssueQuery query) { | |||
addMandatoryValuesToFacet(facets, PARAM_SEVERITIES, Severity.ALL); | |||
addMandatoryValuesToFacet(facets, PARAM_STATUSES, ISSUE_STATUSES); | |||
addMandatoryValuesToFacet(facets, PARAM_IMPACT_SOFTWARE_QUALITIES, enumToStringCollection(SoftwareQuality.values())); | |||
addMandatoryValuesToFacet(facets, PARAM_IMPACT_SEVERITIES, enumToStringCollection(org.sonar.api.issue.impact.Severity.values())); | |||
addMandatoryValuesToFacet(facets, PARAM_CLEAN_CODE_ATTRIBUTE_CATEGORIES, enumToStringCollection(CleanCodeAttributeCategory.values())); | |||
addMandatoryValuesToFacet(facets, PARAM_RESOLUTIONS, concat(singletonList(""), RESOLUTIONS)); | |||
addMandatoryValuesToFacet(facets, FACET_PROJECTS, query.projectUuids()); | |||
addMandatoryValuesToFacet(facets, PARAM_FILES, query.files()); | |||
@@ -512,6 +549,10 @@ public class SearchAction implements IssuesWsAction { | |||
addMandatoryValuesToFacet(facets, PARAM_CODE_VARIANTS, request.getCodeVariants()); | |||
} | |||
private static Collection<String> enumToStringCollection(Enum<?>... enumValues) { | |||
return Arrays.stream(enumValues).map(Enum::name).toList(); | |||
} | |||
private static void setTypesFacet(Facets facets) { | |||
Map<String, Long> typeFacet = facets.get(PARAM_TYPES); | |||
if (typeFacet != null) { | |||
@@ -575,6 +616,9 @@ public class SearchAction implements IssuesWsAction { | |||
.setRules(request.paramAsStrings(PARAM_RULES)) | |||
.setSort(request.param(Param.SORT)) | |||
.setSeverities(request.paramAsStrings(PARAM_SEVERITIES)) | |||
.setImpactSeverities(request.paramAsStrings(PARAM_IMPACT_SEVERITIES)) | |||
.setImpactSoftwareQualities(request.paramAsStrings(PARAM_IMPACT_SOFTWARE_QUALITIES)) | |||
.setCleanCodeAttributesCategories(request.paramAsStrings(PARAM_CLEAN_CODE_ATTRIBUTE_CATEGORIES)) | |||
.setStatuses(request.paramAsStrings(PARAM_STATUSES)) | |||
.setTags(request.paramAsStrings(PARAM_TAGS)) | |||
.setTypes(allRuleTypesExceptHotspotsIfEmpty(request.paramAsStrings(PARAM_TYPES))) |
@@ -31,6 +31,7 @@ import java.util.stream.Collectors; | |||
import org.sonar.api.resources.Language; | |||
import org.sonar.api.resources.Languages; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.rules.CleanCodeAttribute; | |||
import org.sonar.api.rules.RuleType; | |||
import org.sonar.api.utils.DateUtils; | |||
import org.sonar.api.utils.Duration; | |||
@@ -173,6 +174,21 @@ public class SearchResponseFormat { | |||
issueBuilder.setKey(dto.getKey()); | |||
issueBuilder.setType(Common.RuleType.forNumber(dto.getType())); | |||
CleanCodeAttribute cleanCodeAttribute = dto.getCleanCodeAttribute(); | |||
String cleanCodeAttributeString = cleanCodeAttribute != null ? cleanCodeAttribute.name() : null; | |||
String cleanCodeAttributeCategoryString = cleanCodeAttribute != null ? cleanCodeAttribute.getAttributeCategory().name() : null; | |||
if (cleanCodeAttributeString != null) { | |||
issueBuilder.setCleanCodeAttribute(Common.CleanCodeAttribute.valueOf(cleanCodeAttributeString)); | |||
issueBuilder.setCleanCodeAttributeCategory(Common.CleanCodeAttributeCategory.valueOf(cleanCodeAttributeCategoryString)); | |||
} | |||
issueBuilder.addAllImpacts(dto.getEffectiveImpacts().entrySet() | |||
.stream() | |||
.map(entry -> Common.Impact.newBuilder() | |||
.setSoftwareQuality(Common.SoftwareQuality.valueOf(entry.getKey().name())) | |||
.setSeverity(Common.ImpactSeverity.valueOf(entry.getValue().name())) | |||
.build()) | |||
.toList()); | |||
ComponentDto component = data.getComponentByUuid(dto.getComponentUuid()); | |||
issueBuilder.setComponent(component.getKey()); | |||
setBranchOrPr(component, issueBuilder, data); |
@@ -80,6 +80,7 @@ public class SetSeverityAction implements IssuesWsAction { | |||
.setSince("3.6") | |||
.setChangelog( | |||
new Change("10.2", "This endpoint is now deprecated."), | |||
new Change("10.2", "Add 'impacts', 'cleanCodeAttribute', 'cleanCodeAttributeCategory' fields to the response"), | |||
new Change("9.6", "Response field 'ruleDescriptionContextKey' added"), | |||
new Change("8.8", "The response field components.uuid is removed"), | |||
new Change("6.5", "the database ids of the components are removed from the response"), |
@@ -74,6 +74,7 @@ public class SetTagsAction implements IssuesWsAction { | |||
.setDescription("Set tags on an issue. <br/>" + | |||
"Requires authentication and Browse permission on project") | |||
.setChangelog( | |||
new Change("10.2", "Add 'impacts', 'cleanCodeAttribute', 'cleanCodeAttributeCategory' fields to the response"), | |||
new Change("9.6", "Response field 'ruleDescriptionContextKey' added"), | |||
new Change("8.8", "The response field components.uuid is removed"), | |||
new Change("6.5", "the database ids of the components are removed from the response"), |
@@ -83,6 +83,7 @@ public class SetTypeAction implements IssuesWsAction { | |||
"</ul>") | |||
.setSince("5.5") | |||
.setChangelog( | |||
new Change("10.2", "Add 'impacts', 'cleanCodeAttribute', 'cleanCodeAttributeCategory' fields to the response"), | |||
new Change("10.2", "This endpoint is now deprecated."), | |||
new Change("9.6", "Response field 'ruleDescriptionContextKey' added"), | |||
new Change("8.8", "The response field components.uuid is removed"), |
@@ -26,6 +26,7 @@ import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.stream.Collectors; | |||
import org.sonar.api.rules.CleanCodeAttribute; | |||
import org.sonar.api.server.ServerSide; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
@@ -95,6 +96,20 @@ public class PullTaintActionProtobufObjectGenerator implements ProtobufObjectGen | |||
taintBuilder.setSeverity(Common.Severity.valueOf(issueDto.getSeverity())); | |||
} | |||
taintBuilder.setType(Common.RuleType.forNumber(issueDto.getType())); | |||
CleanCodeAttribute cleanCodeAttribute = issueDto.getCleanCodeAttribute(); | |||
String cleanCodeAttributeString = cleanCodeAttribute != null ? cleanCodeAttribute.name() : null; | |||
String cleanCodeAttributeCategoryString = cleanCodeAttribute != null ? cleanCodeAttribute.getAttributeCategory().name() : null; | |||
if (cleanCodeAttributeString != null) { | |||
taintBuilder.setCleanCodeAttribute(Common.CleanCodeAttribute.valueOf(cleanCodeAttributeString)); | |||
taintBuilder.setCleanCodeAttributeCategory(Common.CleanCodeAttributeCategory.valueOf(cleanCodeAttributeCategoryString)); | |||
} | |||
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())) | |||
.build()) | |||
.toList()); | |||
taintBuilder.setClosed(false); | |||
taintBuilder.setMainLocation(locationBuilder.build()); | |||
issueDto.getOptionalRuleDescriptionContextKey().ifPresent(taintBuilder::setRuleDescriptionContextKey); |
@@ -2,6 +2,14 @@ | |||
"issue": { | |||
"key": "AVibidgv1LF0E-ru2DVv", | |||
"rule": "squid:S2301", | |||
"cleanCodeAttribute": "CLEAR", | |||
"cleanCodeAttributeCategory": "INTENTIONAL", | |||
"impacts": [ | |||
{ | |||
"softwareQuality": "SECURITY", | |||
"severity": "HIGH" | |||
} | |||
], | |||
"severity": "MAJOR", | |||
"component": "org.sonarsource.sonarlint.intellij:sonarlint-intellij:src/main/java/org/sonarlint/intellij/core/ServerIssueUpdater.java", | |||
"project": "org.sonarsource.sonarlint.intellij:sonarlint-intellij", |
@@ -3,6 +3,14 @@ | |||
"key": "AVibidgv1LF0E-ru2DVv", | |||
"rule": "squid:S2301", | |||
"severity": "MAJOR", | |||
"cleanCodeAttribute": "CLEAR", | |||
"cleanCodeAttributeCategory": "INTENTIONAL", | |||
"impacts": [ | |||
{ | |||
"softwareQuality": "SECURITY", | |||
"severity": "HIGH" | |||
} | |||
], | |||
"component": "org.sonarsource.sonarlint.intellij:sonarlint-intellij:src/main/java/org/sonarlint/intellij/core/ServerIssueUpdater.java", | |||
"project": "org.sonarsource.sonarlint.intellij:sonarlint-intellij", | |||
"line": 78, |
@@ -2,6 +2,14 @@ | |||
"issue": { | |||
"key": "AVibidgv1LF0E-ru2DVv", | |||
"rule": "squid:S2301", | |||
"cleanCodeAttribute": "CLEAR", | |||
"cleanCodeAttributeCategory": "INTENTIONAL", | |||
"impacts": [ | |||
{ | |||
"softwareQuality": "SECURITY", | |||
"severity": "HIGH" | |||
} | |||
], | |||
"severity": "MAJOR", | |||
"component": "org.sonarsource.sonarlint.intellij:sonarlint-intellij:src/main/java/org/sonarlint/intellij/core/ServerIssueUpdater.java", | |||
"project": "org.sonarsource.sonarlint.intellij:sonarlint-intellij", |
@@ -2,6 +2,14 @@ | |||
"issue": { | |||
"key": "AVibidgv1LF0E-ru2DVv", | |||
"rule": "squid:S2301", | |||
"cleanCodeAttribute": "CLEAR", | |||
"cleanCodeAttributeCategory": "INTENTIONAL", | |||
"impacts": [ | |||
{ | |||
"softwareQuality": "SECURITY", | |||
"severity": "HIGH" | |||
} | |||
], | |||
"severity": "MAJOR", | |||
"component": "org.sonarsource.sonarlint.intellij:sonarlint-intellij:src/main/java/org/sonarlint/intellij/core/ServerIssueUpdater.java", | |||
"project": "org.sonarsource.sonarlint.intellij:sonarlint-intellij", |
@@ -3,6 +3,14 @@ | |||
"key": "AVibidgv1LF0E-ru2DVv", | |||
"rule": "squid:S2301", | |||
"severity": "MAJOR", | |||
"cleanCodeAttribute": "CLEAR", | |||
"cleanCodeAttributeCategory": "INTENTIONAL", | |||
"impacts": [ | |||
{ | |||
"softwareQuality": "SECURITY", | |||
"severity": "HIGH" | |||
} | |||
], | |||
"component": "org.sonarsource.sonarlint.intellij:sonarlint-intellij:src/main/java/org/sonarlint/intellij/core/ServerIssueUpdater.java", | |||
"project": "org.sonarsource.sonarlint.intellij:sonarlint-intellij", | |||
"line": 78, |
@@ -1,20 +1,23 @@ | |||
# The response contains a single protocol buffer message: TaintVulnerabilityPullQueryTimestamp followed by 0..n number of TaintLite protocol buffer messages. | |||
# The response contains a single protocol buffer message: TaintVulnerabilityPullQueryTimestamp followed by 0..n number of TaintVulnerabilityLite protocol buffer messages. | |||
message TaintVulnerabilityPullQueryTimestamp { | |||
required int64 queryTimestamp = 1; | |||
} | |||
message TaintLite { | |||
message TaintVulnerabilityLite { | |||
required string key = 1; | |||
optional int64 creationDate = 2; | |||
optional bool resolved = 3; | |||
optional string ruleKey = 4; | |||
optional string severity = 5; | |||
optional string type = 6; | |||
optional sonarqube.ws.commons.Severity severity = 5; | |||
optional sonarqube.ws.commons.RuleType type = 6; | |||
optional Location mainLocation = 7; | |||
optional bool closed = 8; | |||
optional Flow flows = 9; | |||
repeated Flow flows = 9; | |||
optional bool assignedToSubscribedUser = 10; | |||
optional string ruleDescriptionContextKey = 11; | |||
optional sonarqube.ws.commons.CleanCodeAttribute cleanCodeAttribute = 12; | |||
optional sonarqube.ws.commons.CleanCodeAttributeCategory cleanCodeAttributeCategory = 13; | |||
repeated sonarqube.ws.commons.Impact impacts = 14; | |||
} | |||
message Location { |
@@ -13,6 +13,14 @@ | |||
"status": "RESOLVED", | |||
"resolution": "WONTFIX", | |||
"severity": "MAJOR", | |||
"cleanCodeAttribute": "CLEAR", | |||
"cleanCodeAttributeCategory": "INTENTIONAL", | |||
"impacts": [ | |||
{ | |||
"softwareQuality": "SECURITY", | |||
"severity": "HIGH" | |||
} | |||
], | |||
"message": "Remove this unused private \"getKee\" method.", | |||
"messageFormattings": [ | |||
{ |
@@ -3,6 +3,14 @@ | |||
"key": "AVibidgv1LF0E-ru2DVv", | |||
"rule": "squid:S2301", | |||
"severity": "MAJOR", | |||
"cleanCodeAttribute": "CLEAR", | |||
"cleanCodeAttributeCategory": "INTENTIONAL", | |||
"impacts": [ | |||
{ | |||
"softwareQuality": "SECURITY", | |||
"severity": "HIGH" | |||
} | |||
], | |||
"component": "org.sonarsource.sonarlint.intellij:sonarlint-intellij:src/main/java/org/sonarlint/intellij/core/ServerIssueUpdater.java", | |||
"project": "org.sonarsource.sonarlint.intellij:sonarlint-intellij", | |||
"line": 78, |
@@ -3,6 +3,14 @@ | |||
"key": "AVibidgv1LF0E-ru2DVv", | |||
"rule": "squid:S2301", | |||
"severity": "MAJOR", | |||
"cleanCodeAttribute": "CLEAR", | |||
"cleanCodeAttributeCategory": "INTENTIONAL", | |||
"impacts": [ | |||
{ | |||
"softwareQuality": "SECURITY", | |||
"severity": "HIGH" | |||
} | |||
], | |||
"component": "org.sonarsource.sonarlint.intellij:sonarlint-intellij:src/main/java/org/sonarlint/intellij/core/ServerIssueUpdater.java", | |||
"project": "org.sonarsource.sonarlint.intellij:sonarlint-intellij", | |||
"line": 78, |
@@ -3,6 +3,14 @@ | |||
"key": "AVibidgv1LF0E-ru2DVv", | |||
"rule": "squid:S2301", | |||
"severity": "MAJOR", | |||
"cleanCodeAttribute": "CLEAR", | |||
"cleanCodeAttributeCategory": "INTENTIONAL", | |||
"impacts": [ | |||
{ | |||
"softwareQuality": "SECURITY", | |||
"severity": "HIGH" | |||
} | |||
], | |||
"component": "org.sonarsource.sonarlint.intellij:sonarlint-intellij:src/main/java/org/sonarlint/intellij/core/ServerIssueUpdater.java", | |||
"project": "org.sonarsource.sonarlint.intellij:sonarlint-intellij", | |||
"line": 78, |
@@ -30,6 +30,7 @@ import org.junit.Test; | |||
import org.junit.runner.RunWith; | |||
import org.mockito.junit.MockitoJUnitRunner; | |||
import org.sonar.api.resources.Languages; | |||
import org.sonar.api.rules.CleanCodeAttribute; | |||
import org.sonar.api.utils.Duration; | |||
import org.sonar.api.utils.Durations; | |||
import org.sonar.db.DbTester; | |||
@@ -51,6 +52,7 @@ import static java.lang.System.currentTimeMillis; | |||
import static java.util.stream.Collectors.toList; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.groups.Tuple.tuple; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
@@ -122,6 +124,8 @@ public class SearchResponseFormatFormatOperationTest { | |||
private void assertIssueEqualsIssueDto(Issue issue, IssueDto issueDto) { | |||
assertThat(issue.getKey()).isEqualTo(issueDto.getKey()); | |||
assertThat(issue.getCleanCodeAttribute()).isEqualTo(Common.CleanCodeAttribute.valueOf(issueDto.getCleanCodeAttribute().name())); | |||
assertThat(issue.getCleanCodeAttributeCategory()).isEqualTo(Common.CleanCodeAttributeCategory.valueOf(issueDto.getCleanCodeAttribute().getAttributeCategory().name())); | |||
assertThat(issue.getType().getNumber()).isEqualTo(issueDto.getType()); | |||
assertThat(issue.getComponent()).isEqualTo(issueDto.getComponentKey()); | |||
assertThat(issue.getRule()).isEqualTo(issueDto.getRuleKey().toString()); | |||
@@ -140,6 +144,13 @@ public class SearchResponseFormatFormatOperationTest { | |||
assertThat(issue.getQuickFixAvailable()).isEqualTo(issueDto.isQuickFixAvailable()); | |||
assertThat(issue.getRuleDescriptionContextKey()).isEqualTo(issueDto.getOptionalRuleDescriptionContextKey().orElse(null)); | |||
assertThat(new ArrayList<>(issue.getCodeVariantsList())).containsExactlyInAnyOrderElementsOf(issueDto.getCodeVariants()); | |||
assertThat(issue.getImpactsList()) | |||
.extracting(Common.Impact::getSoftwareQuality, Common.Impact::getSeverity) | |||
.containsExactlyInAnyOrderElementsOf(issueDto.getEffectiveImpacts() | |||
.entrySet() | |||
.stream() | |||
.map(entry -> tuple(Common.SoftwareQuality.valueOf(entry.getKey().name()), Common.ImpactSeverity.valueOf(entry.getValue().name()))) | |||
.collect(toList())); | |||
} | |||
@Test | |||
@@ -295,6 +306,7 @@ public class SearchResponseFormatFormatOperationTest { | |||
componentDto = component; | |||
issueDto = newIssue(ruleDto, component.branchUuid(), component.getKey(), component) | |||
.setType(CODE_SMELL) | |||
.setCleanCodeAttribute(CleanCodeAttribute.CLEAR) | |||
.setRuleDescriptionContextKey("context_key_" + randomAlphanumeric(5)) | |||
.setAssigneeUuid(userDto.getUuid()) | |||
.setResolution("resolution_" + randomAlphanumeric(5)) |
@@ -54,10 +54,8 @@ public class IssuesWsParameters { | |||
public static final String PARAM_TYPE = "type"; | |||
public static final String PARAM_ISSUES = "issues"; | |||
public static final String PARAM_SEVERITIES = "severities"; | |||
public static final String PARAM_SOFTWARE_QUALITIES = "softwareQualities"; | |||
//TODO: To be discussed for the naming | |||
public static final String PARAM_SOFTWARE_QUALITIES_SEVERTIIES = "softwareQualitiesSeverities"; | |||
public static final String PARAM_IMPACT_SOFTWARE_QUALITIES = "impactSoftwareQualities"; | |||
public static final String PARAM_IMPACT_SEVERITIES = "impactSeverities"; | |||
public static final String PARAM_CLEAN_CODE_ATTRIBUTE_CATEGORIES = "cleanCodeAttributeCategories"; | |||
public static final String PARAM_STATUSES = "statuses"; | |||
public static final String PARAM_RESOLUTIONS = "resolutions"; |
@@ -78,6 +78,47 @@ enum RuleScope { | |||
ALL = 2; | |||
} | |||
enum CleanCodeAttribute { | |||
CONVENTIONAL = 0; | |||
FORMATTED = 1; | |||
IDENTIFIABLE = 2; | |||
CLEAR = 3; | |||
COMPLETE = 4; | |||
EFFICIENT = 5; | |||
LOGICAL = 6; | |||
DISTINCT = 7; | |||
FOCUSED = 8; | |||
MODULAR = 9; | |||
TESTED = 10; | |||
LAWFUL = 11; | |||
RESPECTFUL = 12; | |||
TRUSTWORTHY = 13; | |||
} | |||
enum CleanCodeAttributeCategory { | |||
ADAPTABLE = 0; | |||
CONSISTENT = 1; | |||
INTENTIONAL = 2; | |||
RESPONSIBLE = 3; | |||
} | |||
message Impact { | |||
required SoftwareQuality softwareQuality = 1; | |||
required ImpactSeverity severity = 2; | |||
} | |||
enum SoftwareQuality { | |||
MAINTAINABILITY = 0; | |||
RELIABILITY = 1; | |||
SECURITY = 2; | |||
} | |||
enum ImpactSeverity { | |||
LOW = 0; | |||
MEDIUM = 1; | |||
HIGH = 2; | |||
} | |||
// Lines start at 1 and line offsets start at 0 | |||
message TextRange { | |||
// Start line. Should never be absent |
@@ -163,6 +163,9 @@ message Issue { | |||
repeated sonarqube.ws.commons.MessageFormatting messageFormattings = 38; | |||
repeated string codeVariants = 39; | |||
optional sonarqube.ws.commons.CleanCodeAttribute cleanCodeAttribute = 40; | |||
optional sonarqube.ws.commons.CleanCodeAttributeCategory cleanCodeAttributeCategory = 41; | |||
repeated sonarqube.ws.commons.Impact impacts = 42; | |||
} | |||
message Transitions { | |||
@@ -289,6 +292,9 @@ message TaintVulnerabilityLite { | |||
repeated Flow flows = 9; | |||
optional bool assignedToSubscribedUser = 10; | |||
optional string ruleDescriptionContextKey = 11; | |||
optional sonarqube.ws.commons.CleanCodeAttribute cleanCodeAttribute = 12; | |||
optional sonarqube.ws.commons.CleanCodeAttributeCategory cleanCodeAttributeCategory = 13; | |||
repeated sonarqube.ws.commons.Impact impacts = 14; | |||
} | |||
message Flow { |