SCANCLI-223 Experiment with the Gradle Tooling API#278
Conversation
| sonar.projectBaseDir=/home/sebastian.zumbrunn/code/sonar-scanner-engine | ||
| sonar.sources= | ||
| sonar.tests= | ||
| sonar.exclusions=cloud/license-api/**,cloud/plugins/sonar-xoo-plugin/**,cloud/process-executor/**,cloud/sarif-parser/**,cloud/sonar-scanner-engine/**,cloud/sonar-scanner-protocol/**,cloud/sensor-test-fixtures/**,cloud/sonar-core/**,cloud/sonar-scanner-engine-light/**,cloud/sonar-scanner-extension-a3s/**,cloud/sonar-scanner-extension-api/**,cloud/sonar-scanner-extension-architecture/**,cloud/sonar-scanner-extension-sca/**,cloud/sonar-scanner-plugin-framework/**,cloud/sonar-scanner-report-viewer/**,cloud/sonar-scanner-spring-di/**,cloud/webapi-client/**,server/plugins/sonar-xoo-plugin/**,server/private/core-extension-common/**,server/private/core-extension-developer-scanner/**,server/private/license-api/**,server/sonar-scanner-engine/**,server/sonar-scanner-protocol/**,server/sonar-core/**,server/sonar-plugin-api-impl/**,server/sonar-ws/**,shared/log-utils/**,shared/plugin-api-scanner-impl/**,shared/protobuf-utils/**,shared/scanner-engine-commons/**,shared/sonar-channel/**,shared/sonar-duplications/**,shared/sonar-scanner-extension-framework/** | ||
| sonar.modules=cloud_license_api,cloud_plugins_sonar_xoo_plugin,cloud_process_executor,cloud_sarif_parser,cloud_scanner_engine_cloud,cloud_scanner_engine_protocol_cloud,cloud_sensor_test_fixtures,cloud_sonar_core,cloud_sonar_scanner_engine_light,cloud_sonar_scanner_extension_a3s,cloud_sonar_scanner_extension_api,cloud_sonar_scanner_extension_architecture,cloud_sonar_scanner_extension_sca,cloud_sonar_scanner_plugin_framework,cloud_sonar_scanner_report_viewer,cloud_sonar_scanner_spring_di,cloud_webapi_client,server_plugins_sonar_xoo_plugin,server_private_core_extension_common,server_private_core_extension_developer_scanner,server_private_license_api,server_scanner_engine_community,server_scanner_engine_protocol_server,server_sonar_core,server_sonar_plugin_api_impl,server_sonar_ws,shared_log_utils,shared_plugin_api_scanner_impl,shared_protobuf_utils,shared_scanner_engine_commons,shared_sonar_channel,shared_sonar_duplications,shared_sonar_scanner_extension_framework | ||
| cloud_license_api.sonar.projectBaseDir=/home/sebastian.zumbrunn/code/sonar-scanner-engine/cloud/license-api | ||
| cloud_license_api.sonar.exclusions= | ||
| cloud_license_api.sonar.sources=/home/sebastian.zumbrunn/code/sonar-scanner-engine/cloud/license-api/src/main/java | ||
| cloud_license_api.sonar.tests=/home/sebastian.zumbrunn/code/sonar-scanner-engine/cloud/license-api/src/test/java | ||
| cloud_license_api.sonar.java.libraries=/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/com.google.code.findbugs/jsr305/3.0.2/25ea2e8b0c338a877313bd4672d3fe056ea78f0d/jsr305-3.0.2.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.sonarsource.api.plugin/sonar-plugin-api/13.8.0.4399/6667ac51f1440d2c6f6170e380555b47b66cd76c/sonar-plugin-api-13.8.0.4399.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/1.7.30/b5a4b6d16ab13e34a88fae84c35cd5d68cac922c/slf4j-api-1.7.30.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/com.google.guava/guava/33.6.0-jre/c376b13067cc99a5774403530953f7b05a91e218/guava-33.6.0-jre.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-csv/1.14.1/467354980fade8528b6a9f9bdf7f4f19ab9b3373/commons-csv-1.14.1.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/commons-codec/commons-codec/1.21.0/d95f998db5f89900fe895daf6cd2cddcb2f1d64b/commons-codec-1.21.0.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.22.0/5b1e18bc0ad651ed878029d83f88d9c8189fd51e/commons-io-2.22.0.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-lang3/3.20.0/65897b3e5731220962e659e001904af3c3cbeba9/commons-lang3-3.20.0.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/2.0.18/78a9e7a37cd6360e0b818e86341b24123d28d4df/slf4j-api-2.0.18.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/com.google.guava/failureaccess/1.0.3/aeaffd00d57023a2c947393ed251f0354f0985fc/failureaccess-1.0.3.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/com.google.guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/b421526c5f297295adef1c886e5246c39d4ac629/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.jspecify/jspecify/1.0.0/7425a601c1c7ec76645a78d22b8c6a627edee507/jspecify-1.0.0.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/com.google.errorprone/error_prone_annotations/2.47.0/e64e70c8e2b5a30ce7f1b6c9e3eb7016881e0411/error_prone_annotations-2.47.0.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/3.1/a892ca9507839bbdb900d64310ac98256cab992f/j2objc-annotations-3.1.jar | ||
| cloud_license_api.sonar.java.test.libraries=/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/com.google.code.findbugs/jsr305/3.0.2/25ea2e8b0c338a877313bd4672d3fe056ea78f0d/jsr305-3.0.2.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.sonarsource.api.plugin/sonar-plugin-api/13.8.0.4399/6667ac51f1440d2c6f6170e380555b47b66cd76c/sonar-plugin-api-13.8.0.4399.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/1.7.30/b5a4b6d16ab13e34a88fae84c35cd5d68cac922c/slf4j-api-1.7.30.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/com.google.guava/guava/33.6.0-jre/c376b13067cc99a5774403530953f7b05a91e218/guava-33.6.0-jre.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-csv/1.14.1/467354980fade8528b6a9f9bdf7f4f19ab9b3373/commons-csv-1.14.1.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/commons-codec/commons-codec/1.21.0/d95f998db5f89900fe895daf6cd2cddcb2f1d64b/commons-codec-1.21.0.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.22.0/5b1e18bc0ad651ed878029d83f88d9c8189fd51e/commons-io-2.22.0.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-lang3/3.20.0/65897b3e5731220962e659e001904af3c3cbeba9/commons-lang3-3.20.0.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/2.0.18/78a9e7a37cd6360e0b818e86341b24123d28d4df/slf4j-api-2.0.18.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/com.google.guava/failureaccess/1.0.3/aeaffd00d57023a2c947393ed251f0354f0985fc/failureaccess-1.0.3.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/com.google.guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/b421526c5f297295adef1c886e5246c39d4ac629/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.jspecify/jspecify/1.0.0/7425a601c1c7ec76645a78d22b8c6a627edee507/jspecify-1.0.0.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/com.google.errorprone/error_prone_annotations/2.47.0/e64e70c8e2b5a30ce7f1b6c9e3eb7016881e0411/error_prone_annotations-2.47.0.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/3.1/a892ca9507839bbdb900d64310ac98256cab992f/j2objc-annotations-3.1.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.junit.jupiter/junit-jupiter-params/6.1.0/6e6dcbd963a6c16217350535a640e1c0fde0d619/junit-jupiter-params-6.1.0.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.junit.jupiter/junit-jupiter-api/6.1.0/5376d10370f32af4f3b1b7a378906ee58dcdacb3/junit-jupiter-api-6.1.0.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.junit.platform/junit-platform-commons/6.1.0/3bb0447338b81f4396648c406d3e1c22f65f689/junit-platform-commons-6.1.0.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.junit.jupiter/junit-jupiter/6.1.0/52aef21f8c9fa491ff7eb20008e39102a8479f79/junit-jupiter-6.1.0.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.assertj/assertj-core/3.27.7/2f4f64f054c9d618d4b1d89e7611559f5e2cfff7/assertj-core-3.27.7.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/junit/junit/4.13.2/8ac9e16d933b6fb43bc7f576336b8f4d7eb5ba12/junit-4.13.2.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/net.bytebuddy/byte-buddy/1.18.3/c35b2e4bf0e22e4d492936d46506bb2e6d8fafc8/byte-buddy-1.18.3.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-core/1.3/42a25dc3219429f0e5d060061f71acb49bf010a0/hamcrest-core-1.3.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.opentest4j/opentest4j/1.3.0/152ea56b3a72f655d4fd677fc0ef2596c3dd5e6e/opentest4j-1.3.0.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.apiguardian/apiguardian-api/1.1.2/a231e0d844d2721b0fa1b238006d15c6ded6842a/apiguardian-api-1.1.2.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.junit.jupiter/junit-jupiter-engine/6.1.0/82414ee1a0308d2f096c37d317b93b66c13dbb9a/junit-jupiter-engine-6.1.0.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.junit.platform/junit-platform-launcher/6.1.0/78124de837a3e0b9e4e32a2c80ba47117f7f8c60/junit-platform-launcher-6.1.0.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.junit.vintage/junit-vintage-engine/6.1.0/af18e7c935d0b0a31f484adab7d9d15083b15b09/junit-vintage-engine-6.1.0.jar,/home/sebastian.zumbrunn/.gradle/caches/modules-2/files-2.1/org.junit.platform/junit-platform-engine/6.1.0/754271e8493a0be2838f3500b30971969b8603d0/junit-platform-engine-6.1.0.jar | ||
| cloud_license_api.sonar.java.source=17 | ||
| cloud_plugins_sonar_xoo_plugin.sonar.projectBaseDir=/home/sebastian.zumbrunn/code/sonar-scanner-engine/cloud/plugins/sonar-xoo-plugin | ||
| cloud_plugins_sonar_xoo_plugin.sonar.exclusions= | ||
| cloud_plugins_sonar_xoo_plugin.sonar.sources=/home/sebastian.zumbrunn/code/sonar-scanner-engine/cloud/plugins/sonar-xoo-plugin/src/main/java |
There was a problem hiding this comment.
💡 Quality: Committed generated sample leaks developer home path/username
scanner-engine-sonar-project.properties is a 234-line generated artifact committed at the repository root. Every entry contains absolute, machine-specific paths from a developer's workstation (e.g. /home/sebastian.zumbrunn/code/... and /home/sebastian.zumbrunn/.gradle/caches/...), embedding a personal username and local Gradle cache layout. Generated/sample output with hardcoded local paths is not reproducible, can go stale, and unnecessarily exposes a developer's environment.
If this sample is needed for documentation, consider moving it under docs/ with sanitized/placeholder paths (e.g. /path/to/project), or omit it and reference the comparison doc instead. At minimum it should not live at the repo root.
Was this helpful? React with 👍 / 👎
b4acdfe to
0ed596e
Compare
| private static IdeaProject loadIdeaProject(Path projectRoot) { | ||
| GradleConnector connector = GradleConnector.newConnector() | ||
| .forProjectDirectory(projectRoot.toFile()); | ||
|
|
||
| try (ProjectConnection connection = connector.connect()) { | ||
| return connection.getModel(IdeaProject.class); | ||
| } catch (Exception e) { | ||
| throw new IllegalStateException("Failed to load the Gradle IDEA model from " + projectRoot, e); | ||
| } | ||
| } |
There was a problem hiding this comment.
⚠️ Edge Case: Dump mode triggers a real Gradle build with no version pinning
loadIdeaProject creates a GradleConnector with only forProjectDirectory(...) and then calls connection.getModel(IdeaProject.class). Without useGradleVersion(), useDistribution(), or useBuildDistribution(), the Tooling API resolves the Gradle distribution from the target project's wrapper (or downloads the connector's default), and configuring the IDEA model executes a full Gradle configuration phase on the user's machine. Consequences: (1) network access to download a Gradle distribution may be required, which can fail in offline/CI environments; (2) the resolved Gradle version may be incompatible with tooling-api 8.14.5 (the Tooling API only supports a bounded range of Gradle versions); (3) any build-script error surfaces as a wrapped IllegalStateException. For a CLI feature this behavior should be documented and ideally the supported Gradle version range validated up front. Since this is an experimental/draft feature this is acceptable for now but should be addressed before shipping.
Pin or validate the Gradle version and document the runtime Gradle execution requirement.:
// Optionally pin / validate the Gradle version to avoid surprises:
GradleConnector connector = GradleConnector.newConnector()
.forProjectDirectory(projectRoot.toFile());
// e.g. .useGradleVersion("8.14.5") or document that the project's wrapper is used
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
| <artifactsToPublish>${project.groupId}:${project.artifactId}:zip,${project.groupId}:${project.artifactId}:zip:linux-x64,${project.groupId}:${project.artifactId}:zip:linux-aarch64,${project.groupId}:${project.artifactId}:zip:windows-x64,${project.groupId}:${project.artifactId}:zip:macosx-x64,${project.groupId}:${project.artifactId}:zip:macosx-aarch64,${project.groupId}:${project.artifactId}:json:cyclonedx</artifactsToPublish> | ||
|
|
||
| <maven.compiler.release>11</maven.compiler.release> | ||
| <gradle.tooling.api.version>8.14.5</gradle.tooling.api.version> |
There was a problem hiding this comment.
💡 Quality: Experimental feature adds ~3MB and a new external repo to the CLI
Adding gradle-tooling-api pulls a sizeable dependency into the shipped distribution: the requireFilesSize enforcer rule was bumped from 9.2-9.3MB to 12.1-12.2MB, i.e. roughly +3MB on every published artifact (linux/windows/macos x64/aarch64). It also introduces a new required Maven repository (https://repo.gradle.org/gradle/libs-releases) to the build. For an experimental/draft feature, weighing this permanent size and build-dependency cost against the value is worth doing before merge — consider whether the dumper should ship in the main CLI artifact at all, or be a separate/optional module.
Re-evaluate bundling the tooling-api into the core CLI distribution.:
<!-- Consider scoping the gradle-tooling-api dependency to a separate artifact
or feature module rather than bundling ~3MB into every CLI distribution. -->
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
| if (cli.isDumpGradleJavaProperties()) { | ||
| configureLogging(cli.properties()); | ||
| dumpGradleJavaProperties(); | ||
| displayExecutionResult(stats, SUCCESS); | ||
| status = Exit.SUCCESS; | ||
| return; | ||
| } |
There was a problem hiding this comment.
💡 Quality: Dump mode bypasses skip handling and uses only CLI properties
In analyze(), the cli.isDumpGradleJavaProperties() branch returns early before conf.properties() and checkSkip(p) are evaluated, and it configures logging from cli.properties() only (ignoring global/project sonar-scanner.properties and environment settings). As a result sonar.scanner.skip is not honored in dump mode, and verbose/debug logging configured via property files (rather than -D/-X) will not take effect. This may be intentional for the POC, but if dump mode is meant to behave consistently with normal runs it should resolve the full property set (or at least honor the skip flag) before generating output.
Resolve full properties and honor skip/logging in dump mode.:
if (cli.isDumpGradleJavaProperties()) {
Properties p = conf.properties();
checkSkip(p);
configureLogging(p);
dumpGradleJavaProperties();
displayExecutionResult(stats, SUCCESS);
status = Exit.SUCCESS;
return;
}
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
CI failed: The build failed because the 'gradle-tooling-api' dependency could not be resolved from the internal SonarSource repository.OverviewThe build failed during the dependency resolution phase of the Maven lifecycle. A single failure pattern was identified where a new dependency requirement could not be satisfied by the configured artifact repository. FailuresMissing Dependency: gradle-tooling-api (confidence: high)
Summary
Code Review
|
| Auto-apply | Compact | Unblock |
|
|
|
Was this helpful? React with 👍 / 👎 | Gitar
Summary by Gitar
--dump-gradle-java-propertiesoption to generatesonar-project.propertiesfrom Gradle builds.GradleJavaPropertiesDumperto interface with thegradle-tooling-apiand map project metadata.gradle-tooling-apidependency inpom.xml.sonar-scanner-engine-issue-comparison.mddetailing the semantic analysis gap between Gradle and property-dumped scans.scanner-engine-sonar-project.propertiesfile.This will update automatically on new commits.