diff --git a/its/ruling/src/test/java/org/sonar/python/it/RulingHelper.java b/its/ruling/src/test/java/org/sonar/python/it/RulingHelper.java index 67a6552108..685cf8a155 100644 --- a/its/ruling/src/test/java/org/sonar/python/it/RulingHelper.java +++ b/its/ruling/src/test/java/org/sonar/python/it/RulingHelper.java @@ -43,7 +43,10 @@ static OrchestratorExtension getOrchestrator(Edition sonarEdition) { .useDefaultAdminCredentialsForBuilds(true) .setSonarVersion(System.getProperty(SQ_VERSION_PROPERTY, DEFAULT_SQ_VERSION)) .setEdition(sonarEdition) - .addPlugin(FileLocation.byWildcardMavenFilename(new File("../../sonar-python-plugin/target"), "sonar-python-plugin-*.jar")) +// .addPlugin(FileLocation.byWildcardMavenFilename(new File("../../sonar-python-plugin/target"), "sonar-python-plugin-*.jar")) + .addPlugin(FileLocation.byWildcardMavenFilename( + new File("/Users/maksim.grebeniuk/Work/github.com/sonar-python-enterprise/sonar-python-enterprise-plugin/target"), + "sonar-python-enterprise-plugin-*.jar")) .addPlugin(MavenLocation.of("org.sonarsource.sonar-lits-plugin", "sonar-lits-plugin", "0.11.0.2659")) .setServerProperty("sonar.telemetry.enable", "false"); // Disable telemetry waiting for ORCH-497 diff --git a/python-checks/src/main/java/org/sonar/python/checks/CheckList.java b/python-checks/src/main/java/org/sonar/python/checks/CheckList.java index 5edb41e830..bef9d04a5d 100644 --- a/python-checks/src/main/java/org/sonar/python/checks/CheckList.java +++ b/python-checks/src/main/java/org/sonar/python/checks/CheckList.java @@ -19,6 +19,9 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import org.sonar.api.ce.ComputeEngineSide; +import org.sonar.api.scanner.ScannerSide; +import org.sonar.api.server.ServerSide; import org.sonar.python.checks.cdk.DisabledEFSEncryptionCheck; import org.sonar.python.checks.cdk.DisabledESDomainEncryptionCheck; import org.sonar.python.checks.cdk.DisabledRDSEncryptionCheck; @@ -105,17 +108,19 @@ import org.sonar.python.checks.tests.NotDiscoverableTestMethodCheck; import org.sonar.python.checks.tests.SkippedTestNoReasonCheck; import org.sonar.python.checks.tests.UnconditionalAssertionCheck; +import org.sonarsource.api.sonarlint.SonarLintSide; -public final class CheckList { +@ScannerSide +@ServerSide +@ComputeEngineSide +@SonarLintSide +public class CheckList { public static final String REPOSITORY_KEY = "python"; public static final String IPYTHON_REPOSITORY_KEY = "ipython"; - private CheckList() { - } - - public static Iterable> getChecks() { + public Iterable> getChecks() { return Collections.unmodifiableSet(new HashSet<>(Arrays.asList( AfterJumpStatementCheck.class, AllBranchesAreIdenticalCheck.class, diff --git a/python-checks/src/test/java/org/sonar/python/checks/CheckListTest.java b/python-checks/src/test/java/org/sonar/python/checks/CheckListTest.java index ccad6fce2e..de13888bef 100644 --- a/python-checks/src/test/java/org/sonar/python/checks/CheckListTest.java +++ b/python-checks/src/test/java/org/sonar/python/checks/CheckListTest.java @@ -61,7 +61,7 @@ void count() { count++; } } - assertThat(Iterables.size(CheckList.getChecks())).isEqualTo(count); + assertThat(Iterables.size(new CheckList().getChecks())).isEqualTo(count); } /** @@ -69,7 +69,7 @@ void count() { */ @Test void test() { - Iterable> checks = CheckList.getChecks(); + Iterable> checks = new CheckList().getChecks(); for (Class cls : checks) { String testName = '/' + cls.getName().replace('.', '/') + "Test.class"; diff --git a/sample-py-plugin/pom.xml b/sample-py-plugin/pom.xml new file mode 100644 index 0000000000..0ae246d076 --- /dev/null +++ b/sample-py-plugin/pom.xml @@ -0,0 +1,15 @@ + + + 4.0.0org.sonarsource.pythonpython4.26-SNAPSHOT + + sample-py-plugin + + + 21 + 21 + UTF-8 + + + \ No newline at end of file diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/IPynbRuleRepository.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/IPynbRuleRepository.java index 5928889475..c7076e08f8 100644 --- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/IPynbRuleRepository.java +++ b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/IPynbRuleRepository.java @@ -35,9 +35,11 @@ public class IPynbRuleRepository implements RulesDefinition { private static final Set TEMPLATE_RULE_KEYS = Collections.singleton("CommentRegularExpression"); private final SonarRuntime runtime; + private final CheckList checkList; - public IPynbRuleRepository(SonarRuntime runtime) { + public IPynbRuleRepository(SonarRuntime runtime, CheckList checkList) { this.runtime = runtime; + this.checkList = checkList; } @Override @@ -60,8 +62,8 @@ public void define(Context context) { repository.done(); } - private static List> getCheckClasses() { - return StreamSupport.stream(CheckList.getChecks().spliterator(), false) + private List> getCheckClasses() { + return StreamSupport.stream(checkList.getChecks().spliterator(), false) .map(check -> (Class) check) .collect(Collectors.toList()); } diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/IPynbSensor.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/IPynbSensor.java index a4d5c159de..c12d0d531d 100644 --- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/IPynbSensor.java +++ b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/IPynbSensor.java @@ -49,13 +49,20 @@ public final class IPynbSensor implements Sensor { private static final String FAIL_FAST_PROPERTY_NAME = "sonar.internal.analysis.failFast"; private final SensorTelemetryStorage sensorTelemetryStorage; - public IPynbSensor(FileLinesContextFactory fileLinesContextFactory, CheckFactory checkFactory, NoSonarFilter noSonarFilter) { - this(fileLinesContextFactory, checkFactory, noSonarFilter, null); + public IPynbSensor(FileLinesContextFactory fileLinesContextFactory, + CheckFactory checkFactory, + NoSonarFilter noSonarFilter, + CheckList checkList) { + this(fileLinesContextFactory, checkFactory, noSonarFilter, null, checkList); } - public IPynbSensor(FileLinesContextFactory fileLinesContextFactory, CheckFactory checkFactory, NoSonarFilter noSonarFilter, @Nullable PythonIndexer indexer) { + public IPynbSensor(FileLinesContextFactory fileLinesContextFactory, + CheckFactory checkFactory, + NoSonarFilter noSonarFilter, + @Nullable PythonIndexer indexer, + CheckList checkList) { this.checks = new PythonChecks(checkFactory) - .addChecks(CheckList.IPYTHON_REPOSITORY_KEY, CheckList.getChecks()); + .addChecks(CheckList.IPYTHON_REPOSITORY_KEY, checkList.getChecks()); this.fileLinesContextFactory = fileLinesContextFactory; this.noSonarFilter = noSonarFilter; this.indexer = indexer; diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonPlugin.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonPlugin.java index a3f7ada6dd..66b9af68bb 100644 --- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonPlugin.java +++ b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonPlugin.java @@ -39,6 +39,7 @@ import org.sonar.plugins.python.ruff.RuffSensor; import org.sonar.plugins.python.warnings.AnalysisWarningsWrapper; import org.sonar.plugins.python.xunit.PythonXUnitSensor; +import org.sonar.python.checks.CheckList; import static org.sonar.plugins.python.api.PythonVersionUtils.PYTHON_VERSION_KEY; @@ -58,7 +59,7 @@ public class PythonPlugin implements Plugin { @Override public void define(Context context) { - + registerCheckList(context); context.addExtensions( PropertyDefinition.builder(PYTHON_FILE_SUFFIXES_KEY) .index(10) @@ -83,15 +84,14 @@ public void define(Context context) { .build(), PropertyDefinition.builder(PYTHON_VERSION_KEY) - .index(12) - .name("Python versions") - .description("Comma-separated list of Python versions this project is compatible with.") - .multiValues(true) - .category(PYTHON_CATEGORY) - .subCategory(GENERAL) - .onQualifiers(Qualifiers.PROJECT) - .build(), - + .index(12) + .name("Python versions") + .description("Comma-separated list of Python versions this project is compatible with.") + .multiValues(true) + .category(PYTHON_CATEGORY) + .subCategory(GENERAL) + .onQualifiers(Qualifiers.PROJECT) + .build(), Python.class, PythonProfile.class, @@ -122,6 +122,11 @@ public void define(Context context) { } } + protected void registerCheckList(Context context) { + LOG.info("Registering check list"); + context.addExtension(CheckList.class); + } + private static void addCoberturaExtensions(Context context) { context.addExtensions( PropertyDefinition.builder(PythonCoverageSensor.REPORT_PATHS_KEY) @@ -238,6 +243,10 @@ private static void addRuffExtensions(Context context) { RuffRulesDefinition.class); } + protected void registerRuleRepositories(Context context) { + + } + static class SonarLintPluginAPIManager { public void addSonarlintPythonIndexer(Context context, SonarLintPluginAPIVersion sonarLintPluginAPIVersion) { diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonRuleRepository.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonRuleRepository.java index 9a213c11e7..da3a2c1aa4 100644 --- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonRuleRepository.java +++ b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonRuleRepository.java @@ -35,9 +35,11 @@ public class PythonRuleRepository implements RulesDefinition { private static final Set TEMPLATE_RULE_KEYS = Collections.singleton("CommentRegularExpression"); private final SonarRuntime runtime; + private final CheckList checkList; - public PythonRuleRepository(SonarRuntime runtime) { + public PythonRuleRepository(SonarRuntime runtime, CheckList checkList) { this.runtime = runtime; + this.checkList = checkList; } @Override @@ -56,8 +58,8 @@ public void define(Context context) { repository.done(); } - private static List> getCheckClasses() { - return StreamSupport.stream(CheckList.getChecks().spliterator(), false) + private List> getCheckClasses() { + return StreamSupport.stream(checkList.getChecks().spliterator(), false) .map(check -> (Class) check) .collect(Collectors.toList()); } diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonSensor.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonSensor.java index 2ff0ae4950..1544568446 100644 --- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonSensor.java +++ b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonSensor.java @@ -74,28 +74,28 @@ public final class PythonSensor implements Sensor { * Constructor to be used by pico if neither PythonCustomRuleRepository nor PythonIndexer are to be found and injected. */ public PythonSensor(FileLinesContextFactory fileLinesContextFactory, CheckFactory checkFactory, - NoSonarFilter noSonarFilter, AnalysisWarningsWrapper analysisWarnings) { - this(fileLinesContextFactory, checkFactory, noSonarFilter, null, null, null, analysisWarnings); + NoSonarFilter noSonarFilter, AnalysisWarningsWrapper analysisWarnings, CheckList checkList) { + this(fileLinesContextFactory, checkFactory, noSonarFilter, null, null, null, analysisWarnings, checkList); } public PythonSensor(FileLinesContextFactory fileLinesContextFactory, CheckFactory checkFactory, NoSonarFilter noSonarFilter, - PythonCustomRuleRepository[] customRuleRepositories, AnalysisWarningsWrapper analysisWarnings) { - this(fileLinesContextFactory, checkFactory, noSonarFilter, customRuleRepositories, null, null, analysisWarnings); + PythonCustomRuleRepository[] customRuleRepositories, AnalysisWarningsWrapper analysisWarnings, CheckList checkList) { + this(fileLinesContextFactory, checkFactory, noSonarFilter, customRuleRepositories, null, null, analysisWarnings, checkList); } public PythonSensor(FileLinesContextFactory fileLinesContextFactory, CheckFactory checkFactory, NoSonarFilter noSonarFilter, - PythonIndexer indexer, SonarLintCache sonarLintCache, AnalysisWarningsWrapper analysisWarnings) { + PythonIndexer indexer, SonarLintCache sonarLintCache, AnalysisWarningsWrapper analysisWarnings, CheckList checkList) { // ^^ This constructor implicitly assumes that a PythonIndexer and a SonarLintCache are always available at the same time. // In practice, this is currently the case, since both are provided by PythonPlugin under the same conditions. // See also PythonPlugin::SonarLintPluginAPIManager::addSonarlintPythonIndexer. - this(fileLinesContextFactory, checkFactory, noSonarFilter, null, indexer, sonarLintCache, analysisWarnings); + this(fileLinesContextFactory, checkFactory, noSonarFilter, null, indexer, sonarLintCache, analysisWarnings, checkList); } public PythonSensor(FileLinesContextFactory fileLinesContextFactory, CheckFactory checkFactory, NoSonarFilter noSonarFilter, @Nullable PythonCustomRuleRepository[] customRuleRepositories, @Nullable PythonIndexer indexer, - @Nullable SonarLintCache sonarLintCache, AnalysisWarningsWrapper analysisWarnings) { + @Nullable SonarLintCache sonarLintCache, AnalysisWarningsWrapper analysisWarnings, CheckList checkList) { this.checks = new PythonChecks(checkFactory) - .addChecks(CheckList.REPOSITORY_KEY, CheckList.getChecks()) + .addChecks(CheckList.REPOSITORY_KEY, checkList.getChecks()) .addCustomChecks(customRuleRepositories); this.fileLinesContextFactory = fileLinesContextFactory; this.noSonarFilter = noSonarFilter; diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/IPynbRuleRepositoryTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/IPynbRuleRepositoryTest.java index 3652c144ca..61737c1295 100644 --- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/IPynbRuleRepositoryTest.java +++ b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/IPynbRuleRepositoryTest.java @@ -79,7 +79,7 @@ private static RulesDefinition.Repository buildRepository() { private static RulesDefinition.Repository buildRepository(int majorVersion, int minorVersion) { SonarRuntime sonarRuntime = SonarRuntimeImpl.forSonarQube(Version.create(majorVersion, minorVersion), SonarQubeSide.SERVER, SonarEdition.DEVELOPER); - IPynbRuleRepository ruleRepository = new IPynbRuleRepository(sonarRuntime); + IPynbRuleRepository ruleRepository = new IPynbRuleRepository(sonarRuntime, new CheckList()); RulesDefinition.Context context = new RulesDefinition.Context(); ruleRepository.define(context); return context.repository(CheckList.IPYTHON_REPOSITORY_KEY); diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/IPynbSensorTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/IPynbSensorTest.java index 5a0f3b2046..f1c8599c17 100644 --- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/IPynbSensorTest.java +++ b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/IPynbSensorTest.java @@ -131,7 +131,7 @@ private IPynbSensor sensor(PythonIndexer indexer) { FileLinesContext fileLinesContext = mock(FileLinesContext.class); when(fileLinesContextFactory.createFor(Mockito.any(InputFile.class))).thenReturn(fileLinesContext); CheckFactory checkFactory = new CheckFactory(activeRules); - return new IPynbSensor(fileLinesContextFactory, checkFactory, mock(NoSonarFilter.class), indexer); + return new IPynbSensor(fileLinesContextFactory, checkFactory, mock(NoSonarFilter.class), indexer, new CheckList()); } private PythonInputFile inputFile(String name) { @@ -174,7 +174,7 @@ private IPynbSensor notebookSensor() { FileLinesContext fileLinesContext = mock(FileLinesContext.class); when(fileLinesContextFactory.createFor(Mockito.any(InputFile.class))).thenReturn(fileLinesContext); CheckFactory checkFactory = new CheckFactory(activeRules); - return new IPynbSensor(fileLinesContextFactory, checkFactory, mock(NoSonarFilter.class)); + return new IPynbSensor(fileLinesContextFactory, checkFactory, mock(NoSonarFilter.class), new CheckList()); } @Test diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonPluginTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonPluginTest.java index 98e9e30fa3..57f0cd1f17 100644 --- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonPluginTest.java +++ b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonPluginTest.java @@ -43,10 +43,10 @@ class PythonPluginTest { void testGetExtensions() { Version v79 = Version.create(7, 9); SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(v79, SonarQubeSide.SERVER, SonarEdition.DEVELOPER); - assertThat(extensions(runtime)).hasSize(33); + assertThat(extensions(runtime)).hasSize(34); assertThat(extensions(runtime)).contains(AnalysisWarningsWrapper.class); assertThat(extensions(SonarRuntimeImpl.forSonarLint(v79))) - .hasSize(14) + .hasSize(15) .contains(SonarLintCache.class); } diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonRuleRepositoryTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonRuleRepositoryTest.java index fd08205f0d..5a16b6d28a 100644 --- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonRuleRepositoryTest.java +++ b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonRuleRepositoryTest.java @@ -131,7 +131,7 @@ private static RulesDefinition.Repository buildRepository() { private static RulesDefinition.Repository buildRepository(int majorVersion, int minorVersion) { SonarRuntime sonarRuntime = SonarRuntimeImpl.forSonarQube(Version.create(majorVersion, minorVersion), SonarQubeSide.SERVER, SonarEdition.DEVELOPER); - PythonRuleRepository ruleRepository = new PythonRuleRepository(sonarRuntime); + PythonRuleRepository ruleRepository = new PythonRuleRepository(sonarRuntime, new CheckList()); RulesDefinition.Context context = new RulesDefinition.Context(); ruleRepository.define(context); return context.repository(CheckList.REPOSITORY_KEY); diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonSensorTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonSensorTest.java index 62fafc0740..cdac05974d 100644 --- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonSensorTest.java +++ b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonSensorTest.java @@ -1488,15 +1488,15 @@ private PythonSensor sensor(@Nullable PythonCustomRuleRepository[] customRuleRep when(fileLinesContextFactory.createFor(Mockito.any(InputFile.class))).thenReturn(fileLinesContext); CheckFactory checkFactory = new CheckFactory(activeRules); if (indexer == null && customRuleRepositories == null) { - return new PythonSensor(fileLinesContextFactory, checkFactory, mock(NoSonarFilter.class), analysisWarnings); + return new PythonSensor(fileLinesContextFactory, checkFactory, mock(NoSonarFilter.class), analysisWarnings, new CheckList()); } if (indexer == null) { - return new PythonSensor(fileLinesContextFactory, checkFactory, mock(NoSonarFilter.class), customRuleRepositories, analysisWarnings); + return new PythonSensor(fileLinesContextFactory, checkFactory, mock(NoSonarFilter.class), customRuleRepositories, analysisWarnings, new CheckList()); } if (customRuleRepositories == null) { - return new PythonSensor(fileLinesContextFactory, checkFactory, mock(NoSonarFilter.class), indexer, new SonarLintCache(), analysisWarnings); + return new PythonSensor(fileLinesContextFactory, checkFactory, mock(NoSonarFilter.class), indexer, new SonarLintCache(), analysisWarnings, new CheckList()); } - return new PythonSensor(fileLinesContextFactory, checkFactory, mock(NoSonarFilter.class), customRuleRepositories, indexer, new SonarLintCache(), analysisWarnings); + return new PythonSensor(fileLinesContextFactory, checkFactory, mock(NoSonarFilter.class), customRuleRepositories, indexer, new SonarLintCache(), analysisWarnings, new CheckList()); } private SonarLintPythonIndexer pythonIndexer(List files) {