From 7054dc9bf9ddd30eebf038094d6cc9b4a3be5db2 Mon Sep 17 00:00:00 2001 From: Michal Duda Date: Thu, 13 Jun 2019 17:27:43 +0200 Subject: [PATCH] SONAR-12182 drop "sonar.branch" from SQ --- build.gradle | 2 +- .../src/pages/analysis/analysis-parameters.md | 3 +- .../src/pages/branches/branches-faq.md | 4 -- .../sonar/server/project/ws/CreateAction.java | 1 + .../server/project/ws/CreateActionTest.java | 3 ++ .../scanner/bootstrap/GlobalContainer.java | 5 +- .../scanner/scan/ProjectScanContainer.java | 22 ++++++--- .../sonar/scanner/scan/ScanProperties.java | 4 ++ .../mediumtest/ScannerMediumTester.java | 47 ++++++++++++++++++- .../branch/DeprecatedBranchMediumTest.java | 45 +++++++++++++++--- .../mediumtest/fs/FileSystemMediumTest.java | 7 ++- .../fs/ProjectBuilderMediumTest.java | 2 + .../scanner/mediumtest/scm/ScmMediumTest.java | 2 + 13 files changed, 121 insertions(+), 26 deletions(-) diff --git a/build.gradle b/build.gradle index c2b993e2bdb..aa04813445d 100644 --- a/build.gradle +++ b/build.gradle @@ -236,7 +236,7 @@ subprojects { dependency 'org.postgresql:postgresql:42.2.5' dependency 'org.reflections:reflections:0.9.9' dependency 'org.simpleframework:simple:4.1.21' - dependency 'org.sonarsource.orchestrator:sonar-orchestrator:3.24.0.1993' + dependency 'org.sonarsource.orchestrator:sonar-orchestrator:3.25.0.2071' dependency 'org.sonarsource.update-center:sonar-update-center-common:1.18.0.487' dependency 'org.subethamail:subethasmtp:3.1.7' dependency 'xml-apis:xml-apis:1.4.01' diff --git a/server/sonar-docs/src/pages/analysis/analysis-parameters.md b/server/sonar-docs/src/pages/analysis/analysis-parameters.md index 0c893b81081..03f1825b8a5 100644 --- a/server/sonar-docs/src/pages/analysis/analysis-parameters.md +++ b/server/sonar-docs/src/pages/analysis/analysis-parameters.md @@ -99,7 +99,6 @@ Key | Description | Default | ![](/images/cross.svg) These parameters are listed for completeness, but are deprecated and should not be used in new analyses. Key | Description ----|----|--- -`sonar.branch` **![](/images/cross.svg)Deprecated since SQ 6.7** | _The Developer Edition provides fuller-featured branch functionality._ Manage SCM branches. Two branches of the same project are considered to be different projects in SonarQube. As a consequence issues found in a project A in a branch B1 are not linked to issues found for this project A in a branch B2. There is no way to automatically resolve issues from B2 when they are resolved in B1 as again A-B1 & A-B2 are considered separated projects. +---|----|--- `sonar.links.scm_dev` **![](/images/cross.svg)Deprecated since SQ 7.1** | Developer connection. | `` for Maven projects diff --git a/server/sonar-docs/src/pages/branches/branches-faq.md b/server/sonar-docs/src/pages/branches/branches-faq.md index ea6d8855a5e..009839e4516 100644 --- a/server/sonar-docs/src/pages/branches/branches-faq.md +++ b/server/sonar-docs/src/pages/branches/branches-faq.md @@ -21,10 +21,6 @@ No, you don't need to be connected to a SCM. But if you use Git or SVN we can be ## What if I mark an Issue "Won't Fix" or "False-Positive" in a branch? It be replicated as such when merging my short-lived branch into the Master. Each time there is an analysis of a long-lived branch, we look at the issues on the short-lived branches and try to synchronize them with the newly raised issues on the long-lived branch. In case you made some changes on the issues (false-positive, won't fix), these changes will be reported on the long-lived branch. -## Can I still use 'sonar.branch'? -`sonar.branch` is deprecated. You can still use it but it will behave the same way it always has: a separate project will be created. We encourage you to smoothly migrate your users to the new parameter `sonar.branch.name`. -Please note you cannot use `sonar.branch` together with `sonar.branch.name`. - ## Can I manually delete a branch? This can be achieved by going into the Administration menu at Project's level, then Branches. diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/ws/CreateAction.java b/server/sonar-server/src/main/java/org/sonar/server/project/ws/CreateAction.java index 5f5877c402a..490593a6e2b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/project/ws/CreateAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/project/ws/CreateAction.java @@ -93,6 +93,7 @@ public class CreateAction implements ProjectsWsAction { .setExampleValue("SonarQube"); action.createParam(PARAM_BRANCH) + .setDeprecatedSince("7.8") .setDescription("SCM Branch of the project. The key of the project will become key:branch, for instance 'SonarQube:branch-5.0'") .setExampleValue("branch-5.0"); diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/ws/CreateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/ws/CreateActionTest.java index ebae2a8d207..cddc20157bd 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/project/ws/CreateActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/project/ws/CreateActionTest.java @@ -392,6 +392,9 @@ public class CreateActionTest { WebService.Param name = definition.param(PARAM_NAME); assertThat(name.isRequired()).isTrue(); assertThat(name.description()).isEqualTo("Name of the project. If name is longer than 500, it is abbreviated."); + + WebService.Param branch = definition.param(PARAM_BRANCH); + assertThat(branch.deprecatedSince()).isNotNull(); } private CreateWsResponse call(CreateRequest request) { diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalContainer.java index 9b407ba2a3d..e600bf3b3b7 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalContainer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalContainer.java @@ -28,6 +28,7 @@ import org.sonar.api.Plugin; import org.sonar.api.SonarEdition; import org.sonar.api.SonarQubeSide; import org.sonar.api.SonarQubeVersion; +import org.sonar.api.SonarRuntime; import org.sonar.api.internal.MetadataLoader; import org.sonar.api.internal.SonarRuntimeImpl; import org.sonar.api.utils.MessageException; @@ -100,9 +101,7 @@ public class GlobalContainer extends ComponentContainer { PluginClassloaderFactory.class, ScannerPluginJarExploder.class, ExtensionInstaller.class, - new SonarQubeVersion(apiVersion), - SonarRuntimeImpl.forSonarQube(apiVersion, SonarQubeSide.SCANNER, edition), new GlobalServerSettingsProvider(), new GlobalConfigurationProvider(), new ScannerWsClientProvider(), @@ -115,6 +114,7 @@ public class GlobalContainer extends ComponentContainer { Clock.systemDefaultZone(), new MetricsRepositoryProvider(), UuidFactoryImpl.INSTANCE); + addIfMissing(SonarRuntimeImpl.forSonarQube(apiVersion, SonarQubeSide.SCANNER, edition), SonarRuntime.class); addIfMissing(ScannerPluginInstaller.class, PluginInstaller.class); add(CoreExtensionRepositoryImpl.class, CoreExtensionsLoader.class, ScannerCoreExtensionsInstaller.class); addIfMissing(DefaultGlobalSettingsLoader.class, GlobalSettingsLoader.class); @@ -138,7 +138,6 @@ public class GlobalContainer extends ComponentContainer { if (!analysisMode.equals("publish")) { throw MessageException.of("The preview mode, along with the 'sonar.analysis.mode' parameter, is no more supported. You should stop using this parameter."); } - new ProjectScanContainer(this).execute(); LOG.info("Analysis total time: {}", formatTime(System.currentTimeMillis() - startTime)); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java index c9f85f3111d..71ab90450b8 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java @@ -21,6 +21,8 @@ package org.sonar.scanner.scan; import com.google.common.annotations.VisibleForTesting; import javax.annotation.Nullable; +import org.sonar.api.SonarEdition; +import org.sonar.api.SonarRuntime; import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.FileMetadata; import org.sonar.api.batch.fs.internal.InputModuleHierarchy; @@ -30,6 +32,7 @@ import org.sonar.api.issue.NoSonarFilter; import org.sonar.api.resources.Languages; import org.sonar.api.resources.ResourceTypes; import org.sonar.api.scan.filesystem.PathResolver; +import org.sonar.api.utils.MessageException; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.core.config.ScannerProperties; @@ -321,15 +324,22 @@ public class ProjectScanContainer extends ComponentContainer { GlobalAnalysisMode analysisMode = getComponentByType(GlobalAnalysisMode.class); InputModuleHierarchy tree = getComponentByType(InputModuleHierarchy.class); ScanProperties properties = getComponentByType(ScanProperties.class); + SonarRuntime sonarRuntime = getComponentByType(SonarRuntime.class); properties.validate(); properties.organizationKey().ifPresent(k -> LOG.info("Organization key: {}", k)); - - String branch = tree.root().definition().getBranch(); - if (branch != null) { - LOG.info("Branch key: {}", branch); - LOG.warn("The use of \"sonar.branch\" is deprecated and replaced by \"{}\". See {}.", - ScannerProperties.BRANCH_NAME, ScannerProperties.BRANCHES_DOC_LINK); + if (sonarRuntime.getEdition() == SonarEdition.SONARCLOUD) { + String branch = tree.root().definition().getBranch(); + if (branch != null) { + LOG.info("Branch key: {}", branch); + LOG.warn("The use of \"sonar.branch\" is deprecated and replaced by \"{}\". See {}.", + ScannerProperties.BRANCH_NAME, ScannerProperties.BRANCHES_DOC_LINK); + } + } else { + properties.get("sonar.branch").ifPresent(deprecatedBranch -> { + throw MessageException.of("The 'sonar.branch' parameter is no longer supported. You should stop using it. " + + "Branch analysis is available in Developer Edition and above. See https://redirect.sonarsource.com/editions/developer.html for more information."); + }); } BranchConfiguration branchConfig = getComponentByType(BranchConfiguration.class); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ScanProperties.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ScanProperties.java index 1033292a4b8..22a7751c035 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ScanProperties.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ScanProperties.java @@ -66,6 +66,10 @@ public class ScanProperties { return configuration.get(BRANCH_NAME); } + public Optional get(String propertyKey) { + return configuration.get(propertyKey); + } + public Path metadataFilePath() { Optional metadataFilePath = configuration.get(METADATA_FILE_PATH_KEY); if (metadataFilePath.isPresent()) { diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java index 28cb9ba3ed8..2eb7a188e8b 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java @@ -41,12 +41,17 @@ import javax.annotation.Nullable; import org.apache.commons.io.FileUtils; import org.junit.rules.ExternalResource; import org.sonar.api.Plugin; +import org.sonar.api.SonarEdition; +import org.sonar.api.SonarProduct; +import org.sonar.api.SonarQubeSide; +import org.sonar.api.SonarRuntime; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Metric; import org.sonar.api.rule.RuleKey; import org.sonar.api.server.rule.RulesDefinition; import org.sonar.api.server.rule.RulesDefinition.Repository; import org.sonar.api.utils.DateUtils; +import org.sonar.api.utils.Version; import org.sonar.batch.bootstrapper.Batch; import org.sonar.batch.bootstrapper.EnvironmentInformation; import org.sonar.batch.bootstrapper.LogOutput; @@ -89,6 +94,7 @@ public class ScannerMediumTester extends ExternalResource { private final FakeRulesLoader rulesLoader = new FakeRulesLoader(); private final FakeQualityProfileLoader qualityProfiles = new FakeQualityProfileLoader(); private final FakeActiveRulesLoader activeRules = new FakeActiveRulesLoader(); + private final FakeSonarRuntime sonarRuntime = new FakeSonarRuntime(); private LogOutput logOutput = null; private static void createWorkingDirs() throws IOException { @@ -220,7 +226,7 @@ public class ScannerMediumTester extends ExternalResource { } @Override - protected void before() throws Throwable { + protected void before() { try { createWorkingDirs(); } catch (IOException e) { @@ -287,6 +293,7 @@ public class ScannerMediumTester extends ExternalResource { tester.activeRules, tester.globalSettingsLoader, tester.projectSettingsLoader, + tester.sonarRuntime, result) .setLogOutput(tester.logOutput) .build().execute(); @@ -404,6 +411,39 @@ public class ScannerMediumTester extends ExternalResource { } } + private static class FakeSonarRuntime implements SonarRuntime { + + private SonarEdition edition; + + FakeSonarRuntime() { + this.edition = SonarEdition.COMMUNITY; + } + + @Override + public Version getApiVersion() { + return Version.create(7, 8); + } + + @Override + public SonarProduct getProduct() { + return SonarProduct.SONARQUBE; + } + + @Override + public SonarQubeSide getSonarQubeSide() { + return SonarQubeSide.SCANNER; + } + + @Override + public SonarEdition getEdition() { + return edition; + } + + public void setEdition(SonarEdition edition) { + this.edition = edition; + } + } + public ScannerMediumTester setBranchType(BranchType branchType) { branchConfiguration.branchType = branchType; return this; @@ -424,6 +464,11 @@ public class ScannerMediumTester extends ExternalResource { return this; } + public ScannerMediumTester setEdition(SonarEdition edition) { + this.sonarRuntime.setEdition(edition); + return this; + } + private class FakeBranchConfigurationLoader implements BranchConfigurationLoader { @Override public BranchConfiguration load(Map localSettings, Supplier> settingsSupplier, ProjectBranches branches, ProjectPullRequests pullRequests) { diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/branch/DeprecatedBranchMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/branch/DeprecatedBranchMediumTest.java index 41ea161bc72..627e285af3a 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/branch/DeprecatedBranchMediumTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/branch/DeprecatedBranchMediumTest.java @@ -31,9 +31,11 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; +import org.sonar.api.SonarEdition; import org.sonar.api.batch.fs.internal.DefaultInputFile; -import org.sonar.scanner.mediumtest.ScannerMediumTester; +import org.sonar.api.utils.MessageException; import org.sonar.scanner.mediumtest.AnalysisResult; +import org.sonar.scanner.mediumtest.ScannerMediumTester; import org.sonar.xoo.XooPlugin; import org.sonar.xoo.rule.XooRulesDefinition; @@ -55,6 +57,15 @@ public class DeprecatedBranchMediumTest { .addActiveRule("xoo", "xoo:OneIssuePerFile", null, "One Issue Per File", null, null, null) .addDefaultQProfile("xoo", "Sonar Way"); + @Rule + public ScannerMediumTester testerSC = new ScannerMediumTester() + .setEdition(SonarEdition.SONARCLOUD) + .registerPlugin("xoo", new XooPlugin()) + .addRules(new XooRulesDefinition()) + // active a rule just to be sure that xoo files are published + .addActiveRule("xoo", "xoo:OneIssuePerFile", null, "One Issue Per File", null, null, null) + .addDefaultQProfile("xoo", "Sonar Way"); + private File baseDir; private Map commonProps; @@ -75,14 +86,34 @@ public class DeprecatedBranchMediumTest { } @Test - public void scanProjectWithBranch() throws IOException { + public void scanProjectWithBranchOnSonarQube() throws IOException { + File srcDir = new File(baseDir, "src"); + srcDir.mkdir(); + + File xooFile = new File(srcDir, "sample.xoo"); + FileUtils.write(xooFile, "Sample xoo\ncontent"); + + thrown.expect(MessageException.class); + thrown.expectMessage("The 'sonar.branch' parameter is no longer supported. You should stop using it. " + + "Branch analysis is available in Developer Edition and above. See https://redirect.sonarsource.com/editions/developer.html for more information."); + + tester.newAnalysis() + .properties(ImmutableMap.builder() + .putAll(commonProps) + .put("sonar.branch", "branch") + .build()) + .execute(); + } + + @Test + public void scanProjectWithBranchOnSonarCloud() throws IOException { File srcDir = new File(baseDir, "src"); srcDir.mkdir(); File xooFile = new File(srcDir, "sample.xoo"); FileUtils.write(xooFile, "Sample xoo\ncontent"); - AnalysisResult result = tester.newAnalysis() + AnalysisResult result = testerSC.newAnalysis() .properties(ImmutableMap.builder() .putAll(commonProps) .put("sonar.branch", "branch") @@ -97,7 +128,7 @@ public class DeprecatedBranchMediumTest { assertThat(result.getReportReader().readMetadata().getDeprecatedBranch()).isEqualTo("branch"); - result = tester.newAnalysis() + result = testerSC.newAnalysis() .properties(ImmutableMap.builder() .putAll(commonProps) .put("sonar.branch", "") @@ -109,14 +140,14 @@ public class DeprecatedBranchMediumTest { } @Test - public void scanMultiModuleWithBranch() throws IOException { + public void scanMultiModuleWithBranchOnSonarCloud() throws IOException { Path srcDir = baseDir.toPath().resolve("moduleA").resolve("src"); Files.createDirectories(srcDir); File xooFile = new File(srcDir.toFile(), "sample.xoo"); FileUtils.write(xooFile, "Sample xoo\ncontent"); - AnalysisResult result = tester.newAnalysis() + AnalysisResult result = testerSC.newAnalysis() .properties(ImmutableMap.builder() .putAll(commonProps) .put("sonar.branch", "branch") @@ -133,7 +164,7 @@ public class DeprecatedBranchMediumTest { assertThat(result.getReportReader().readMetadata().getDeprecatedBranch()).isEqualTo("branch"); - result = tester.newAnalysis() + result = testerSC.newAnalysis() .properties(ImmutableMap.builder() .putAll(commonProps) .put("sonar.branch", "") diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java index af073681944..cb1537ae00c 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java @@ -34,6 +34,7 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; import org.sonar.api.CoreProperties; +import org.sonar.api.SonarEdition; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.utils.MessageException; @@ -65,6 +66,7 @@ public class FileSystemMediumTest { @Rule public ScannerMediumTester tester = new ScannerMediumTester() + .setEdition(SonarEdition.SONARCLOUD) .registerPlugin("xoo", new XooPlugin()) .addDefaultQProfile("xoo", "Sonar Way") .addDefaultQProfile("xoo2", "Sonar Way"); @@ -152,7 +154,7 @@ public class FileSystemMediumTest { } @Test - public void logBranchNameAndType() throws IOException { + public void logBranchNameAndType() { builder.put("sonar.branch.name", "my-branch"); File srcDir = new File(baseDir, "src"); assertThat(srcDir.mkdir()).isTrue(); @@ -1065,7 +1067,8 @@ public class FileSystemMediumTest { .execute(); assertThat(result.inputFiles()).hasSize(1); - assertThat(logTester.logs(LoggerLevel.WARN)).contains("File '" + xooFile2.getAbsolutePath() + "' is ignored. It is not located in module basedir '" + new File(baseDir, "moduleA") + "'."); + assertThat(logTester.logs(LoggerLevel.WARN)) + .contains("File '" + xooFile2.getAbsolutePath() + "' is ignored. It is not located in module basedir '" + new File(baseDir, "moduleA") + "'."); } @Test diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/ProjectBuilderMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/ProjectBuilderMediumTest.java index f61411b4898..b90b24d96e7 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/ProjectBuilderMediumTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/ProjectBuilderMediumTest.java @@ -30,6 +30,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; +import org.sonar.api.SonarEdition; import org.sonar.api.batch.bootstrap.ProjectBuilder; import org.sonar.api.utils.MessageException; import org.sonar.scanner.mediumtest.AnalysisResult; @@ -56,6 +57,7 @@ public class ProjectBuilderMediumTest { @Rule public ScannerMediumTester tester = new ScannerMediumTester() + .setEdition(SonarEdition.SONARCLOUD) .registerPlugin("xoo", new XooPluginWithBuilder(projectBuilder)) .addRules(new XooRulesDefinition()) .addDefaultQProfile("xoo", "Sonar Way") diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/scm/ScmMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/scm/ScmMediumTest.java index b317ac1c4cb..16d3e528e91 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/scm/ScmMediumTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/scm/ScmMediumTest.java @@ -31,6 +31,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; +import org.sonar.api.SonarEdition; import org.sonar.api.utils.log.LogTester; import org.sonar.scanner.mediumtest.ScannerMediumTester; import org.sonar.scanner.mediumtest.ScannerMediumTester.AnalysisBuilder; @@ -64,6 +65,7 @@ public class ScmMediumTest { @Rule public ScannerMediumTester tester = new ScannerMediumTester() + .setEdition(SonarEdition.SONARCLOUD) .registerPlugin("xoo", new XooPlugin()) .addDefaultQProfile("xoo", "Sonar Way") .addRules(new XooRulesDefinition()) -- 2.39.5