From 0551227705b77579f5bb483820c27e9355519b42 Mon Sep 17 00:00:00 2001 From: jycr Date: Fri, 14 Apr 2023 18:25:32 +0200 Subject: [PATCH] green-code-initiative/ecoCode#92 refactor(rule/python): moves Python rules into `ecocode-rules-specifications` module --- ecocode-rules-specifications/pom.xml | 19 +++ .../src/main/assembly/python.xml | 22 ++++ .../rules/python/PythonRulesRepository.java | 8 ++ .../src/main/rules/EC34/python/EC34.asciidoc | 0 .../src/main/rules/EC4/python/EC4.asciidoc | 0 .../src/main/rules/EC69/python/EC69.asciidoc | 0 .../src/main/rules/EC7/EC7.json | 15 +++ .../src/main/rules/EC7/python/EC7.asciidoc | 0 .../src/main/rules/EC72/python/EC72.asciidoc | 0 .../src/main/rules/EC74/python/EC74.asciidoc | 0 python-plugin/pom.xml | 74 ++++++------ .../python/PythonRuleRepository.java | 113 +++++++----------- .../python/PythonRuleRepositoryTest.java | 5 +- 13 files changed, 152 insertions(+), 104 deletions(-) create mode 100644 ecocode-rules-specifications/src/main/assembly/python.xml create mode 100644 ecocode-rules-specifications/src/main/java/io/ecocode/rules/python/PythonRulesRepository.java rename python-plugin/src/main/resources/fr/greencodeinitiative/l10n/python/rules/python/EC34.html => ecocode-rules-specifications/src/main/rules/EC34/python/EC34.asciidoc (100%) rename python-plugin/src/main/resources/fr/greencodeinitiative/l10n/python/rules/python/EC4.html => ecocode-rules-specifications/src/main/rules/EC4/python/EC4.asciidoc (100%) rename python-plugin/src/main/resources/fr/greencodeinitiative/l10n/python/rules/python/EC69.html => ecocode-rules-specifications/src/main/rules/EC69/python/EC69.asciidoc (100%) create mode 100644 ecocode-rules-specifications/src/main/rules/EC7/EC7.json rename python-plugin/src/main/resources/fr/greencodeinitiative/l10n/python/rules/python/EC7.html => ecocode-rules-specifications/src/main/rules/EC7/python/EC7.asciidoc (100%) rename python-plugin/src/main/resources/fr/greencodeinitiative/l10n/python/rules/python/EC72.html => ecocode-rules-specifications/src/main/rules/EC72/python/EC72.asciidoc (100%) rename python-plugin/src/main/resources/fr/greencodeinitiative/l10n/python/rules/python/EC74.html => ecocode-rules-specifications/src/main/rules/EC74/python/EC74.asciidoc (100%) diff --git a/ecocode-rules-specifications/pom.xml b/ecocode-rules-specifications/pom.xml index 3d3d93d25..1144d4f31 100644 --- a/ecocode-rules-specifications/pom.xml +++ b/ecocode-rules-specifications/pom.xml @@ -81,6 +81,13 @@ + + + + + + + @@ -118,6 +125,18 @@ + + assembly-python + prepare-package + + single + + + + ${project.basedir}/src/main/assembly/python.xml + + + true diff --git a/ecocode-rules-specifications/src/main/assembly/python.xml b/ecocode-rules-specifications/src/main/assembly/python.xml new file mode 100644 index 000000000..f3b7be8d3 --- /dev/null +++ b/ecocode-rules-specifications/src/main/assembly/python.xml @@ -0,0 +1,22 @@ + + python + + jar + + false + + + ${project.build.outputDirectory} + + io/ecocode/rules/python/*.class + + + + + ${project.build.directory}/python + io/ecocode/rules/python/specifications + + + diff --git a/ecocode-rules-specifications/src/main/java/io/ecocode/rules/python/PythonRulesRepository.java b/ecocode-rules-specifications/src/main/java/io/ecocode/rules/python/PythonRulesRepository.java new file mode 100644 index 000000000..5df4541ae --- /dev/null +++ b/ecocode-rules-specifications/src/main/java/io/ecocode/rules/python/PythonRulesRepository.java @@ -0,0 +1,8 @@ +package io.ecocode.rules.python; + +public class PythonRulesRepository { + public static final String REPOSITORY_KEY = "ecocode-python"; + public static final String NAME = "ecoCode"; + public static final String LANGUAGE = "py"; + public static final String RESOURCE_BASE_PATH = PythonRulesRepository.class.getPackageName().replace('.', '/') + "/specifications"; +} diff --git a/python-plugin/src/main/resources/fr/greencodeinitiative/l10n/python/rules/python/EC34.html b/ecocode-rules-specifications/src/main/rules/EC34/python/EC34.asciidoc similarity index 100% rename from python-plugin/src/main/resources/fr/greencodeinitiative/l10n/python/rules/python/EC34.html rename to ecocode-rules-specifications/src/main/rules/EC34/python/EC34.asciidoc diff --git a/python-plugin/src/main/resources/fr/greencodeinitiative/l10n/python/rules/python/EC4.html b/ecocode-rules-specifications/src/main/rules/EC4/python/EC4.asciidoc similarity index 100% rename from python-plugin/src/main/resources/fr/greencodeinitiative/l10n/python/rules/python/EC4.html rename to ecocode-rules-specifications/src/main/rules/EC4/python/EC4.asciidoc diff --git a/python-plugin/src/main/resources/fr/greencodeinitiative/l10n/python/rules/python/EC69.html b/ecocode-rules-specifications/src/main/rules/EC69/python/EC69.asciidoc similarity index 100% rename from python-plugin/src/main/resources/fr/greencodeinitiative/l10n/python/rules/python/EC69.html rename to ecocode-rules-specifications/src/main/rules/EC69/python/EC69.asciidoc diff --git a/ecocode-rules-specifications/src/main/rules/EC7/EC7.json b/ecocode-rules-specifications/src/main/rules/EC7/EC7.json new file mode 100644 index 000000000..46c194d56 --- /dev/null +++ b/ecocode-rules-specifications/src/main/rules/EC7/EC7.json @@ -0,0 +1,15 @@ +{ + "title": "Avoid creating getter and setter methods in classes", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "eco-design", + "performance", + "ecocode" + ], + "defaultSeverity": "Minor" +} diff --git a/python-plugin/src/main/resources/fr/greencodeinitiative/l10n/python/rules/python/EC7.html b/ecocode-rules-specifications/src/main/rules/EC7/python/EC7.asciidoc similarity index 100% rename from python-plugin/src/main/resources/fr/greencodeinitiative/l10n/python/rules/python/EC7.html rename to ecocode-rules-specifications/src/main/rules/EC7/python/EC7.asciidoc diff --git a/python-plugin/src/main/resources/fr/greencodeinitiative/l10n/python/rules/python/EC72.html b/ecocode-rules-specifications/src/main/rules/EC72/python/EC72.asciidoc similarity index 100% rename from python-plugin/src/main/resources/fr/greencodeinitiative/l10n/python/rules/python/EC72.html rename to ecocode-rules-specifications/src/main/rules/EC72/python/EC72.asciidoc diff --git a/python-plugin/src/main/resources/fr/greencodeinitiative/l10n/python/rules/python/EC74.html b/ecocode-rules-specifications/src/main/rules/EC74/python/EC74.asciidoc similarity index 100% rename from python-plugin/src/main/resources/fr/greencodeinitiative/l10n/python/rules/python/EC74.html rename to ecocode-rules-specifications/src/main/rules/EC74/python/EC74.asciidoc diff --git a/python-plugin/pom.xml b/python-plugin/pom.xml index bfef526ff..8ad6e2d58 100644 --- a/python-plugin/pom.xml +++ b/python-plugin/pom.xml @@ -16,20 +16,36 @@ https://github.com/green-code-initiative/ecoCode/tree/main/python-plugin + + ${project.groupId} + ecocode-rules-specifications + ${project.version} + python + org.sonarsource.python sonar-python-plugin sonar-plugin + provided org.sonarsource.sonarqube sonar-plugin-api + provided + + + + org.sonarsource.analyzer-commons + sonar-analyzer-commons + provided + org.sonarsource.sonarqube sonar-plugin-api-impl + test @@ -65,44 +81,32 @@ true python:${sonar.python.version} ${sonarqube.version} + python ${java.version} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + org.apache.maven.plugins + maven-shade-plugin + + + package + + shade + + + + + *:ecocode-rules-specifications + + META-INF/** + + + + + + + org.apache.maven.plugins maven-dependency-plugin diff --git a/python-plugin/src/main/java/fr/greencodeinitiative/python/PythonRuleRepository.java b/python-plugin/src/main/java/fr/greencodeinitiative/python/PythonRuleRepository.java index 2a6f0225c..1623e345f 100644 --- a/python-plugin/src/main/java/fr/greencodeinitiative/python/PythonRuleRepository.java +++ b/python-plugin/src/main/java/fr/greencodeinitiative/python/PythonRuleRepository.java @@ -19,63 +19,66 @@ */ package fr.greencodeinitiative.python; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import fr.greencodeinitiative.python.checks.AvoidFullSQLRequest; import fr.greencodeinitiative.python.checks.AvoidGettersAndSetters; import fr.greencodeinitiative.python.checks.AvoidGlobalVariableInFunctionCheck; import fr.greencodeinitiative.python.checks.AvoidSQLRequestInLoop; import fr.greencodeinitiative.python.checks.AvoidTryCatchFinallyCheck; import fr.greencodeinitiative.python.checks.NoFunctionCallWhenDeclaringForLoop; -import org.apache.commons.lang.StringUtils; +import org.sonar.api.SonarEdition; +import org.sonar.api.SonarProduct; +import org.sonar.api.SonarQubeSide; +import org.sonar.api.SonarRuntime; import org.sonar.api.server.rule.RulesDefinition; -import org.sonar.api.server.rule.RulesDefinitionAnnotationLoader; +import org.sonar.api.utils.Version; import org.sonar.plugins.python.api.PythonCustomRuleRepository; +import org.sonarsource.analyzer.commons.RuleMetadataLoader; -public class PythonRuleRepository implements RulesDefinition, PythonCustomRuleRepository { +import java.util.ArrayList; +import java.util.List; - public static final String LANGUAGE = "py"; - public static final String NAME = "ecoCode"; - public static final String RESOURCE_BASE_PATH = "/fr/greencodeinitiative/l10n/python/rules/python/"; - public static final String REPOSITORY_KEY = "ecocode-python"; +import static io.ecocode.rules.python.PythonRulesRepository.LANGUAGE; +import static io.ecocode.rules.python.PythonRulesRepository.NAME; +import static io.ecocode.rules.python.PythonRulesRepository.REPOSITORY_KEY; +import static io.ecocode.rules.python.PythonRulesRepository.RESOURCE_BASE_PATH; - @Override - public void define(Context context) { - NewRepository repository = context.createRepository(repositoryKey(), LANGUAGE).setName(NAME); - - new RulesDefinitionAnnotationLoader().load(repository, checkClasses().toArray(new Class[] {})); +public class PythonRuleRepository implements RulesDefinition, PythonCustomRuleRepository { + private static final List> ANNOTATED_RULE_CLASSES = List.of( + AvoidGettersAndSetters.class, + AvoidGlobalVariableInFunctionCheck.class, + AvoidSQLRequestInLoop.class, + AvoidTryCatchFinallyCheck.class, + NoFunctionCallWhenDeclaringForLoop.class, + AvoidFullSQLRequest.class + ); + private static final Version SONARQUBE_RUNTIME_VERSION = Version.create(9, 8); + private static final SonarRuntime SONARQUBE_RUNTIME = new SonarRuntime() { + @Override + public Version getApiVersion() { + return SONARQUBE_RUNTIME_VERSION; + } - // technical debt - Map remediationCosts = new HashMap<>(); - remediationCosts.put(AvoidSQLRequestInLoop.RULE_KEY, "10min"); - remediationCosts.put(AvoidFullSQLRequest.RULE_KEY, "20min"); - repository.rules().forEach(rule -> { - String debt = remediationCosts.get(rule.key()); + @Override + public SonarProduct getProduct() { + return SonarProduct.SONARQUBE; + } - // TODO DDC : create support to use org.apache.commons.lang.StringUtils -// if (StringUtils.isBlank(debt)) { - if (debt == null || debt.trim().equals("")) { - // default debt to 5min for issue correction - rule.setDebtRemediationFunction( - rule.debtRemediationFunctions().constantPerIssue("5min")); - } else { - rule.setDebtRemediationFunction( - rule.debtRemediationFunctions().constantPerIssue(debt)); - } - }); + @Override + public SonarQubeSide getSonarQubeSide() { + return SonarQubeSide.SCANNER; + } - // HTML description - repository.rules().forEach(rule -> - rule.setHtmlDescription(loadResource(RESOURCE_BASE_PATH + rule.key() + ".html"))); + @Override + public SonarEdition getEdition() { + return SonarEdition.COMMUNITY; + } + }; + @Override + public void define(Context context) { + NewRepository repository = context.createRepository(REPOSITORY_KEY, LANGUAGE).setName(NAME); + RuleMetadataLoader ruleMetadataLoader = new RuleMetadataLoader(RESOURCE_BASE_PATH, SONARQUBE_RUNTIME); + ruleMetadataLoader.addRulesByAnnotatedClass(repository, ANNOTATED_RULE_CLASSES); repository.done(); } @@ -86,30 +89,6 @@ public String repositoryKey() { @Override public List checkClasses() { - return Arrays.asList( - AvoidGettersAndSetters.class, - AvoidGlobalVariableInFunctionCheck.class, - AvoidSQLRequestInLoop.class, - AvoidTryCatchFinallyCheck.class, - NoFunctionCallWhenDeclaringForLoop.class, - AvoidFullSQLRequest.class - ); - } - - private String loadResource(String path) { - URL resource = getClass().getResource(path); - if (resource == null) { - throw new IllegalStateException("Resource not found: " + path); - } - ByteArrayOutputStream result = new ByteArrayOutputStream(); - try (InputStream in = resource.openStream()) { - byte[] buffer = new byte[1024]; - for (int len = in.read(buffer); len != -1; len = in.read(buffer)) { - result.write(buffer, 0, len); - } - return new String(result.toByteArray(), StandardCharsets.UTF_8); - } catch (IOException e) { - throw new IllegalStateException("Failed to read resource: " + path, e); - } + return new ArrayList<>(ANNOTATED_RULE_CLASSES); } } diff --git a/python-plugin/src/test/java/fr/greencodeinitiative/python/PythonRuleRepositoryTest.java b/python-plugin/src/test/java/fr/greencodeinitiative/python/PythonRuleRepositoryTest.java index 101ff2841..7ef22526f 100644 --- a/python-plugin/src/test/java/fr/greencodeinitiative/python/PythonRuleRepositoryTest.java +++ b/python-plugin/src/test/java/fr/greencodeinitiative/python/PythonRuleRepositoryTest.java @@ -21,6 +21,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import io.ecocode.rules.python.PythonRulesRepository; import org.assertj.core.api.SoftAssertions; import org.junit.Before; import org.junit.Test; @@ -37,12 +38,12 @@ public void init() { pythonRuleRepository = new PythonRuleRepository(); context = new RulesDefinition.Context(); pythonRuleRepository.define(context); - repository = context.repository(PythonRuleRepository.REPOSITORY_KEY); + repository = context.repository(PythonRulesRepository.REPOSITORY_KEY); } @Test public void test() { - assertThat(pythonRuleRepository.repositoryKey()).isEqualTo(PythonRuleRepository.REPOSITORY_KEY); + assertThat(pythonRuleRepository.repositoryKey()).isEqualTo(PythonRulesRepository.REPOSITORY_KEY); assertThat(context.repositories()).hasSize(1).extracting("key").containsExactly(pythonRuleRepository.repositoryKey()); assertThat(context.repositories().get(0).rules()).hasSize(6); assertThat(pythonRuleRepository.checkClasses()).hasSize(6);