diff options
author | Godin <mandrikov@gmail.com> | 2010-12-08 19:22:18 +0000 |
---|---|---|
committer | Godin <mandrikov@gmail.com> | 2010-12-08 19:22:18 +0000 |
commit | 85ad745aaee19225e0abbb11abd167e39a8b1e95 (patch) | |
tree | 37139954f8e33512388964ae4f4059666745c5cf | |
parent | e3b4152afad73825c08a72c7e17432fb97638970 (diff) | |
download | sonarqube-85ad745aaee19225e0abbb11abd167e39a8b1e95.tar.gz sonarqube-85ad745aaee19225e0abbb11abd167e39a8b1e95.zip |
SONAR-1809: Export / import alerts attached to a quality profile
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>></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><</operator> + <error>60</error> + <warning>80</warning> + </alert> + </alerts> +</profile>
\ No newline at end of file |