Skip to content

Commit

Permalink
SONAR-8730 replace severity by rule type in new issues notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
sns-seb authored and ehartmann committed Oct 2, 2017
1 parent 2ce4dce commit c85249a
Show file tree
Hide file tree
Showing 17 changed files with 231 additions and 276 deletions.
Expand Up @@ -91,7 +91,7 @@ public void execute() {


private void doExecute(Component project) { private void doExecute(Component project) {
long analysisDate = analysisMetadataHolder.getAnalysisDate(); long analysisDate = analysisMetadataHolder.getAnalysisDate();
Predicate<Issue> isOnLeakPredicate = i -> i.isNew() && i.creationDate().getTime() >= truncateToSeconds(analysisDate); Predicate<DefaultIssue> isOnLeakPredicate = i -> i.isNew() && i.creationDate().getTime() >= truncateToSeconds(analysisDate);
NewIssuesStatistics newIssuesStats = new NewIssuesStatistics(isOnLeakPredicate); NewIssuesStatistics newIssuesStats = new NewIssuesStatistics(isOnLeakPredicate);
try (CloseableIterator<DefaultIssue> issues = issueCache.traverse()) { try (CloseableIterator<DefaultIssue> issues = issueCache.traverse()) {
processIssues(newIssuesStats, issues, project); processIssues(newIssuesStats, issues, project);
Expand Down
Expand Up @@ -19,16 +19,16 @@
*/ */
package org.sonar.server.issue.notification; package org.sonar.server.issue.notification;


import com.google.common.collect.Lists;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import java.util.Locale; import java.util.Locale;
import org.sonar.api.config.EmailSettings; import org.sonar.api.config.EmailSettings;
import org.sonar.api.i18n.I18n; import org.sonar.api.i18n.I18n;
import org.sonar.api.notifications.Notification; import org.sonar.api.notifications.Notification;
import org.sonar.api.rule.Severity; import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.DateUtils;
import org.sonar.plugins.emailnotifications.api.EmailMessage; import org.sonar.plugins.emailnotifications.api.EmailMessage;
import org.sonar.plugins.emailnotifications.api.EmailTemplate; import org.sonar.plugins.emailnotifications.api.EmailTemplate;
Expand Down Expand Up @@ -79,7 +79,7 @@ public EmailMessage format(Notification notification) {


StringBuilder message = new StringBuilder(); StringBuilder message = new StringBuilder();
message.append("Project: ").append(projectName).append(NEW_LINE).append(NEW_LINE); message.append("Project: ").append(projectName).append(NEW_LINE).append(NEW_LINE);
appendSeverity(message, notification); appendRuleType(message, notification);
appendAssignees(message, notification); appendAssignees(message, notification);
appendRules(message, notification); appendRules(message, notification);
appendTags(message, notification); appendTags(message, notification);
Expand All @@ -97,7 +97,7 @@ public EmailMessage format(Notification notification) {
protected String subject(Notification notification, String projectName) { protected String subject(Notification notification, String projectName) {
return String.format("%s: %s new issues (new debt: %s)", return String.format("%s: %s new issues (new debt: %s)",
projectName, projectName,
notification.getFieldValue(Metric.SEVERITY + COUNT), notification.getFieldValue(Metric.RULE_TYPE + COUNT),
notification.getFieldValue(Metric.EFFORT + COUNT)); notification.getFieldValue(Metric.EFFORT + COUNT));
} }


Expand Down Expand Up @@ -145,23 +145,24 @@ protected void appendRules(StringBuilder message, Notification notification) {
genericAppendOfMetric(Metric.RULE, "Rules", message, notification); genericAppendOfMetric(Metric.RULE, "Rules", message, notification);
} }


protected void appendSeverity(StringBuilder message, Notification notification) { protected void appendRuleType(StringBuilder message, Notification notification) {
message message
.append(String.format("%s new issues (new debt: %s)", .append(String.format("%s new issues (new debt: %s)",
notification.getFieldValue(Metric.SEVERITY + COUNT), notification.getFieldValue(Metric.RULE_TYPE + COUNT),
notification.getFieldValue(Metric.EFFORT + COUNT))) notification.getFieldValue(Metric.EFFORT + COUNT)))
.append(NEW_LINE).append(NEW_LINE) .append(NEW_LINE).append(NEW_LINE)
.append(TAB) .append(TAB)
.append("Severity") .append("Type")
.append(NEW_LINE) .append(NEW_LINE)
.append(TAB) .append(TAB)
.append(TAB); .append(TAB);


for (Iterator<String> severityIterator = Lists.reverse(Severity.ALL).iterator(); severityIterator.hasNext();) {
String severity = severityIterator.next(); for (Iterator<RuleType> ruleTypeIterator = Arrays.asList(RuleType.BUG, RuleType.VULNERABILITY, RuleType.CODE_SMELL).iterator(); ruleTypeIterator.hasNext();) {
String severityLabel = i18n.message(getLocale(), "severity." + severity, severity); RuleType ruleType = ruleTypeIterator.next();
message.append(severityLabel).append(": ").append(notification.getFieldValue(Metric.SEVERITY + DOT + severity + COUNT)); String ruleTypeLabel = i18n.message(getLocale(), "rule_type." + ruleType, ruleType.name());
if (severityIterator.hasNext()) { message.append(ruleTypeLabel).append(": ").append(notification.getFieldValue(Metric.RULE_TYPE + DOT + ruleType + COUNT));
if (ruleTypeIterator.hasNext()) {
message.append(TAB); message.append(TAB);
} }
} }
Expand Down
Expand Up @@ -49,7 +49,7 @@ protected void appendAssignees(StringBuilder message, Notification notification)
@Override @Override
protected String subject(Notification notification, String projectName) { protected String subject(Notification notification, String projectName) {
return String.format("You have %s new issues on project %s", return String.format("You have %s new issues on project %s",
notification.getFieldValue(Metric.SEVERITY + COUNT), notification.getFieldValue(Metric.RULE_TYPE + COUNT),
projectName); projectName);
} }


Expand Down
Expand Up @@ -19,7 +19,7 @@
*/ */
package org.sonar.server.issue.notification; package org.sonar.server.issue.notification;


import com.google.common.collect.ImmutableMap; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
Expand All @@ -30,7 +30,7 @@
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.sonar.api.notifications.Notification; import org.sonar.api.notifications.Notification;
import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity; import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.Duration; import org.sonar.api.utils.Duration;
import org.sonar.api.utils.Durations; import org.sonar.api.utils.Durations;
Expand All @@ -49,7 +49,7 @@
import static org.sonar.server.issue.notification.NewIssuesEmailTemplate.FIELD_PROJECT_KEY; import static org.sonar.server.issue.notification.NewIssuesEmailTemplate.FIELD_PROJECT_KEY;
import static org.sonar.server.issue.notification.NewIssuesEmailTemplate.FIELD_PROJECT_NAME; import static org.sonar.server.issue.notification.NewIssuesEmailTemplate.FIELD_PROJECT_NAME;
import static org.sonar.server.issue.notification.NewIssuesEmailTemplate.FIELD_PROJECT_UUID; import static org.sonar.server.issue.notification.NewIssuesEmailTemplate.FIELD_PROJECT_UUID;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.SEVERITY; import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.RULE_TYPE;


public class NewIssuesNotification extends Notification { public class NewIssuesNotification extends Notification {


Expand Down Expand Up @@ -90,10 +90,10 @@ public NewIssuesNotification setProject(String projectKey, String projectUuid, S
} }


public NewIssuesNotification setStatistics(String projectName, NewIssuesStatistics.Stats stats) { public NewIssuesNotification setStatistics(String projectName, NewIssuesStatistics.Stats stats) {
setDefaultMessage(stats.getDistributedMetricStats(SEVERITY).getOnLeak() + " new issues on " + projectName + ".\n"); setDefaultMessage(stats.getDistributedMetricStats(RULE_TYPE).getOnLeak() + " new issues on " + projectName + ".\n");


try (DbSession dbSession = dbClient.openSession(false)) { try (DbSession dbSession = dbClient.openSession(false)) {
setSeverityStatistics(stats); setRuleTypeStatistics(stats);
setAssigneesStatistics(stats); setAssigneesStatistics(stats);
setTagsStatistics(stats); setTagsStatistics(stats);
setComponentsStatistics(dbSession, stats); setComponentsStatistics(dbSession, stats);
Expand All @@ -111,7 +111,7 @@ private void setRuleStatistics(DbSession dbSession, NewIssuesStatistics.Stats st
.map(Map.Entry::getKey) .map(Map.Entry::getKey)
.map(RuleKey::parse) .map(RuleKey::parse)
.collect(MoreCollectors.toSet(fiveBiggest.size())); .collect(MoreCollectors.toSet(fiveBiggest.size()));
ImmutableMap<String, RuleDefinitionDto> ruleByRuleKey = dbClient.ruleDao().selectDefinitionByKeys(dbSession, ruleKeys) Map<String, RuleDefinitionDto> ruleByRuleKey = dbClient.ruleDao().selectDefinitionByKeys(dbSession, ruleKeys)
.stream() .stream()
.collect(MoreCollectors.uniqueIndex(s -> s.getKey().toString())); .collect(MoreCollectors.uniqueIndex(s -> s.getKey().toString()));
int i = 1; int i = 1;
Expand Down Expand Up @@ -186,14 +186,13 @@ public NewIssuesNotification setDebt(Duration debt) {
return this; return this;
} }


private void setSeverityStatistics(NewIssuesStatistics.Stats stats) { private void setRuleTypeStatistics(NewIssuesStatistics.Stats stats) {
DistributedMetricStatsInt distributedMetricStats = stats.getDistributedMetricStats(SEVERITY); DistributedMetricStatsInt distributedMetricStats = stats.getDistributedMetricStats(RULE_TYPE);
setFieldValue(SEVERITY + COUNT, String.valueOf(distributedMetricStats.getOnLeak())); setFieldValue(RULE_TYPE + COUNT, String.valueOf(distributedMetricStats.getOnLeak()));
for (String severity : Severity.ALL) { Arrays.stream(RuleType.values())
setFieldValue( .forEach(ruleType -> setFieldValue(
SEVERITY + DOT + severity + COUNT, RULE_TYPE + DOT + ruleType + COUNT,
String.valueOf(distributedMetricStats.getForLabel(severity).map(MetricStatsInt::getOnLeak).orElse(0))); String.valueOf(distributedMetricStats.getForLabel(ruleType.name()).map(MetricStatsInt::getOnLeak).orElse(0))));
}
} }


@Override @Override
Expand Down
Expand Up @@ -23,27 +23,27 @@
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.sonar.api.issue.Issue;
import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.Duration; import org.sonar.api.utils.Duration;
import org.sonar.core.issue.DefaultIssue;


import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.ASSIGNEE; import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.ASSIGNEE;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.COMPONENT; import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.COMPONENT;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.RULE; import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.RULE;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.SEVERITY; import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.RULE_TYPE;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.TAG; import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.TAG;


public class NewIssuesStatistics { public class NewIssuesStatistics {
private final Predicate<Issue> onLeakPredicate; private final Predicate<DefaultIssue> onLeakPredicate;
private final Map<String, Stats> assigneesStatistics = new LinkedHashMap<>(); private final Map<String, Stats> assigneesStatistics = new LinkedHashMap<>();
private final Stats globalStatistics; private final Stats globalStatistics;


public NewIssuesStatistics(Predicate<Issue> onLeakPredicate) { public NewIssuesStatistics(Predicate<DefaultIssue> onLeakPredicate) {
this.onLeakPredicate = onLeakPredicate; this.onLeakPredicate = onLeakPredicate;
this.globalStatistics = new Stats(onLeakPredicate); this.globalStatistics = new Stats(onLeakPredicate);
} }


public void add(Issue issue) { public void add(DefaultIssue issue) {
globalStatistics.add(issue); globalStatistics.add(issue);
String login = issue.assignee(); String login = issue.assignee();
if (login != null) { if (login != null) {
Expand Down Expand Up @@ -72,7 +72,7 @@ public boolean hasIssuesOffLeak() {
} }


public enum Metric { public enum Metric {
SEVERITY(true), TAG(true), COMPONENT(true), ASSIGNEE(true), EFFORT(false), RULE(true); RULE_TYPE(true), TAG(true), COMPONENT(true), ASSIGNEE(true), EFFORT(false), RULE(true);
private final boolean isComputedByDistribution; private final boolean isComputedByDistribution;


Metric(boolean isComputedByDistribution) { Metric(boolean isComputedByDistribution) {
Expand All @@ -93,11 +93,11 @@ public String toString() {
} }


public static class Stats { public static class Stats {
private final Predicate<Issue> onLeakPredicate; private final Predicate<DefaultIssue> onLeakPredicate;
private final Map<Metric, DistributedMetricStatsInt> distributions = new EnumMap<>(Metric.class); private final Map<Metric, DistributedMetricStatsInt> distributions = new EnumMap<>(Metric.class);
private MetricStatsLong effortStats = new MetricStatsLong(); private MetricStatsLong effortStats = new MetricStatsLong();


public Stats(Predicate<Issue> onLeakPredicate) { public Stats(Predicate<DefaultIssue> onLeakPredicate) {
this.onLeakPredicate = onLeakPredicate; this.onLeakPredicate = onLeakPredicate;
for (Metric metric : Metric.values()) { for (Metric metric : Metric.values()) {
if (metric.isComputedByDistribution()) { if (metric.isComputedByDistribution()) {
Expand All @@ -106,9 +106,9 @@ public Stats(Predicate<Issue> onLeakPredicate) {
} }
} }


public void add(Issue issue) { public void add(DefaultIssue issue) {
boolean isOnLeak = onLeakPredicate.test(issue); boolean isOnLeak = onLeakPredicate.test(issue);
distributions.get(SEVERITY).increment(issue.severity(), isOnLeak); distributions.get(RULE_TYPE).increment(issue.type().name(), isOnLeak);
String componentUuid = issue.componentUuid(); String componentUuid = issue.componentUuid();
if (componentUuid != null) { if (componentUuid != null) {
distributions.get(COMPONENT).increment(componentUuid, isOnLeak); distributions.get(COMPONENT).increment(componentUuid, isOnLeak);
Expand Down Expand Up @@ -139,15 +139,15 @@ public MetricStatsLong effort() {
} }


public boolean hasIssues() { public boolean hasIssues() {
return getDistributedMetricStats(SEVERITY).getTotal() > 0; return getDistributedMetricStats(RULE_TYPE).getTotal() > 0;
} }


public boolean hasIssuesOnLeak() { public boolean hasIssuesOnLeak() {
return getDistributedMetricStats(SEVERITY).getOnLeak() > 0; return getDistributedMetricStats(RULE_TYPE).getOnLeak() > 0;
} }


public boolean hasIssuesOffLeak() { public boolean hasIssuesOffLeak() {
return getDistributedMetricStats(SEVERITY).getOffLeak() > 0; return getDistributedMetricStats(RULE_TYPE).getOffLeak() > 0;
} }


@Override @Override
Expand Down

0 comments on commit c85249a

Please sign in to comment.