Skip to content

Upgrades to major dependencies (java 25, kotlin 2.3.21, gradle 9.5.0, AGP 9.3.1) - #308

Merged
DanielJette merged 6 commits into
mainfrom
java-25
Aug 17, 2026
Merged

Upgrades to major dependencies (java 25, kotlin 2.3.21, gradle 9.5.0, AGP 9.3.1)#308
DanielJette merged 6 commits into
mainfrom
java-25

Conversation

@DanielJette

@DanielJette DanielJette commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

What does this change accomplish?

Caution

Critical Update Needed: Check your configuration files.
This release uses Java 25 which requires you to update your app to use Java 25.
Java 25 also requires Android Gradle Plugin 9.x — the published artifacts are Java 25 bytecode and cannot be consumed by AGP 8.x

  • Upgrade kotlin to 2.3.21, gradle to 9.5.0 and AGP to 9.3.1
  • Upgrade all project files to use Java 25
    • Java 25 requires you to update your app to use Java 25
    • Requires Android Gradle Plugin 9.x. The published artifacts are Java 25 bytecode (class file
      major version 69) and cannot be consumed by AGP 8.x
    • Gradle 9.5.0 is required to build; kotlinOptions, lintOptions, packagingOptions and the
      legacy libraryVariants API have been migrated to their AGP 9 replacements
    • Removed ScreenshotScenarioRule.assertSame() with an ActivityScenario context parameter
      (JVM name assertSameContext). Kotlin 2.3 makes it ambiguous with the no-arg assertSame()
      at any call site where an ActivityScenario is an implicit receiver, such as inside
      ActivityScenario.test { }, so it could no longer be called. Set the scenario explicitly
      instead: rule.withScenario(scenario).assertSame()

@AndroidTestifyBot AndroidTestifyBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the AGP 9 / Gradle 9.5 / Kotlin 2.3 / Java 25 migration. The DSL migration itself is in good shape — lintOptionslint, packagingOptionspackaging, kotlinOptionskotlin { compilerOptions }, the deviceslocalDevices swap, dropping kotlin-android in favour of AGP's built-in Kotlin, and kapt→KSP all look correct, and the inline comments explaining the non-obvious AGP 9 replacements are appreciated. I verified locally on JDK 25 that :Library:bundleReleaseAar / :Ktx:bundleReleaseAar still produce testify-6.0.0.aar / testify-ktx-6.0.0.aar, and that ktlintCheck genuinely runs again on 14.2.0 (13.x was silently a no-op under AGP 9).

Three things need fixing before this merges:

1. Removing archivesBaseName renamed the androidTest APKs and broke the instrumented-test CI steps. The AAR name was preserved via the new BundleAar block, but the APK name wasn't. :Ktx:assembleDebugAndroidTest now emits Ktx-debug-androidTest.apk and :Library:assembleDebugAndroidTest emits Library-debug-androidTest.apk, while bitrise.yml:219-220 and bitrise.yml:254-255 still point at testify-debug-androidTest.apk / testify-ktx-debug-androidTest.apk. That's why the Ktx check is already red; Library will follow. Details and a verified fix in the inline comment.

2. The GitHub Actions workflows were never bumped off Java 21/17. bitrise.yml moved to 25, but .github/workflows/flix_sample.yml still pins java-version: 21 and is failing on this PR with error: invalid source release: 25, and .github/workflows/central_release.yml still pins java-version: 17, which would break Maven Central publishing on the next release.

3. :GmdSample no longer builds under AGP 9. androidx.databinding:viewbinding:9.3.1 declares minCompileSdk=34 (8.13.2 declared minCompileSdk=1), and the sample is still on compileSdk 33, so :GmdSample:assembleDebug fails outright. No bitrise workflow covers GMD, so CI won't catch it.

Also worth deciding before release (non-blocking on this diff): the published AARs are now Java 25 bytecode — I confirmed classes.jar in testify-6.0.0.aar is class file major version 69. That forces every consumer onto JDK 25 and AGP 9, which is a larger breaking change than the CHANGELOG currently conveys. See the CHANGELOG comment.

The rest are minor notes inline.

Comment thread Library/build.gradle
Comment thread bitrise.yml
Comment thread Samples/Gmd/build.gradle Outdated
}

android {
compileSdk 33

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

compileSdk 33 no longer works under AGP 9. :GmdSample:assembleDebug fails on this branch:

> A failure occurred while executing CheckAarMetadataWorkAction
   > 1. Dependency 'androidx.databinding:viewbinding:9.3.1' requires libraries and applications
        that depend on it to compile against version 34 or later of the Android APIs.
        :GmdSample is currently compiled against android-33.

This is a regression from the AGP bump, not pre-existing: viewbinding:8.13.2 declares minCompileSdk=1, viewbinding:9.3.1 declares minCompileSdk=34. The module uses viewBinding true, so it's unavoidable — compileSdk needs to go to 34+ (and targetSdk 33 is probably worth revisiting at the same time).

Note there's no test_gmd workflow in bitrise.yml, so CI stays green on this — it only shows up when someone builds the sample.

Separately: is jumping this sample from Java 1.8 straight to 25 intentional? It's the "old project" sample, so 1.8 may have been deliberate coverage for consumers who haven't migrated.

Comment thread CHANGELOG.md
Comment thread gradle/libs.versions.toml
@@ -1,6 +1,8 @@
#Sun Aug 16 15:39:16 EDT 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Machine-local timestamp from the wrapper task — worth dropping, it just creates churn on every wrapper update. (Adding distributionSha256Sum is a nice improvement, keep that.)

Comment thread Library/src/main/java/dev/testify/scenario/ScreenshotScenarioRule.kt Outdated
Restore archive base names:
- Gradle 9 removed the `archivesBaseName` property; replace it with
  `base { archivesName = pom.artifact }` in the five published modules.
  This drives the androidTest APK name as well as the AAR, so dropping it
  had renamed the APKs that bitrise.yml pins and turned the Ktx and
  Library instrumented-test steps red.

Move CI off the old JDKs:
- flix_sample.yml: java-version 21 -> 25 (was failing with
  "invalid source release: 25").
- central_release.yml: java-version 17 -> 25, and refresh
  actions/checkout@v2 -> v4 and actions/setup-java@v1 -> v4, since v1
  cannot resolve JDK 25 and v4 requires an explicit distribution.

Fix samples that no longer build under AGP 9:
- GmdSample: compileSdk 33 -> 36. androidx.databinding:viewbinding:9.3.1
  declares minCompileSdk=34, so checkDebugAarMetadata failed outright.
- LegacySample: compileSdk -> 36 to satisfy the AAR metadata of the
  Testify modules it depends on, and drop the contradictory
  `compileSdkVersion 35` from defaultConfig. targetSdk stays at 35.

Fix Plugin unit tests (run by bitrise as Plugin:test):
- Bump mockk to 1.14.11. JDK 25 reimplemented java.io over NIO
  (IoOverNioFileSystem), so mockk 1.13.16 could not mock java.io.File and
  every AdbTest failed with an NPE out of the real getAbsolutePath().
- Pull the ktlint plugin version from the included build's own catalog
  instead of hardcoding it, so it cannot drift from the root catalog.

Remove the ActivityScenario context-parameter overload of
ScreenshotScenarioRule.assertSame():
- Kotlin 2.3 makes it ambiguous with the no-arg assertSame() at any call
  site where an ActivityScenario is an implicit receiver, such as inside
  ActivityScenario.test { }, which broke compilation of LegacySample's
  androidTest sources. The overload was also what set the scenario, so
  hiding rather than removing it compiles but throws
  ScenarioRequiredException at runtime.
- Update ScenarioMainActivityScreenshotTest to set the scenario
  explicitly via withScenario(this), matching the pattern used by every
  other scenario test in the repo.

Also drop the machine-local timestamp from gradle-wrapper.properties and
document the consumer impact of Java 25 bytecode in the CHANGELOG.
mockk 1.14.5 bundles a Byte Buddy that officially supports up to Java 24
and rejects class file major version 69:

  java.lang.IllegalArgumentException: Java 25 (69) is not supported by the
  current version of Byte Buddy which officially supports Java 24 (68)

Every mockk-based unit test in :Library and :Ktx failed with MockKException
as a result, which is what turned the Ktx bitrise workflow red at its
android-unit-test step.

This is the same version already used by the :Plugin included build, where
an older mockk additionally could not mock java.io.File on JDK 25.

@AndroidTestifyBot AndroidTestifyBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All seven points addressed. Re-verified on JDK 25 at c355dade:

Was Now
Library-debug-androidTest.apk / Ktx-debug-androidTest.apk testify-debug-androidTest.apk / testify-ktx-debug-androidTest.apk — matches bitrise.yml:219-220 and :254-255; AAR still testify-6.0.0.aar
flix_sample.yml on JDK 21, central_release.yml on JDK 17 both on 25 (plus checkout@v4 / setup-java@v4)
:GmdSample:assembleDebug failing on checkDebugAarMetadata builds clean on compileSdk 36
Plugin pinning ktlint 13.1.0 inline alias(libs.plugins.ktlint) at 14.2.0

Plugin:test, Plugin:ktlintCheck, :Library:testDebugUnitTest and :Ktx:testDebugUnitTest all pass locally with mockk 1.14.11, and all 15 CI checks are green — including the two emulator shards and the Library/Ktx instrumented-test steps that were consuming the misnamed APKs.

Two notes on the parts that went beyond the review:

The assertSame() removal is better than what I suggested, and my premise was wrong. I claimed the context-parameter overload had no callers; it did — launchActivity<MainActivity>().test { rule.assertSame() } in the Legacy sample resolved to it via the implicit ActivityScenario receiver, which is invisible at the call site. That makes this a genuine behavioural trap rather than dead API: had the diagnostic just been suppressed, that call would have kept compiling while silently binding to the no-arg overload. Removing it and rewriting the call as rule.withScenario(this).assertSame() is the right resolution, and the CHANGELOG entry explains the migration well. I checked the remaining rule.assertSame() sites in Library/src/androidTest/**/scenario/ — they all use .use { scenario -> … } with a named parameter and call withScenario(scenario) first, so none of them were bound to the removed overload.

Good catch on Samples/Legacy. defaultConfig { compileSdkVersion 35 } was silently overriding the outer compileSdk 34 through Groovy's owner delegation — removing it and setting compileSdk 36 once is the correct fix, not just a version bump.

Non-blocking, for later:

  • :GmdSample still has no bitrise workflow, so nothing guards the compileSdk fix. Given AGP 9 broke it once via a transitive minCompileSdk, a build-only workflow would be cheap insurance.
  • Plugins/Gradle/gradle/libs.versions.toml keeps gradle = "8.13.2" and kotlin = "2.2.0". I read that as deliberate — compileOnly libs.gradle plus a JVM 17 target keeps the plugin loadable in AGP 8 consumers' daemons even though the library artifacts now require AGP 9 — but flagging it in case the intent was to move it too.

LGTM.

@DanielJette
DanielJette merged commit 396a59a into main Aug 17, 2026
15 checks passed
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.

2 participants