pico.addSingleton(QProfileLookup.class);
pico.addSingleton(QProfileProjectOperations.class);
pico.addSingleton(QProfileProjectLookup.class);
+ pico.addSingleton(QProfileComparator.class);
pico.addSingleton(BuiltInProfiles.class);
pico.addSingleton(QProfileRestoreBuiltInAction.class);
pico.addSingleton(QProfileSearchAction.class);
pico.addSingleton(QProfileInheritanceAction.class);
pico.addSingleton(QProfileChangeParentAction.class);
pico.addSingleton(QProfileChangelogAction.class);
+ pico.addSingleton(QProfileCompareAction.class);
pico.addSingleton(QProfilesWs.class);
pico.addSingleton(ProfilesWs.class);
pico.addSingleton(RuleActivationActions.class);
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.qualityprofile;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.MapDifference;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.qualityprofile.db.QualityProfileDto;
+import org.sonar.core.util.NonNullInputFunction;
+import org.sonar.server.db.DbClient;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+public class QProfileComparator implements ServerComponent {
+
+ private final DbClient dbClient;
+
+ private final QProfileLoader profileLoader;
+
+ public QProfileComparator(DbClient dbClient, QProfileLoader profileLoader) {
+ this.dbClient = dbClient;
+ this.profileLoader = profileLoader;
+ }
+
+ public QProfileComparisonResult compare(String leftKey, String rightKey) {
+ QProfileComparisonResult result = new QProfileComparisonResult();
+
+ DbSession dbSession = dbClient.openSession(false);
+
+ try {
+ compare(leftKey, rightKey, dbSession, result);
+ } finally {
+ dbSession.close();
+ }
+
+ return result;
+ }
+
+ private void compare(String leftKey, String rightKey, DbSession session, QProfileComparisonResult result) {
+ result.left = dbClient.qualityProfileDao().getByKey(session, leftKey);
+ Preconditions.checkArgument(result.left != null, String.format("Could not find left profile '%s'", leftKey));
+ result.right = dbClient.qualityProfileDao().getByKey(session, rightKey);
+ Preconditions.checkArgument(result.right != null, String.format("Could not find right profile '%s'", leftKey));
+
+ Map<RuleKey, ActiveRule> leftActiveRulesByRuleKey = loadActiveRules(leftKey);
+ Map<RuleKey, ActiveRule> rightActiveRulesByRuleKey = loadActiveRules(rightKey);
+
+ Set<RuleKey> allRules = Sets.newHashSet();
+ allRules.addAll(leftActiveRulesByRuleKey.keySet());
+ allRules.addAll(rightActiveRulesByRuleKey.keySet());
+
+ for (RuleKey ruleKey : allRules) {
+ if (!leftActiveRulesByRuleKey.containsKey(ruleKey)) {
+ result.inRight.put(ruleKey, rightActiveRulesByRuleKey.get(ruleKey));
+ } else if (!rightActiveRulesByRuleKey.containsKey(ruleKey)) {
+ result.inLeft.put(ruleKey, leftActiveRulesByRuleKey.get(ruleKey));
+ } else {
+ compare(leftActiveRulesByRuleKey.get(ruleKey), rightActiveRulesByRuleKey.get(ruleKey), result);
+ }
+ }
+ }
+
+ private void compare(ActiveRule leftRule, ActiveRule rightRule, QProfileComparisonResult result) {
+ RuleKey key = leftRule.key().ruleKey();
+ if (leftRule.params().equals(rightRule.params()) && leftRule.severity().equals(rightRule.severity())) {
+ result.same.put(key, leftRule);
+ } else {
+ ActiveRuleDiff diff = new ActiveRuleDiff();
+ diff.key = key;
+
+ if (leftRule.severity().equals(rightRule.severity())) {
+ diff.leftSeverity = diff.rightSeverity = leftRule.severity();
+ } else {
+ diff.leftSeverity = leftRule.severity();
+ diff.rightSeverity = rightRule.severity();
+ }
+
+ diff.paramDifference = Maps.difference(leftRule.params(), rightRule.params());
+ result.modified.put(key, diff);
+ }
+ }
+
+ private Map<RuleKey, ActiveRule> loadActiveRules(String profileKey) {
+ return Maps.uniqueIndex(profileLoader.findActiveRulesByProfile(profileKey), new NonNullInputFunction<ActiveRule, RuleKey>() {
+ @Override
+ protected RuleKey doApply(ActiveRule input) {
+ return input.key().ruleKey();
+ }
+ });
+ }
+
+ public static class QProfileComparisonResult {
+
+ private QualityProfileDto left;
+ private QualityProfileDto right;
+ private Map<RuleKey, ActiveRule> inLeft = Maps.newHashMap();
+ private Map<RuleKey, ActiveRule> inRight = Maps.newHashMap();
+ private Map<RuleKey, ActiveRuleDiff> modified = Maps.newHashMap();
+ private Map<RuleKey, ActiveRule> same = Maps.newHashMap();
+
+ public QualityProfileDto left() {
+ return left;
+ }
+
+ public QualityProfileDto right() {
+ return right;
+ }
+
+ public Map<RuleKey, ActiveRule> inLeft() {
+ return inLeft;
+ }
+
+ public Map<RuleKey, ActiveRule> inRight() {
+ return inRight;
+ }
+
+ public Map<RuleKey, ActiveRuleDiff> modified() {
+ return modified;
+ }
+
+ public Map<RuleKey, ActiveRule> same() {
+ return same;
+ }
+
+ public Collection<RuleKey> collectRuleKeys() {
+ Set<RuleKey> keys = Sets.newHashSet();
+ keys.addAll(inLeft.keySet());
+ keys.addAll(inRight.keySet());
+ keys.addAll(modified.keySet());
+ keys.addAll(same.keySet());
+ return keys;
+ }
+ }
+
+ public static class ActiveRuleDiff {
+ private RuleKey key;
+ private String leftSeverity;
+ private String rightSeverity;
+ private MapDifference<String, String> paramDifference;
+
+ public RuleKey key() {
+ return key;
+ }
+
+ public String leftSeverity() {
+ return leftSeverity;
+ }
+
+ public String rightSeverity() {
+ return rightSeverity;
+ }
+
+ public MapDifference<String, String> paramDifference() {
+ return paramDifference;
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.qualityprofile.ws;
+
+import com.google.common.collect.MapDifference.ValueDifference;
+import com.google.common.collect.Maps;
+import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Languages;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService.NewAction;
+import org.sonar.api.server.ws.WebService.NewController;
+import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.core.qualityprofile.db.QualityProfileDto;
+import org.sonar.core.util.NonNullInputFunction;
+import org.sonar.server.qualityprofile.ActiveRule;
+import org.sonar.server.qualityprofile.QProfileComparator;
+import org.sonar.server.qualityprofile.QProfileComparator.ActiveRuleDiff;
+import org.sonar.server.qualityprofile.QProfileComparator.QProfileComparisonResult;
+import org.sonar.server.rule.Rule;
+import org.sonar.server.rule.RuleRepositories;
+import org.sonar.server.rule.RuleRepositories.Repository;
+import org.sonar.server.rule.RuleService;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+public class QProfileCompareAction implements BaseQProfileWsAction {
+
+ private static final String PARAM_LEFT_KEY = "leftKey";
+ private static final String PARAM_RIGHT_KEY = "rightKey";
+
+ private final QProfileComparator comparator;
+ private final RuleService ruleService;
+ private final RuleRepositories ruleRepositories;
+ private final Languages languages;
+
+ public QProfileCompareAction(QProfileComparator comparator, RuleService ruleService, RuleRepositories ruleRepositories, Languages languages) {
+ this.comparator = comparator;
+ this.ruleService = ruleService;
+ this.ruleRepositories = ruleRepositories;
+ this.languages = languages;
+ }
+
+ @Override
+ public void define(NewController context) {
+ NewAction compare = context.createAction("compare")
+ .setDescription("Compare two quality profiles.")
+ .setHandler(this)
+ .setResponseExample(getClass().getResource("example-compare.json"))
+ .setSince("5.2");
+
+ compare.createParam(PARAM_LEFT_KEY)
+ .setDescription("A profile key.")
+ .setExampleValue("java-sonar-way-12345")
+ .setRequired(true);
+
+ compare.createParam(PARAM_RIGHT_KEY)
+ .setDescription("Another profile key.")
+ .setExampleValue("java-sonar-way-with-findbugs-23456")
+ .setRequired(true);
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+ String leftKey = request.mandatoryParam(PARAM_LEFT_KEY);
+ String rightKey = request.mandatoryParam(PARAM_RIGHT_KEY);
+
+ QProfileComparisonResult result = comparator.compare(leftKey, rightKey);
+
+ List<Rule> referencedRules = ruleService.getByKeys(result.collectRuleKeys());
+ Map<RuleKey, Rule> rulesByKey = Maps.uniqueIndex(referencedRules, new NonNullInputFunction<Rule, RuleKey>() {
+ @Override
+ protected RuleKey doApply(Rule input) {
+ return input.key();
+ }
+ });
+
+ writeResult(response.newJsonWriter(), result, rulesByKey);
+ }
+
+ private void writeResult(JsonWriter json, QProfileComparisonResult result, Map<RuleKey, Rule> rulesByKey) {
+ json.beginObject();
+
+ json.name("left").beginObject();
+ writeProfile(json, result.left());
+ json.endObject();
+
+ json.name("right").beginObject();
+ writeProfile(json, result.right());
+ json.endObject();
+
+ json.name("inLeft");
+ writeRules(json, result.inLeft(), rulesByKey);
+
+ json.name("inRight");
+ writeRules(json, result.inRight(), rulesByKey);
+
+ json.name("modified");
+ writeDifferences(json, result.modified(), rulesByKey);
+
+ json.name("same");
+ writeRules(json, result.same(), rulesByKey);
+
+ json.endObject().close();
+ }
+
+ private void writeProfile(JsonWriter json, QualityProfileDto profile) {
+ json.prop("key", profile.getKey())
+ .prop("name", profile.getName());
+ }
+
+ private void writeRules(JsonWriter json, Map<RuleKey, ActiveRule> activeRules, Map<RuleKey, Rule> rulesByKey) {
+ json.beginArray();
+ for (Entry<RuleKey, ActiveRule> activeRule : activeRules.entrySet()) {
+ RuleKey key = activeRule.getKey();
+ ActiveRule value = activeRule.getValue();
+
+ json.beginObject();
+ writeRule(json, key, rulesByKey);
+ json.prop("severity", value.severity());
+ json.endObject();
+ }
+ json.endArray();
+ }
+
+ private void writeRule(JsonWriter json, RuleKey key, Map<RuleKey, Rule> rulesByKey) {
+ String repositoryKey = key.repository();
+ json.prop("key", key.toString())
+ .prop("name", rulesByKey.get(key).name())
+ .prop("pluginKey", repositoryKey);
+
+ Repository repo = ruleRepositories.repository(repositoryKey);
+ if (repo != null) {
+ String languageKey = repo.getLanguage();
+ Language language = languages.get(languageKey);
+
+ json.prop("pluginName", repo.getName());
+ json.prop("languageKey", languageKey);
+ json.prop("languageName", language == null ? null : language.getName());
+ }
+ }
+
+ private void writeDifferences(JsonWriter json, Map<RuleKey, ActiveRuleDiff> modified, Map<RuleKey, Rule> rulesByKey) {
+ json.beginArray();
+ for (Entry<RuleKey, ActiveRuleDiff> diffEntry : modified.entrySet()) {
+ RuleKey key = diffEntry.getKey();
+ ActiveRuleDiff value = diffEntry.getValue();
+ json.beginObject();
+ writeRule(json, key, rulesByKey);
+
+ json.name("left").beginObject();
+ json.prop("severity", value.leftSeverity());
+ json.name("params").beginObject();
+ for (Entry<String, ValueDifference<String>> valueDiff : value.paramDifference().entriesDiffering().entrySet()) {
+ json.prop(valueDiff.getKey(), valueDiff.getValue().leftValue());
+ }
+ for (Entry<String, String> valueDiff : value.paramDifference().entriesOnlyOnLeft().entrySet()) {
+ json.prop(valueDiff.getKey(), valueDiff.getValue());
+ }
+ // params
+ json.endObject();
+ // left
+ json.endObject();
+
+ json.name("right").beginObject();
+ json.prop("severity", value.rightSeverity());
+ json.name("params").beginObject();
+ for (Entry<String, ValueDifference<String>> valueDiff : value.paramDifference().entriesDiffering().entrySet()) {
+ json.prop(valueDiff.getKey(), valueDiff.getValue().rightValue());
+ }
+ for (Entry<String, String> valueDiff : value.paramDifference().entriesOnlyOnRight().entrySet()) {
+ json.prop(valueDiff.getKey(), valueDiff.getValue());
+ }
+ // params
+ json.endObject();
+ // right
+ json.endObject();
+
+ // rule
+ json.endObject();
+ }
+ json.endArray();
+ }
+
+}
--- /dev/null
+{
+ "left" : {
+ "key" : "js-my-profile-19170",
+ "name" : "My Profile"
+ },
+ "right" : {
+ "key" : "js-my-other-profile-12367",
+ "name" : "My Other Profile"
+ },
+ "same" : [
+ {
+ "key" : "javascript:EqEqEq",
+ "pluginKey" : "javascript",
+ "pluginName" : "SonarQube",
+ "languageKey": "js",
+ "languageName": "JavaScript",
+ "name" : "\"===\" and \"!==\" should be used instead of \"==\" and \"!=\"",
+ "severity" : "MAJOR"
+ }
+ ],
+ "inLeft" : [
+ {
+ "key" : "javascript:TrailingWhitespace",
+ "pluginKey" : "javascript",
+ "pluginName" : "SonarQube",
+ "languageKey": "js",
+ "languageName": "JavaScript",
+ "name" : "Avoid trailing whitespaces",
+ "severity" : "MAJOR"
+ }
+ ],
+ "inRight" : [
+ {
+ "key" : "javascript:TabCharacter",
+ "pluginKey" : "javascript",
+ "pluginName" : "SonarQube",
+ "languageKey": "js",
+ "languageName": "JavaScript",
+ "name" : "Avoid use of tabulation character",
+ "severity" : "MINOR"
+ }
+ ],
+ "modified" : [
+ {
+ "key" : "javascript:ExcessiveParameterList",
+ "pluginKey" : "javascript",
+ "pluginName" : "SonarQube",
+ "languageKey": "js",
+ "languageName": "JavaScript",
+ "name" : "Avoid function with too many parameters",
+ "right" : {
+ "severity" : "MAJOR",
+ "params" : {
+ "maximumFunctionParameters" : "7"
+ }
+ },
+ "left" : {
+ "severity" : "MAJOR",
+ "params" : {
+ "maximumFunctionParameters" : "10"
+ }
+ }
+ }
+ ]
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.qualityprofile.ws;
+
+import org.apache.commons.lang.StringUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.server.rule.RuleParamType;
+import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.qualityprofile.db.ActiveRuleDto;
+import org.sonar.core.qualityprofile.db.ActiveRuleParamDto;
+import org.sonar.core.qualityprofile.db.QualityProfileDto;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.core.rule.RuleParamDto;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.qualityprofile.QProfileName;
+import org.sonar.server.qualityprofile.QProfileTesting;
+import org.sonar.server.tester.ServerTester;
+import org.sonar.server.ws.WsTester;
+
+public class QProfileCompareActionMediumTest {
+
+ @ClassRule
+ public static ServerTester tester = new ServerTester().addXoo()
+ .addComponents(new RulesDefinition() {
+ @Override
+ public void define(Context context) {
+ context.createRepository("blah", "xoo")
+ .setName("Blah")
+ .done();
+ }
+ });
+
+ private DbClient db;
+
+ private WsTester wsTester;
+
+ private DbSession session;
+
+ @Before
+ public void setUp() throws Exception {
+ tester.clearDbAndIndexes();
+ db = tester.get(DbClient.class);
+ session = db.openSession(false);
+
+ wsTester = new WsTester(tester.get(QProfilesWs.class));
+ }
+
+ @After
+ public void tearDown() {
+ session.close();
+ }
+
+ @Test
+ public void compare_nominal() throws Exception {
+ RuleDto rule1 = createRule("xoo", "rule1");
+ RuleDto rule2 = createRule("xoo", "rule2");
+ RuleDto rule3 = createRule("xoo", "rule3");
+ RuleDto rule4 = createRuleWithParam("xoo", "rule4");
+ RuleDto rule5 = createRule("xoo", "rule5");
+
+ /*
+ * Profile 1:
+ * - rule 1 active (on both profiles) => "same"
+ * - rule 2 active (only in this profile) => "inLeft"
+ * - rule 4 active with different parameters => "modified"
+ * - rule 5 active with different severity => "modified"
+ */
+ QualityProfileDto profile1 = createProfile("xoo", "Profile 1", "xoo-profile-1-01234");
+ createActiveRule(rule1, profile1);
+ createActiveRule(rule2, profile1);
+ createActiveRuleWithParam(rule4, profile1, "polop");
+ createActiveRuleWithSeverity(rule5, profile1, Severity.MINOR);
+ session.commit();
+
+ /*
+ * Profile 1:
+ * - rule 1 active (on both profiles) => "same"
+ * - rule 3 active (only in this profile) => "inRight"
+ * - rule 4 active with different parameters => "modified"
+ */
+ QualityProfileDto profile2 = createProfile("xoo", "Profile 2", "xoo-profile-2-12345");
+ createActiveRule(rule1, profile2);
+ createActiveRule(rule3, profile2);
+ createActiveRuleWithParam(rule4, profile2, "palap");
+ createActiveRuleWithSeverity(rule5, profile2, Severity.MAJOR);
+ session.commit();
+
+ wsTester.newGetRequest("api/qualityprofiles", "compare")
+ .setParam("leftKey", profile1.getKey())
+ .setParam("rightKey", profile2.getKey())
+ .execute().assertJson(this.getClass(), "compare_nominal.json");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void fail_on_missing_left_param() throws Exception {
+ wsTester.newGetRequest("api/qualityprofiles", "compare")
+ .setParam("rightKey", "polop")
+ .execute();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void fail_on_missing_right_param() throws Exception {
+ wsTester.newGetRequest("api/qualityprofiles", "compare")
+ .setParam("leftKey", "polop")
+ .execute();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void fail_on_left_profile_not_found() throws Exception {
+ createProfile("xoo", "Right", "xoo-right-12345");
+ wsTester.newGetRequest("api/qualityprofiles", "compare")
+ .setParam("leftKey", "polop")
+ .setParam("rightKey", "xoo-right-12345")
+ .execute();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void fail_on_right_profile_not_found() throws Exception {
+ createProfile("xoo", "Left", "xoo-left-12345");
+ wsTester.newGetRequest("api/qualityprofiles", "compare")
+ .setParam("leftKey", "xoo-left-12345")
+ .setParam("rightKey", "polop")
+ .execute();
+ }
+
+ private QualityProfileDto createProfile(String lang, String name, String key) {
+ QualityProfileDto profile = QProfileTesting.newDto(new QProfileName(lang, name), key);
+ db.qualityProfileDao().insert(session, profile);
+ session.commit();
+ return profile;
+ }
+
+ private RuleDto createRule(String lang, String id) {
+ RuleDto rule = RuleDto.createFor(RuleKey.of("blah", id))
+ .setName(StringUtils.capitalize(id))
+ .setLanguage(lang)
+ .setSeverity(Severity.BLOCKER)
+ .setStatus(RuleStatus.READY);
+ db.ruleDao().insert(session, rule);
+ RuleParamDto param = RuleParamDto.createFor(rule).setName("param_" + id).setType(RuleParamType.STRING.toString());
+ db.ruleDao().addRuleParam(session, rule, param);
+ return rule;
+ }
+
+ private RuleDto createRuleWithParam(String lang, String id) {
+ RuleDto rule = createRule(lang, id);
+ RuleParamDto param = RuleParamDto.createFor(rule).setName("param_" + id).setType(RuleParamType.STRING.toString());
+ db.ruleDao().addRuleParam(session, rule, param);
+ return rule;
+ }
+
+ private ActiveRuleDto createActiveRule(RuleDto rule, QualityProfileDto profile) {
+ ActiveRuleDto activeRule = ActiveRuleDto.createFor(profile, rule)
+ .setSeverity(rule.getSeverityString());
+ db.activeRuleDao().insert(session, activeRule);
+ return activeRule;
+ }
+
+ private ActiveRuleDto createActiveRuleWithParam(RuleDto rule, QualityProfileDto profile, String value) {
+ ActiveRuleDto activeRule = createActiveRule(rule, profile);
+ RuleParamDto paramDto = db.ruleDao().findRuleParamsByRuleKey(session, rule.getKey()).get(0);
+ ActiveRuleParamDto activeRuleParam = ActiveRuleParamDto.createFor(paramDto).setValue(value);
+ db.activeRuleDao().addParam(session, activeRule, activeRuleParam);
+ return activeRule;
+ }
+
+ private ActiveRuleDto createActiveRuleWithSeverity(RuleDto rule, QualityProfileDto profile, String severity) {
+ ActiveRuleDto activeRule = ActiveRuleDto.createFor(profile, rule)
+ .setSeverity(severity);
+ db.activeRuleDao().insert(session, activeRule);
+ return activeRule;
+ }
+}
--- /dev/null
+{
+ "left" : {
+ "key" : "xoo-profile-1-01234",
+ "name" : "Profile 1"
+ },
+ "right" : {
+ "key" : "xoo-profile-2-12345",
+ "name" : "Profile 2"
+ },
+ "same" : [
+ {
+ "key" : "blah:rule1",
+ "pluginKey" : "blah",
+ "pluginName" : "Blah",
+ "languageKey": "xoo",
+ "languageName": "Xoo",
+ "name" : "Rule1",
+ "severity" : "BLOCKER"
+ }
+ ],
+ "inLeft" : [
+ {
+ "key" : "blah:rule2",
+ "pluginKey" : "blah",
+ "pluginName" : "Blah",
+ "languageKey": "xoo",
+ "languageName": "Xoo",
+ "name" : "Rule2",
+ "severity" : "BLOCKER"
+ }
+ ],
+ "inRight" : [
+ {
+ "key" : "blah:rule3",
+ "pluginKey" : "blah",
+ "pluginName" : "Blah",
+ "languageKey": "xoo",
+ "languageName": "Xoo",
+ "name" : "Rule3",
+ "severity" : "BLOCKER"
+ }
+ ],
+ "modified" : [
+ {
+ "key" : "blah:rule4",
+ "pluginKey" : "blah",
+ "pluginName" : "Blah",
+ "languageKey": "xoo",
+ "languageName": "Xoo",
+ "name" : "Rule4",
+ "left" : {
+ "severity" : "BLOCKER",
+ "params" : {
+ "param_rule4" : "polop"
+ }
+ },
+ "right" : {
+ "severity" : "BLOCKER",
+ "params" : {
+ "param_rule4" : "palap"
+ }
+ }
+ },
+ {
+ "key" : "blah:rule5",
+ "pluginKey" : "blah",
+ "pluginName" : "Blah",
+ "languageKey": "xoo",
+ "languageName": "Xoo",
+ "name" : "Rule5",
+ "left" : {
+ "severity" : "MINOR"
+ },
+ "right" : {
+ "severity" : "MAJOR"
+ }
+ }
+ ]
+}