diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4c44d247..09f957cf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,12 +11,13 @@ jobs: java: [8, 11] sonar: - "" - - "8.3.0.34182" - "8.9.0.43852" include: - java: 8 sonar: "" archive: "yes" + - java: 11 + sonar: "9.0.0.45539" runs-on: ubuntu-latest diff --git a/sonar-groovy-plugin/src/main/java/org/sonar/plugins/groovy/GroovySensor.java b/sonar-groovy-plugin/src/main/java/org/sonar/plugins/groovy/GroovySensor.java index 5e857f87..cf81e874 100644 --- a/sonar-groovy-plugin/src/main/java/org/sonar/plugins/groovy/GroovySensor.java +++ b/sonar-groovy-plugin/src/main/java/org/sonar/plugins/groovy/GroovySensor.java @@ -254,6 +254,7 @@ public String toString() { public static List getExtensions() { return Arrays.asList( GroovySensor.class, + GroovySonarWayProfile.class, PropertyDefinition.builder(IGNORE_HEADER_COMMENTS) .name("Ignore Header Comments") .description( diff --git a/sonar-groovy-plugin/src/main/java/org/sonar/plugins/groovy/GroovySonarWayProfile.java b/sonar-groovy-plugin/src/main/java/org/sonar/plugins/groovy/GroovySonarWayProfile.java new file mode 100644 index 00000000..cd6477a4 --- /dev/null +++ b/sonar-groovy-plugin/src/main/java/org/sonar/plugins/groovy/GroovySonarWayProfile.java @@ -0,0 +1,60 @@ +/* + * Sonar Groovy Plugin + * Copyright (C) 2010-2021 SonarQube Community + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.groovy; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition; +import org.sonar.plugins.groovy.codenarc.CodeNarcRulesDefinition; +import org.sonar.plugins.groovy.foundation.Groovy; +import org.sonarsource.api.sonarlint.SonarLintSide; + +@SonarLintSide +public class GroovySonarWayProfile implements BuiltInQualityProfilesDefinition { + + @Override + public void define(Context context) { + NewBuiltInQualityProfile sonarWay = + context.createBuiltInQualityProfile("Sonar way", Groovy.KEY); + + addRulesFromText(CodeNarcRulesDefinition.REPOSITORY_KEY, sonarWay); + sonarWay.done(); + } + + private static void addRulesFromText(String repo, NewBuiltInQualityProfile profile) { + try (BufferedReader reader = + new BufferedReader( + new InputStreamReader( + GroovySonarWayProfile.class.getResourceAsStream("profile-default.txt"), + StandardCharsets.UTF_8))) { + reader + .lines() + .forEach( + (String rule) -> { + if (!rule.isEmpty()) { + profile.activateRule(repo, rule); + } + }); + } catch (IOException e) { + throw new IllegalStateException("Failed to read: profile-default.txt", e); + } + } +} diff --git a/sonar-groovy-plugin/src/main/java/org/sonar/plugins/groovy/codenarc/CodeNarcSensor.java b/sonar-groovy-plugin/src/main/java/org/sonar/plugins/groovy/codenarc/CodeNarcSensor.java index 379d0d1a..305cbb84 100644 --- a/sonar-groovy-plugin/src/main/java/org/sonar/plugins/groovy/codenarc/CodeNarcSensor.java +++ b/sonar-groovy-plugin/src/main/java/org/sonar/plugins/groovy/codenarc/CodeNarcSensor.java @@ -226,7 +226,6 @@ public static List getExtensions() { return Arrays.asList( CodeNarcRulesDefinition.class, CodeNarcSensor.class, - SonarWayProfile.class, PropertyDefinition.builder(CODENARC_REPORT_PATHS) .name("CodeNarc Reports") .description( diff --git a/sonar-groovy-plugin/src/main/java/org/sonar/plugins/groovy/codenarc/SonarWayProfile.java b/sonar-groovy-plugin/src/main/java/org/sonar/plugins/groovy/codenarc/SonarWayProfile.java deleted file mode 100644 index 2e566197..00000000 --- a/sonar-groovy-plugin/src/main/java/org/sonar/plugins/groovy/codenarc/SonarWayProfile.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Sonar Groovy Plugin - * Copyright (C) 2010-2021 SonarQube Community - *   - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.plugins.groovy.codenarc; - -import org.sonar.api.profiles.ProfileDefinition; -import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.profiles.XMLProfileParser; -import org.sonar.api.utils.ValidationMessages; - -public class SonarWayProfile extends ProfileDefinition { - private XMLProfileParser xmlProfileParser; - - public SonarWayProfile(XMLProfileParser xmlProfileParser) { - this.xmlProfileParser = xmlProfileParser; - } - - @Override - public RulesProfile createProfile(ValidationMessages messages) { - return xmlProfileParser.parseResource(getClass().getClassLoader(), "org/sonar/plugins/groovy/profile-sonar-way.xml", messages); - } -} diff --git a/sonar-groovy-plugin/src/main/resources/org/sonar/plugins/groovy/profile-default.txt b/sonar-groovy-plugin/src/main/resources/org/sonar/plugins/groovy/profile-default.txt new file mode 100644 index 00000000..91541f5a --- /dev/null +++ b/sonar-groovy-plugin/src/main/resources/org/sonar/plugins/groovy/profile-default.txt @@ -0,0 +1,58 @@ +org.codenarc.rule.basic.AssignmentInConditionalRule +org.codenarc.rule.exceptions.CatchErrorRule +org.codenarc.rule.exceptions.CatchExceptionRule +org.codenarc.rule.exceptions.CatchNullPointerExceptionRule +org.codenarc.rule.exceptions.CatchRuntimeExceptionRule +org.codenarc.rule.design.CloneableWithoutCloneRule +org.codenarc.rule.braces.ElseBlockBracesRule +org.codenarc.rule.grails.GrailsPublicControllerMethodRule.fixed +org.codenarc.rule.grails.GrailsServletContextReferenceRule +org.codenarc.rule.grails.GrailsStatelessServiceRule +org.codenarc.rule.size.NestedBlockDepthRule +org.codenarc.rule.concurrency.NestedSynchronizationRule +org.codenarc.rule.logging.PrintStackTraceRule +org.codenarc.rule.logging.PrintlnRule +org.codenarc.rule.basic.ReturnFromFinallyBlockRule +org.codenarc.rule.concurrency.SynchronizedMethodRule +org.codenarc.rule.logging.SystemErrPrintRule +org.codenarc.rule.logging.SystemOutPrintRule +org.codenarc.rule.concurrency.SystemRunFinalizersOnExitRule +org.codenarc.rule.concurrency.ThreadYieldRule +org.codenarc.rule.exceptions.ThrowErrorRule +org.codenarc.rule.exceptions.ThrowExceptionRule +org.codenarc.rule.basic.ThrowExceptionFromFinallyBlockRule +org.codenarc.rule.exceptions.ThrowNullPointerExceptionRule +org.codenarc.rule.exceptions.ThrowRuntimeExceptionRule +org.codenarc.rule.exceptions.ThrowThrowableRule +org.codenarc.rule.imports.UnnecessaryGroovyImportRule +org.codenarc.rule.imports.UnusedImportRule +org.codenarc.rule.unused.UnusedPrivateFieldRule +org.codenarc.rule.unused.UnusedPrivateMethodRule +org.codenarc.rule.unused.UnusedVariableRule.fixed +org.codenarc.rule.concurrency.VolatileLongOrDoubleFieldRule +org.codenarc.rule.basic.DuplicateCaseStatementRule +org.codenarc.rule.basic.EmptyCatchBlockRule +org.codenarc.rule.basic.EmptyElseBlockRule +org.codenarc.rule.basic.EmptyFinallyBlockRule +org.codenarc.rule.basic.EmptyForStatementRule +org.codenarc.rule.basic.EmptyIfStatementRule +org.codenarc.rule.basic.EmptyInstanceInitializerRule +org.codenarc.rule.basic.EmptyMethodRule +org.codenarc.rule.basic.EmptyStaticInitializerRule +org.codenarc.rule.basic.EmptySwitchStatementRule +org.codenarc.rule.basic.EmptySynchronizedStatementRule +org.codenarc.rule.basic.EmptyTryBlockRule +org.codenarc.rule.basic.EmptyWhileStatementRule +org.codenarc.rule.basic.EqualsAndHashCodeRule +org.codenarc.rule.basic.EqualsOverloadedRule +org.codenarc.rule.basic.EmptyClassRule +org.codenarc.rule.imports.DuplicateImportRule +org.codenarc.rule.imports.ImportFromSamePackageRule +org.codenarc.rule.imports.ImportFromSunPackagesRule +org.codenarc.rule.naming.ClassNameSameAsFilenameRule +org.codenarc.rule.unused.UnusedPrivateMethodParameterRule +org.codenarc.rule.unused.UnusedMethodParameterRule +org.codenarc.rule.convention.ConfusingTernaryRule +org.codenarc.rule.convention.InvertedIfElseRule +org.codenarc.rule.convention.VectorIsObsoleteRule +org.codenarc.rule.convention.HashtableIsObsoleteRule diff --git a/sonar-groovy-plugin/src/main/resources/org/sonar/plugins/groovy/profile-sonar-way.xml b/sonar-groovy-plugin/src/main/resources/org/sonar/plugins/groovy/profile-sonar-way.xml deleted file mode 100644 index 295db6bf..00000000 --- a/sonar-groovy-plugin/src/main/resources/org/sonar/plugins/groovy/profile-sonar-way.xml +++ /dev/null @@ -1,328 +0,0 @@ - - Sonar way - grvy - - - grvy - org.codenarc.rule.basic.AssignmentInConditionalRule - MAJOR - - - grvy - org.codenarc.rule.exceptions.CatchErrorRule - MAJOR - - - grvy - org.codenarc.rule.exceptions.CatchExceptionRule - MAJOR - - - grvy - org.codenarc.rule.exceptions.CatchNullPointerExceptionRule - CRITICAL - - - grvy - org.codenarc.rule.exceptions.CatchRuntimeExceptionRule - CRITICAL - - - grvy - org.codenarc.rule.design.CloneableWithoutCloneRule - MINOR - - - grvy - org.codenarc.rule.braces.ElseBlockBracesRule - MINOR - - - grvy - org.codenarc.rule.grails.GrailsPublicControllerMethodRule.fixed - MINOR - - - grvy - org.codenarc.rule.grails.GrailsServletContextReferenceRule - MINOR - - - grvy - org.codenarc.rule.grails.GrailsStatelessServiceRule - MAJOR - - - grvy - org.codenarc.rule.size.NestedBlockDepthRule - MAJOR - - - grvy - org.codenarc.rule.concurrency.NestedSynchronizationRule - CRITICAL - - - grvy - org.codenarc.rule.logging.PrintStackTraceRule - MAJOR - - - grvy - org.codenarc.rule.logging.PrintlnRule - MINOR - - - grvy - org.codenarc.rule.basic.ReturnFromFinallyBlockRule - MAJOR - - - grvy - org.codenarc.rule.concurrency.SynchronizedMethodRule - MAJOR - - - grvy - org.codenarc.rule.logging.SystemErrPrintRule - MAJOR - - - grvy - org.codenarc.rule.logging.SystemOutPrintRule - INFO - - - grvy - org.codenarc.rule.concurrency.SystemRunFinalizersOnExitRule - MAJOR - - - grvy - org.codenarc.rule.concurrency.ThreadYieldRule - CRITICAL - - - grvy - org.codenarc.rule.exceptions.ThrowErrorRule - MAJOR - - - grvy - org.codenarc.rule.exceptions.ThrowExceptionRule - MAJOR - - - grvy - org.codenarc.rule.basic.ThrowExceptionFromFinallyBlockRule - MAJOR - - - grvy - org.codenarc.rule.exceptions.ThrowNullPointerExceptionRule - MAJOR - - - grvy - org.codenarc.rule.exceptions.ThrowRuntimeExceptionRule - MAJOR - - - grvy - org.codenarc.rule.exceptions.ThrowThrowableRule - MAJOR - - - grvy - org.codenarc.rule.imports.UnnecessaryGroovyImportRule - MAJOR - - - grvy - org.codenarc.rule.imports.UnusedImportRule - MAJOR - - - grvy - org.codenarc.rule.unused.UnusedPrivateFieldRule - MAJOR - - - grvy - org.codenarc.rule.unused.UnusedPrivateMethodRule - MAJOR - - - grvy - org.codenarc.rule.unused.UnusedVariableRule.fixed - MAJOR - - - grvy - org.codenarc.rule.concurrency.VolatileLongOrDoubleFieldRule - MAJOR - - - - - grvy - org.codenarc.rule.basic.DuplicateCaseStatementRule - MINOR - - - - grvy - org.codenarc.rule.basic.EmptyCatchBlockRule - MINOR - - - - grvy - org.codenarc.rule.basic.EmptyElseBlockRule - MINOR - - - - grvy - org.codenarc.rule.basic.EmptyFinallyBlockRule - MINOR - - - - grvy - org.codenarc.rule.basic.EmptyForStatementRule - MINOR - - - - grvy - org.codenarc.rule.basic.EmptyIfStatementRule - MINOR - - - - grvy - org.codenarc.rule.basic.EmptyInstanceInitializerRule - MINOR - - - - grvy - org.codenarc.rule.basic.EmptyMethodRule - MINOR - - - - grvy - org.codenarc.rule.basic.EmptyStaticInitializerRule - MINOR - - - - grvy - org.codenarc.rule.basic.EmptySwitchStatementRule - MINOR - - - - grvy - org.codenarc.rule.basic.EmptySynchronizedStatementRule - MINOR - - - - grvy - org.codenarc.rule.basic.EmptyTryBlockRule - MINOR - - - - grvy - org.codenarc.rule.basic.EmptyWhileStatementRule - MINOR - - - - grvy - org.codenarc.rule.basic.EqualsAndHashCodeRule - MINOR - - - - grvy - org.codenarc.rule.basic.EqualsOverloadedRule - MINOR - - - - grvy - org.codenarc.rule.basic.EmptyClassRule - MINOR - - - - grvy - org.codenarc.rule.imports.DuplicateImportRule - MAJOR - - - - grvy - org.codenarc.rule.imports.ImportFromSamePackageRule - MAJOR - - - - grvy - org.codenarc.rule.imports.ImportFromSunPackagesRule - MINOR - - - - grvy - org.codenarc.rule.naming.ClassNameSameAsFilenameRule - MINOR - - - - grvy - org.codenarc.rule.unused.UnusedPrivateMethodParameterRule - MINOR - - - - grvy - org.codenarc.rule.unused.UnusedMethodParameterRule - MINOR - - - - grvy - org.codenarc.rule.convention.ConfusingTernaryRule - MAJOR - - - - grvy - org.codenarc.rule.convention.InvertedIfElseRule - MAJOR - - - - grvy - org.codenarc.rule.convention.VectorIsObsoleteRule - MINOR - - - - grvy - org.codenarc.rule.convention.HashtableIsObsoleteRule - MINOR - - - - - - - - diff --git a/sonar-groovy-plugin/src/test/java/org/sonar/plugins/groovy/GroovySonarWayProfileTest.java b/sonar-groovy-plugin/src/test/java/org/sonar/plugins/groovy/GroovySonarWayProfileTest.java new file mode 100644 index 00000000..b5e1c677 --- /dev/null +++ b/sonar-groovy-plugin/src/test/java/org/sonar/plugins/groovy/GroovySonarWayProfileTest.java @@ -0,0 +1,72 @@ +/* + * Sonar Groovy Plugin + * Copyright (C) 2010-2021 SonarQube Community + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.groovy; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.junit.Test; +import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition; +import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.BuiltInActiveRule; +import org.sonar.api.server.rule.RulesDefinition; +import org.sonar.api.utils.ValidationMessages; +import org.sonar.plugins.groovy.codenarc.CodeNarcRulesDefinition; +import org.sonar.plugins.groovy.foundation.Groovy; + +public class GroovySonarWayProfileTest { + + @Test + public void shouldCreateSonarWayProfile() { + ValidationMessages messages = ValidationMessages.create(); + + GroovySonarWayProfile profileDef = new GroovySonarWayProfile(); + BuiltInQualityProfilesDefinition.Context profileContext = + new BuiltInQualityProfilesDefinition.Context(); + profileDef.define(profileContext); + BuiltInQualityProfilesDefinition.BuiltInQualityProfile profile = + profileContext.profile(Groovy.KEY, "Sonar way"); + assertThat(profile.language()).isEqualTo(Groovy.KEY); + List activeRules = profile.rules(); + assertThat(activeRules).as("Expected number of rules in profile").hasSize(58); + assertThat(profile.name()).isEqualTo("Sonar way"); + + // Check that we use severity from the read rule and not default one. + assertThat(activeRules.get(0).overriddenSeverity()).isNull(); + assertThat(messages.hasErrors()).isFalse(); + + // Check that all rules in "Sonar way" actually exist + CodeNarcRulesDefinition definition = new CodeNarcRulesDefinition(); + RulesDefinition.Context rulesContext = new RulesDefinition.Context(); + definition.define(rulesContext); + RulesDefinition.Repository repository = + rulesContext.repository(CodeNarcRulesDefinition.REPOSITORY_KEY); + + Set rules = new HashSet<>(); + for (RulesDefinition.Rule rule : repository.rules()) { + rules.add(rule.key()); + } + for (BuiltInActiveRule activeRule : profile.rules()) { + assertThat(rules.contains(activeRule.ruleKey())) + .as("No such rule: " + activeRule.ruleKey()) + .isTrue(); + } + } +} diff --git a/sonar-groovy-plugin/src/test/java/org/sonar/plugins/groovy/codenarc/SonarWayProfileTest.java b/sonar-groovy-plugin/src/test/java/org/sonar/plugins/groovy/codenarc/SonarWayProfileTest.java deleted file mode 100644 index 1eb36278..00000000 --- a/sonar-groovy-plugin/src/test/java/org/sonar/plugins/groovy/codenarc/SonarWayProfileTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Sonar Groovy Plugin - * Copyright (C) 2010-2021 SonarQube Community - *   - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.plugins.groovy.codenarc; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.HashMap; -import java.util.Map; -import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import org.sonar.api.profiles.ProfileDefinition; -import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.profiles.XMLProfileParser; -import org.sonar.api.rules.ActiveRule; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.RuleFinder; -import org.sonar.api.server.rule.RulesDefinition; -import org.sonar.api.utils.ValidationMessages; -import org.sonar.plugins.groovy.foundation.Groovy; - -public class SonarWayProfileTest { - - @Test - public void shouldCreateProfile() { - ProfileDefinition profileDefinition = - new SonarWayProfile(new XMLProfileParser(newRuleFinder())); - ValidationMessages messages = ValidationMessages.create(); - RulesProfile profile = profileDefinition.createProfile(messages); - - assertThat(profile.getName()).isEqualTo("Sonar way"); - assertThat(profile.getLanguage()).isEqualTo(Groovy.KEY); - assertThat(profile.getActiveRules()).hasSize(58); - assertThat(messages.hasErrors()).isFalse(); - - CodeNarcRulesDefinition definition = new CodeNarcRulesDefinition(); - RulesDefinition.Context context = new RulesDefinition.Context(); - definition.define(context); - RulesDefinition.Repository repository = - context.repository(CodeNarcRulesDefinition.REPOSITORY_KEY); - - Map rules = new HashMap<>(); - for (RulesDefinition.Rule rule : repository.rules()) { - rules.put(rule.key(), rule); - } - for (ActiveRule activeRule : profile.getActiveRules()) { - assertThat(rules.containsKey(activeRule.getConfigKey())) - .as("No such rule: " + activeRule.getConfigKey()) - .isTrue(); - } - } - - private RuleFinder newRuleFinder() { - RuleFinder ruleFinder = mock(RuleFinder.class); - when(ruleFinder.findByKey(anyString(), anyString())) - .thenAnswer( - new Answer() { - public Rule answer(InvocationOnMock iom) throws Throwable { - return Rule.create( - (String) iom.getArguments()[0], - (String) iom.getArguments()[1], - (String) iom.getArguments()[1]); - } - }); - return ruleFinder; - } -}