import java.util.Date;
import java.util.List;
import java.util.Optional;
+import java.util.Set;
+import org.jetbrains.annotations.NotNull;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.ArgumentCaptor;
import org.sonar.api.config.internal.MapSettings;
-import org.sonar.api.issue.Issue;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
-import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.ce.task.projectanalysis.analysis.Branch;
@Test
public void process_new_issue() {
- ruleRepositoryRule.add(RuleKey.of("xoo", "S001"));
+ ruleRepositoryRule.add(RuleTesting.XOO_X1);
when(analysisMetadataHolder.isBranch()).thenReturn(true);
- ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
- .setMsg("the message")
- .setRuleRepository("xoo")
- .setRuleKey("S001")
- .setSeverity(Constants.Severity.BLOCKER)
- .build();
+ ScannerReport.Issue reportIssue = getReportIssue(RuleTesting.XOO_X1);
reportReader.putIssues(FILE_REF, singletonList(reportIssue));
underTest.visitAny(FILE);
- assertThat(newArrayList(protoIssueCache.traverse())).hasSize(1);
+ List<DefaultIssue> issues = newArrayList(protoIssueCache.traverse());
+ assertThat(issues).hasSize(1);
+ assertThat(issues.get(0).codeVariants()).containsExactlyInAnyOrder("foo", "bar");
}
@Test
addBaseIssue(ruleKey);
// Issue from report has severity blocker
- ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
- .setMsg("new message")
- .setRuleRepository(ruleKey.repository())
- .setRuleKey(ruleKey.rule())
- .setSeverity(Constants.Severity.BLOCKER)
- .build();
+ ScannerReport.Issue reportIssue = getReportIssue(ruleKey);
reportReader.putIssues(FILE_REF, singletonList(reportIssue));
underTest.visitAny(FILE);
addBaseIssue(ruleKey);
// Issue from report has severity blocker
- ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
- .setMsg("the message")
- .setRuleRepository(ruleKey.repository())
- .setRuleKey(ruleKey.rule())
- .setSeverity(Constants.Severity.BLOCKER)
- .build();
+ ScannerReport.Issue reportIssue = getReportIssue(ruleKey);
reportReader.putIssues(FILE_REF, singletonList(reportIssue));
underTest.visitAny(FILE);
@Test
public void execute_issue_visitors() {
- ruleRepositoryRule.add(RuleKey.of("xoo", "S001"));
- ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
- .setMsg("the message")
- .setRuleRepository("xoo")
- .setRuleKey("S001")
- .setSeverity(Constants.Severity.BLOCKER)
- .build();
+ ruleRepositoryRule.add(RuleTesting.XOO_X1);
+ ScannerReport.Issue reportIssue = getReportIssue(RuleTesting.XOO_X1);
reportReader.putIssues(FILE_REF, singletonList(reportIssue));
underTest.visitAny(FILE);
verify(issueVisitor).beforeComponent(FILE);
verify(issueVisitor).afterComponent(FILE);
verify(issueVisitor).onIssue(eq(FILE), defaultIssueCaptor.capture());
- assertThat(defaultIssueCaptor.getValue().ruleKey().rule()).isEqualTo("S001");
+ assertThat(defaultIssueCaptor.getValue().ruleKey().rule()).isEqualTo("x1");
}
@Test
addBaseIssue(ruleKey);
// Issue from report has severity blocker
- ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
- .setMsg("new message")
- .setRuleRepository(ruleKey.repository())
- .setRuleKey(ruleKey.rule())
- .setSeverity(Constants.Severity.BLOCKER)
- .build();
+ ScannerReport.Issue reportIssue = getReportIssue(ruleKey);
reportReader.putIssues(FILE_REF, singletonList(reportIssue));
when(fileStatuses.isDataUnchanged(FILE)).thenReturn(true);
addBaseIssueOnBranch(ruleKey);
// Issue from report has severity blocker
- ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
- .setMsg("the message")
- .setRuleRepository(ruleKey.repository())
- .setRuleKey(ruleKey.rule())
- .setSeverity(Constants.Severity.BLOCKER)
- .build();
+ ScannerReport.Issue reportIssue = getReportIssue(ruleKey);
reportReader.putIssues(FILE_REF, singletonList(reportIssue));
underTest.visitAny(FILE);
dbTester.getDbClient().issueDao().insert(dbTester.getSession(), issue);
dbTester.getSession().commit();
}
+
+ @NotNull
+ private static ScannerReport.Issue getReportIssue(RuleKey ruleKey) {
+ return ScannerReport.Issue.newBuilder()
+ .setMsg("the message")
+ .setRuleRepository(ruleKey.repository())
+ .setRuleKey(ruleKey.rule())
+ .addAllCodeVariants(Set.of("foo", "bar"))
+ .setSeverity(Constants.Severity.BLOCKER)
+ .build();
+ }
}
updater.setPastMessage(raw, base.getMessage(), base.getMessageFormattings(), changeContext);
updater.setPastGap(raw, base.gap(), changeContext);
updater.setPastEffort(raw, base.effort(), changeContext);
+ updater.setCodeVariants(raw, requireNonNull(base.codeVariants()), changeContext);
}
public void doAutomaticTransition(DefaultIssue issue) {
issue.setLocations(dbLocationsBuilder.build());
issue.setQuickFixAvailable(reportIssue.getQuickFixAvailable());
issue.setRuleDescriptionContextKey(reportIssue.hasRuleDescriptionContextKey() ? reportIssue.getRuleDescriptionContextKey() : null);
+ issue.setCodeVariants(reportIssue.getCodeVariantsList());
return issue;
}
public class ProtobufIssueDiskCache implements DiskCache<DefaultIssue> {
private static final String TAGS_SEPARATOR = ",";
- private static final Splitter TAGS_SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings();
+ private static final Splitter STRING_LIST_SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings();
private final File file;
private final System2 system2;
defaultIssue.setChecksum(next.hasChecksum() ? next.getChecksum() : null);
defaultIssue.setAuthorLogin(next.hasAuthorLogin() ? next.getAuthorLogin() : null);
next.getCommentsList().forEach(c -> defaultIssue.addComment(toDefaultIssueComment(c)));
- defaultIssue.setTags(ImmutableSet.copyOf(TAGS_SPLITTER.split(next.getTags())));
+ defaultIssue.setTags(ImmutableSet.copyOf(STRING_LIST_SPLITTER.split(next.getTags())));
+ defaultIssue.setCodeVariants(ImmutableSet.copyOf(STRING_LIST_SPLITTER.split(next.getCodeVariants())));
defaultIssue.setRuleDescriptionContextKey(next.hasRuleDescriptionContextKey() ? next.getRuleDescriptionContextKey() : null);
defaultIssue.setLocations(next.hasLocations() ? next.getLocations() : null);
defaultIssue.setIsFromExternalRuleEngine(next.getIsFromExternalRuleEngine());
ofNullable(defaultIssue.authorLogin()).ifPresent(builder::setAuthorLogin);
defaultIssue.defaultIssueComments().forEach(c -> builder.addComments(toProtoComment(c)));
ofNullable(defaultIssue.tags()).ifPresent(t -> builder.setTags(String.join(TAGS_SEPARATOR, t)));
+ ofNullable(defaultIssue.codeVariants()).ifPresent(codeVariant -> builder.setCodeVariants(String.join(TAGS_SEPARATOR, codeVariant)));
ofNullable(defaultIssue.getLocations()).ifPresent(l -> builder.setLocations((DbIssues.Locations) l));
defaultIssue.getRuleDescriptionContextKey().ifPresent(builder::setRuleDescriptionContextKey);
builder.setIsFromExternalRuleEngine(defaultIssue.isFromExternalRuleEngine());
optional bool isNoLongerNewCodeReferenceIssue = 43;
optional string ruleDescriptionContextKey = 44;
optional sonarqube.db.issues.MessageFormattings messageFormattings = 45;
+ optional string codeVariants = 46;
}
message Comment {
package org.sonar.ce.task.projectanalysis.issue;
import java.util.Date;
+import java.util.Set;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.rules.RuleType;
.setKey("RAW_KEY")
.setRuleKey(XOO_X1)
.setRuleDescriptionContextKey("spring")
+ .setCodeVariants(Set.of("foo", "bar"))
.setCreationDate(parseDate("2015-10-01"))
.setUpdateDate(parseDate("2015-10-02"))
.setCloseDate(parseDate("2015-10-03"));
.setMessageFormattings(messageFormattings)
.setGap(15d)
.setRuleDescriptionContextKey("hibernate")
+ .setCodeVariants(Set.of("donut"))
.setEffort(Duration.create(15L))
.setManualSeverity(false)
.setLocations(issueLocations)
assertThat(raw.assignee()).isEqualTo("base assignee uuid");
assertThat(raw.authorLogin()).isEqualTo("base author");
assertThat(raw.tags()).containsOnly("base tag");
+ assertThat(raw.codeVariants()).containsOnly("foo", "bar");
assertThat(raw.effort()).isEqualTo(DEFAULT_DURATION);
assertThat(raw.isOnDisabledRule()).isTrue();
assertThat(raw.selectedAt()).isEqualTo(1000L);
verify(updater).setPastSeverity(raw, BLOCKER, issueChangeContext);
verify(updater).setPastLine(raw, 10);
verify(updater).setRuleDescriptionContextKey(raw, "hibernate");
+ verify(updater).setCodeVariants(raw, Set.of("donut"), issueChangeContext);
verify(updater).setPastMessage(raw, "message with code", messageFormattings, issueChangeContext);
verify(updater).setPastEffort(raw, Duration.create(15L), issueChangeContext);
verify(updater).setPastLocations(raw, issueLocations);
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
+import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.rules.RuleType;
public static final String TECHNICAL_DEBT = "technicalDebt";
public static final String LINE = "line";
public static final String TAGS = "tags";
+ public static final String CODE_VARIANTS = "code_variants";
- private static final Joiner CHANGELOG_TAG_JOINER = Joiner.on(" ").skipNulls();
+ private static final Joiner CHANGELOG_LIST_JOINER = Joiner.on(" ").skipNulls();
public boolean setType(DefaultIssue issue, RuleType type, IssueChangeContext context) {
if (!Objects.equals(type, issue.type())) {
Set<String> oldTags = new HashSet<>(issue.tags());
if (!oldTags.equals(newTags)) {
issue.setFieldChange(context, TAGS,
- oldTags.isEmpty() ? null : CHANGELOG_TAG_JOINER.join(oldTags),
- newTags.isEmpty() ? null : CHANGELOG_TAG_JOINER.join(newTags));
+ oldTags.isEmpty() ? null : CHANGELOG_LIST_JOINER.join(oldTags),
+ newTags.isEmpty() ? null : CHANGELOG_LIST_JOINER.join(newTags));
issue.setTags(newTags);
issue.setUpdateDate(context.date());
issue.setChanged(true);
return false;
}
+ public boolean setCodeVariants(DefaultIssue issue, Set<String> currentCodeVariants, IssueChangeContext context) {
+ Set<String> newCodeVariants = getNewCodeVariants(issue);
+ if (!currentCodeVariants.equals(newCodeVariants)) {
+ issue.setFieldChange(context, CODE_VARIANTS,
+ currentCodeVariants.isEmpty() ? null : CHANGELOG_LIST_JOINER.join(currentCodeVariants),
+ newCodeVariants.isEmpty() ? null : CHANGELOG_LIST_JOINER.join(newCodeVariants));
+ issue.setCodeVariants(newCodeVariants);
+ issue.setUpdateDate(context.date());
+ issue.setChanged(true);
+ issue.setSendNotifications(true);
+ return true;
+ }
+ return false;
+ }
+
+ private static Set<String> getNewCodeVariants(DefaultIssue issue) {
+ Set<String> issueCodeVariants = issue.codeVariants();
+ if (issueCodeVariants == null) {
+ return Set.of();
+ }
+ return issueCodeVariants.stream()
+ .map(String::trim)
+ .filter(s -> !s.isEmpty())
+ .collect(Collectors.toSet());
+ }
+
public void setIssueComponent(DefaultIssue issue, String newComponentUuid, String newComponentKey, Date updateDate) {
if (!Objects.equals(newComponentUuid, issue.componentUuid())) {
issue.setComponentUuid(newComponentUuid);
*/
package org.sonar.server.issue;
+import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
+import java.util.HashSet;
import java.util.List;
import java.util.Random;
-import java.util.function.Predicate;
+import java.util.Set;
import org.apache.commons.lang.time.DateUtils;
import org.junit.Test;
+import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.Duration;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.FieldDiffs;
import static org.sonar.server.issue.IssueFieldsSetter.SEVERITY;
import static org.sonar.server.issue.IssueFieldsSetter.STATUS;
import static org.sonar.server.issue.IssueFieldsSetter.TECHNICAL_DEBT;
+import static org.sonar.server.issue.IssueFieldsSetter.TYPE;
import static org.sonar.server.issue.IssueFieldsSetter.UNUSED;
public class IssueFieldsSetterTest {
.hasMessage("It's not possible to update the assignee with this method, please use assign()");
}
+ @Test
+ public void set_type() {
+ issue.setType(RuleType.CODE_SMELL);
+ boolean updated = underTest.setType(issue, RuleType.BUG, context);
+ assertThat(updated).isTrue();
+ assertThat(issue.type()).isEqualTo(RuleType.BUG);
+ assertThat(issue.manualSeverity()).isFalse();
+ assertThat(issue.mustSendNotifications()).isFalse();
+
+ FieldDiffs.Diff diff = issue.currentChange().get(TYPE);
+ assertThat(diff.oldValue()).isEqualTo(RuleType.CODE_SMELL);
+ assertThat(diff.newValue()).isEqualTo(RuleType.BUG);
+ }
+
@Test
public void set_severity() {
boolean updated = underTest.setSeverity(issue, "BLOCKER", context);
assertThat(diff.newValue()).isNull();
}
+ @Test
+ public void setCodeVariants_whenCodeVariantAdded_shouldBeUpdated() {
+ Set<String> currentCodeVariants = new HashSet<>(Arrays.asList("linux"));
+ Set<String> newCodeVariants = new HashSet<>(Arrays.asList("linux", "windows"));
+
+ issue.setCodeVariants(newCodeVariants);
+ boolean updated = underTest.setCodeVariants(issue, currentCodeVariants, context);
+ assertThat(updated).isTrue();
+ assertThat(issue.codeVariants()).contains("linux", "windows");
+
+ FieldDiffs.Diff diff = issue.currentChange().get("code_variants");
+ assertThat(diff.oldValue()).isEqualTo("linux");
+ assertThat(diff.newValue()).isEqualTo("linux windows");
+ assertThat(issue.mustSendNotifications()).isTrue();
+ }
+
+ @Test
+ public void setCodeVariants_whenCodeVariantsUnchanged_shouldNotBeUpdated() {
+ Set<String> currentCodeVariants = new HashSet<>(Arrays.asList("linux", "windows"));
+ Set<String> newCodeVariants = new HashSet<>(Arrays.asList("windows", "linux"));
+
+ issue.setCodeVariants(newCodeVariants);
+ boolean updated = underTest.setCodeVariants(issue, currentCodeVariants, context);
+ assertThat(updated).isFalse();
+ assertThat(issue.currentChange()).isNull();
+ }
+
@Test
public void set_message() {
boolean updated = underTest.setMessage(issue, "the message", context);