aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycle.java10
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCache.java3
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/protobuf/issue_cache.proto1
-rw-r--r--server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycleTest.java11
-rw-r--r--server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCacheTest.java22
-rw-r--r--server/sonar-db-dao/src/it/java/org/sonar/db/issue/IssueDaoIT.java3
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/issue/IndexedIssueDto.java15
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDto.java16
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml25
-rw-r--r--server/sonar-db-dao/src/schema/schema-sq.ddl3
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/issue/IndexedIssueDtoTest.java5
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/issue/IssueDtoTest.java2
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v103/AddCleanCodeAttributeColumnInIssuesTable.java54
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v103/DbVersion103.java1
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v103/AddCleanCodeAttributeColumnInIssuesTableTest.java51
-rw-r--r--server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v103/AddCleanCodeAttributeColumnInIssuesTableTest/schema.sql38
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/issue/IssueFieldsSetter.java20
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIteratorForSingleChunk.java5
-rw-r--r--server/sonar-server-common/src/test/java/org/sonar/server/issue/IssueFieldsSetterTest.java22
-rw-r--r--server/sonar-webserver-webapi/src/it/java/org/sonar/server/issue/WebIssueStorageIT.java4
-rw-r--r--server/sonar-webserver-webapi/src/it/java/org/sonar/server/issue/ws/PullTaintActionIT.java4
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java2
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/pull/PullTaintActionProtobufObjectGenerator.java2
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchResponseFormatFormatOperationTest.java4
-rw-r--r--sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java16
25 files changed, 306 insertions, 33 deletions
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycle.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycle.java
index 39bffffc47e..c1f7f2e72cd 100644
--- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycle.java
+++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycle.java
@@ -26,6 +26,7 @@ import java.util.Optional;
import javax.inject.Inject;
import org.jetbrains.annotations.NotNull;
import org.sonar.api.issue.Issue;
+import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.rules.RuleType;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.core.issue.DefaultIssue;
@@ -38,6 +39,7 @@ import org.sonar.server.issue.IssueFieldsSetter;
import org.sonar.server.issue.workflow.IssueWorkflow;
import static java.util.Objects.requireNonNull;
+import static java.util.Optional.ofNullable;
import static org.sonar.core.issue.IssueChangeContext.issueChangeContextByScanBuilder;
/**
@@ -83,6 +85,11 @@ public class IssueLifecycle {
issue.setEffort(debtCalculator.calculate(issue));
setType(issue, rule);
setStatus(issue, rule);
+ setCleanCodeAttribute(issue, rule);
+ }
+
+ private static void setCleanCodeAttribute(DefaultIssue issue, Rule rule) {
+ issue.setCleanCodeAttribute(ofNullable(rule.cleanCodeAttribute()).orElse(CleanCodeAttribute.defaultCleanCodeAttribute()));
}
private static void setType(DefaultIssue issue, Rule rule) {
@@ -129,6 +136,7 @@ public class IssueLifecycle {
to.setManualSeverity(true);
to.setSeverity(from.severity());
}
+ to.setCleanCodeAttribute(from.getCleanCodeAttribute());
copyChangesOfIssueFromOtherBranch(to, from);
}
@@ -181,6 +189,7 @@ public class IssueLifecycle {
raw.setChanged(true);
}
setType(raw, rule);
+ setCleanCodeAttribute(raw, rule);
copyFields(raw, base);
base.changes().forEach(raw::addChange);
@@ -204,6 +213,7 @@ public class IssueLifecycle {
updater.setPastEffort(raw, base.effort(), changeContext);
updater.setCodeVariants(raw, requireNonNull(base.codeVariants()), changeContext);
updater.setImpacts(raw, base.impacts(), changeContext);
+ updater.setCleanCodeAttribute(raw, base.getCleanCodeAttribute(), changeContext);
}
public void doAutomaticTransition(DefaultIssue issue) {
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCache.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCache.java
index 4e015401a3b..39f5c138bef 100644
--- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCache.java
+++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCache.java
@@ -35,6 +35,7 @@ import javax.annotation.CheckForNull;
import org.sonar.api.issue.impact.Severity;
import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.System2;
@@ -138,6 +139,7 @@ public class ProtobufIssueDiskCache implements DiskCache<DefaultIssue> {
defaultIssue.setSelectedAt(next.hasSelectedAt() ? next.getSelectedAt() : null);
defaultIssue.setQuickFixAvailable(next.getQuickFixAvailable());
defaultIssue.setIsNoLongerNewCodeReferenceIssue(next.getIsNoLongerNewCodeReferenceIssue());
+ defaultIssue.setCleanCodeAttribute(next.hasCleanCodeAttribute() ? CleanCodeAttribute.valueOf(next.getCleanCodeAttribute()) : null);
if (next.hasAnticipatedTransitionUuid()) {
defaultIssue.setAnticipatedTransitionUuid(next.getAnticipatedTransitionUuid());
}
@@ -156,6 +158,7 @@ public class ProtobufIssueDiskCache implements DiskCache<DefaultIssue> {
builder.clear();
builder.setKey(defaultIssue.key());
builder.setRuleType(defaultIssue.type().getDbConstant());
+ ofNullable(defaultIssue.getCleanCodeAttribute()).ifPresent(value -> builder.setCleanCodeAttribute(value.name()));
ofNullable(defaultIssue.componentUuid()).ifPresent(builder::setComponentUuid);
builder.setComponentKey(defaultIssue.componentKey());
builder.setProjectUuid(defaultIssue.projectUuid());
diff --git a/server/sonar-ce-task-projectanalysis/src/main/protobuf/issue_cache.proto b/server/sonar-ce-task-projectanalysis/src/main/protobuf/issue_cache.proto
index 77eabd0a214..8b8c05049f8 100644
--- a/server/sonar-ce-task-projectanalysis/src/main/protobuf/issue_cache.proto
+++ b/server/sonar-ce-task-projectanalysis/src/main/protobuf/issue_cache.proto
@@ -85,6 +85,7 @@ message Issue {
optional string assigneeLogin = 47;
optional string anticipatedTransitionUuid = 48;
repeated Impact impacts = 49;
+ optional string cleanCodeAttribute = 50;
}
message Comment {
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycleTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycleTest.java
index 8c925bc46fb..1f8758d5533 100644
--- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycleTest.java
+++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycleTest.java
@@ -25,6 +25,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.issue.impact.Severity;
import org.sonar.api.issue.impact.SoftwareQuality;
+import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.Duration;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
@@ -93,6 +94,7 @@ public class IssueLifecycleTest {
assertThat(issue.effort()).isEqualTo(DEFAULT_DURATION);
assertThat(issue.isNew()).isTrue();
assertThat(issue.isCopied()).isFalse();
+ assertThat(issue.getCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.CONVENTIONAL);
}
@Test
@@ -123,6 +125,7 @@ public class IssueLifecycleTest {
.setIsNewCodeReferenceIssue(true);
fromShort.setResolution("resolution");
fromShort.setStatus("status");
+ fromShort.setCleanCodeAttribute(CleanCodeAttribute.COMPLETE);
Date commentDate = new Date();
fromShort.addComment(new DefaultIssueComment()
@@ -154,6 +157,7 @@ public class IssueLifecycleTest {
assertThat(raw.resolution()).isEqualTo("resolution");
assertThat(raw.status()).isEqualTo("status");
+ assertThat(raw.getCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.COMPLETE);
assertThat(raw.defaultIssueComments())
.extracting(DefaultIssueComment::issueKey, DefaultIssueComment::createdAt, DefaultIssueComment::userUuid, DefaultIssueComment::markdownText)
.containsOnly(tuple("raw", commentDate, "user_uuid", "A comment"));
@@ -184,6 +188,7 @@ public class IssueLifecycleTest {
.setKey("short");
fromShort.setResolution("resolution");
fromShort.setStatus("status");
+ fromShort.setCleanCodeAttribute(CleanCodeAttribute.DISTINCT);
Date commentDate = new Date();
fromShort.addComment(new DefaultIssueComment()
@@ -211,6 +216,7 @@ public class IssueLifecycleTest {
assertThat(raw.resolution()).isEqualTo("resolution");
assertThat(raw.status()).isEqualTo("status");
+ assertThat(raw.getCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.DISTINCT);
assertThat(raw.defaultIssueComments())
.extracting(DefaultIssueComment::issueKey, DefaultIssueComment::createdAt, DefaultIssueComment::userUuid, DefaultIssueComment::markdownText)
.containsOnly(tuple("raw", commentDate, "user_uuid", "A comment"));
@@ -295,6 +301,7 @@ public class IssueLifecycleTest {
.setCreationDate(parseDate("2015-01-01"))
.setUpdateDate(parseDate("2015-01-02"))
.setCloseDate(parseDate("2015-01-03"))
+ .setCleanCodeAttribute(CleanCodeAttribute.FOCUSED)
.setResolution(RESOLUTION_FIXED)
.setStatus(STATUS_CLOSED)
.setSeverity(BLOCKER)
@@ -321,6 +328,7 @@ public class IssueLifecycleTest {
assertThat(raw.isNew()).isFalse();
assertThat(raw.isCopied()).isTrue();
+ assertThat(raw.getCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.FOCUSED);
assertThat(raw.key()).isNotNull();
assertThat(raw.key()).isNotEqualTo(base.key());
assertThat(raw.creationDate()).isEqualTo(base.creationDate());
@@ -387,6 +395,7 @@ public class IssueLifecycleTest {
.setKey("RAW_KEY")
.setRuleKey(XOO_X1)
.setRuleDescriptionContextKey("spring")
+ .setCleanCodeAttribute(CleanCodeAttribute.IDENTIFIABLE)
.setCodeVariants(Set.of("foo", "bar"))
.addImpact(SoftwareQuality.MAINTAINABILITY, Severity.HIGH)
.setCreationDate(parseDate("2015-10-01"))
@@ -413,6 +422,7 @@ public class IssueLifecycleTest {
.setKey("BASE_KEY")
.setCreationDate(parseDate("2015-01-01"))
.setUpdateDate(parseDate("2015-01-02"))
+ .setCleanCodeAttribute(CleanCodeAttribute.FOCUSED)
.setResolution(RESOLUTION_FALSE_POSITIVE)
.setStatus(STATUS_RESOLVED)
.setSeverity(BLOCKER)
@@ -468,6 +478,7 @@ public class IssueLifecycleTest {
verify(updater).setPastMessage(raw, "message with code", messageFormattings, issueChangeContext);
verify(updater).setPastEffort(raw, Duration.create(15L), issueChangeContext);
verify(updater).setPastLocations(raw, issueLocations);
+ verify(updater).setCleanCodeAttribute(raw, CleanCodeAttribute.FOCUSED, issueChangeContext);
}
@Test
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCacheTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCacheTest.java
index 340bb259769..f65c91bfbda 100644
--- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCacheTest.java
+++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCacheTest.java
@@ -25,6 +25,7 @@ import org.junit.Test;
import org.sonar.api.issue.impact.Severity;
import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.rules.RuleType;
import org.sonar.core.issue.DefaultIssue;
@@ -68,6 +69,17 @@ public class ProtobufIssueDiskCacheTest {
}
@Test
+ public void toDefaultIssue_whenCleanCodeAttributeIsSet_shouldSetItInDefaultIssue() {
+ IssueCache.Issue issue = prepareIssueWithCompulsoryFields()
+ .setCleanCodeAttribute(CleanCodeAttribute.FOCUSED.name())
+ .build();
+
+ DefaultIssue defaultIssue = ProtobufIssueDiskCache.toDefaultIssue(issue);
+
+ assertThat(defaultIssue.getCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.FOCUSED);
+ }
+
+ @Test
public void toProto_whenRuleDescriptionContextKeySet_shouldCopyToIssueProto() {
DefaultIssue defaultIssue = createDefaultIssueWithMandatoryFields();
defaultIssue.setRuleDescriptionContextKey(TEST_CONTEXT_KEY);
@@ -102,6 +114,16 @@ public class ProtobufIssueDiskCacheTest {
);
}
+ @Test
+ public void toProto_whenCleanCodeAttributeIsSet_shouldCopyToIssueProto() {
+ DefaultIssue defaultIssue = createDefaultIssueWithMandatoryFields();
+ defaultIssue.setCleanCodeAttribute(CleanCodeAttribute.FOCUSED);
+
+ IssueCache.Issue issue = ProtobufIssueDiskCache.toProto(IssueCache.Issue.newBuilder(), defaultIssue);
+
+ assertThat(issue.getCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.FOCUSED.name());
+ }
+
private IssueCache.Impact toImpact(SoftwareQuality softwareQuality, Severity severity) {
return IssueCache.Impact.newBuilder().setSoftwareQuality(softwareQuality.name()).setSeverity(severity.name()).build();
}
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/issue/IssueDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/issue/IssueDaoIT.java
index f5ecdafdf3c..145c9ad786b 100644
--- a/server/sonar-db-dao/src/it/java/org/sonar/db/issue/IssueDaoIT.java
+++ b/server/sonar-db-dao/src/it/java/org/sonar/db/issue/IssueDaoIT.java
@@ -134,6 +134,7 @@ public class IssueDaoIT {
.setManualSeverity(false)
.setMessage("the message")
.setRuleDescriptionContextKey(TEST_CONTEXT_KEY)
+ .setRuleCleanCodeAttribute(RULE.getCleanCodeAttribute())
.setLine(500)
.setEffort(10L)
.setGap(3.14)
@@ -164,7 +165,7 @@ public class IssueDaoIT {
assertThat(issue.getIssueCloseDate()).isNotNull();
assertThat(issue.getRuleRepo()).isEqualTo(RULE.getRepositoryKey());
assertThat(issue.getRule()).isEqualTo(RULE.getRuleKey());
- assertThat(issue.getCleanCodeAttribute()).isEqualTo(RULE.getCleanCodeAttribute());
+ assertThat(issue.getEffectiveCleanCodeAttribute()).isEqualTo(RULE.getCleanCodeAttribute());
assertThat(issue.parseLocations()).isNull();
assertThat(issue.getImpacts())
.extracting(ImpactDto::getSeverity, ImpactDto::getSoftwareQuality)
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IndexedIssueDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IndexedIssueDto.java
index b4f84bfa9f3..ec56e1ef8d9 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IndexedIssueDto.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IndexedIssueDto.java
@@ -33,6 +33,7 @@ public final class IndexedIssueDto {
private Integer line = null;
private String resolution = null;
private String cleanCodeAttribute = null;
+ private String ruleCleanCodeAttribute = null;
private String severity = null;
private String status = null;
private Long effort = null;
@@ -312,11 +313,23 @@ public final class IndexedIssueDto {
}
public String getCleanCodeAttribute() {
- return cleanCodeAttribute;
+ if (cleanCodeAttribute != null) {
+ return cleanCodeAttribute;
+ }
+ return ruleCleanCodeAttribute;
}
public IndexedIssueDto setCleanCodeAttribute(String cleanCodeAttribute) {
this.cleanCodeAttribute = cleanCodeAttribute;
return this;
}
+
+ public String getRuleCleanCodeAttribute() {
+ return ruleCleanCodeAttribute;
+ }
+
+ public IndexedIssueDto setRuleCleanCodeAttribute(String ruleCleanCodeAttribute) {
+ this.ruleCleanCodeAttribute = ruleCleanCodeAttribute;
+ return this;
+ }
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDto.java
index d933e0b45fd..00b1342dbe3 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDto.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDto.java
@@ -116,6 +116,7 @@ public final class IssueDto implements Serializable {
//non-persisted fields
private Set<ImpactDto> ruleDefaultImpacts = new HashSet<>();
private CleanCodeAttribute cleanCodeAttribute;
+ private CleanCodeAttribute ruleCleanCodeAttribute;
public IssueDto() {
// nothing to do
@@ -158,6 +159,7 @@ public final class IssueDto implements Serializable {
.setIsNewCodeReferenceIssue(issue.isNewCodeReferenceIssue())
.setCodeVariants(issue.codeVariants())
.replaceAllImpacts(mapToImpactDto(issue.impacts()))
+ .setCleanCodeAttribute(issue.getCleanCodeAttribute())
// technical dates
.setCreatedAt(now)
.setUpdatedAt(now);
@@ -215,6 +217,7 @@ public final class IssueDto implements Serializable {
.setIsNewCodeReferenceIssue(issue.isNewCodeReferenceIssue())
.setCodeVariants(issue.codeVariants())
.replaceAllImpacts(mapToImpactDto(issue.impacts()))
+ .setCleanCodeAttribute(issue.getCleanCodeAttribute())
// technical date
.setUpdatedAt(now);
}
@@ -771,8 +774,11 @@ public final class IssueDto implements Serializable {
}
@CheckForNull
- public CleanCodeAttribute getCleanCodeAttribute() {
- return cleanCodeAttribute;
+ public CleanCodeAttribute getEffectiveCleanCodeAttribute() {
+ if (cleanCodeAttribute != null) {
+ return cleanCodeAttribute;
+ }
+ return ruleCleanCodeAttribute;
}
public IssueDto setCleanCodeAttribute(CleanCodeAttribute cleanCodeAttribute) {
@@ -780,6 +786,11 @@ public final class IssueDto implements Serializable {
return this;
}
+ public IssueDto setRuleCleanCodeAttribute(CleanCodeAttribute ruleCleanCodeAttribute) {
+ this.ruleCleanCodeAttribute = ruleCleanCodeAttribute;
+ return this;
+ }
+
public Optional<String> getClosedChangeData() {
return Optional.ofNullable(closedChangeData);
}
@@ -887,6 +898,7 @@ public final class IssueDto implements Serializable {
issue.setQuickFixAvailable(quickFixAvailable);
issue.setIsNewCodeReferenceIssue(isNewCodeReferenceIssue);
issue.setCodeVariants(getCodeVariants());
+ issue.setCleanCodeAttribute(cleanCodeAttribute);
impacts.forEach(i -> issue.addImpact(i.getSoftwareQuality(), i.getSeverity()));
return issue;
}
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml
index a731ea97d42..62b53297cf2 100644
--- a/server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml
+++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml
@@ -32,7 +32,8 @@
r.plugin_name as ruleRepo,
r.language as language,
r.security_standards as securityStandards,
- r.clean_code_attribute as cleanCodeAttribute,
+ i.clean_code_attribute as cleanCodeAttribute,
+ r.clean_code_attribute as ruleCleanCodeAttribute,
p.kee as componentKey,
i.component_uuid as componentUuid,
p.path as filePath,
@@ -73,7 +74,8 @@
i.project_uuid,
i.issue_type,
i.quick_fix_available,
- i.code_variants
+ i.code_variants,
+ i.clean_code_attribute
</sql>
<sql id="isNewCodeReferenceIssue" databaseId="mssql">
@@ -143,7 +145,8 @@
INSERT INTO issues (kee, rule_uuid, severity, manual_severity,
message, message_formattings, line, locations, gap, effort, status, tags, rule_description_context_key,
resolution, checksum, assignee, author_login, issue_creation_date, issue_update_date,
- issue_close_date, created_at, updated_at, component_uuid, project_uuid, issue_type, quick_fix_available, code_variants)
+ issue_close_date, created_at, updated_at, component_uuid, project_uuid, issue_type, quick_fix_available, code_variants,
+ clean_code_attribute)
VALUES (
#{kee,jdbcType=VARCHAR},
#{ruleUuid,jdbcType=VARCHAR},
@@ -164,7 +167,8 @@
#{createdAt,jdbcType=BIGINT}, #{updatedAt,jdbcType=BIGINT},
#{componentUuid,jdbcType=VARCHAR}, #{projectUuid,jdbcType=VARCHAR}, #{type,jdbcType=INTEGER},
#{quickFixAvailable, jdbcType=BOOLEAN},
- #{codeVariantsString,jdbcType=VARCHAR})
+ #{codeVariantsString,jdbcType=VARCHAR},
+ #{effectiveCleanCodeAttribute,jdbcType=VARCHAR})
</insert>
<insert id="insertAsNewCodeOnReferenceBranch" parameterType="NewCodeReferenceIssue" useGeneratedKeys="false">
@@ -220,7 +224,8 @@
issue_close_date=#{issueCloseTime,jdbcType=BIGINT},
updated_at=#{updatedAt,jdbcType=BIGINT},
issue_type=#{type,jdbcType=INTEGER},
- code_variants=#{codeVariantsString,jdbcType=VARCHAR}
+ code_variants=#{codeVariantsString,jdbcType=VARCHAR},
+ clean_code_attribute=#{effectiveCleanCodeAttribute,jdbcType=VARCHAR}
where kee = #{kee}
</update>
@@ -251,7 +256,8 @@
issue_close_date=#{issueCloseTime,jdbcType=BIGINT},
updated_at=#{updatedAt,jdbcType=BIGINT},
issue_type=#{type,jdbcType=INTEGER},
- code_variants=#{codeVariantsString,jdbcType=VARCHAR}
+ code_variants=#{codeVariantsString,jdbcType=VARCHAR},
+ clean_code_attribute=#{effectiveCleanCodeAttribute,jdbcType=VARCHAR}
where kee = #{kee} and updated_at &lt;= #{selectedAt}
</update>
@@ -350,7 +356,8 @@
i.issue_update_date as issueUpdateDate,
r.uuid as ruleUuid,
r.language as language,
- r.clean_code_attribute as cleanCodeAttribute,
+ i.clean_code_attribute as cleanCodeAttribute,
+ r.clean_code_attribute as ruleCleanCodeAttribute,
c.uuid as componentUuid,
c.path,
c.scope,
@@ -791,7 +798,6 @@
r.rule_type as ruleType,
r.plugin_name as ruleRepo,
r.plugin_rule_key as ruleKey,
- r.clean_code_attribute as cleanCodeAttribute,
i.message as message,
i.message_formattings as messageFormattings,
i.severity as severity,
@@ -804,7 +810,8 @@
i.rule_description_context_key as ruleDescriptionContextKey,
<include refid="issueImpactsColumns"/>
<include refid="ruleDefaultImpactsColumns"/>
- r.clean_code_attribute as cleanCodeAttribute
+ i.clean_code_attribute as cleanCodeAttribute,
+ r.clean_code_attribute as ruleCleanCodeAttribute
</sql>
<select id="selectByBranch" parameterType="map" resultMap="issueResultMap" resultOrdered="true">
diff --git a/server/sonar-db-dao/src/schema/schema-sq.ddl b/server/sonar-db-dao/src/schema/schema-sq.ddl
index 79d702ed087..3c513e7c904 100644
--- a/server/sonar-db-dao/src/schema/schema-sq.ddl
+++ b/server/sonar-db-dao/src/schema/schema-sq.ddl
@@ -459,7 +459,8 @@ CREATE TABLE "ISSUES"(
"QUICK_FIX_AVAILABLE" BOOLEAN,
"RULE_DESCRIPTION_CONTEXT_KEY" CHARACTER VARYING(50),
"MESSAGE_FORMATTINGS" BINARY LARGE OBJECT,
- "CODE_VARIANTS" CHARACTER VARYING(4000)
+ "CODE_VARIANTS" CHARACTER VARYING(4000),
+ "CLEAN_CODE_ATTRIBUTE" CHARACTER VARYING(40)
);
ALTER TABLE "ISSUES" ADD CONSTRAINT "PK_ISSUES" PRIMARY KEY("KEE");
CREATE INDEX "ISSUES_ASSIGNEE" ON "ISSUES"("ASSIGNEE" NULLS FIRST);
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/issue/IndexedIssueDtoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/issue/IndexedIssueDtoTest.java
index 24ba25aed7f..d4ef1a54658 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/issue/IndexedIssueDtoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/issue/IndexedIssueDtoTest.java
@@ -37,6 +37,7 @@ public class IndexedIssueDtoTest {
.setStatus("status")
.setNewCodeReferenceIssue(true)
.setCleanCodeAttribute("cleanCodeAttribute")
+ .setRuleCleanCodeAttribute("ruleCleanCodeAttribute")
.setCodeVariants("codeVariants")
.setSecurityStandards("securityStandards")
.setComponentUuid("componentUuid")
@@ -63,13 +64,13 @@ public class IndexedIssueDtoTest {
assertThat(indexedIssueDto)
.extracting(IndexedIssueDto::getIssueKey, IndexedIssueDto::getAssignee, IndexedIssueDto::getAuthorLogin, IndexedIssueDto::getStatus,
- IndexedIssueDto::isNewCodeReferenceIssue, IndexedIssueDto::getCleanCodeAttribute, IndexedIssueDto::getCodeVariants,
+ IndexedIssueDto::isNewCodeReferenceIssue, IndexedIssueDto::getCleanCodeAttribute, IndexedIssueDto::getRuleCleanCodeAttribute, IndexedIssueDto::getCodeVariants,
IndexedIssueDto::getSecurityStandards, IndexedIssueDto::getComponentUuid, IndexedIssueDto::getIssueCloseDate, IndexedIssueDto::getIssueCreationDate,
IndexedIssueDto::getIssueUpdateDate, IndexedIssueDto::getEffort, IndexedIssueDto::isMain, IndexedIssueDto::getLanguage, IndexedIssueDto::getLine,
IndexedIssueDto::getPath, IndexedIssueDto::getProjectUuid, IndexedIssueDto::getQualifier, IndexedIssueDto::getResolution,
IndexedIssueDto::getRuleUuid, IndexedIssueDto::getScope, IndexedIssueDto::getSeverity, IndexedIssueDto::getTags, IndexedIssueDto::getIssueType,
IndexedIssueDto::getBranchUuid)
- .containsExactly("issueKey", "assignee", "authorLogin", "status", true, "cleanCodeAttribute", "codeVariants", "securityStandards",
+ .containsExactly("issueKey", "assignee", "authorLogin", "status", true, "cleanCodeAttribute", "ruleCleanCodeAttribute", "codeVariants", "securityStandards",
"componentUuid", 1L, 2L, 3L, 4L, true, "language", 5, "path", "projectUuid", "qualifier", "resolution", "ruleUuid",
"scope", "severity", "tags", 6, "branchUuid");
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/issue/IssueDtoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/issue/IssueDtoTest.java
index 7530893e97c..d7e64ea110f 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/issue/IssueDtoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/issue/IssueDtoTest.java
@@ -138,7 +138,7 @@ public class IssueDtoTest {
assertThat(dto.getRuleRepo()).isEqualTo("java");
assertThat(dto.getRule()).isEqualTo("AvoidCycle");
assertThat(dto.getRuleKey()).hasToString("java:AvoidCycle");
- assertThat(dto.getCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.CLEAR);
+ assertThat(dto.getEffectiveCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.CLEAR);
assertThat(dto.getLanguage()).isEqualTo("xoo");
assertThat(dto.isExternal()).isTrue();
}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v103/AddCleanCodeAttributeColumnInIssuesTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v103/AddCleanCodeAttributeColumnInIssuesTable.java
new file mode 100644
index 00000000000..7fbed8dffbf
--- /dev/null
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v103/AddCleanCodeAttributeColumnInIssuesTable.java
@@ -0,0 +1,54 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v103;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.db.DatabaseUtils;
+import org.sonar.server.platform.db.migration.def.ColumnDef;
+import org.sonar.server.platform.db.migration.def.VarcharColumnDef;
+import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+public class AddCleanCodeAttributeColumnInIssuesTable extends DdlChange {
+ private static final String TABLE_NAME = "issues";
+ private static final String COLUMN_NAME = "clean_code_attribute";
+ private static final int NEW_COLUMN_SIZE = 40;
+
+
+ public AddCleanCodeAttributeColumnInIssuesTable(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ try (Connection connection = getDatabase().getDataSource().getConnection()) {
+ if (!DatabaseUtils.tableColumnExists(connection, TABLE_NAME, COLUMN_NAME)) {
+ ColumnDef columnDef = VarcharColumnDef.newVarcharColumnDefBuilder()
+ .setColumnName(COLUMN_NAME)
+ .setLimit(NEW_COLUMN_SIZE)
+ .setIsNullable(true)
+ .build();
+ context.execute(new AddColumnsBuilder(getDialect(), TABLE_NAME).addColumn(columnDef).build());
+ }
+ }
+ }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v103/DbVersion103.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v103/DbVersion103.java
index e7f216fae9b..82bbeea7384 100644
--- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v103/DbVersion103.java
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v103/DbVersion103.java
@@ -45,6 +45,7 @@ public class DbVersion103 implements DbVersion {
.add(10_3_001, "Add table 'github_perms_mapping'", CreateGithubPermissionsMappingTable.class)
.add(10_3_002, "Create unique index on 'github_perms_mapping'", CreateUniqueIndexForGithubPermissionsMappingTable.class)
.add(10_3_003, "Add default mappings to 'github_perms_mapping'", PopulateGithubPermissionsMapping.class)
+ .add(10_3_004, "Add 'clean_code_attribute' column in 'issues' table", AddCleanCodeAttributeColumnInIssuesTable.class);
;
}
}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v103/AddCleanCodeAttributeColumnInIssuesTableTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v103/AddCleanCodeAttributeColumnInIssuesTableTest.java
new file mode 100644
index 00000000000..fc952e6ec47
--- /dev/null
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v103/AddCleanCodeAttributeColumnInIssuesTableTest.java
@@ -0,0 +1,51 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v103;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+import static org.assertj.core.api.Assertions.assertThatCode;
+
+public class AddCleanCodeAttributeColumnInIssuesTableTest {
+ private static final String TABLE_NAME = "issues";
+ private static final String COLUMN_NAME = "clean_code_attribute";
+
+ @Rule
+ public final CoreDbTester db = CoreDbTester.createForSchema(AddCleanCodeAttributeColumnInIssuesTableTest.class, "schema.sql");
+
+ private final AddCleanCodeAttributeColumnInIssuesTable underTest = new AddCleanCodeAttributeColumnInIssuesTable(db.database());
+
+ @Test
+ public void execute_whenColumnDoesNotExist_shouldCreateColumn() throws SQLException {
+ db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+ underTest.execute();
+ db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, Types.VARCHAR, 40, true);
+ }
+
+ @Test
+ public void execute_whenColumnsAlreadyExists_shouldNotFail() throws SQLException {
+ underTest.execute();
+ assertThatCode(underTest::execute).doesNotThrowAnyException();
+ }
+}
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v103/AddCleanCodeAttributeColumnInIssuesTableTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v103/AddCleanCodeAttributeColumnInIssuesTableTest/schema.sql
new file mode 100644
index 00000000000..2746ed4bc7b
--- /dev/null
+++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v103/AddCleanCodeAttributeColumnInIssuesTableTest/schema.sql
@@ -0,0 +1,38 @@
+CREATE TABLE "ISSUES"(
+ "KEE" CHARACTER VARYING(50) NOT NULL,
+ "RULE_UUID" CHARACTER VARYING(40),
+ "SEVERITY" CHARACTER VARYING(10),
+ "MANUAL_SEVERITY" BOOLEAN NOT NULL,
+ "MESSAGE" CHARACTER VARYING(4000),
+ "LINE" INTEGER,
+ "GAP" DOUBLE PRECISION,
+ "STATUS" CHARACTER VARYING(20),
+ "RESOLUTION" CHARACTER VARYING(20),
+ "CHECKSUM" CHARACTER VARYING(1000),
+ "ASSIGNEE" CHARACTER VARYING(255),
+ "AUTHOR_LOGIN" CHARACTER VARYING(255),
+ "EFFORT" INTEGER,
+ "CREATED_AT" BIGINT,
+ "UPDATED_AT" BIGINT,
+ "ISSUE_CREATION_DATE" BIGINT,
+ "ISSUE_UPDATE_DATE" BIGINT,
+ "ISSUE_CLOSE_DATE" BIGINT,
+ "TAGS" CHARACTER VARYING(4000),
+ "COMPONENT_UUID" CHARACTER VARYING(50),
+ "PROJECT_UUID" CHARACTER VARYING(50),
+ "LOCATIONS" BINARY LARGE OBJECT,
+ "ISSUE_TYPE" TINYINT,
+ "FROM_HOTSPOT" BOOLEAN,
+ "QUICK_FIX_AVAILABLE" BOOLEAN,
+ "RULE_DESCRIPTION_CONTEXT_KEY" CHARACTER VARYING(50),
+ "MESSAGE_FORMATTINGS" BINARY LARGE OBJECT,
+ "CODE_VARIANTS" CHARACTER VARYING(4000)
+);
+ALTER TABLE "ISSUES" ADD CONSTRAINT "PK_ISSUES" PRIMARY KEY("KEE");
+CREATE INDEX "ISSUES_ASSIGNEE" ON "ISSUES"("ASSIGNEE" NULLS FIRST);
+CREATE INDEX "ISSUES_COMPONENT_UUID" ON "ISSUES"("COMPONENT_UUID" NULLS FIRST);
+CREATE INDEX "ISSUES_CREATION_DATE" ON "ISSUES"("ISSUE_CREATION_DATE" NULLS FIRST);
+CREATE INDEX "ISSUES_PROJECT_UUID" ON "ISSUES"("PROJECT_UUID" NULLS FIRST);
+CREATE INDEX "ISSUES_RESOLUTION" ON "ISSUES"("RESOLUTION" NULLS FIRST);
+CREATE INDEX "ISSUES_UPDATED_AT" ON "ISSUES"("UPDATED_AT" NULLS FIRST);
+CREATE INDEX "ISSUES_RULE_UUID" ON "ISSUES"("RULE_UUID" NULLS FIRST);
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/IssueFieldsSetter.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/IssueFieldsSetter.java
index d1e640604cf..9d64b033738 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/issue/IssueFieldsSetter.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/IssueFieldsSetter.java
@@ -33,6 +33,7 @@ import javax.annotation.Nullable;
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.issue.impact.Severity;
import org.sonar.api.issue.impact.SoftwareQuality;
+import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.ServerSide;
import org.sonar.api.server.rule.RuleTagFormat;
@@ -46,6 +47,7 @@ import org.sonar.db.user.UserIdDto;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Strings.isNullOrEmpty;
+import static java.util.Objects.requireNonNull;
/**
* Updates issue fields and chooses if changes must be kept in history.
@@ -57,6 +59,7 @@ public class IssueFieldsSetter {
public static final String UNUSED = "";
public static final String SEVERITY = "severity";
public static final String TYPE = "type";
+ public static final String CLEAN_CODE_ATTRIBUTE = "cleanCodeAttribute";
public static final String ASSIGNEE = "assignee";
public static final String RESOLUTION = "resolution";
public static final String STATUS = "status";
@@ -323,8 +326,8 @@ public class IssueFieldsSetter {
for (int i = 0; i < l1c.getMessageFormattingCount(); i++) {
if (l1c.getMessageFormatting(i).getStart() != l2.getMessageFormatting(i).getStart()
- || l1c.getMessageFormatting(i).getEnd() != l2.getMessageFormatting(i).getEnd()
- || l1c.getMessageFormatting(i).getType() != l2.getMessageFormatting(i).getType()) {
+ || l1c.getMessageFormatting(i).getEnd() != l2.getMessageFormatting(i).getEnd()
+ || l1c.getMessageFormatting(i).getType() != l2.getMessageFormatting(i).getType()) {
return false;
}
}
@@ -441,6 +444,19 @@ public class IssueFieldsSetter {
return false;
}
+ public boolean setCleanCodeAttribute(DefaultIssue raw, @Nullable CleanCodeAttribute previousCleanCodeAttribute, IssueChangeContext changeContext) {
+ CleanCodeAttribute newCleanCodeAttribute = requireNonNull(raw.getCleanCodeAttribute());
+ if (Objects.equals(previousCleanCodeAttribute, newCleanCodeAttribute)) {
+ return false;
+ }
+ raw.setFieldChange(changeContext, CLEAN_CODE_ATTRIBUTE, previousCleanCodeAttribute, newCleanCodeAttribute.name());
+ raw.setCleanCodeAttribute(newCleanCodeAttribute);
+ raw.setUpdateDate(changeContext.date());
+ raw.setChanged(true);
+ return true;
+
+ }
+
private static Set<String> getNewCodeVariants(DefaultIssue issue) {
Set<String> issueCodeVariants = issue.codeVariants();
if (issueCodeVariants == null) {
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIteratorForSingleChunk.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIteratorForSingleChunk.java
index d83383d3557..97222e5315f 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIteratorForSingleChunk.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIteratorForSingleChunk.java
@@ -91,10 +91,9 @@ class IssueIteratorForSingleChunk implements IssueIterator {
doc.setSeverity(indexedIssueDto.getSeverity());
String cleanCodeAttributeCategory = Optional.ofNullable(indexedIssueDto.getCleanCodeAttribute())
.map(CleanCodeAttribute::valueOf)
- .map(cleanCodeAttribute -> cleanCodeAttribute.getAttributeCategory().name())
+ .map(CleanCodeAttribute::getAttributeCategory)
+ .map(Enum::name)
.orElse(null);
- //TODO SONAR-20073 uncomment once clean code attribute is set to not-null
- //.orElseThrow(() -> new IllegalStateException("Clean Code Attribute is missing for issue " + key));
doc.setCleanCodeAttributeCategory(cleanCodeAttributeCategory);
doc.setStatus(indexedIssueDto.getStatus());
doc.setEffort(indexedIssueDto.getEffort());
diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/issue/IssueFieldsSetterTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/issue/IssueFieldsSetterTest.java
index 3003da52cea..9813c161737 100644
--- a/server/sonar-server-common/src/test/java/org/sonar/server/issue/IssueFieldsSetterTest.java
+++ b/server/sonar-server-common/src/test/java/org/sonar/server/issue/IssueFieldsSetterTest.java
@@ -31,6 +31,7 @@ import org.apache.commons.lang.time.DateUtils;
import org.junit.Test;
import org.sonar.api.issue.impact.Severity;
import org.sonar.api.issue.impact.SoftwareQuality;
+import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.Duration;
import org.sonar.core.issue.DefaultIssue;
@@ -750,4 +751,25 @@ public class IssueFieldsSetterTest {
assertThat(updated).isTrue();
assertThat(issue.getRuleDescriptionContextKey()).contains(DEFAULT_RULE_DESCRIPTION_CONTEXT_KEY);
}
+
+ @Test
+ public void setCleanCodeAttribute_whenCleanCodeAttributeChanged_shouldUpdateIssue() {
+ issue.setCleanCodeAttribute(CleanCodeAttribute.CLEAR);
+ boolean updated = underTest.setCleanCodeAttribute(issue, CleanCodeAttribute.COMPLETE, context);
+
+ assertThat(updated).isTrue();
+ assertThat(issue.getCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.CLEAR);
+ assertThat(issue.currentChange().get("cleanCodeAttribute"))
+ .extracting(FieldDiffs.Diff::oldValue, FieldDiffs.Diff::newValue)
+ .containsExactly(CleanCodeAttribute.COMPLETE, CleanCodeAttribute.CLEAR.name());
+ }
+
+ @Test
+ public void setCleanCodeAttribute_whenCleanCodeAttributeNotChanged_shouldNotUpdateIssue() {
+ issue.setCleanCodeAttribute(CleanCodeAttribute.CLEAR);
+ boolean updated = underTest.setCleanCodeAttribute(issue, CleanCodeAttribute.CLEAR, context);
+
+ assertThat(updated).isFalse();
+ assertThat(issue.getCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.CLEAR);
+ }
}
diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/issue/WebIssueStorageIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/issue/WebIssueStorageIT.java
index a856e374b6b..3a227ed644c 100644
--- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/issue/WebIssueStorageIT.java
+++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/issue/WebIssueStorageIT.java
@@ -119,7 +119,7 @@ public class WebIssueStorageIT {
assertThat(createdIssues).hasSize(1);
- assertThat(createdIssues.iterator().next().getCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.CLEAR);
+ assertThat(createdIssues.iterator().next().getEffectiveCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.CLEAR);
assertThat(createdIssues.iterator().next().getEffectiveImpacts()).isEqualTo(Map.of(SoftwareQuality.MAINTAINABILITY, Severity.HIGH));
assertThat(db.countRowsOfTable("issues")).isOne();
@@ -166,7 +166,7 @@ public class WebIssueStorageIT {
Collection<IssueDto> updatedIssues = underTest.save(db.getSession(), singletonList(issue));
assertThat(updatedIssues).hasSize(1);
- assertThat(updatedIssues.iterator().next().getCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.CLEAR);
+ assertThat(updatedIssues.iterator().next().getEffectiveCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.CLEAR);
assertThat(updatedIssues.iterator().next().getEffectiveImpacts()).isEqualTo(Map.of(SoftwareQuality.MAINTAINABILITY, Severity.HIGH));
assertThat(db.countRowsOfTable("issues")).isOne();
diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/issue/ws/PullTaintActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/issue/ws/PullTaintActionIT.java
index 4e6e21e2851..1ea0306bdba 100644
--- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/issue/ws/PullTaintActionIT.java
+++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/issue/ws/PullTaintActionIT.java
@@ -256,9 +256,9 @@ public class PullTaintActionIT {
assertThat(taintLite.getType()).isEqualTo(Common.RuleType.forNumber(issueDto.getType()));
assertThat(taintLite.getAssignedToSubscribedUser()).isTrue();
assertThat(taintLite.getCleanCodeAttribute())
- .isEqualTo(Common.CleanCodeAttribute.valueOf(issueDto.getCleanCodeAttribute().name()));
+ .isEqualTo(Common.CleanCodeAttribute.valueOf(issueDto.getEffectiveCleanCodeAttribute().name()));
assertThat(taintLite.getCleanCodeAttributeCategory())
- .isEqualTo(Common.CleanCodeAttributeCategory.valueOf(issueDto.getCleanCodeAttribute().getAttributeCategory().name()));
+ .isEqualTo(Common.CleanCodeAttributeCategory.valueOf(issueDto.getEffectiveCleanCodeAttribute().getAttributeCategory().name()));
assertThat(taintLite.getImpactsList())
.extracting(Common.Impact::getSoftwareQuality, Common.Impact::getSeverity)
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java
index e164e6a50ac..be54e0acf3b 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java
@@ -174,7 +174,7 @@ public class SearchResponseFormat {
issueBuilder.setKey(dto.getKey());
issueBuilder.setType(Common.RuleType.forNumber(dto.getType()));
- CleanCodeAttribute cleanCodeAttribute = dto.getCleanCodeAttribute();
+ CleanCodeAttribute cleanCodeAttribute = dto.getEffectiveCleanCodeAttribute();
if (cleanCodeAttribute != null) {
issueBuilder.setCleanCodeAttribute(Common.CleanCodeAttribute.valueOf(cleanCodeAttribute.name()));
issueBuilder.setCleanCodeAttributeCategory(Common.CleanCodeAttributeCategory.valueOf(cleanCodeAttribute.getAttributeCategory().name()));
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/pull/PullTaintActionProtobufObjectGenerator.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/pull/PullTaintActionProtobufObjectGenerator.java
index 73d6916b69f..ae920de34c2 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/pull/PullTaintActionProtobufObjectGenerator.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/pull/PullTaintActionProtobufObjectGenerator.java
@@ -96,7 +96,7 @@ public class PullTaintActionProtobufObjectGenerator implements ProtobufObjectGen
taintBuilder.setSeverity(Common.Severity.valueOf(issueDto.getSeverity()));
}
taintBuilder.setType(Common.RuleType.forNumber(issueDto.getType()));
- CleanCodeAttribute cleanCodeAttribute = issueDto.getCleanCodeAttribute();
+ CleanCodeAttribute cleanCodeAttribute = issueDto.getEffectiveCleanCodeAttribute();
String cleanCodeAttributeString = cleanCodeAttribute != null ? cleanCodeAttribute.name() : null;
String cleanCodeAttributeCategoryString = cleanCodeAttribute != null ? cleanCodeAttribute.getAttributeCategory().name() : null;
if (cleanCodeAttributeString != null) {
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchResponseFormatFormatOperationTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchResponseFormatFormatOperationTest.java
index 070aec1d96c..b33f55b275a 100644
--- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchResponseFormatFormatOperationTest.java
+++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchResponseFormatFormatOperationTest.java
@@ -124,8 +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.getCleanCodeAttribute()).isEqualTo(Common.CleanCodeAttribute.valueOf(issueDto.getEffectiveCleanCodeAttribute().name()));
+ assertThat(issue.getCleanCodeAttributeCategory()).isEqualTo(Common.CleanCodeAttributeCategory.valueOf(issueDto.getEffectiveCleanCodeAttribute().getAttributeCategory().name()));
assertThat(issue.getType().getNumber()).isEqualTo(issueDto.getType());
assertThat(issue.getComponent()).isEqualTo(issueDto.getComponentKey());
assertThat(issue.getRule()).isEqualTo(issueDto.getRuleKey().toString());
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java
index dfd104b19cb..aa69711c00a 100644
--- a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java
+++ b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java
@@ -45,6 +45,7 @@ import org.sonar.api.issue.Issue;
import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
+import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.Duration;
import org.sonar.core.issue.tracking.Trackable;
@@ -94,7 +95,7 @@ public class DefaultIssue implements Issue, Trackable, org.sonar.api.ce.measure.
// all changes
// -- contains only current change (if any) on CE side unless reopening a closed issue or copying issue from base branch
- // when analyzing a branch from the first time
+ // when analyzing a branch from the first time
private List<FieldDiffs> changes = null;
// true if the issue did not exist in the previous scan.
@@ -135,6 +136,7 @@ public class DefaultIssue implements Issue, Trackable, org.sonar.api.ce.measure.
private String anticipatedTransitionUuid = null;
private Map<SoftwareQuality, org.sonar.api.issue.impact.Severity> impacts = new EnumMap<>(SoftwareQuality.class);
+ private CleanCodeAttribute cleanCodeAttribute = null;
@Override
public String key() {
@@ -443,7 +445,6 @@ public class DefaultIssue implements Issue, Trackable, org.sonar.api.ce.measure.
return this;
}
-
public DefaultIssue setNew(boolean b) {
isNew = b;
return this;
@@ -713,6 +714,16 @@ public class DefaultIssue implements Issue, Trackable, org.sonar.api.ce.measure.
return this;
}
+ public DefaultIssue setCleanCodeAttribute(@Nullable CleanCodeAttribute cleanCodeAttribute) {
+ this.cleanCodeAttribute = cleanCodeAttribute;
+ return this;
+ }
+
+ @Nullable
+ public CleanCodeAttribute getCleanCodeAttribute() {
+ return cleanCodeAttribute;
+ }
+
@Override
public Integer getLine() {
return line;
@@ -742,5 +753,4 @@ public class DefaultIssue implements Issue, Trackable, org.sonar.api.ce.measure.
public Date getUpdateDate() {
return updateDate;
}
-
}