import org.apache.commons.lang.StringUtils;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.resources.Languages;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
+import org.sonar.api.rules.CleanCodeAttribute;
+import org.sonar.api.rules.RuleType;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.server.ws.WebService;
import org.sonar.core.util.Uuids;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
+import org.sonar.db.issue.ImpactDto;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
import org.sonar.db.qualityprofile.QProfileDto;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.sonar.api.issue.impact.Severity.HIGH;
public class CompareActionIT {
@Rule
public UserSessionRule userSession = UserSessionRule.standalone();
- private DbClient dbClient = db.getDbClient();
- private DbSession session = db.getSession();
+ private final DbClient dbClient = db.getDbClient();
+ private final DbSession session = db.getSession();
- private WsActionTester ws = new WsActionTester(
+ private final WsActionTester ws = new WsActionTester(
new CompareAction(db.getDbClient(), new QProfileComparison(db.getDbClient()), new Languages(LanguageTesting.newLanguage("xoo", "Xoo"))));
@Test
.execute().assertJson(this.getClass(), "compare_nominal.json");
}
+ @Test
+ public void compare_whenSecurityHotspot_shouldReturnEmptyCleanCodeInformation() {
+ createRepository("blah", "xoo", "Blah");
+
+ RuleDto rule1 = createSecurityHotspot("xoo", "rule1");
+ RuleDto rule2 = createSecurityHotspot("xoo", "rule2");
+
+ QProfileDto profile1 = createProfile("xoo", "Profile 1", "xoo-profile-1-01234");
+ createActiveRule(rule1, profile1);
+
+ QProfileDto profile2 = createProfile("xoo", "Profile 2", "xoo-profile-2-12345");
+ createActiveRule(rule2, profile2);
+ session.commit();
+
+ ws.newRequest()
+ .setParam("leftKey", profile1.getKee())
+ .setParam("rightKey", profile2.getKee())
+ .execute().assertJson(this.getClass(), "compare_hotspot.json");
+ }
+
@Test
public void compare_param_on_left() {
RuleDto rule1 = createRuleWithParam("xoo", "rule1");
.setLanguage(lang)
.setSeverity(Severity.BLOCKER)
.setScope(Scope.MAIN)
- .setStatus(RuleStatus.READY);
+ .setStatus(RuleStatus.READY)
+ .setCleanCodeAttribute(CleanCodeAttribute.EFFICIENT)
+ .addDefaultImpact(new ImpactDto(Uuids.createFast(), SoftwareQuality.RELIABILITY, HIGH));
RuleDto ruleDto = rule;
dbClient.ruleDao().insert(session, ruleDto);
return ruleDto;
}
+ private RuleDto createSecurityHotspot(String lang, String id) {
+ RuleDto rule = createFor(RuleKey.of("blah", id))
+ .setUuid(Uuids.createFast())
+ .setName(StringUtils.capitalize(id))
+ .setLanguage(lang)
+ .setSeverity(Severity.BLOCKER)
+ .setScope(Scope.MAIN)
+ .setStatus(RuleStatus.READY)
+ .setType(RuleType.SECURITY_HOTSPOT);
+ dbClient.ruleDao().insert(session, rule);
+ return rule;
+ }
+
private static RuleDto createFor(RuleKey key) {
return new RuleDto()
.setRepositoryKey(key.repository())
--- /dev/null
+{
+ "left": {
+ "key": "xoo-profile-1-01234",
+ "name": "Profile 1"
+ },
+ "right": {
+ "key": "xoo-profile-2-12345",
+ "name": "Profile 2"
+ },
+ "inLeft": [
+ {
+ "key": "blah:rule1",
+ "name": "Rule1",
+ "pluginKey": "blah",
+ "pluginName": "Blah",
+ "languageKey": "xoo",
+ "languageName": "Xoo",
+ "impacts": []
+ }
+ ],
+ "inRight": [
+ {
+ "key": "blah:rule2",
+ "name": "Rule2",
+ "pluginKey": "blah",
+ "pluginName": "Blah",
+ "languageKey": "xoo",
+ "languageName": "Xoo",
+ "impacts": []
+ }
+ ],
+ "modified": [],
+ "same": []
+}
"languageKey": "xoo",
"languageName": "Xoo",
"name" : "Rule1",
- "severity" : "BLOCKER"
+ "cleanCodeAttributeCategory": "INTENTIONAL",
+ "impacts": [
+ {
+ "softwareQuality": "RELIABILITY",
+ "severity": "HIGH"
+ }
+ ]
}
],
"inLeft" : [
"languageKey": "xoo",
"languageName": "Xoo",
"name" : "Rule2",
- "severity" : "BLOCKER"
+ "cleanCodeAttributeCategory": "INTENTIONAL",
+ "impacts": [
+ {
+ "softwareQuality": "RELIABILITY",
+ "severity": "HIGH"
+ }
+ ]
}
],
"inRight" : [
"languageKey": "xoo",
"languageName": "Xoo",
"name" : "Rule3",
- "severity" : "BLOCKER"
+ "cleanCodeAttributeCategory": "INTENTIONAL",
+ "impacts": [
+ {
+ "softwareQuality": "RELIABILITY",
+ "severity": "HIGH"
+ }
+ ]
}
],
"modified" : [
"languageKey": "xoo",
"languageName": "Xoo",
"name" : "Rule4",
+ "cleanCodeAttributeCategory": "INTENTIONAL",
+ "impacts": [
+ {
+ "softwareQuality": "RELIABILITY",
+ "severity": "HIGH"
+ }
+ ],
"left" : {
"severity" : "BLOCKER",
"params" : {
"languageKey": "xoo",
"languageName": "Xoo",
"name" : "Rule5",
+ "cleanCodeAttributeCategory": "INTENTIONAL",
+ "impacts": [
+ {
+ "softwareQuality": "RELIABILITY",
+ "severity": "HIGH"
+ }
+ ],
"left" : {
"severity" : "MINOR"
},
import org.sonar.api.resources.Language;
import org.sonar.api.resources.Languages;
import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.CleanCodeAttribute;
+import org.sonar.api.server.ws.Change;
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.utils.text.JsonWriter;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
+import org.sonar.db.issue.ImpactDto;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.QProfileDto;
import org.sonar.db.rule.RuleDto;
private static final String ATTRIBUTE_LANGUAGE_KEY = "languageKey";
private static final String ATTRIBUTE_LANGUAGE_NAME = "languageName";
private static final String ATTRIBUTE_PARAMS = "params";
+ private static final String ATTRIBUTE_CLEAN_CODE_ATTRIBUTE_CATEGORY = "cleanCodeAttributeCategory";
+ private static final String ATTRIBUTE_IMPACTS = "impacts";
+ private static final String ATTRIBUTE_IMPACT_SOFTWARE_QUALITY = "softwareQuality";
+ private static final String ATTRIBUTE_IMPACT_SEVERITY = "severity";
private static final String PARAM_LEFT_KEY = "leftKey";
private static final String PARAM_RIGHT_KEY = "rightKey";
.setHandler(this)
.setInternal(true)
.setResponseExample(getClass().getResource("compare-example.json"))
- .setSince("5.2");
+ .setSince("5.2")
+ .setChangelog(
+ new Change("10.3", String.format("Added '%s' and '%s' fields", ATTRIBUTE_CLEAN_CODE_ATTRIBUTE_CATEGORY, ATTRIBUTE_IMPACTS)),
+ new Change("10.3", String.format("Dropped '%s' field from '%s', '%s' and '%s' objects",
+ ATTRIBUTE_SEVERITY, ATTRIBUTE_SAME, ATTRIBUTE_IN_LEFT, ATTRIBUTE_IN_RIGHT)));
compare.createParam(PARAM_LEFT_KEY)
.setDescription("Profile key.")
private void writeRules(JsonWriter json, Map<RuleKey, ActiveRuleDto> activeRules, Map<RuleKey, RuleDto> rulesByKey,
Map<String, RuleRepositoryDto> repositoriesByKey) {
json.beginArray();
- for (Entry<RuleKey, ActiveRuleDto> activeRule : activeRules.entrySet()) {
- RuleKey key = activeRule.getKey();
- ActiveRuleDto value = activeRule.getValue();
-
+ for (RuleKey key : activeRules.keySet()) {
json.beginObject();
RuleDto rule = rulesByKey.get(key);
writeRule(json, rule, repositoriesByKey.get(rule.getRepositoryKey()));
- json.prop(ATTRIBUTE_SEVERITY, value.getSeverityString());
json.endObject();
}
json.endArray();
json.prop(ATTRIBUTE_LANGUAGE_KEY, languageKey);
json.prop(ATTRIBUTE_LANGUAGE_NAME, language == null ? null : language.getName());
}
+
+ CleanCodeAttribute cleanCodeAttribute = rule.getCleanCodeAttribute();
+ if (cleanCodeAttribute != null) {
+ json.prop(ATTRIBUTE_CLEAN_CODE_ATTRIBUTE_CATEGORY, cleanCodeAttribute.getAttributeCategory().toString());
+ }
+ json.name(ATTRIBUTE_IMPACTS);
+ json.beginArray();
+ for (ImpactDto impact : rule.getDefaultImpacts()) {
+ json.beginObject();
+ json.prop(ATTRIBUTE_IMPACT_SOFTWARE_QUALITY, impact.getSoftwareQuality().toString());
+ json.prop(ATTRIBUTE_IMPACT_SEVERITY, impact.getSeverity().toString());
+ json.endObject();
+ }
+ json.endArray();
}
private void writeDifferences(JsonWriter json, Map<RuleKey, ActiveRuleDiff> modified, Map<RuleKey, RuleDto> rulesByKey,
"languageKey": "js",
"languageName": "JavaScript",
"name" : "\"===\" and \"!==\" should be used instead of \"==\" and \"!=\"",
- "severity" : "MAJOR"
+ "cleanCodeAttributeCategory": "INTENTIONAL",
+ "impacts": [
+ {
+ "softwareQuality": "RELIABILITY",
+ "severity": "MEDIUM"
+ }
+ ]
}
],
"inLeft" : [
"languageKey": "js",
"languageName": "JavaScript",
"name" : "Avoid trailing whitespaces",
- "severity" : "MAJOR"
+ "cleanCodeAttributeCategory": "CONSISTENT",
+ "impacts": [
+ {
+ "softwareQuality": "MAINTAINABILITY",
+ "severity": "LOW"
+ }
+ ]
}
],
"inRight" : [
"languageKey": "js",
"languageName": "JavaScript",
"name" : "Avoid use of tabulation character",
- "severity" : "MINOR"
+ "cleanCodeAttributeCategory": "CONSISTENT",
+ "impacts": [
+ {
+ "softwareQuality": "MAINTAINABILITY",
+ "severity": "LOW"
+ }
+ ]
}
],
"modified" : [
"languageKey": "js",
"languageName": "JavaScript",
"name" : "Avoid function with too many parameters",
+ "cleanCodeAttributeCategory": "ADAPTABLE",
+ "impacts": [
+ {
+ "softwareQuality": "MAINTAINABILITY",
+ "severity": "HIGH"
+ }
+ ],
"right" : {
"severity" : "MAJOR",
"params" : {