Fix descriptor set generation when the project version changes - #184
Merged
alexander-yevsyukov merged 5 commits intoJun 25, 2026
Merged
Conversation
`GenerateProtoTask` is a cacheable task whose key is the `.proto` sources and
the compiler configuration only. The descriptor set file name embeds the
project version, and the `desc.ref` file points at that name. After a
version-only change the Proto sources are unchanged, so the build cache
restored a descriptor set produced for the previous version while `desc.ref`
referenced the new name — leaving Protobuf types unresolvable at runtime
(`UnknownTypeException`).
Declare the project version as an explicit, lazily-read input of the task so a
version change invalidates the cached descriptor set and regenerates it, and
its reference file, with matching names. Caching is preserved for all other
changes. This mirrors the `inputs.property("projectVersion", ...)` approach
already used in `LicenseReporter`.
Add a regression test to `BuildCacheSpec` that bumps the version with the
build cache on and asserts the descriptor set and its reference file are
regenerated consistently.
Fixes #183.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #184 +/- ##
=========================================
Coverage 90.45% 90.45%
Complexity 554 554
=========================================
Files 122 122
Lines 2241 2243 +2
Branches 311 311
=========================================
+ Hits 2027 2029 +2
Misses 93 93
Partials 121 121 🚀 New features to boost your workflow:
|
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a Gradle build-cache correctness issue in protobuf-setup-plugins where Protobuf descriptor set generation could be restored from cache after a version-only change, causing desc.ref to point at a non-existent (new-version) descriptor file name and leading to UnknownTypeException at runtime.
Changes:
- Declare the project version as an explicit (lazy) input to
GenerateProtoTaskinDescriptorSetFilePluginto ensure version bumps invalidate the cache entry. - Add a regression test in
BuildCacheSpecthat seeds the build cache, bumps the project version, runsclean, and asserts the descriptor set is regenerated and consistent withdesc.ref. - Includes routine version/dependency/config sync updates (notably in config-distributed paths).
Reviewed changes
Copilot reviewed 18 out of 20 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| version.gradle.kts | Bumps published version to 2.0.0-SNAPSHOT.402. |
| protobuf-setup-plugins/src/test/kotlin/io/spine/tools/protobuf/gradle/plugin/BuildCacheSpec.kt | Adds regression coverage for cache behavior across version bumps. |
| protobuf-setup-plugins/src/main/kotlin/io/spine/tools/protobuf/gradle/plugin/DescriptorSetFilePlugin.kt | Adds a lazy task input so version changes invalidate the build-cache entry for descriptor generation. |
| init-submodules | Config-sync change (config-managed; out of scope here). |
| docs/dependencies/pom.xml | Updates docs dependency metadata version to .402. |
| docs/dependencies/dependencies.md | Regenerates dependency report for .402 (including new generation timestamp). |
| buildSrc/src/main/kotlin/io/spine/dependency/test/Testcontainers.kt | Adds Testcontainers coordinates (buildSrc/config-managed; out of scope here). |
| buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt | Updates local ToolBase versions (buildSrc/config-managed; out of scope here). |
| buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt | Updates Core JVM compiler versions (buildSrc/config-managed; out of scope here). |
| buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvm.kt | Updates Core JVM version (buildSrc/config-managed; out of scope here). |
| buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt | Updates compiler fallback versions (buildSrc/config-managed; out of scope here). |
| buildSrc/src/main/kotlin/io/spine/dependency/lib/PerfMark.kt | Adds PerfMark coordinates (buildSrc/config-managed; out of scope here). |
| buildSrc/src/main/kotlin/io/spine/dependency/lib/GoogleCloud.kt | Updates Google Cloud library versions (buildSrc/config-managed; out of scope here). |
| buildSrc/src/main/kotlin/io/spine/dependency/lib/GoogleApis.kt | Updates Google API library versions (buildSrc/config-managed; out of scope here). |
| .idea/kotlinc.xml | IDE config sync (config-managed; out of scope here). |
| .gitignore | Shared config block updates (config-managed; out of scope here). |
| .github/workflows/secret-scan.yml | New workflow (config-distributed per PR description; out of scope here). |
| .github/workflows/build-on-ubuntu.yml | Workflow updates (config-managed; out of scope here). |
| .claude/settings.json | Claude settings sync (config-managed; out of scope here). |
Files not reviewed (1)
- .idea/kotlinc.xml: Generated file
Address review feedback on PR #184: the descriptor set file name is derived from the full Maven coordinates (group, artifact ID, version, classifier), so keying the `GenerateProtoTask` cache on the project version alone left a group- or artifact-ID change able to restore a descriptor set produced under a different name — the same `desc.ref`/descriptor mismatch the fix set out to prevent. Key the task on the computed descriptor set file name instead, which already embeds every naming component. This still fixes the reported version-bump case (#183) and additionally covers group, artifact-ID, and classifier changes. The input is read from the same `descriptorSetFile` used for the output path, so the cache key and the produced name can never disagree. Add a regression test that changes only the project group (version unchanged) and asserts the descriptor set is regenerated rather than restored from the build cache. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
armiol
approved these changes
Jun 25, 2026
alexander-yevsyukov
deleted the
fix-descriptor-generation-when-version-changes
branch
June 25, 2026 08:02
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.
Summary
Fixes #183.
GenerateProtoTaskis a cacheable task whose key is the.protosources and thecompiler configuration only. The descriptor set file name is derived from the project's
full Maven coordinates (
<group>_<artifactId>_<version>_<classifier>.desc), and thedesc.reffile points at that name. After a coordinate-only change (most commonly aversion bump) the
.protosources are unchanged, so with the Gradle build cache on,generateProtois restored from the cache — bringing back a descriptor set produced underthe previous name while
desc.refreferences the new name. The mismatch leavesProtobuf types unresolvable at runtime (
UnknownTypeException), which surfaces asintermittent, hard-to-diagnose CI/test failures after any version bump.
Fix
DescriptorSetFilePluginnow declares the descriptor set file name as an explicitinput of the
GenerateProtoTask:inputs.property("descriptorSetName", descriptorSetFile.name)The name embeds every output-determining coordinate (group, artifact ID, version,
classifier), so any change to it invalidates the cache key and regenerates the descriptor
set together with its
desc.ref— while caching is preserved for every other change. Theinput is read from the same
descriptorSetFileused for the output path, so the cache keyand the produced name can never disagree. Caching stays on; only the cache key is
corrected.
Tests
Added regression tests to
BuildCacheSpecthat seed the build cache, change onecoordinate (the version in one test, the group in another) leaving the
.protosources unchanged, run
cleanwith the cache on, then assert thatgenerateProtore-executes instead of restoring a stale descriptor and that the descriptor set and
desc.refare consistent at the new coordinates. Each test fails without the fix(
generateProtoisFROM_CACHE, stale name) and passes with it.Verification:
./gradlew build dokkaGeneratepasses; all tests in:protobuf-setup-pluginspass; detekt and Dokka are clean.Note for reviewers
Beyond the descriptor-set fix, this branch also carries a routine
configsubmodule +dependency sync and the
2.0.0-SNAPSHOT.401 → .402version bump (pre-existing branchpreparation). Those config-distributed files are owned by the
configrepository and areout of scope for review here.
🤖 Generated with Claude Code