]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-20547 Add CCT attributes in api/qualityprofiles/compare
authorEric Giffon <eric.giffon@sonarsource.com>
Thu, 28 Sep 2023 12:59:34 +0000 (14:59 +0200)
committersonartech <sonartech@sonarsource.com>
Tue, 10 Oct 2023 20:02:44 +0000 (20:02 +0000)
server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/CompareActionIT.java
server/sonar-webserver-webapi/src/it/resources/org/sonar/server/qualityprofile/ws/CompareActionIT/compare_hotspot.json [new file with mode: 0644]
server/sonar-webserver-webapi/src/it/resources/org/sonar/server/qualityprofile/ws/CompareActionIT/compare_nominal.json
server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/CompareAction.java
server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualityprofile/ws/compare-example.json

index 0e5274a4673e9da8a2430d79f2f613e970120ba3..c038389293b0c93b7b9f5b491a00d1f5202b71ac 100644 (file)
@@ -22,16 +22,20 @@ package org.sonar.server.qualityprofile.ws;
 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;
@@ -47,6 +51,7 @@ import org.sonar.server.ws.WsActionTester;
 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 {
 
@@ -57,10 +62,10 @@ 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
@@ -106,6 +111,26 @@ public class CompareActionIT {
       .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");
@@ -206,12 +231,27 @@ public class CompareActionIT {
       .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())
diff --git a/server/sonar-webserver-webapi/src/it/resources/org/sonar/server/qualityprofile/ws/CompareActionIT/compare_hotspot.json b/server/sonar-webserver-webapi/src/it/resources/org/sonar/server/qualityprofile/ws/CompareActionIT/compare_hotspot.json
new file mode 100644 (file)
index 0000000..2135cb0
--- /dev/null
@@ -0,0 +1,34 @@
+{
+  "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": []
+}
index 1d0ef292292fcd4290046c1fb63d278810cf90e8..d2885aac7631f9cd2840e4516ac3fb5a9c55afbd 100644 (file)
          "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"
          },
index 1cc445fa9b3d6243b81f86ddf26ffc2e4931da08..f74db463ebb0fa8f9227d81a7be05e23f0e8ceb1 100644 (file)
@@ -29,6 +29,8 @@ import javax.annotation.Nullable;
 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;
@@ -36,6 +38,7 @@ import org.sonar.api.server.ws.WebService.NewController;
 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;
@@ -64,6 +67,10 @@ public class CompareAction implements QProfileWsAction {
   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";
@@ -85,7 +92,11 @@ public class CompareAction implements QProfileWsAction {
       .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.")
@@ -152,14 +163,10 @@ public class CompareAction implements QProfileWsAction {
   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();
@@ -179,6 +186,20 @@ public class CompareAction implements QProfileWsAction {
       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,
index 82f84ee04467fa8ff3ae6e3a39f4b03dc15dd93d..18dcb2d7e648ea01c2c66ac8a5f4b138ab8a4ca5 100644 (file)
          "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" : {