Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sonar scanning #11

Merged
merged 3 commits into from
Jan 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ dependencies {
// null-checker
implementation "net.ltgt.gradle:gradle-errorprone-plugin:3.1.0"

// sonar
implementation "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:4.4.1.3373"

// dependencies added by the plugin
// not used in the plugin code, but here Dependabot will keep them up to date
addedDependencies "com.uber.nullaway:nullaway:0.10.21@jar"
Expand Down
3 changes: 3 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
org.gradle.caching=true

version = 0.0.0-SNAPSHOT

dk.mada.style.sonar.projectKey = jskov_mada-style-gradle
dk.mada.style.sonar.organization = jskov-github
30 changes: 29 additions & 1 deletion src/main/java/dk/mada/style/MadaStylePlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.logging.Logger;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.quality.CheckstyleExtension;
import org.gradle.api.plugins.quality.CheckstylePlugin;
import org.sonarqube.gradle.SonarExtension;
import org.sonarqube.gradle.SonarQubePlugin;

import com.diffplug.gradle.spotless.SpotlessExtension;
import com.diffplug.gradle.spotless.SpotlessPlugin;
Expand All @@ -13,6 +16,7 @@
import dk.mada.style.config.PluginConfiguration;
import dk.mada.style.configurators.CheckstyleConfigurator;
import dk.mada.style.configurators.ErrorProneConfigurator;
import dk.mada.style.configurators.SonarConfigurator;
import dk.mada.style.configurators.SpotlessConfigurator;
import net.ltgt.gradle.errorprone.ErrorPronePlugin;

Expand All @@ -26,8 +30,11 @@ public void apply(Project project) {
}

private void applyPlugins(Project project) {
Logger logger = project.getLogger();
logger.info("Applying mada.style plugin");

var configuration = new PluginConfiguration(project);
var configExtractor = new ConfigFileExtractor(project.getLogger(), project.getGradle().getGradleHomeDir().toPath());
var configExtractor = new ConfigFileExtractor(logger, project.getGradle().getGradleHomeDir().toPath());

if (configuration.isCheckstyleActive()) {
project.getPluginManager().apply("checkstyle");
Expand All @@ -47,6 +54,16 @@ private void applyPlugins(Project project) {
project.getPlugins().withType(ErrorPronePlugin.class,
ep -> new ErrorProneConfigurator(project, configuration.errorProne(), configuration.nullchecker()).configure());
}

if (configuration.isSonarActive()) {
// This should be a Gradle property, but is a system property
// https://sonarsource.atlassian.net/browse/SONARGRADL-134
System.setProperty("sonar.gradle.skipCompile", "true");

project.getPluginManager().apply("org.sonarqube");

project.getPlugins().withType(SonarQubePlugin.class, sp -> lazyConfigureSonar(project, configuration));
}
}

/**
Expand All @@ -72,4 +89,15 @@ private void lazyConfigureFormatter(Project project, PluginConfiguration configu
project.getExtensions().configure(SpotlessExtension.class,
se -> new SpotlessConfigurator(project.getLogger(), configuration.formatter(), configExtractor).configure(se));
}

/**
* Lazy configure sonar extension.
*
* @param project the project
* @param configuration the plugin configuration
*/
private void lazyConfigureSonar(Project project, PluginConfiguration configuration) {
project.getExtensions().configure(SonarExtension.class,
se -> new SonarConfigurator(project, configuration.sonar()).configure(se));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public Path getLocalConfigFile(String path) {
throw new IllegalStateException("Failed to read " + path + " from data checksums: " + dataChecksums);
}

String suffix = "." + path.replaceAll(".*[.]", "");
String suffix = path.substring(path.lastIndexOf('.'));
String filename = path.replace('/', ':').replace(suffix, "") + "-" + value + suffix;

Path targetFile = madaConfigDir.resolve(filename);
Expand Down
62 changes: 46 additions & 16 deletions src/main/java/dk/mada/style/config/PluginConfiguration.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package dk.mada.style.config;

import java.util.Map;

import org.gradle.api.Project;
import org.jspecify.annotations.Nullable;

Expand All @@ -21,7 +23,9 @@ public class PluginConfiguration {
/** The parsed formatter configuration. */
private final FormatterConfiguration formatterConf;
/** The parsed null-checker configuration. */
private final NullcheckerConfiguration nullcheckerProps;
private final NullcheckerConfiguration nullcheckerConf;
/** The parsed sonar configuration. */
private final SonarConfiguration sonarConf;

/**
* Checkstyle configuration.
Expand All @@ -38,6 +42,19 @@ public record CheckstyleConfiguration(boolean enabled, boolean ignoreFailures, b
@Nullable String configPath) {
}

/**
* ErrorProne configuration.
*
* @param enabled flag to activate error prone
* @param ignoreTestSource flag to ignore test source files
* @param ignoreGeneratedSource flag to ignore generated source files
* @param excludePathsRegexp a regular expression of source paths to ignore
* @param disabledRules a comma-separated list of rule names to disable
*/
public record ErrorProneConfiguration(boolean enabled, boolean ignoreTestSource, boolean ignoreGeneratedSource,
String excludePathsRegexp, String disabledRules) {
}

/**
* Formatter configuration.
*
Expand All @@ -60,16 +77,12 @@ public record NullcheckerConfiguration(boolean enabled, String includePackages,
}

/**
* ErrorProne configuration.
* SonarSource sonar configuration.
*
* @param enabled flag to activate error prone
* @param ignoreTestSource flag to ignore test source files
* @param ignoreGeneratedSource flag to ignore generated source files
* @param excludePathsRegexp a regular expression of source paths to ignore
* @param disabledRules a comma-separated list of rule names to disable
* @param enabled flag to activate sonar
* @param madaConventionProperties convention properties for sonar
*/
public record ErrorProneConfiguration(boolean enabled, boolean ignoreTestSource, boolean ignoreGeneratedSource,
String excludePathsRegexp, String disabledRules) {
public record SonarConfiguration(boolean enabled, Map<String, String> madaConventionProperties) {
}

/**
Expand Down Expand Up @@ -105,10 +118,17 @@ public PluginConfiguration(Project project) {
getProperty("formatter.exclude", ""),
getNullableProperty("formatter.eclipse-config-path", null));

nullcheckerProps = new NullcheckerConfiguration(
nullcheckerConf = new NullcheckerConfiguration(
getBoolProperty("null-checker.enabled", true),
getProperty("null-checker.include-packages", "dk"),
getProperty("null-checker.exclude-packages", ""));

sonarConf = new SonarConfiguration(
getBoolProperty("sonar.enabled", true),
Map.of(
"sonar.host.url", "https://sonarcloud.io",
"sonar.inclusions", "**/src/main/**",
"sonar.sourceEncoding", "UTF-8"));
}

/** {@return the CheckStyle configuration} */
Expand All @@ -131,24 +151,34 @@ public boolean isErrorProneActive() {
return errorProne().enabled();
}

/** {@return the formatter configuration} */
public FormatterConfiguration formatter() {
return formatterConf;
}

/** {@return true if the formatter is active} */
public boolean isFormatterActive() {
return formatter().enabled();
}

/** {@return the formatter configuration} */
public FormatterConfiguration formatter() {
return formatterConf;
/** {@return the null-checker configuration} */
public NullcheckerConfiguration nullchecker() {
return nullcheckerConf;
}

/** {@return true if the null-checker is active} */
public boolean isNullcheckerActive() {
return nullchecker().enabled();
}

/** {@return the null-checker configuration} */
public NullcheckerConfiguration nullchecker() {
return nullcheckerProps;
/** {@return the sonar configuration} */
public SonarConfiguration sonar() {
return sonarConf;
}

/** {@return true if sonar is active} */
public boolean isSonarActive() {
return sonar().enabled();
}

private boolean getBoolProperty(String name, boolean defaultValue) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.gradle.api.logging.Logger;
import org.gradle.api.plugins.quality.Checkstyle;
import org.gradle.api.plugins.quality.CheckstyleExtension;
import org.gradle.api.tasks.TaskContainer;

import dk.mada.style.config.ConfigFileExtractor;
import dk.mada.style.config.PluginConfiguration.CheckstyleConfiguration;
Expand Down Expand Up @@ -56,17 +57,16 @@ public void configure(CheckstyleExtension ce) {
if (toolVersion != null) {
ce.setToolVersion(toolVersion);
}
TaskContainer taskContainer = project.getTasks();
if (checkstyleConfig.ignoreTestSource()) {
project.getTasks().named("checkstyleTest", this::disableTask);
taskContainer.named("checkstyleTest", this::disableTask);
}

if (checkstyleConfig.ignoreGeneratedSource()) {
project.getTasks().withType(Checkstyle.class, t -> {
if (t.getName().endsWith("Apt")) {
disableTask(t);
}
});
}
taskContainer.withType(Checkstyle.class, t -> {
if (checkstyleConfig.ignoreGeneratedSource() && t.getName().endsWith("Apt")) {
disableTask(t);
}
});
}

private void disableTask(Task t) {
Expand Down
66 changes: 66 additions & 0 deletions src/main/java/dk/mada/style/configurators/SonarConfigurator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package dk.mada.style.configurators;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import org.gradle.api.Project;
import org.gradle.api.logging.Logger;
import org.gradle.api.plugins.quality.Checkstyle;
import org.gradle.api.tasks.TaskContainer;
import org.sonarqube.gradle.SonarExtension;
import org.sonarqube.gradle.SonarTask;

import dk.mada.style.config.PluginConfiguration.SonarConfiguration;

/**
* Configures Sonar.
*/
public class SonarConfigurator {
/** The gradle project. */
private final Project project;
/** The gradle logger. */
private final Logger logger;
/** The sonarqube configuration. */
private final SonarConfiguration sonarConfig;

/**
* Creates new instance.
*
* @param project the gradle project
* @param sonarConfig the sonarqube configuration
*/
public SonarConfigurator(Project project, SonarConfiguration sonarConfig) {
this.project = project;
this.logger = project.getLogger();
this.sonarConfig = sonarConfig;
}

/**
* Configures the sonarqube extension.
*
* @param se the spotless extension
*/
public void configure(SonarExtension se) {
logger.info("dk.mada.style configure sonar");

TaskContainer taskContainer = project.getTasks();

// Make sonar depend on checkstyle tasks (we want sonar to run last)
taskContainer.withType(SonarTask.class, sonar -> taskContainer.withType(Checkstyle.class, sonar::dependsOn));

Map<String, String> inputProps = project.getProperties().entrySet().stream()
.filter(e -> !e.getKey().equals("dk.mada.style.sonar.enabled"))
.filter(e -> e.getKey().startsWith("dk.mada.style.sonar."))
.collect(Collectors.toMap(e -> e.getKey().replace("dk.mada.style.", ""), e -> Objects.toString(e.getValue())));

Map<String, String> combinedMadaSonarProps = new HashMap<>();
combinedMadaSonarProps.putAll(sonarConfig.madaConventionProperties());
combinedMadaSonarProps.putAll(inputProps);

logger.info("Set sonar properties: {}", combinedMadaSonarProps);

se.properties(sp -> combinedMadaSonarProps.forEach(sp::property));
}
}
2 changes: 1 addition & 1 deletion src/main/resources/config/checkstyle/checkstyle-mada.xml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@

<!-- Checks for Headers -->
<!-- See https://checkstyle.org/config_header.html -->
<!-- <module name="Header"> -->
<!-- <module name="Header"> --> <!-- NOSONAR -->
<!-- <property name="headerFile" value="${checkstyle.header.file}"/> -->
<!-- <property name="fileExtensions" value="java"/> -->
<!-- </module> -->
Expand Down