aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGodin <mandrikov@gmail.com>2010-12-08 19:22:18 +0000
committerGodin <mandrikov@gmail.com>2010-12-08 19:22:18 +0000
commit85ad745aaee19225e0abbb11abd167e39a8b1e95 (patch)
tree37139954f8e33512388964ae4f4059666745c5cf
parente3b4152afad73825c08a72c7e17432fb97638970 (diff)
downloadsonarqube-85ad745aaee19225e0abbb11abd167e39a8b1e95.tar.gz
sonarqube-85ad745aaee19225e0abbb11abd167e39a8b1e95.zip
SONAR-1809: Export / import alerts attached to a quality profile
-rw-r--r--plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayProfileTest.java5
-rw-r--r--plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayWithFindbugsProfileTest.java3
-rw-r--r--plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SunConventionsProfileTest.java3
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileParser.java57
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileSerializer.java23
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/profiles/XMLProfileParserTest.java42
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/profiles/XMLProfileSerializerTest.java16
-rw-r--r--sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileParserTest/importProfileWithAlerts.xml21
-rw-r--r--sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileSerializerTest/exportAlerts.xml14
9 files changed, 166 insertions, 18 deletions
diff --git a/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayProfileTest.java b/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayProfileTest.java
index 23a39650517..fef7df549a4 100644
--- a/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayProfileTest.java
+++ b/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayProfileTest.java
@@ -22,6 +22,7 @@ package org.sonar.plugins.checkstyle;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import org.sonar.api.measures.MetricFinder;
import org.sonar.api.profiles.ProfileDefinition;
import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.profiles.XMLProfileParser;
@@ -40,7 +41,7 @@ public class SonarWayProfileTest {
@Test
public void shouldCreateProfile() {
- ProfileDefinition sonarWay = new SonarWayProfile(new XMLProfileParser(newRuleFinder()));
+ ProfileDefinition sonarWay = new SonarWayProfile(new XMLProfileParser(newRuleFinder(), mock(MetricFinder.class)));
ValidationMessages validation = ValidationMessages.create();
RulesProfile profile = sonarWay.createProfile(validation);
assertThat(profile.getActiveRulesByRepository(CheckstyleConstants.REPOSITORY_KEY).size(), greaterThan(1));
@@ -49,7 +50,7 @@ public class SonarWayProfileTest {
private RuleFinder newRuleFinder() {
RuleFinder ruleFinder = mock(RuleFinder.class);
- when(ruleFinder.findByKey(anyString(), anyString())).thenAnswer(new Answer<Rule>(){
+ when(ruleFinder.findByKey(anyString(), anyString())).thenAnswer(new Answer<Rule>() {
public Rule answer(InvocationOnMock iom) throws Throwable {
return Rule.create((String) iom.getArguments()[0], (String) iom.getArguments()[1], (String) iom.getArguments()[1]);
}
diff --git a/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayWithFindbugsProfileTest.java b/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayWithFindbugsProfileTest.java
index d5af6c0b236..c53eff084ca 100644
--- a/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayWithFindbugsProfileTest.java
+++ b/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayWithFindbugsProfileTest.java
@@ -22,6 +22,7 @@ package org.sonar.plugins.checkstyle;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import org.sonar.api.measures.MetricFinder;
import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.profiles.XMLProfileParser;
import org.sonar.api.rules.Rule;
@@ -39,7 +40,7 @@ public class SonarWayWithFindbugsProfileTest {
@Test
public void shouldBeSameAsSonarWay() {
RuleFinder ruleFinder = newRuleFinder();
- SonarWayProfile sonarWay = new SonarWayProfile(new XMLProfileParser(ruleFinder));
+ SonarWayProfile sonarWay = new SonarWayProfile(new XMLProfileParser(ruleFinder, mock(MetricFinder.class)));
RulesProfile withoutFindbugs = sonarWay.createProfile(ValidationMessages.create());
RulesProfile withFindbugs = new SonarWayWithFindbugsProfile(sonarWay).createProfile(ValidationMessages.create());
assertThat(withFindbugs.getActiveRules().size(), is(withoutFindbugs.getActiveRules().size()));
diff --git a/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SunConventionsProfileTest.java b/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SunConventionsProfileTest.java
index 147006e30eb..4f2bb9361d8 100644
--- a/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SunConventionsProfileTest.java
+++ b/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SunConventionsProfileTest.java
@@ -23,6 +23,7 @@ import org.hamcrest.core.Is;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import org.sonar.api.measures.MetricFinder;
import org.sonar.api.profiles.ProfileDefinition;
import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.profiles.XMLProfileParser;
@@ -39,7 +40,7 @@ import static org.mockito.Mockito.when;
public class SunConventionsProfileTest {
@Test
public void shouldCreateProfile() {
- ProfileDefinition definition = new SunConventionsProfile(new XMLProfileParser(newRuleFinder()));
+ ProfileDefinition definition = new SunConventionsProfile(new XMLProfileParser(newRuleFinder(), mock(MetricFinder.class)));
ValidationMessages validation = ValidationMessages.create();
RulesProfile sunProfile = definition.createProfile(validation);
assertThat(sunProfile.getActiveRulesByRepository(CheckstyleConstants.REPOSITORY_KEY).size(), greaterThan(1));
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileParser.java b/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileParser.java
index 571e2fd6d9b..3ecff6e74fb 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileParser.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileParser.java
@@ -27,29 +27,34 @@ import org.codehaus.staxmate.SMInputFactory;
import org.codehaus.staxmate.in.SMHierarchicCursor;
import org.codehaus.staxmate.in.SMInputCursor;
import org.sonar.api.ServerComponent;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.measures.MetricFinder;
import org.sonar.api.rules.ActiveRule;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.RulePriority;
import org.sonar.api.utils.ValidationMessages;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+
/**
* @since 2.3
*/
public final class XMLProfileParser implements ServerComponent {
private RuleFinder ruleFinder;
+ private MetricFinder metricFinder;
- public XMLProfileParser(RuleFinder ruleFinder) {
+ public XMLProfileParser(RuleFinder ruleFinder, MetricFinder metricFinder) {
this.ruleFinder = ruleFinder;
+ this.metricFinder = metricFinder;
}
public RulesProfile parseResource(ClassLoader classloader, String xmlClassPath, ValidationMessages messages) {
@@ -75,6 +80,10 @@ public final class XMLProfileParser implements ServerComponent {
SMInputCursor rulesCursor = cursor.childElementCursor("rule");
processRules(rulesCursor, profile, messages);
+ } else if (StringUtils.equals("alerts", nodeName)) {
+ SMInputCursor alertsCursor = cursor.childElementCursor("alert");
+ processAlerts(alertsCursor, profile, messages);
+
} else if (StringUtils.equals("name", nodeName)) {
profile.setName(StringUtils.trim(cursor.collectDescendantText(false)));
@@ -105,8 +114,7 @@ public final class XMLProfileParser implements ServerComponent {
// just so it won't try to load DTD in if there's DOCTYPE
xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
- SMInputFactory inputFactory = new SMInputFactory(xmlFactory);
- return inputFactory;
+ return new SMInputFactory(xmlFactory);
}
private void processRules(SMInputCursor rulesCursor, RulesProfile profile, ValidationMessages messages) throws XMLStreamException {
@@ -144,7 +152,8 @@ public final class XMLProfileParser implements ServerComponent {
ActiveRule activeRule = profile.activateRule(rule, priority);
for (Map.Entry<String, String> entry : parameters.entrySet()) {
if (rule.getParam(entry.getKey()) == null) {
- messages.addWarningText("The parameter '" + entry.getKey() + "' does not exist in the rule: [repository=" + repositoryKey + ", key=" + key + "]");
+ messages.addWarningText("The parameter '" + entry.getKey() + "' does not exist in the rule: [repository=" + repositoryKey
+ + ", key=" + key + "]");
} else {
activeRule.setParameter(entry.getKey(), entry.getValue());
}
@@ -173,5 +182,41 @@ public final class XMLProfileParser implements ServerComponent {
}
}
+ private void processAlerts(SMInputCursor alertsCursor, RulesProfile profile, ValidationMessages messages) throws XMLStreamException {
+ while (alertsCursor.getNext() != null) {
+ SMInputCursor alertCursor = alertsCursor.childElementCursor();
+
+ String metricKey = null, operator = "", valueError = "", valueWarning = "";
+
+ while (alertCursor.getNext() != null) {
+ String nodeName = alertCursor.getLocalName();
+
+ if (StringUtils.equals("metric", nodeName)) {
+ metricKey = StringUtils.trim(alertCursor.collectDescendantText(false));
+
+ } else if (StringUtils.equals("operator", nodeName)) {
+ operator = StringUtils.trim(alertCursor.collectDescendantText(false));
+
+ } else if (StringUtils.equals("warning", nodeName)) {
+ valueWarning = StringUtils.trim(alertCursor.collectDescendantText(false));
+
+ } else if (StringUtils.equals("error", nodeName)) {
+ valueError = StringUtils.trim(alertCursor.collectDescendantText(false));
+ }
+ }
+
+ Metric metric = metricFinder.findByKey(metricKey);
+ if (metric == null) {
+ messages.addWarningText("Metric '" + metricKey + "' does not exist");
+ } else {
+ Alert alert = new Alert();
+ alert.setMetric(metric);
+ alert.setOperator(operator);
+ alert.setValueError(valueError);
+ alert.setValueWarning(valueWarning);
+ profile.getAlerts().add(alert);
+ }
+ }
+ }
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileSerializer.java b/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileSerializer.java
index 263c8171f01..e462aa809f3 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileSerializer.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileSerializer.java
@@ -38,6 +38,7 @@ public final class XMLProfileSerializer implements ServerComponent {
try {
appendHeader(profile, writer);
appendRules(profile, writer);
+ appendAlerts(profile, writer);
appendFooter(writer);
} catch (IOException e) {
@@ -101,6 +102,28 @@ public final class XMLProfileSerializer implements ServerComponent {
}
}
+ private void appendAlerts(RulesProfile profile, Writer writer) throws IOException {
+ if (!profile.getAlerts().isEmpty()) {
+ writer.append("<alerts>");
+ for (Alert alert : profile.getAlerts()) {
+ appendAlert(alert, writer);
+ }
+ writer.append("</alerts>");
+ }
+ }
+
+ private void appendAlert(Alert alert, Writer writer) throws IOException {
+ writer.append("<alert><metric>");
+ StringEscapeUtils.escapeXml(writer, alert.getMetric().getKey());
+ writer.append("</metric><operator>");
+ StringEscapeUtils.escapeXml(writer, alert.getOperator());
+ writer.append("</operator><warning>");
+ StringEscapeUtils.escapeXml(writer, alert.getValueWarning());
+ writer.append("</warning><error>");
+ StringEscapeUtils.escapeXml(writer, alert.getValueError());
+ writer.append("</error></alert>");
+ }
+
private void appendFooter(Writer writer) throws IOException {
writer.append("</profile>");
}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/profiles/XMLProfileParserTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/profiles/XMLProfileParserTest.java
index 6c31b9d2688..6a6ca1af8da 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/profiles/XMLProfileParserTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/profiles/XMLProfileParserTest.java
@@ -22,6 +22,8 @@ package org.sonar.api.profiles;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.measures.MetricFinder;
import org.sonar.api.rules.ActiveRule;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
@@ -44,8 +46,7 @@ public class XMLProfileParserTest {
@Test
public void importProfile() throws UnsupportedEncodingException {
ValidationMessages validation = ValidationMessages.create();
- RuleFinder ruleFinder = newRuleFinder();
- RulesProfile profile = new XMLProfileParser(ruleFinder).parseResource(getClass().getClassLoader(), "org/sonar/api/profiles/XMLProfileParserTest/importProfile.xml", validation);
+ RulesProfile profile = parse("importProfile.xml", validation);
assertThat(profile.getLanguage(), is("java"));
assertThat(profile.getName(), is("sonar way"));
@@ -57,8 +58,7 @@ public class XMLProfileParserTest {
@Test
public void nameAndLanguageShouldBeMandatory() throws UnsupportedEncodingException {
ValidationMessages validation = ValidationMessages.create();
- RuleFinder ruleFinder = newRuleFinder();
- RulesProfile profile = new XMLProfileParser(ruleFinder).parseResource(getClass().getClassLoader(), "org/sonar/api/profiles/XMLProfileParserTest/nameAndLanguageShouldBeMandatory.xml", validation);
+ parse("nameAndLanguageShouldBeMandatory.xml", validation);
assertThat(validation.getErrors().size(), is(2));
assertThat(validation.getErrors().get(0), containsString(""));
@@ -68,8 +68,7 @@ public class XMLProfileParserTest {
@Test
public void importProfileWithRuleParameters() throws UnsupportedEncodingException {
ValidationMessages validation = ValidationMessages.create();
- RuleFinder ruleFinder = newRuleFinder();
- RulesProfile profile = new XMLProfileParser(ruleFinder).parseResource(getClass().getClassLoader(), "org/sonar/api/profiles/XMLProfileParserTest/importProfileWithRuleParameters.xml", validation);
+ RulesProfile profile = parse("importProfileWithRuleParameters.xml", validation);
assertThat(validation.hasErrors(), is(false));
assertThat(validation.hasWarnings(), is(false));
@@ -81,14 +80,41 @@ public class XMLProfileParserTest {
@Test
public void importProfileWithUnknownRuleParameter() throws UnsupportedEncodingException {
ValidationMessages validation = ValidationMessages.create();
- RuleFinder ruleFinder = newRuleFinder();
- RulesProfile profile = new XMLProfileParser(ruleFinder).parseResource(getClass().getClassLoader(), "org/sonar/api/profiles/XMLProfileParserTest/importProfileWithUnknownRuleParameter.xml", validation);
+ RulesProfile profile = parse("importProfileWithUnknownRuleParameter.xml", validation);
assertThat(validation.getWarnings().size(), is(1));
ActiveRule rule = profile.getActiveRule("checkstyle", "IllegalRegexp");
assertThat(rule.getParameter("unknown"), nullValue());
}
+ @Test
+ public void importProfileWithAlerts() {
+ ValidationMessages validation = ValidationMessages.create();
+ RulesProfile profile = parse("importProfileWithAlerts.xml", validation);
+
+ assertThat(profile.getAlerts().size(), is(1));
+ Alert alert = profile.getAlerts().get(0);
+ assertThat(alert.getMetric().getKey(), is("complexity"));
+ assertThat(alert.getOperator(), is(Alert.OPERATOR_GREATER));
+ assertThat(alert.getValueWarning(), is("10"));
+ assertThat(alert.getValueError(), is("12"));
+ }
+
+ private RulesProfile parse(String resource, ValidationMessages validation) {
+ return new XMLProfileParser(newRuleFinder(), newMetricFinder())
+ .parseResource(getClass().getClassLoader(), "org/sonar/api/profiles/XMLProfileParserTest/" + resource, validation);
+ }
+
+ private MetricFinder newMetricFinder() {
+ MetricFinder metricFinder = mock(MetricFinder.class);
+ when(metricFinder.findByKey(anyString())).thenAnswer(new Answer<Metric>() {
+ public Metric answer(InvocationOnMock iom) throws Throwable {
+ return new Metric((String) iom.getArguments()[0]);
+ }
+ });
+ return metricFinder;
+ }
+
private RuleFinder newRuleFinder() {
RuleFinder ruleFinder = mock(RuleFinder.class);
when(ruleFinder.findByKey(anyString(), anyString())).thenAnswer(new Answer<Rule>() {
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/profiles/XMLProfileSerializerTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/profiles/XMLProfileSerializerTest.java
index 90169f10dab..e63801dea3b 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/profiles/XMLProfileSerializerTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/profiles/XMLProfileSerializerTest.java
@@ -24,6 +24,7 @@ import org.apache.commons.lang.CharUtils;
import org.custommonkey.xmlunit.Diff;
import org.custommonkey.xmlunit.XMLUnit;
import org.junit.Test;
+import org.sonar.api.measures.Metric;
import org.sonar.api.rules.ActiveRule;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RulePriority;
@@ -75,6 +76,21 @@ public class XMLProfileSerializerTest {
assertSimilarXml("/org/sonar/api/profiles/XMLProfileSerializerTest/exportRuleParameters.xml", writer.toString());
}
+ @Test
+ public void exportAlerts() throws Exception {
+ Writer writer = new StringWriter();
+ RulesProfile profile = RulesProfile.create("sonar way", "java");
+ Alert alert = new Alert();
+ alert.setMetric(new Metric("coverage"));
+ alert.setOperator(Alert.OPERATOR_SMALLER);
+ alert.setValueError("60");
+ alert.setValueWarning("80");
+ profile.getAlerts().add(alert);
+ new XMLProfileSerializer().write(profile, writer);
+
+ assertSimilarXml("/org/sonar/api/profiles/XMLProfileSerializerTest/exportAlerts.xml", writer.toString());
+ }
+
public static void assertSimilarXml(String pathToExpectedXml, String xml) throws IOException, SAXException {
InputStream stream = XMLProfileSerializerTest.class.getResourceAsStream(pathToExpectedXml);
try {
diff --git a/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileParserTest/importProfileWithAlerts.xml b/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileParserTest/importProfileWithAlerts.xml
new file mode 100644
index 00000000000..3a34a304562
--- /dev/null
+++ b/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileParserTest/importProfileWithAlerts.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated by Sonar -->
+<profile>
+ <name>sonar way</name>
+ <language>java</language>
+ <rules>
+ <rule>
+ <repositoryKey>checkstyle</repositoryKey>
+ <key>IllegalRegexp</key>
+ <priority>CRITICAL</priority>
+ </rule>
+ </rules>
+ <alerts>
+ <alert>
+ <metric>complexity</metric>
+ <operator>&gt;</operator>
+ <error>12</error>
+ <warning>10</warning>
+ </alert>
+ </alerts>
+</profile> \ No newline at end of file
diff --git a/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileSerializerTest/exportAlerts.xml b/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileSerializerTest/exportAlerts.xml
new file mode 100644
index 00000000000..1a1859836c8
--- /dev/null
+++ b/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileSerializerTest/exportAlerts.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated by Sonar -->
+<profile>
+ <name>sonar way</name>
+ <language>java</language>
+ <alerts>
+ <alert>
+ <metric>coverage</metric>
+ <operator>&lt;</operator>
+ <error>60</error>
+ <warning>80</warning>
+ </alert>
+ </alerts>
+</profile> \ No newline at end of file