Skip to content

fix: refuse a KSP that does not pair with the project's Kotlin version - #584

Open
zantvoort wants to merge 1 commit into
mainfrom
fix/gradle-plugin-ksp-mismatch
Open

zantvoort wants to merge 1 commit into
mainfrom
fix/gradle-plugin-ksp-mismatch

Conversation

@zantvoort

Copy link
Copy Markdown
Collaborator

Fixes #575

What happened

With st.orm on a root project's classpath, a subproject that applies id("com.google.devtools.ksp") without a version inherits the bundled KSP 2.3.10. The plugin only asked whether a ksp configuration exists, never which KSP created it, so on Kotlin 2.0 and 2.1 the build ran a KSP that does not pair with the compiler and failed later inside the Kotlin Gradle plugin with a linkage error that names neither KSP nor Kotlin (KotlinJvmCompilerOptions.getJvmDefault()).

What changed

  • The plugin reads the version of the KSP plugin instance the project holds (the KSP_VERSION constant the KSP Gradle plugin carries, through that instance's classloader, so the lookup reaches the KSP that actually resolved) and refuses one that does not pair with the project's Kotlin version. The failure names both versions, the paired plugin line to declare, and the multi-project shape: declare it once in the root plugins block with apply false and apply it in each subproject without a version. The check runs only when the metamodel processor is on, since that is what runs inside KSP.
  • Pairing is decided per Kotlin line: a Kotlin-paired KSP (<kotlin>-<ksp>) pairs with the line its prefix names, a Kotlin-independent KSP (2.3+) with every line whose recommendation is such a build. A newer KSP patch than the bundled one is therefore not refused.
  • Kotlin 2.2 joins the automatic path. KotlinVariants maps 2.2 to the bundled 2.3.10; a smoke test compiles a metamodel on Kotlin 2.2.21 with the bundled KSP, which settles the boundary the matrix comment claimed. The mismatch rule then covers Kotlin 2.0 and 2.1.
  • The missing-KSP failure derives its "Kotlin 2.2+" wording from the matrix instead of a literal.

Verified resolution shapes (Kotlin 2.1.21, run against the released 1.14.1 plugin before the change)

Root plugins block Subproject Resolved KSP
st.orm apply false ksp without version 2.3.10 (bundled, wrong)
st.orm apply false + ksp version "2.1.21-2.0.2" apply false ksp without version 2.1.21-2.0.2
st.orm apply false ksp version "2.1.21-2.0.2" "plugin is already on the classpath"

Tests

  • KotlinVariantsTest: the pairing rule and the new 2.2 mapping.
  • KspMismatchFunctionalTest (new, mavenLocal-resolved like KspAutoApplyFunctionalTest): a declared mismatch in a single project, a subproject inheriting the bundled KSP, the root apply false form wiring the processor into the paired KSP, a newer KSP patch on the same line accepted, and metamodel.set(false) leaving the choice to the build.
  • KspAutoApplyFunctionalTest: Kotlin 2.2.21 gets the bundled KSP applied; KotlinPathFunctionalTest gains the 2.2 row.
  • SmokeCompileTest: a Kotlin 2.2.21 entity compiles and generates its metamodel with the bundled KSP (smoke-gated as the other compiles).

./gradlew build -Dstorm.smoke=true: 40 functional tests, 0 failures.

Docs

docs/installation.md (boundary, refusal, multi-project shape), docs/getting-started.md, docs/ktor-integration.md, README.md, website/static/skills/storm-setup.md, tutorialTheme.js (kspRequired dropped on the Kotlin 2.2 variant, so the quickstart and REST tutorial snippets lose the KSP line there), and CHANGELOG.md (Unreleased entry, and the upgrade note about subprojects now says what to do on Kotlin 2.0 and 2.1). versioned_docs/ is untouched, so the doc change shows at /docs/next until the next release snapshots it.

The Gradle plugin compares the KSP the build resolved with the recommendation for the project's Kotlin version and fails with the paired plugin line to declare and where to put it, in the shape of the failure for a missing KSP. The version is read from the constant the applied KSP plugin instance carries, so the check reaches the KSP that actually resolved, the bundled one or one the build declared. A subproject that applies KSP without a version inherits the bundled one from a root classpath carrying st.orm; on Kotlin 2.0 and 2.1 that KSP fails inside the Kotlin Gradle plugin with a linkage error naming neither. In a multi-project build the paired KSP is declared once in the root plugins block with apply false, which beats the bundled preference.

Kotlin 2.2 joins the automatic path: the bundled KSP compiles a metamodel on Kotlin 2.2, which the smoke test settles, so the refusal covers Kotlin 2.0 and 2.1 only. The docs, the setup skill, the tutorial variants and the changelog carry the new boundary.

Fixes #575
@zantvoort zantvoort added this to the 1.14.2 milestone Sep 15, 2026
@codecov

codecov Bot commented Sep 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gradle plugin: refuse a KSP that does not pair with the project's Kotlin version

1 participant