feat[oss-licenses]: Add full Gradle Configuration Cache support#365
Merged
timothyfroehlich merged 12 commits intoMar 3, 2026
Conversation
* Update Android Gradle Plugin to 9.0.1 * Update Gradle Wrapper to 9.3.1 * Update Kotlin plugin to 2.3.10 * Update Protobuf, Guava, Truth, and Gson * Bump version to 0.10.11-SNAPSHOT
* Remove `markNotCompatibleWithConfigurationCache` from `OssLicensesPlugin` * Add `testConfigurationCache` to `EndToEndTest` to verify cache reuse * Suppress Protobuf security warnings in `gradle.properties` caused by AGP dependencies
* Refactor `DependencyUtil` to resolve artifacts using `ArtifactView` and `ArtifactResolutionQuery` instead of accessing `ResolvedConfiguration` directly. * Pass resolved artifacts as inputs to `LicensesTask` via a new `artifactFiles` property to avoid project access during execution. * Add `ArtifactFiles` data class to hold resolved POM and library files. * Update `OssLicensesPlugin` to provide lazy artifact resolution. * Update `EndToEndTest` to verify configuration cache compatibility.
xyarco
previously approved these changes
Mar 3, 2026
rlazo
previously approved these changes
Mar 3, 2026
This commit updates the copyright headers for all modified Google-owned source files to include the 2026 year range, as per Google's open-source policy. For files missing headers, the original publication year was retrieved from Git history and used as the start of the range.
1aff4c7 to
3404aa1
Compare
xyarco
approved these changes
Mar 3, 2026
This was referenced Mar 3, 2026
Closed
liutikas
reviewed
Mar 9, 2026
| markNotCompatibleWithConfigurationCache(it) | ||
| it.dependenciesJson.set(dependencyTask.flatMap { it.dependenciesJson }) | ||
|
|
||
| it.artifactFiles.set(project.provider { |
Collaborator
There was a problem hiding this comment.
Wrapping into a project.provider is usually a code smell for the underlying provider not being lazy.
Why does DependencyUtil.resolveArtifacts not return a lazy FileCollection?
Member
Author
There was a problem hiding this comment.
It should. I'll follow up with a fix.
timothyfroehlich
added a commit
that referenced
this pull request
Mar 10, 2026
This commit modernizes the oss-licenses-plugin for Gradle 9.4 compatibility and enables full support for the Gradle Build Cache. Key issues resolved: - Implicit Dependency Failures: Gradle 9.x enforces strict task graph validation. The redundant LicensesCleanUpTask was removed because it conflicted with generation tasks over the build directory. Standard 'clean' now handles this idiomatically. - Plugin Validation Errors: Modernized tasks to pass 'validatePlugins' by opting into @CacheableTask and implementing property normalization with @PathSensitive. - Technical Debt: Refactored artifact resolution to use the Lazy Provider API, addressing feedback from PR #365 and improving configuration phase performance. - Test Matrix: Modernized E2E tests to include AGP 9.0/9.1/9.2 and enabled strict configuration cache validation across the matrix. Closes #356, #300, #299, #246.
mikepenz
added a commit
to mikepenz/AboutLibraries
that referenced
this pull request
Apr 13, 2026
…solation compatible Refactor dependency resolution so all `Project` access happens during the configuration phase, never at task execution time. The plugin now passes both `--configuration-cache` and `org.gradle.unsafe.isolated-projects=true` without discarding the cache entry, while producing byte-for-byte identical output to the previous implementation. Approach mirrors google/play-services-plugins#365 (oss-licenses-plugin): - `BaseAboutLibrariesTask` exposes `configToCoordinateKeys` (`@Input MapProperty<String, String>`) populated lazily via `resolutionResult.rootComponent.map {}`, encoding coordinates as plain strings so the value type stays config-cache serialisable. - `pomFileMap` (`@Internal MapProperty<String, String>`) holds `<group:artifact:version> -> POM file path`, populated via a `project.provider {}` that runs `resolvePomFiles` during config-cache store. `pomFiles` (`@InputFiles ConfigurableFileCollection`) is derived from the same `MapProperty` so the heavy resolution executes exactly once per build, while still tracking POM content for UP-TO-DATE checks. - `resolvePomFiles` walks every selected configuration's `ResolvedComponentResult` to gather coordinates (incl. platform/BOM dependencies), fetches direct POMs in a single detached configuration, then iteratively resolves parent POMs ONE AT A TIME via per-coordinate detached configurations. The one-at-a-time fetch is required because Gradle silently dedupes overlapping `group:artifact` versions inside a single detached configuration, which previously caused parent metadata loss for transitives like `guava-parent:26.0-android` vs `guava-parent:33.3.1-jre`. - `MavenXpp3Reader` is used during config phase to extract `<parent>` coordinates so the entire parent-POM hierarchy is pre-resolved. The execution-time `Maven Model Builder` then loads parents from the pre-populated `pomFileMap` instead of an on-demand `ModelResolver` that needed `project.dependencies` / `project.configurations`. - `DependencyCollector` is split into `loadDependencyCoordinates(root)` (config time, pure walk over the resolution tree) and `loadDependenciesFromCoordinates(coords, pomFileMap)` (execution time, pure POM parsing). A defensive `syntheticModelSource` fallback handles the rare case of a parent POM that could not be resolved. - `exclusionPatterns` switches from `SetProperty<Pattern>` to `SetProperty<String>` because `java.util.regex.Pattern` is not config-cache serialisable; patterns are compiled to `Regex` once per `process()` invocation. - `AboutLibrariesIdTask` reads `configurationNames` instead of the now- removed `variantToDependencyData` property. - `AboutLibrariesExportComplianceTask` moves three previously class-level mutable `HashSet`/`HashMap` fields into `action()` locals so the task is side-effect-free. - `Configuration.isTest` no longer traverses `config.hierarchy`, removing configuration-graph realisation from the cheap filter step. Test coverage (37 tests / 0 failures across 6 suites): - `OutputCorrectnessTest` (new, 13 tests): parent-POM inheritance, multi-version parent POM regression, BOM include/exclude with `includePlatform`, `compileOnly` / `runtimeOnly` / `api` collection, sub-project skipping, deterministic output across runs, exact-version pinning, exclusion-regex (incl. alternation), full-field smoke test. - `ConfigurationCacheTest` adds: multi-version parent POM cache survival, end-to-end project-isolation test (`org.gradle.unsafe.isolated-projects` + `--configuration-cache`). - `PerformanceTest` threshold raised to 30s for cold-daemon environments. - All test files updated to gson 2.11.0 / slf4j 2.0.16 / jackson 2.18.2. - `FunctionalTest` filename corrected to `aboutlibraries.json`. End-to-end verification: `gradle exportLibraryDefinitions --configuration-cache` with `org.gradle.unsafe.isolated-projects=true` on a 25-library project (incl. platform BOM, compileOnly, runtimeOnly) produces an MD5-identical 697-line JSON to the OLD implementation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
mikepenz
added a commit
to mikepenz/AboutLibraries
that referenced
this pull request
Apr 13, 2026
…solation compatible Refactor dependency resolution so all `Project` access happens during the configuration phase, never at task execution time. The plugin now passes both `--configuration-cache` and `org.gradle.unsafe.isolated-projects=true` without discarding the cache entry, while producing byte-for-byte identical output to the previous implementation. Approach mirrors google/play-services-plugins#365 (oss-licenses-plugin): - `BaseAboutLibrariesTask` exposes `configToCoordinateKeys` (`@Input MapProperty<String, String>`) populated lazily via `resolutionResult.rootComponent.map {}`, encoding coordinates as plain strings so the value type stays config-cache serialisable. - `pomFileMap` (`@Internal MapProperty<String, String>`) holds `<group:artifact:version> -> POM file path`, populated via a `project.provider {}` that runs `resolvePomFiles` during config-cache store. `pomFiles` (`@InputFiles ConfigurableFileCollection`) is derived from the same `MapProperty` so the heavy resolution executes exactly once per build, while still tracking POM content for UP-TO-DATE checks. - `resolvePomFiles` walks every selected configuration's `ResolvedComponentResult` to gather coordinates (incl. platform/BOM dependencies), fetches direct POMs in a single detached configuration, then iteratively resolves parent POMs ONE AT A TIME via per-coordinate detached configurations. The one-at-a-time fetch is required because Gradle silently dedupes overlapping `group:artifact` versions inside a single detached configuration, which previously caused parent metadata loss for transitives like `guava-parent:26.0-android` vs `guava-parent:33.3.1-jre`. - `MavenXpp3Reader` is used during config phase to extract `<parent>` coordinates so the entire parent-POM hierarchy is pre-resolved. The execution-time `Maven Model Builder` then loads parents from the pre-populated `pomFileMap` instead of an on-demand `ModelResolver` that needed `project.dependencies` / `project.configurations`. - `DependencyCollector` is split into `loadDependencyCoordinates(root)` (config time, pure walk over the resolution tree) and `loadDependenciesFromCoordinates(coords, pomFileMap)` (execution time, pure POM parsing). A defensive `syntheticModelSource` fallback handles the rare case of a parent POM that could not be resolved. - `exclusionPatterns` switches from `SetProperty<Pattern>` to `SetProperty<String>` because `java.util.regex.Pattern` is not config-cache serialisable; patterns are compiled to `Regex` once per `process()` invocation. - `AboutLibrariesIdTask` reads `configurationNames` instead of the now- removed `variantToDependencyData` property. - `AboutLibrariesExportComplianceTask` moves three previously class-level mutable `HashSet`/`HashMap` fields into `action()` locals so the task is side-effect-free. - `Configuration.isTest` no longer traverses `config.hierarchy`, removing configuration-graph realisation from the cheap filter step. Test coverage (37 tests / 0 failures across 6 suites): - `OutputCorrectnessTest` (new, 13 tests): parent-POM inheritance, multi-version parent POM regression, BOM include/exclude with `includePlatform`, `compileOnly` / `runtimeOnly` / `api` collection, sub-project skipping, deterministic output across runs, exact-version pinning, exclusion-regex (incl. alternation), full-field smoke test. - `ConfigurationCacheTest` adds: multi-version parent POM cache survival, end-to-end project-isolation test (`org.gradle.unsafe.isolated-projects` + `--configuration-cache`). - `PerformanceTest` threshold raised to 30s for cold-daemon environments. - All test files updated to gson 2.11.0 / slf4j 2.0.16 / jackson 2.18.2. - `FunctionalTest` filename corrected to `aboutlibraries.json`. End-to-end verification: `gradle exportLibraryDefinitions --configuration-cache` with `org.gradle.unsafe.isolated-projects=true` on a 25-library project (incl. platform BOM, compileOnly, runtimeOnly) produces an MD5-identical 697-line JSON to the OLD implementation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This PR introduces full support for Gradle's Configuration Cache to the
oss-licenses-plugin, allowing for significant build speed improvements in subsequent runs.Key Architectural Changes
Unified Lazy Dependency Resolution:
DependencyUtil.groovyto perform artifact resolution during the configuration phase instead of the execution phase.ArtifactViewandArtifactResolutionQueryagainst the variant'sruntimeConfiguration.Provider.LicensesTaskvia a new@Inputproperty (MapProperty<String, ArtifactFiles> artifactFiles), ensuring the task remains a pure, cacheable function.Test Infrastructure & Parallelization:
EndToEndTest.ktto remove the previous@Parameterizedsetup. The tests are now "unrolled" into concrete subclasses, allowing Gradle to execute them in parallel, significantly reducing CI time.build.gradle.ktswhere thetesttask'sdoFirstclosure was capturing the Gradle script object, which blocked configuration caching.DependencyResolutionTest.javato programmatically verify that the resolution engine correctly handles version conflicts, transitives, and scoped dependencies.testAbsentDependencyReportto verify correct fallback behavior on debug variants where the AGP dependency report is absent.Version & Tooling:
0.11.0for release.9.0.1and Gradle Wrapper to9.3.1.Related Changes
ArtifactFiles.groovydata class.