aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-scanner-engine/src/main
diff options
context:
space:
mode:
authorPierre Guillot <pierre.guillot@sonarsource.com>2024-12-10 15:29:09 +0100
committerSteve Marion <steve.marion@sonarsource.com>2024-12-18 11:13:21 +0100
commitd639a965bce7acafb004906cd07a8f0b5f7af993 (patch)
tree647cd646abddb12dfeeef7e637aa33b4658f1049 /sonar-scanner-engine/src/main
parent451c1c2e4856ec3df87f86189fcdb25b31794027 (diff)
downloadsonarqube-d639a965bce7acafb004906cd07a8f0b5f7af993.tar.gz
sonarqube-d639a965bce7acafb004906cd07a8f0b5f7af993.zip
SONAR-22998 fetch active rules with a dedicated endpoint
Co-authored-by: Julien HENRY <julien.henry@sonarsource.com>
Diffstat (limited to 'sonar-scanner-engine/src/main')
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/DefaultLanguagesLoader.java4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesLoader.java2
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesProvider.java51
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/DefaultActiveRulesLoader.java173
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/LoadedActiveRule.java12
5 files changed, 97 insertions, 145 deletions
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/DefaultLanguagesLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/DefaultLanguagesLoader.java
index 58aeb9695f8..4a34d21d016 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/DefaultLanguagesLoader.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/DefaultLanguagesLoader.java
@@ -39,8 +39,7 @@ public class DefaultLanguagesLoader implements LanguagesLoader {
"js", "javascript",
"ts", "typescript",
"py", "python",
- "web", "html"
- );
+ "web", "html");
private final DefaultScannerWsClient wsClient;
@@ -76,7 +75,6 @@ public class DefaultLanguagesLoader implements LanguagesLoader {
return new Language(lang);
}
-
private String[] getFileSuffixes(String languageKey) {
return getPropertyForLanguage("sonar.%s.file.suffixes", languageKey);
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesLoader.java
index 1bd49f3ec27..06358376c69 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesLoader.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesLoader.java
@@ -22,5 +22,5 @@ package org.sonar.scanner.rule;
import java.util.List;
public interface ActiveRulesLoader {
- List<LoadedActiveRule> load(String qualityProfileKey);
+ List<LoadedActiveRule> load(String projectKey);
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesProvider.java
index eb703522dc3..a6d7f7666aa 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesProvider.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesProvider.java
@@ -19,21 +19,16 @@
*/
package org.sonar.scanner.rule;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
import java.util.Map;
-import java.util.Set;
import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
import org.sonar.api.batch.rule.internal.DefaultActiveRules;
import org.sonar.api.batch.rule.internal.NewActiveRule;
import org.sonar.api.issue.impact.Severity;
import org.sonar.api.issue.impact.SoftwareQuality;
-import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
+import org.sonar.scanner.bootstrap.ScannerProperties;
import org.springframework.context.annotation.Bean;
/**
@@ -45,34 +40,22 @@ public class ActiveRulesProvider {
private static final String LOG_MSG = "Load active rules";
@Bean("ActiveRules")
- public DefaultActiveRules provide(ActiveRulesLoader loader, QualityProfiles qProfiles) {
+ public DefaultActiveRules provide(ActiveRulesLoader loader, ScannerProperties props) {
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
- DefaultActiveRules activeRules = load(loader, qProfiles);
+ DefaultActiveRules activeRules = load(loader, props.getProjectKey());
profiler.stopInfo();
return activeRules;
}
- private static DefaultActiveRules load(ActiveRulesLoader loader, QualityProfiles qProfiles) {
-
- Collection<String> qProfileKeys = getKeys(qProfiles);
- Set<RuleKey> loadedRulesKey = new HashSet<>();
+ private static DefaultActiveRules load(ActiveRulesLoader loader, String projectKey) {
ActiveRulesBuilder builder = new ActiveRulesBuilder();
-
- for (String qProfileKey : qProfileKeys) {
- Collection<LoadedActiveRule> qProfileRules = load(loader, qProfileKey);
-
- for (LoadedActiveRule r : qProfileRules) {
- if (!loadedRulesKey.contains(r.getRuleKey())) {
- loadedRulesKey.add(r.getRuleKey());
- builder.addRule(transform(r, qProfileKey, r.getDeprecatedKeys()));
- }
- }
- }
-
+ loader.load(projectKey).stream()
+ .map(ActiveRulesProvider::transform)
+ .forEach(builder::addRule);
return builder.build();
}
- private static NewActiveRule transform(LoadedActiveRule activeRule, String qProfileKey, Set<RuleKey> deprecatedKeys) {
+ private static NewActiveRule transform(LoadedActiveRule activeRule) {
NewActiveRule.Builder builder = new NewActiveRule.Builder();
builder
.setRuleKey(activeRule.getRuleKey())
@@ -83,8 +66,8 @@ public class ActiveRulesProvider {
.setLanguage(activeRule.getLanguage())
.setInternalKey(activeRule.getInternalKey())
.setTemplateRuleKey(activeRule.getTemplateRuleKey())
- .setQProfileKey(qProfileKey)
- .setDeprecatedKeys(deprecatedKeys);
+ .setQProfileKey(activeRule.getQProfileKey())
+ .setDeprecatedKeys(activeRule.getDeprecatedKeys());
// load parameters
if (activeRule.getParams() != null) {
for (Map.Entry<String, String> params : activeRule.getParams().entrySet()) {
@@ -100,18 +83,4 @@ public class ActiveRulesProvider {
return builder.build();
}
-
- private static List<LoadedActiveRule> load(ActiveRulesLoader loader, String qProfileKey) {
- return loader.load(qProfileKey);
- }
-
- private static Collection<String> getKeys(QualityProfiles qProfiles) {
- List<String> keys = new ArrayList<>(qProfiles.findAll().size());
-
- for (QProfile qp : qProfiles.findAll()) {
- keys.add(qp.getKey());
- }
-
- return keys;
- }
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/DefaultActiveRulesLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/DefaultActiveRulesLoader.java
index 78c047d5903..dad400fb11b 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/DefaultActiveRulesLoader.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/DefaultActiveRulesLoader.java
@@ -19,34 +19,27 @@
*/
package org.sonar.scanner.rule;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.EnumMap;
-import java.util.HashMap;
-import java.util.LinkedList;
+import com.google.gson.Gson;
+import com.google.gson.annotations.SerializedName;
+import com.google.gson.reflect.TypeToken;
+import java.io.Reader;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.stream.Collectors;
-import org.apache.commons.io.IOUtils;
-import org.sonar.api.impl.utils.ScannerUtils;
+import javax.annotation.Nullable;
import org.sonar.api.issue.impact.Severity;
import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.DateUtils;
-import org.sonar.core.rule.ImpactFormatter;
import org.sonar.scanner.http.ScannerWsClient;
-import org.sonarqube.ws.Common;
-import org.sonarqube.ws.Common.Paging;
-import org.sonarqube.ws.Rules;
-import org.sonarqube.ws.Rules.Active;
-import org.sonarqube.ws.Rules.Active.Param;
-import org.sonarqube.ws.Rules.ActiveList;
-import org.sonarqube.ws.Rules.ListResponse;
-import org.sonarqube.ws.Rules.Rule;
import org.sonarqube.ws.client.GetRequest;
+import static java.util.Optional.ofNullable;
+
public class DefaultActiveRulesLoader implements ActiveRulesLoader {
- private static final String RULES_SEARCH_URL = "/api/rules/list.protobuf?";
+ private static final String RULES_ACTIVE_URL = "/api/v2/analysis/active_rules?";
private final ScannerWsClient wsClient;
@@ -55,101 +48,83 @@ public class DefaultActiveRulesLoader implements ActiveRulesLoader {
}
@Override
- public List<LoadedActiveRule> load(String qualityProfileKey) {
- List<LoadedActiveRule> ruleList = new LinkedList<>();
- int page = 1;
- int pageSize = 500;
- long loaded = 0;
-
- while (true) {
- GetRequest getRequest = new GetRequest(getUrl(qualityProfileKey, page, pageSize));
- ListResponse response = loadFromStream(wsClient.call(getRequest).contentStream());
- List<LoadedActiveRule> pageRules = readPage(response);
- ruleList.addAll(pageRules);
-
- Paging paging = response.getPaging();
- loaded += paging.getPageSize();
-
- if (paging.getTotal() <= loaded) {
- break;
- }
- page++;
+ public List<LoadedActiveRule> load(String projectKey) {
+ GetRequest getRequest = new GetRequest(getUrl(projectKey));
+ List<ActiveRuleGson> jsonResponse;
+ try (Reader reader = wsClient.call(getRequest).contentReader()) {
+ jsonResponse = new Gson().fromJson(reader, new TypeToken<ArrayList<ActiveRuleGson>>() {
+ }.getType());
+ } catch (Exception e) {
+ throw new IllegalStateException("Unable to load active rules", e);
}
-
- return ruleList;
+ return convert(jsonResponse);
}
- private static String getUrl(String qualityProfileKey, int page, int pageSize) {
- StringBuilder builder = new StringBuilder(1024);
- builder.append(RULES_SEARCH_URL);
- builder.append("qprofile=").append(ScannerUtils.encodeForUrl(qualityProfileKey));
- builder.append("&ps=").append(pageSize);
- builder.append("&p=").append(page);
- return builder.toString();
+ private static String getUrl(String projectKey) {
+ return RULES_ACTIVE_URL + "projectKey=" + projectKey;
}
- private static ListResponse loadFromStream(InputStream is) {
- try {
- return ListResponse.parseFrom(is);
- } catch (IOException e) {
- throw new IllegalStateException("Failed to load quality profiles", e);
- } finally {
- IOUtils.closeQuietly(is);
- }
+ private static List<LoadedActiveRule> convert(List<ActiveRuleGson> activeRuleGsonList) {
+ return activeRuleGsonList.stream()
+ .map(DefaultActiveRulesLoader::convertActiveRule)
+ .toList();
}
- private static List<LoadedActiveRule> readPage(ListResponse response) {
- List<LoadedActiveRule> loadedRules = new LinkedList<>();
-
- List<Rule> rulesList = response.getRulesList();
- Map<String, ActiveList> actives = response.getActives().getActivesMap();
-
- for (Rule r : rulesList) {
- ActiveList activeList = actives.get(r.getKey());
- Active active = activeList.getActiveList(0);
-
- LoadedActiveRule loadedRule = new LoadedActiveRule();
-
- loadedRule.setRuleKey(RuleKey.parse(r.getKey()));
- loadedRule.setName(r.getName());
- loadedRule.setSeverity(active.getSeverity());
-
- loadedRule.setCreatedAt(DateUtils.dateToLong(DateUtils.parseDateTime(active.getCreatedAt())));
- loadedRule.setUpdatedAt(DateUtils.dateToLong(DateUtils.parseDateTime(active.getUpdatedAt())));
- loadedRule.setLanguage(r.getLang());
- loadedRule.setInternalKey(r.getInternalKey());
- if (r.hasTemplateKey()) {
- RuleKey templateRuleKey = RuleKey.parse(r.getTemplateKey());
- loadedRule.setTemplateRuleKey(templateRuleKey.rule());
- }
-
- Map<String, String> params = new HashMap<>();
+ private static LoadedActiveRule convertActiveRule(ActiveRuleGson activeRule) {
+ LoadedActiveRule loadedRule = new LoadedActiveRule();
+ loadedRule.setRuleKey(convertRuleKey(activeRule.ruleKey()));
+ loadedRule.setName(activeRule.name());
+ loadedRule.setSeverity(activeRule.severity());
+ loadedRule.setCreatedAt(DateUtils.dateToLong(DateUtils.parseDateTime(activeRule.createdAt())));
+ loadedRule.setUpdatedAt(DateUtils.dateToLong(DateUtils.parseDateTime(activeRule.updatedAt())));
+ loadedRule.setLanguage(activeRule.language());
+ loadedRule.setInternalKey(activeRule.internalKey());
+ loadedRule.setQProfileKey(activeRule.qProfileKey());
+ ofNullable(activeRule.templateRuleKey())
+ .map(RuleKey::parse)
+ .map(RuleKey::rule)
+ .ifPresent(loadedRule::setTemplateRuleKey);
+ loadedRule.setParams(activeRule.params() != null ? convertParams(activeRule.params()) : Map.of());
+ loadedRule.setImpacts(activeRule.impacts() != null ? activeRule.impacts() : Map.of());
+ loadedRule.setDeprecatedKeys(convertDeprecatedKeys(activeRule.deprecatedKeys()));
+ return loadedRule;
+ }
- for (Rules.Rule.Param param : r.getParams().getParamsList()) {
- params.put(param.getKey(), param.getDefaultValue());
- }
+ private static Map<String, String> convertParams(List<ParamGson> params) {
+ return params.stream().collect(Collectors.toMap(ParamGson::key, ParamGson::value));
+ }
- // overrides defaultValue if the key is the same
- for (Param param : active.getParamsList()) {
- params.put(param.getKey(), param.getValue());
- }
+ private static Set<RuleKey> convertDeprecatedKeys(@Nullable List<RuleKeyGson> deprecatedKeysList) {
+ return ofNullable(deprecatedKeysList)
+ .orElse(List.of())
+ .stream()
+ .map(value -> RuleKey.of(value.repository(), value.rule()))
+ .collect(Collectors.toSet());
+ }
- loadedRule.setParams(params);
+ private static RuleKey convertRuleKey(RuleKeyGson ruleKey) {
+ return RuleKey.of(ruleKey.repository(), ruleKey.rule());
+ }
- Map<SoftwareQuality, Severity> impacts = new EnumMap<>(SoftwareQuality.class);
- for (Common.Impact impact : active.getImpacts().getImpactsList()) {
- impacts.put(SoftwareQuality.valueOf(impact.getSoftwareQuality().name()), ImpactFormatter.mapImpactSeverity(impact.getSeverity()));
- }
- loadedRule.setImpacts(impacts);
+ record ActiveRuleGson(
+ @SerializedName("ruleKey") RuleKeyGson ruleKey,
+ @SerializedName("name") String name,
+ @SerializedName("severity") String severity,
+ @SerializedName("createdAt") String createdAt,
+ @SerializedName("updatedAt") String updatedAt,
+ @SerializedName("internalKey") @Nullable String internalKey,
+ @SerializedName("language") String language,
+ @SerializedName("templateRuleKey") @Nullable String templateRuleKey,
+ @SerializedName("qProfileKey") String qProfileKey,
+ @SerializedName("deprecatedKeys") @Nullable List<RuleKeyGson> deprecatedKeys,
+ @SerializedName("params") @Nullable List<ParamGson> params,
+ @SerializedName("impacts") @Nullable Map<SoftwareQuality, Severity> impacts) {
+ }
- loadedRule.setDeprecatedKeys(r.getDeprecatedKeys().getDeprecatedKeyList()
- .stream()
- .map(RuleKey::parse)
- .collect(Collectors.toSet()));
- loadedRules.add(loadedRule);
- }
+ record RuleKeyGson(@SerializedName("repository") String repository, @SerializedName("rule") String rule) {
+ }
- return loadedRules;
+ record ParamGson(@SerializedName("key") String key, @SerializedName("value") String value) {
}
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/LoadedActiveRule.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/LoadedActiveRule.java
index 8f2c3643237..b0d1ee6d3b8 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/LoadedActiveRule.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/LoadedActiveRule.java
@@ -39,6 +39,7 @@ public class LoadedActiveRule {
private String templateRuleKey;
private String internalKey;
private Set<RuleKey> deprecatedKeys;
+ private String qProfileKey;
public LoadedActiveRule() {
// nothing to do here
@@ -117,11 +118,12 @@ public class LoadedActiveRule {
this.templateRuleKey = templateRuleKey;
}
+ @CheckForNull
public String getInternalKey() {
return internalKey;
}
- public void setInternalKey(String internalKey) {
+ public void setInternalKey(@Nullable String internalKey) {
this.internalKey = internalKey;
}
@@ -132,4 +134,12 @@ public class LoadedActiveRule {
public void setDeprecatedKeys(Set<RuleKey> deprecatedKeys) {
this.deprecatedKeys = deprecatedKeys;
}
+
+ public String getQProfileKey() {
+ return qProfileKey;
+ }
+
+ public void setQProfileKey(String qProfileKey) {
+ this.qProfileKey = qProfileKey;
+ }
}