Skip to content

Migrate build toolchain to Kotlin 2.2.0 (K2 Compose plugin global)#1722

Open
aleksandar-apostolov wants to merge 7 commits into
develop-v2from
gsd/phase-1-01-kotlin
Open

Migrate build toolchain to Kotlin 2.2.0 (K2 Compose plugin global)#1722
aleksandar-apostolov wants to merge 7 commits into
develop-v2from
gsd/phase-1-01-kotlin

Conversation

@aleksandar-apostolov

@aleksandar-apostolov aleksandar-apostolov commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Goal

Closes AND-1238 — first step of the V2 migration's toolchain modernization. Kotlin 2.2.0 must land before stream-android-core v5 (built against 2.2.0) can be added as a dependency. KSP / coroutines / Compose-K2 bump together to avoid broken intermediate states.

Sequential stack on develop-v2: this PR → AGP 8.7.3 + Gradle 8.10.2 → stream-android-core 5.0.0 dep + StreamClient lifecycle wiring.

Implementation

Version moves in gradle/libs.versions.toml:

Key Before After
kotlin 1.9.25 2.2.0
ksp 1.9.25-1.0.20 2.2.0-2.0.2
kotlinxCoroutines 1.9.0 1.10.2
kotlinTestJunit 1.8.20 2.2.0
hilt 2.52 2.56.2 (KSP 2.2.0 compatibility)

K2 Compose plugin (org.jetbrains.kotlin.plugin.compose) wired globally via both AndroidLibraryComposeConventionPlugin and AndroidApplicationComposeConventionPlugin. Module-level composeOptions { kotlinCompilerExtensionVersion = ... } block deleted — K2 plugin is now the single source of truth.

kotlinOptions { ... }compilerOptions { ... } DSL migration across root build.gradle.kts and KotlinAndroid.kt (K2 hard error). Subprojects block aligned to -Xjvm-default=all. One source fix in PermissionManager.kt — dropped inline on a val constructor param (K2 hard error).

BCV .api dumps regenerated to absorb K2 synthetic-accessor noise — net reduction of 194 lines, zero new public symbols.

Testing

  • ./gradlew clean compileDebugKotlin across all modules + demo-app + tutorials + metrics: green.
  • ./gradlew :demo-app:kspDevelopmentDebugKotlin: green after Hilt bump.
  • ./gradlew testDebugUnitTest: zero failures. @Ignore count holds at 21 baseline.
  • ./gradlew :stream-video-android-ui-compose:assembleDebug -PenableComposeCompilerReports=true: produces non-empty compose_compiler/*-classes.txt.
  • ./gradlew spotlessCheck and apiCheck: green.

Note: ./gradlew detekt is referenced by the pre-push hook but no module declares the task. Captured as follow-up.

Summary by CodeRabbit

  • Chores
    • Upgraded Kotlin toolchain to 2.2.0 with corresponding updates to KSP (2.2.0-2.0.2), kotlinx-coroutines (1.10.2), Hilt (2.56.2), and Kotlin Test (2.2.0).
    • Integrated K2 Compose compiler plugin and updated build system configuration for compatibility.

@aleksandar-apostolov aleksandar-apostolov added the pr:dependencies Dependency updates label Jun 17, 2026
@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled, or the PR is bot-authored.
  • An issue is linked (Linear ticket or GitHub issue), or the PR is bot-authored.

🎉 Great job! This PR is ready for review.

@aleksandar-apostolov aleksandar-apostolov marked this pull request as ready for review June 17, 2026 08:17
@aleksandar-apostolov aleksandar-apostolov requested a review from a team as a code owner June 17, 2026 08:17
@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

SDK Size Comparison 📏

SDK Before After Difference Status
stream-video-android-core 12.05 MB 12.07 MB 0.02 MB 🟢
stream-video-android-ui-xml 5.68 MB 5.66 MB -0.02 MB 🚀
stream-video-android-ui-compose 6.28 MB 6.31 MB 0.03 MB 🟢

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Upgrades Kotlin to 2.2.0 with matching KSP (2.2.0-2.0.2), kotlinx.coroutines (1.10.2), and Hilt (2.56.2) versions. Wires the K2 Compose compiler plugin through convention plugins, removes composeOptions in favor of ComposeCompilerGradlePluginExtension, migrates kotlinOptions to the compilerOptions DSL project-wide, fixes an inline val incompatibility in PermissionManager.kt, and regenerates BCV .api dumps.

Changes

Kotlin 2.2.0 Toolchain Upgrade

Layer / File(s) Summary
Version catalog: Kotlin 2.2.0, KSP, coroutines, Hilt bumps
gradle/libs.versions.toml
kotlin2.2.0, ksp2.2.0-2.0.2, kotlinxCoroutines1.10.2, kotlinTestJunit2.2.0, hilt2.56.2.
Convention plugins: compilerOptions DSL and K2 Compose plugin wiring
build-logic/convention/build.gradle.kts, build-logic/convention/src/main/kotlin/io/getstream/video/KotlinAndroid.kt, build-logic/convention/src/main/kotlin/io/getstream/video/AndroidCompose.kt, build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt, build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt, build.gradle.kts
Enables libs.compose.compiler.gradlePlugin as compileOnly; convention plugins now apply org.jetbrains.kotlin.plugin.compose; KotlinAndroid.kt replaces kotlinOptions helper with kotlinCompilerOptions helper using KotlinJvmCompilerOptions; AndroidCompose.kt activates ComposeCompilerGradlePluginExtension and drops hardcoded composeOptions; root build.gradle.kts uses compilerOptions DSL with -Xjvm-default=all.
K2 source fix and regenerated BCV API dumps
stream-video-android-ui-core/src/main/kotlin/.../PermissionManager.kt, stream-video-android-core/api/stream-video-android-core.api, stream-video-android-ui-compose/api/stream-video-android-ui-compose.api
Removes inline from StreamPermissionManagerImpl constructor callback parameters; core .api dump marks $$serializer classes as final synthetic and Parcelable methods as final; ui-compose .api dump replaces lambda-*/getLambda-<n>$ accessor scheme with getLambda$<id>$ across all ComposableSingletons classes.
Planning summary and @Ignore baseline docs
.planning/phases/01-foundation/01-01-SUMMARY.md, .planning/phases/01-foundation/IGNORE-BASELINE.md
Adds Phase 1 execution summary (version pins, Gradle gauntlet results, deviations, self-check) and IGNORE-BASELINE.md recording the 21-annotation @Ignore threshold for regression detection.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

pr:internal, released

Suggested reviewers

  • PratimMallick

Poem

🐇 Hop hop, Kotlin leaped to two-two-oh,
Compose K2 plugin now steals the show!
compilerOptions replaces the old way,
inline val begone — K2 says "no way"!
BCV dumps refreshed, serializers synthetic,
The rabbit grins: this build is kinetic! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: migrating the build toolchain to Kotlin 2.2.0 with K2 Compose plugin enablement, which is the primary objective of this pull request.
Description check ✅ Passed The PR description follows the template structure with clear Goal, Implementation, and Testing sections that thoroughly document the Kotlin 2.2.0 migration and all related changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch gsd/phase-1-01-kotlin

Warning

Review ran into problems

🔥 Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
build-logic/convention/src/main/kotlin/io/getstream/video/KotlinAndroid.kt (1)

36-40: Add explicit internal visibility to kotlinCompilerOptions helper.

This extension is used only within the convention plugin module and does not need public exposure. Adding internal aligns with the guideline to prefer explicit visibility modifiers and limit API surface.

Proposed fix
-fun Project.kotlinCompilerOptions(block: KotlinJvmCompilerOptions.() -> Unit) {
+internal fun Project.kotlinCompilerOptions(block: KotlinJvmCompilerOptions.() -> Unit) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@build-logic/convention/src/main/kotlin/io/getstream/video/KotlinAndroid.kt`
around lines 36 - 40, The kotlinCompilerOptions extension function lacks an
explicit visibility modifier, making it public by default. Add the internal
keyword before the fun keyword in the kotlinCompilerOptions function declaration
to explicitly restrict its visibility to the convention plugin module only,
aligning with the guideline to prefer explicit visibility modifiers and limit
the API surface of the plugin.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@build-logic/convention/src/main/kotlin/io/getstream/video/KotlinAndroid.kt`:
- Around line 21-25: The property parsing for warningsAsErrors is incorrect
because Gradle properties are stored as Strings, not Booleans. The cast `as?
Boolean` will always return null for String values. Fix this by retrieving the
property as a String and converting it to a Boolean by checking if the string
value equals "true" (case-insensitive), then use that Boolean result to set the
`allWarningsAsErrors` property in the compilerOptions block. This ensures the
actual property value is properly parsed and passed to the Kotlin compiler.

---

Nitpick comments:
In `@build-logic/convention/src/main/kotlin/io/getstream/video/KotlinAndroid.kt`:
- Around line 36-40: The kotlinCompilerOptions extension function lacks an
explicit visibility modifier, making it public by default. Add the internal
keyword before the fun keyword in the kotlinCompilerOptions function declaration
to explicitly restrict its visibility to the convention plugin module only,
aligning with the guideline to prefer explicit visibility modifiers and limit
the API surface of the plugin.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b3c7b0f1-c9ca-4512-8498-1dfdc38e0e93

📥 Commits

Reviewing files that changed from the base of the PR and between 1f7bdfb and d1b155f.

📒 Files selected for processing (12)
  • .planning/phases/01-foundation/01-01-SUMMARY.md
  • .planning/phases/01-foundation/IGNORE-BASELINE.md
  • build-logic/convention/build.gradle.kts
  • build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt
  • build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt
  • build-logic/convention/src/main/kotlin/io/getstream/video/AndroidCompose.kt
  • build-logic/convention/src/main/kotlin/io/getstream/video/KotlinAndroid.kt
  • build.gradle.kts
  • gradle/libs.versions.toml
  • stream-video-android-core/api/stream-video-android-core.api
  • stream-video-android-ui-compose/api/stream-video-android-ui-compose.api
  • stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/permission/PermissionManager.kt

Comment on lines +21 to +25
val warningsAsErrors = properties["warningsAsErrors"] as? Boolean ?: false

freeCompilerArgs = freeCompilerArgs + listOf(
tasks.withType<KotlinCompile>().configureEach {
compilerOptions {
allWarningsAsErrors.set(warningsAsErrors)

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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify current parsing + property source shape.
rg -nP 'warningsAsErrors' build-logic/convention/src/main/kotlin/io/getstream/video/KotlinAndroid.kt
fd -a 'gradle.properties' | xargs -I{} rg -nP '^\s*warningsAsErrors\s*=' {}

Repository: GetStream/stream-video-android

Length of output: 215


🏁 Script executed:

#!/bin/bash
# Check the function signature and imports around line 21
sed -n '1,35p' build-logic/convention/src/main/kotlin/io/getstream/video/KotlinAndroid.kt

Repository: GetStream/stream-video-android

Length of output: 1121


🏁 Script executed:

#!/bin/bash
# Search for all gradle.properties files in the repository
find . -name 'gradle.properties' -type f

Repository: GetStream/stream-video-android

Length of output: 126


🏁 Script executed:

#!/bin/bash
# Check if warningsAsErrors is actually set anywhere
rg 'warningsAsErrors\s*=' --type properties

Repository: GetStream/stream-video-android

Length of output: 109


🏁 Script executed:

#!/bin/bash
# Check gradle.properties files for warningsAsErrors definition
cat ./gradle.properties
echo "---"
cat ./build-logic/gradle.properties

Repository: GetStream/stream-video-android

Length of output: 2389


🏁 Script executed:

#!/bin/bash
# Search for warningsAsErrors in all gradle.properties files
rg 'warningsAsErrors' . -g '*.properties'

Repository: GetStream/stream-video-android

Length of output: 56


🏁 Script executed:

#!/bin/bash
# Check how findProperty is used elsewhere in the codebase for property parsing
rg 'findProperty' build-logic/ -A 2 -B 1

Repository: GetStream/stream-video-android

Length of output: 56


Fix property parsing: properties["warningsAsErrors"] as? Boolean will always be null because Gradle properties are Strings.

When properties are passed via -P flags or gradle.properties, they are stored as Strings. The type cast as? Boolean will fail for all String values, always resulting in null, making allWarningsAsErrors effectively always false.

Proposed fix
-    val warningsAsErrors = properties["warningsAsErrors"] as? Boolean ?: false
+    val warningsAsErrors =
+        findProperty("warningsAsErrors")
+            ?.toString()
+            ?.toBooleanStrictOrNull()
+            ?: false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
val warningsAsErrors = properties["warningsAsErrors"] as? Boolean ?: false
freeCompilerArgs = freeCompilerArgs + listOf(
tasks.withType<KotlinCompile>().configureEach {
compilerOptions {
allWarningsAsErrors.set(warningsAsErrors)
val warningsAsErrors =
findProperty("warningsAsErrors")
?.toString()
?.toBooleanStrictOrNull()
?: false
tasks.withType<KotlinCompile>().configureEach {
compilerOptions {
allWarningsAsErrors.set(warningsAsErrors)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@build-logic/convention/src/main/kotlin/io/getstream/video/KotlinAndroid.kt`
around lines 21 - 25, The property parsing for warningsAsErrors is incorrect
because Gradle properties are stored as Strings, not Booleans. The cast `as?
Boolean` will always return null for String values. Fix this by retrieving the
property as a String and converting it to a Boolean by checking if the string
value equals "true" (case-insensitive), then use that Boolean result to set the
`allWarningsAsErrors` property in the compilerOptions block. This ensures the
actual property value is properly parsed and passed to the Kotlin compiler.

@sonarqubecloud

Copy link
Copy Markdown

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

Labels

pr:dependencies Dependency updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants