ci: test against KSP, Gradle and Kotlin version matrices #145
Workflow file for this run
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
| name: Test | |
| on: | |
| pull_request: | |
| # Also run on main so the Gradle cache is seeded on the default branch; | |
| # pull_request caches are scoped to their own PR and can't be shared. | |
| push: | |
| branches: [ main ] | |
| # Weekly probe against whatever KSP is newest at the time — see ksp-latest. | |
| schedule: | |
| - cron: '0 6 * * 1' | |
| workflow_dispatch: | |
| permissions: | |
| checks: write | |
| contents: read | |
| jobs: | |
| test: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set up JDK | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '17' | |
| # Caches Gradle distribution, dependencies, and build caches. | |
| # Writes only on main (default), so PR runs read without thrashing quota. | |
| - name: Set up Gradle | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Run detekt | |
| run: ./gradlew detekt --continue | |
| - name: Upload detekt reports | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: detekt-reports | |
| path: '**/build/reports/detekt/' | |
| - name: Run tests | |
| run: ./gradlew :kraft-ksp:jvmTest --continue | |
| # Gradle plugin functional tests: real TestKit builds covering the | |
| # wiring, the kraft { } DSL and raw-KSP-args drift pair, error paths, | |
| # and an end-to-end mapper compile against the in-dev kraft artifacts. | |
| - name: Gradle plugin functional tests | |
| run: ./gradlew :kraft-gradle-plugin:test | |
| # Real two-module KMP build: the consumer's converter only exists in the | |
| # producer's klib, so a green build proves cross-module @KraftConverter | |
| # discovery works under kspCommonMainKotlinMetadata (klib classpath). | |
| - name: KMP cross-module integration test | |
| run: ./gradlew :integration-tests:kmp-consumer:jvmTest :integration-tests:kmp-consumer:compileKotlinJs | |
| # Expected-failure counterpart: two producer klibs publish the same converter | |
| # pair, so the consumer's KSP run MUST fail with the classpath ambiguity error. | |
| # Asserts both the failure and the user-facing message. | |
| - name: KMP cross-module ambiguity error test | |
| run: | | |
| set +e | |
| out=$(./gradlew -PkraftAmbiguityFixture=true :integration-tests:kmp-consumer-ambiguous:kspCommonMainKotlinMetadata --console=plain 2>&1) | |
| status=$? | |
| set -e | |
| if [ "$status" -eq 0 ]; then | |
| echo "Expected the ambiguous-consumer build to fail, but it succeeded." | |
| exit 1 | |
| fi | |
| echo "$out" | grep -q "Ambiguous @KraftConverter on the classpath for (kotlin.Int → kotlin.String)" || { | |
| echo "Build failed but without the expected ambiguity message. Output tail:" | |
| echo "$out" | tail -40 | |
| exit 1 | |
| } | |
| - name: Publish test results | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: test-results | |
| path: | | |
| kraft-ksp/build/reports/tests/jvmTest/ | |
| kraft-gradle-plugin/build/reports/tests/test/ | |
| - name: Publish JUnit report | |
| uses: mikepenz/action-junit-report@v6 | |
| if: always() | |
| with: | |
| report_paths: | | |
| kraft-ksp/build/test-results/jvmTest/**/*.xml | |
| kraft-gradle-plugin/build/test-results/test/**/*.xml | |
| # CI-10: KSP-version compatibility. The Gradle plugin functional tests generate | |
| # real consumer projects that apply the KSP plugin, so overriding | |
| # kraft.test.kspVersion exercises Kraft against a KSP other than the catalog's. | |
| # | |
| # Pinned legs: the floor Kraft is built on, plus the newest KSP known-good at | |
| # the time of writing. Deterministic, so a PR that breaks either one fails here | |
| # rather than in a consumer's build. | |
| ksp-compat: | |
| name: KSP ${{ matrix.ksp }} | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| ksp: | |
| - '2.3.3' # floor - the version in gradle/libs.versions.toml | |
| - '2.3.9' # newest known-good at 2026-07-21 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set up JDK | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '17' | |
| - name: Set up Gradle | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Gradle plugin functional tests (KSP ${{ matrix.ksp }}) | |
| run: ./gradlew :kraft-gradle-plugin:test -Pkraft.test.kspVersion=${{ matrix.ksp }} | |
| - name: Publish test results | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: test-results-ksp-${{ matrix.ksp }} | |
| path: kraft-gradle-plugin/build/reports/tests/test/ | |
| # CI-10: Gradle-version compatibility. TestKit runs the generated consumer | |
| # builds on the Gradle running the tests unless kraft.test.gradleVersion says | |
| # otherwise, so without this every run only ever proved Gradle 8.13 works. | |
| # | |
| # 9.6.x drops the Android leg: AGP 8.x (both 8.11.2 and the latest 8.13.2) | |
| # calls org.gradle.api.problems.internal.InternalProblems, removed in Gradle | |
| # 9.6.0, so the Android plugin cannot load. AGP 9.x fixes that, but it ships | |
| # built-in Kotlin and Kraft does not detect that setup yet (F-17). 9.5.1 is | |
| # the last Gradle before the removal, so it still covers Android on AGP 8.x. | |
| gradle-compat: | |
| name: Gradle ${{ matrix.gradle }} | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - gradle: '8.13' # floor - the wrapper version | |
| excludeTags: '' | |
| - gradle: '9.5.1' # last Gradle 9 that can still load AGP 8.x | |
| excludeTags: '' | |
| - gradle: '9.6.1' # newest; Android excluded (see above) | |
| excludeTags: 'android' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set up JDK | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '17' | |
| - name: Set up Gradle | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Gradle plugin functional tests (Gradle ${{ matrix.gradle }}) | |
| run: >- | |
| ./gradlew :kraft-gradle-plugin:test | |
| -Pkraft.test.gradleVersion=${{ matrix.gradle }} | |
| -PkraftExcludeTags=${{ matrix.excludeTags }} | |
| - name: Publish test results | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: test-results-gradle-${{ matrix.gradle }} | |
| path: kraft-gradle-plugin/build/reports/tests/test/ | |
| # CI-10: the newest stack Kraft is known to work on, two Kotlin minors above | |
| # its own 2.2.21 floor. This is the job that backs the claim that a Kotlin or | |
| # KSP upgrade does not strand consumers -- it is tested, not assumed. | |
| # | |
| # Android is excluded here for two separate reasons, neither of them a bug: | |
| # 1. AGP 8.x cannot load on Gradle >= 9.6.0 (removed Problems internals). | |
| # 2. Moving to AGP 9.x is not a drop-in for this fixture: AGP 9 ships | |
| # built-in Kotlin, so applying org.jetbrains.kotlin.android alongside it | |
| # is an error. The fixture (and Kraft's own plugin detection) still | |
| # assume the kotlin-android plugin -- tracked as F-17. | |
| # Android coverage lives on the gradle-compat 8.13 and 9.5.1 legs. | |
| modern-stack: | |
| name: Kotlin 2.4.10 / KSP 2.3.9 / Gradle 9.6.1 | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set up JDK | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '17' | |
| - name: Set up Gradle | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Gradle plugin functional tests (newest stack) | |
| run: >- | |
| ./gradlew :kraft-gradle-plugin:test | |
| -Pkraft.test.kotlinVersion=2.4.10 | |
| -Pkraft.test.kspVersion=2.3.9 | |
| -Pkraft.test.gradleVersion=9.6.1 | |
| -PkraftExcludeTags=android | |
| - name: Publish test results | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: test-results-modern-stack | |
| path: kraft-gradle-plugin/build/reports/tests/test/ | |
| # The pinned matrix above goes stale the moment a new KSP ships. This job | |
| # resolves whatever is newest on Maven Central at run time, so a KSP release | |
| # that breaks Kraft surfaces on the next weekly run instead of in an issue. | |
| # Schedule/manual only - never blocks a PR on an upstream release. | |
| ksp-latest: | |
| name: KSP latest (probe) | |
| if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set up JDK | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '17' | |
| - name: Set up Gradle | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Resolve latest KSP version | |
| id: ksp | |
| run: | | |
| set -euo pipefail | |
| version=$(curl -sSf --max-time 30 \ | |
| 'https://search.maven.org/solrsearch/select?q=g:com.google.devtools.ksp+AND+a:symbol-processing-api&core=gav&rows=1&wt=json' \ | |
| | python3 -c 'import sys,json; print(json.load(sys.stdin)["response"]["docs"][0]["v"])') | |
| if [ -z "$version" ]; then | |
| echo "Could not resolve the latest KSP version." >&2 | |
| exit 1 | |
| fi | |
| echo "Latest KSP on Maven Central: $version" | |
| echo "version=$version" >> "$GITHUB_OUTPUT" | |
| - name: Gradle plugin functional tests (KSP ${{ steps.ksp.outputs.version }}) | |
| run: ./gradlew :kraft-gradle-plugin:test -Pkraft.test.kspVersion=${{ steps.ksp.outputs.version }} | |
| - name: Publish test results | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: test-results-ksp-latest | |
| path: kraft-gradle-plugin/build/reports/tests/test/ |