diff options
author | Godin <mandrikov@gmail.com> | 2010-12-08 14:53:08 +0000 |
---|---|---|
committer | Godin <mandrikov@gmail.com> | 2010-12-08 14:53:08 +0000 |
commit | 1ba217e3e27485a9c4e7176a04acf4cfdd10ac6b (patch) | |
tree | 4400d173987d88c001155c9d1351905930d2756c /sonar-server | |
parent | 74c4ac9a4a5c9df13116862dd5dca982cc3f84bd (diff) | |
download | sonarqube-1ba217e3e27485a9c4e7176a04acf4cfdd10ac6b.tar.gz sonarqube-1ba217e3e27485a9c4e7176a04acf4cfdd10ac6b.zip |
SONAR-1987: Backup/restore user rules
Diffstat (limited to 'sonar-server')
6 files changed, 278 insertions, 13 deletions
diff --git a/sonar-server/src/main/java/org/sonar/server/configuration/Backup.java b/sonar-server/src/main/java/org/sonar/server/configuration/Backup.java index a8ed347761e..eba4e481083 100644 --- a/sonar-server/src/main/java/org/sonar/server/configuration/Backup.java +++ b/sonar-server/src/main/java/org/sonar/server/configuration/Backup.java @@ -56,6 +56,8 @@ public class Backup { backupables.add(new MetricsBackup(session)); backupables.add(new PropertiesBackup(session)); + // Note that order is important, because profile can have reference to rule + backupables.add(new RulesBackup(session)); backupables.add(new ProfilesBackup(session)); } @@ -149,11 +151,9 @@ public class Backup { protected void writeText(QuickWriter writer, String text) { writer.write("<![CDATA["); /* - * See http://jira.codehaus.org/browse/SONAR-1605 - * According to XML specification ( http://www.w3.org/TR/REC-xml/#sec-cdata-sect ) - * CData section may contain everything except of sequence ']]>' - * so we will split all occurrences of this sequence into two CDATA - * first one would contain ']]' and second '>' + * See http://jira.codehaus.org/browse/SONAR-1605 According to XML specification ( + * http://www.w3.org/TR/REC-xml/#sec-cdata-sect ) CData section may contain everything except of sequence ']]>' so we will + * split all occurrences of this sequence into two CDATA first one would contain ']]' and second '>' */ text = StringUtils.replace(text, "]]>", "]]]]><![CDATA[>"); writer.write(text); diff --git a/sonar-server/src/main/java/org/sonar/server/configuration/ProfilesBackup.java b/sonar-server/src/main/java/org/sonar/server/configuration/ProfilesBackup.java index 16f84aad306..3149e62923c 100644 --- a/sonar-server/src/main/java/org/sonar/server/configuration/ProfilesBackup.java +++ b/sonar-server/src/main/java/org/sonar/server/configuration/ProfilesBackup.java @@ -111,9 +111,10 @@ public class ProfilesBackup implements Backupable { for (Iterator<ActiveRule> iar = profile.getActiveRules().iterator(); iar.hasNext();) { ActiveRule activeRule = iar.next(); Rule unMarshalledRule = activeRule.getRule(); - Rule matchingRuleInDb = rulesDao.getRuleByKey(unMarshalledRule.getPluginName(), unMarshalledRule.getKey()); + Rule matchingRuleInDb = rulesDao.getRuleByKey(unMarshalledRule.getRepositoryKey(), unMarshalledRule.getKey()); if (matchingRuleInDb == null) { - LoggerFactory.getLogger(getClass()).error("Unable to find active rule " + unMarshalledRule.getPluginName() + ":" + unMarshalledRule.getKey()); + LoggerFactory.getLogger(getClass()).error( + "Unable to find active rule " + unMarshalledRule.getRepositoryKey() + ":" + unMarshalledRule.getKey()); iar.remove(); continue; } @@ -148,7 +149,8 @@ public class ProfilesBackup implements Backupable { public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { Map<String, String> values = readNode(reader); - return new Alert(null, new Metric(values.get("metric-key")), values.get("operator"), values.get("value-error"), values.get("value-warning")); + return new Alert(null, new Metric(values.get("metric-key")), values.get("operator"), values.get("value-error"), + values.get("value-warning")); } public boolean canConvert(Class type) { @@ -163,7 +165,7 @@ public class ProfilesBackup implements Backupable { public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { ActiveRule rule = (ActiveRule) source; writeNode(writer, "key", rule.getRule().getKey()); - writeNode(writer, "plugin", rule.getRule().getPluginName()); + writeNode(writer, "plugin", rule.getRule().getRepositoryKey()); writeNode(writer, "level", rule.getSeverity().name()); if (!rule.getActiveRuleParams().isEmpty()) { @@ -188,7 +190,8 @@ public class ProfilesBackup implements Backupable { while (reader.hasMoreChildren()) { reader.moveDown(); Map<String, String> valuesParam = readNode(reader); - ActiveRuleParam activeRuleParam = new ActiveRuleParam(null, new RuleParam(null, valuesParam.get("key"), null, null), valuesParam.get("value")); + ActiveRuleParam activeRuleParam = new ActiveRuleParam(null, new RuleParam(null, valuesParam.get("key"), null, null), + valuesParam.get("value")); params.add(activeRuleParam); reader.moveUp(); } diff --git a/sonar-server/src/main/java/org/sonar/server/configuration/RulesBackup.java b/sonar-server/src/main/java/org/sonar/server/configuration/RulesBackup.java new file mode 100644 index 00000000000..62382851002 --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/configuration/RulesBackup.java @@ -0,0 +1,193 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.server.configuration; + +import com.google.common.collect.Lists; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import org.apache.commons.collections.CollectionUtils; +import org.slf4j.LoggerFactory; +import org.sonar.api.database.DatabaseSession; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RuleParam; +import org.sonar.api.rules.RulePriority; +import org.sonar.jpa.dao.RulesDao; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class RulesBackup implements Backupable { + private Collection<Rule> rules; + private RulesDao rulesDao; + private DatabaseSession session; + + public RulesBackup(DatabaseSession session) { + this.rulesDao = new RulesDao(session); + this.session = session; + } + + /** + * For tests. + */ + RulesBackup(Collection<Rule> rules) { + this.rules = rules; + } + + public void exportXml(SonarConfig sonarConfig) { + if (rules == null) { + rules = getUserRules(); + } + sonarConfig.setRules(rules); + } + + public void importXml(SonarConfig sonarConfig) { + disableUserRules(); + if (CollectionUtils.isNotEmpty(sonarConfig.getRules())) { + registerUserRules(sonarConfig.getRules()); + } + } + + private List<Rule> getUserRules() { + List<Rule> rules = rulesDao.getRules(); + List<Rule> userRules = Lists.newArrayList(); + for (Rule rule : rules) { + if (rule.getParent() != null) { + userRules.add(rule); + } + } + return userRules; + } + + private void disableUserRules() { + for (Rule rule : getUserRules()) { + rule.setEnabled(false); + session.save(rule); + } + } + + private void registerUserRules(Collection<Rule> rules) { + for (Rule rule : rules) { + Rule parent = rule.getParent(); + Rule matchingParentRuleInDb = rulesDao.getRuleByKey(parent.getRepositoryKey(), parent.getKey()); + if (matchingParentRuleInDb == null) { + LoggerFactory.getLogger(getClass()).error("Unable to find parent rule " + parent.getRepositoryKey() + ":" + parent.getKey()); + continue; + } + rule.setParent(matchingParentRuleInDb); + Rule matchingRuleInDb = rulesDao.getRuleByKey(rule.getRepositoryKey(), rule.getKey()); + if (matchingRuleInDb != null) { + matchingRuleInDb.setName(rule.getName()); + matchingRuleInDb.setDescription(rule.getDescription()); + matchingRuleInDb.setSeverity(rule.getSeverity()); + matchingRuleInDb.setParams(rule.getParams()); + matchingRuleInDb.setEnabled(true); + session.save(matchingRuleInDb); + } else { + rule.setEnabled(true); + session.save(rule); + } + } + } + + public void configure(XStream xStream) { + xStream.alias("rule", Rule.class); + xStream.registerConverter(new Converter() { + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + Rule rule = (Rule) source; + writeNode(writer, "parentRepositoryKey", rule.getParent().getRepositoryKey()); + writeNode(writer, "parentKey", rule.getParent().getKey()); + writeNode(writer, "repositoryKey", rule.getRepositoryKey()); + writeNode(writer, "key", rule.getKey()); + writeNode(writer, "level", rule.getSeverity().name()); + writeNode(writer, "name", rule.getName()); + writeNode(writer, "description", rule.getDescription()); + + if (!rule.getParams().isEmpty()) { + writer.startNode("params"); + for (RuleParam ruleParam : rule.getParams()) { + writer.startNode("param"); + writeNode(writer, "key", ruleParam.getKey()); + writeNode(writer, "value", ruleParam.getDefaultValue()); + writer.endNode(); + } + writer.endNode(); + } + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + Rule rule = Rule.create(); + + Map<String, String> valuesRule = new HashMap<String, String>(); + while (reader.hasMoreChildren()) { + reader.moveDown(); + valuesRule.put(reader.getNodeName(), reader.getValue()); + if (reader.getNodeName().equals("params")) { + while (reader.hasMoreChildren()) { + reader.moveDown(); + Map<String, String> valuesParam = readNode(reader); + rule.createParameter() + .setKey(valuesParam.get("key")) + .setDefaultValue(valuesParam.get("value")); + reader.moveUp(); + } + } + reader.moveUp(); + } + + Rule parent = Rule.create() + .setRepositoryKey(valuesRule.get("parentRepositoryKey")) + .setKey(valuesRule.get("parentKey")); + rule.setParent(parent) + .setRepositoryKey(valuesRule.get("repositoryKey")) + .setKey(valuesRule.get("key")) + .setName(valuesRule.get("name")) + .setDescription(valuesRule.get("description")) + .setSeverity(RulePriority.valueOf(valuesRule.get("level"))); + return rule; + } + + public boolean canConvert(Class type) { + return Rule.class.equals(type); + } + }); + } + + private void writeNode(HierarchicalStreamWriter writer, String name, String value) { + writer.startNode(name); + writer.setValue(value); + writer.endNode(); + } + + private Map<String, String> readNode(HierarchicalStreamReader reader) { + Map<String, String> values = new HashMap<String, String>(); + while (reader.hasMoreChildren()) { + reader.moveDown(); + values.put(reader.getNodeName(), reader.getValue()); + reader.moveUp(); + } + return values; + } +} diff --git a/sonar-server/src/main/java/org/sonar/server/configuration/SonarConfig.java b/sonar-server/src/main/java/org/sonar/server/configuration/SonarConfig.java index 0426ed45b76..123fc534b54 100644 --- a/sonar-server/src/main/java/org/sonar/server/configuration/SonarConfig.java +++ b/sonar-server/src/main/java/org/sonar/server/configuration/SonarConfig.java @@ -24,6 +24,7 @@ import org.apache.commons.lang.builder.ToStringBuilder; import org.sonar.api.database.configuration.Property; import org.sonar.api.measures.Metric; import org.sonar.api.profiles.RulesProfile; +import org.sonar.api.rules.Rule; import java.util.Collection; import java.util.Date; @@ -41,6 +42,8 @@ public class SonarConfig { private Collection<RulesProfile> profiles; + private Collection<Rule> rules; + public SonarConfig() { } @@ -89,6 +92,14 @@ public class SonarConfig { this.profiles = profiles; } + public Collection<Rule> getRules() { + return rules; + } + + public void setRules(Collection<Rule> rules) { + this.rules = rules; + } + @Override public String toString() { return new ToStringBuilder(this) @@ -99,4 +110,5 @@ public class SonarConfig { .append("profiles", profiles) .toString(); } + } diff --git a/sonar-server/src/test/java/org/sonar/server/configuration/BackupTest.java b/sonar-server/src/test/java/org/sonar/server/configuration/BackupTest.java index 4d6e66d7a0f..6b28a22366e 100644 --- a/sonar-server/src/test/java/org/sonar/server/configuration/BackupTest.java +++ b/sonar-server/src/test/java/org/sonar/server/configuration/BackupTest.java @@ -65,7 +65,8 @@ public class BackupTest { @Test public void shouldReturnAValidXml() throws Exception { - Backup backup = new Backup(Arrays.asList(new MetricsBackup(null), new PropertiesBackup(null), new ProfilesBackup((DatabaseSession) null))); + Backup backup = new Backup(Arrays.asList(new MetricsBackup(null), new PropertiesBackup(null), + new ProfilesBackup((DatabaseSession) null))); SonarConfig sonarConfig = getSonarConfig(); sonarConfig.setMetrics(getMetrics()); sonarConfig.setProperties(getProperties()); @@ -97,7 +98,8 @@ public class BackupTest { @Test public void shouldImportXml() { - Backup backup = new Backup(Arrays.asList(new MetricsBackup(null), new PropertiesBackup(null), new ProfilesBackup((DatabaseSession) null))); + Backup backup = new Backup(Arrays.asList(new MetricsBackup(null), new PropertiesBackup(null), + new ProfilesBackup((DatabaseSession) null))); String xml = getFileFromClasspath("backup-restore-valid.xml"); SonarConfig sonarConfig = backup.getSonarConfigFromXml(xml); @@ -124,7 +126,7 @@ public class BackupTest { assertEquals(RulePriority.MAJOR, testActiveRule.getSeverity()); assertNotNull(testActiveRule.getRule()); assertEquals("test key", testActiveRule.getRule().getKey()); - assertEquals("test plugin", testActiveRule.getRule().getPluginName()); + assertEquals("test plugin", testActiveRule.getRule().getRepositoryKey()); assertEquals(1, testActiveRule.getActiveRuleParams().size()); ActiveRuleParam testActiveRuleParam = testActiveRule.getActiveRuleParams().get(0); diff --git a/sonar-server/src/test/java/org/sonar/server/configuration/RulesBackupTest.java b/sonar-server/src/test/java/org/sonar/server/configuration/RulesBackupTest.java new file mode 100644 index 00000000000..9886fdc5bf0 --- /dev/null +++ b/sonar-server/src/test/java/org/sonar/server/configuration/RulesBackupTest.java @@ -0,0 +1,55 @@ +package org.sonar.server.configuration; + +import org.junit.Test; +import org.sonar.api.rules.Rule; +import org.sonar.jpa.dao.RulesDao; +import org.sonar.jpa.test.AbstractDbUnitTestCase; + +import java.util.Arrays; +import java.util.List; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +public class RulesBackupTest extends AbstractDbUnitTestCase { + + @Test + public void shouldExportRules() { + SonarConfig sonarConfig = new SonarConfig(); + + Rule rule = Rule.create("repo", "key", "name").setDescription("description"); + + Rule userRule = Rule.create("repo", "key2", "name2").setDescription("description2"); + userRule.setParent(rule); + userRule.createParameter("param").setDefaultValue("value"); + + RulesBackup rulesBackup = new RulesBackup(Arrays.asList(userRule)); + rulesBackup.exportXml(sonarConfig); + + assertThat(sonarConfig.getRules().size(), is(1)); + assertTrue(sonarConfig.getRules().iterator().next() == userRule); + } + + @Test + public void shouldImportRules() { + RulesDao rulesDao = getDao().getRulesDao(); + + RulesBackup rulesBackup = new RulesBackup(getSession()); + SonarConfig sonarConfig = new SonarConfig(); + + Rule rule = Rule.create("repo", "key", "name").setDescription("description"); + + Rule userRule = Rule.create("repo", "key2", "name2").setDescription("description2"); + userRule.setParent(rule); + userRule.createParameter("param").setDefaultValue("value"); + + getSession().save(rule); + + sonarConfig.setRules(Arrays.asList(userRule)); + rulesBackup.importXml(sonarConfig); + + List<Rule> rules = rulesDao.getRules(); + assertThat(rules.size(), is(2)); + } +} |