SonarScanner for Gradle: you can now decide when to compile

Hello,

We made a change in the SonarScanner for Gradle so you can control when your code is compiled.

Until today, the SonarScanner for Gradle was behaving like this:

  • when you were running gradle sonar, under the hood, it was triggering/forcing the compilation
  • this was a hard dependency and it was not possible to deactivate it

We made this design choice years ago because, for Java and Kotlin code, the Sonar analyzers must have access to the bytecode to perform an accurate analysis. So forcing the compilation to happen before the scan was a natural choice to be sure to run the scan in good conditions.

The problems of this approach are:

  • you are forced to compile all the targets and for Android projects, you may not want to do that for each scan
  • you canā€™t easily compile with one JDK version and run the scan with another version / itā€™s possible but painful because you have to be explicit with the list of compile steps you donā€™t want to execute while running the sonar task

For these reasons, we decided to align the behavior of the SonarScanner for Gradle with the Maven one.
Our plan is to request users to be explicit and say:

gradle assemble sonar

ā€¦ instead of just:

gradle sonar

The change will happen incrementally to not break all CI configurations:

  • we introduced with v4.4.1 a property to allow users to adopt the new behavior
  • a message will be displayed to invite you to move to the new behavior because the old one is now considered deprecated
  • the SonarQube and SonarCloudā€™s documentations/tutorials will be updated accordingly
  • later we will change the default behavior with the v5.x and no longer force the compilation step

If you want to jump in now, you have to upgrade your SonarScanner for Gradle to v4.4.1 and set the property ā€˜sonar.gradle.skipCompileā€™ to ā€˜trueā€™.

Alex

3 Likes

Hey there.

We use Gradle Kotlin DSL. We tried the following config with true in double quotes as well

sonarqube {
    properties {
        property ("sonar.gradle.skipCompile", true)
        property ("sonar.skipCompile", true)

but it gives no result, we still receive the following notification

The 'sonarqube' task depends on compile tasks. This behavior is now deprecated and will be removed in version 5.x. To avoid implicit compilation, set property 'sonar.gradle.skipCompile' to 'true' and make sure your project is compiled, before analysis has started.
The 'sonar' task depends on compile tasks. This behavior is now deprecated and will be removed in version 5.x. To avoid implicit compilation, set property 'sonar.gradle.skipCompile' to 'true' and make sure your project is compiled, before analysis has started.

Could you please let us know how we should implement this property?

I also created this thread about it: sonar.gradle.skipCompile is not working - #4 by G00fY2

What worked out for us was to set the property in the settings.gradle(.kts) file:

System.setProperty("sonar.gradle.skipCompile", "true")
1 Like

Another option is to configure it in gradle.properties like so:

systemProp.sonar.gradle.skipCompile=true

Alexandre_Gigleux to be honest i find this behaviour to print a warning message extremely annoyingā€¦ because it is not only one, but many, depending how the compile is set up. to switch it off one needs to commit a code change, and with 5 to revert to default one needs again a code change. also to name ā€œskipCompile=trueā€ instead of ā€œcompile=falseā€ is weird by itself.

sonarscanner should know by itself if it needs a compile, and error out if it is not. and THEN print this information.

1 Like

I have set system property to skip compilation.
Now I run gradle build task and after it sonar task. So everything is compile in front and sonar picks up bytecode and analyses it.

As a side-effect Iā€™m getting following Gradle warnings for subprojects when running sonar task:

Resolution of the configuration :projectName:compileClasspath was attempted from a context different than the project context. Have a look at the documentation to understand why this is a problem and how it can be resolved. This behavior has been deprecated. This will fail with an error in Gradle 9.0. For more information, please refer to https://docs.gradle.org/8.5/userguide/viewing_debugging_dependencies.html#sub:resolving-unsafe-configuration-resolution-errors in the Gradle documentation.

Is anyone else also getting this warning because of this skipCompile configuration or is this something project specific that I should resolve?

it didnā€™t help even if I run gradlew assemble sonar, still those configuration warnings are logged

Also see: Setting sonar.gradle.skipCompile through a Gradle property would be nice - SonarQube - Sonar Community (sonarsource.com)

I agree with the intent here but this implementation is awful. I get this message when running gradle clean for example which is clearly not helpful.

Hi folks,

Iā€™m working on upgrading the Micronaut Build plugins to the latest release of the Sonar plugin and noticed this warning:

The ā€˜sonarqubeā€™ task depends on compile tasks. This behavior is now deprecated and will be removed in version 5.x. To avoid implicit compilation, set property ā€˜sonar.gradle.skipCompileā€™ to ā€˜trueā€™ and make sure your project is compiled, before analysis has started.

As a former Gradler, this puzzled me, as this is going in the opposite direction of what you should do with Gradle, and Iā€™m not convinced that this is a good design decision. I found this thread which explains the reason, but unless Iā€™m missing something, I donā€™t think this is a good thing do to.

One reason is that Gradleā€™s design is, for any task, to declare its inputs and outputs. Task dependencies are figured out automatically, based on what you consume. For example, if you consume the ā€œruntimeClasspathā€ configuration, it would figure out automatically that it has to run compileJava (but not compileTestJava) and potentially other tasks which contribute classes to the runtime classpath. This is also why you should in general never use explicit dependsOn, but use implicit task dependencies instead.

One thing which worries me with this new behavior is that now, youā€™re explicitly breaking the rule, which, I think (didnā€™t look at the code) means that the sonar plugin will try to look for classes in a particular directory (e.g build/classes/) assuming that ā€œthe project has been compiledā€. However, there are safety guards in Gradle which precisely detect that a task is consuming the output of another task without adding an explicit dependency. Usually the messages look like this:

Reason: Task ':foo' uses this output of task ':bar' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed

If it does not detect that automatically, this is usually considered a bug in Gradle. This is quite important because Gradle builds should be reproducible and you should precisely never have to run a task explicitly prior to another one for the task to execute properly (and each task should do its work in an ā€œisolatedā€ context).

The reasons mentioned in the original post here do not look like a good reason to change the behavior. Something I would expect, in fact, is that the Sonar plugin would create different analysis tasks for different variants. There would be an analysis task which would trigger it for all variants, but that would be up to the user to tell if they want analysis to be performed on a single variant, by calling an individual task, or on all variants by running the ā€œaggregatingā€ one.

Again maybe Iā€™m missing something, in which case please find my apologies, but at first glance this sounds like a risky design decision that may break in future Gradle releases, with improved implicit task dependency detection. One thing in particular to keep in mind:

Running gradle assemble sonar with the configuration cache enabled will not do what you expect. Since there would be no dependency between assemble and sonar, Gradle will consider that it can run both tasks in parallel (even within a single project). While this isnā€™t the case yet, itā€™s the plan.

1 Like