Skip to content

Commit

Permalink
Fix #4119, #4120, and part of #59: Upgrade to Kotlin 1.6.10 (#4937)
Browse files Browse the repository at this point in the history
## Explanation
Fixes #4119
Fixes #4120
Fixes part of #59

This PR finishes the migration of the codebase to Kotlin 1.6 (addressing
both #4119 and #4120).

Kotlin 1.6 is needed as part of moving rules_kotlin to 1.7.x (which is,
in turn, needed in conjunction with Bazel 6.x to enable strict
dependency checking which significantly simplifies modularization which
is planned for downstream PRs). This PR doesn't actually finish the
movement to that version of rules_kotlin, but it does finish moving the
codebase to a new enough (and no longer pre-release) version of
rules_kotlin to allow using Kotlin 1.6 (over Kotlin 1.4 that the
codebase currently uses): version 1.5.0.

Previous PRs (#5400 and #5402) prepared for the changes here by
addressing large categories of build warnings that have either arisen
from this migration, or from past work. Note that another large category
of warnings have also been addressed in this PR: by moving to Kotlin
1.6, there's no longer a runtime incompatibility between the Kotlin SDK
and the reflection APIs (which was causing a _lot_ of warning output
previously). Between all three PRs, the output is now very clean and
free of nearly all build warnings.

To try and keep the warnings clean long-term, this PR introduces
warnings-as-errors for both Java and Kotlin code. However, please note
some caveats:
- Dagger generated code doesn't follow the Java warnings-as-error flag,
so those warnings were cleaned up manually (and will need to be
generally watched for, unfortunately).
- The version of rules_kotlin used in this PR doesn't directly support
turning on the functionality, but does internally (so a small patch file
has been added to augment rules_kotlin). When the codebase is updated to
rules_kotlin 1.7.x this patch will no longer be needed.
- To ease development, a build configuration flag was added to disable
failure upon encountering build warnings (per
https://bazel.build/run/bazelrc and
https://bazel.build/docs/configurable-attributes#query-and-cquery as an
example), though this needs to be opted into:
  ```sh
  bazel build --config=ignore_build_warnings <target>
  ```

Some other details to note:
- Version 1.6.10 is specifically picked in order to ensure Jetpack
Compose compatibility (for preparation of the work being prototyped in
#5401 to be compatible with the Oppia Android build environment).
- The vast majority of code in this PR is updating parameterized tests
to use a cleaner repeatable annotation pattern that wasn't available in
Kotlin 1.4.
- This upgrade absolutely does have runtime implications, but we're
relying very heavily on existing automated tests to ensure correctness
and no regressions.
- This PR doesn't make an effort to move toward newer Kotlin language
features except where forced (API deprecations) or largely wanted (the
repeatable annotation change).
- android-spotlight and kotlitex have been updated to support newer
versions of Kotlin (as both are custom forks managed in the broader
Oppia GitHub organization).
- Gradle files have been updated to match the same dependency versions
as Bazel (where it was obvious to make changes; some might still be a
bit off).
- The Gradle build configuration was also updated to use Kotlin 1.6.x
(otherwise there would be build incompatibilities with Bazel). I think
this is the last upgrade we can do for Gradle without upgrading AGP
(which will cause us significant issues with the model module, so we're
planning on instead dropping Gradle support).
- API changes that needed to be addressed in this PR due to deprecations
include: ``String.captialize``, ``String.toLowerCase``,
``String.toUpperCase``, ``SendChannel.offer``, and ``Char.toInt``.
- New API changes that have been leveraged in this PR:
``Flow.lastOrNull`` and ``Deferred.asListenableFuture`` (to replace
``SettableFuture`` for safety; this also resulted in nice
simplifications in ``CoroutineExecutorService``).
- The JVM coroutines dependency needed to be split out from Maven and
manually imported with some empty internal Java class files since it
otherwise has some issues being desugared:
bazelbuild/bazel#13553. This is a problem with
the Desugarer used in Bazel 4.x (and maybe later versions, so this
solution will probably need to kept for a while).
- Some Proguard rule updates were needed due to Kotlin SDK changes--see
the Proguard file & comments for specifics.
- Due to dependency changes, the KitKat main dex file was also trimmed
down. I'm fairly certain that it's already crashing on startup, so I
don't care much about this change--it just needs to build. We plan to
remove KitKat entirely eventually, anyway: #5012.
- Jetifier (that is, automatic conversion from support libraries to
Jetpack/AndroidX) support was disabled in Gradle. We don't have it
enabled in Bazel, and it could potentially encourage strange one-version
violations if it was ever actually needed. This is a safer (and likely
more performant) change to make.
- Moshi was updated to 1.13 to support the upgrade in Kotlin. This did
result in a small configuration change due to its annotation processor
being moved. Note that Moshi 1.14 couldn't be supported since it
requires Kotlin 1.7+ which requires rules_kotlin 1.7+. This will be an
option to upgrade in the future.
- Some improvements and fixes were made in
``FilterPerLanguageResources`` (I think it was outputting something
incorrectly before and that's now been fixed as part of a broader
logical reworking of the filtering logic).
- ``com.android.support:support-annotation`` was removed as a dependency
since it was never used in Bazel, and shouldn't be used (since it's
support library and not AndroidX).
- The updates to Moshi and Kotlin dependencies resulted in a bunch of
other transitive dependency updates.
- Note that Gradle doesn't have ``allWarningsAsErrors`` enabled since it
would require fixing more warnings than is exposed in Bazel, and we're
using Bazel builds as the general source of truth for code quality.

## Essential Checklist
- [x] The PR title and explanation each start with "Fix #bugnum: " (If
this PR fixes part of an issue, prefix the title with "Fix part of
#bugnum: ...".)
- [x] Any changes to
[scripts/assets](https://github.com/oppia/oppia-android/tree/develop/scripts/assets)
files have their rationale included in the PR explanation.
- [x] The PR follows the [style
guide](https://github.com/oppia/oppia-android/wiki/Coding-style-guide).
- [x] The PR does not contain any unnecessary code changes from Android
Studio
([reference](https://github.com/oppia/oppia-android/wiki/Guidance-on-submitting-a-PR#undo-unnecessary-changes)).
- [x] The PR is made from a branch that's **not** called "develop" and
is up-to-date with "develop".
- [x] The PR is **assigned** to the appropriate reviewers
([reference](https://github.com/oppia/oppia-android/wiki/Guidance-on-submitting-a-PR#clarification-regarding-assignees-and-reviewers-section)).

## For UI-specific PRs only
N/A -- This is an infrastructural change. While it could inadvertently
affect user-facing code, it shouldn't based on the current passing state
of automated tests.

---------

Co-authored-by: Adhiambo Peres <[email protected]>
Co-authored-by: Sean Lip <[email protected]>
  • Loading branch information
3 people authored Jun 12, 2024
1 parent 3a369ed commit 4c7f811
Show file tree
Hide file tree
Showing 72 changed files with 5,417 additions and 5,962 deletions.
8 changes: 8 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,13 @@ build --android_databinding_use_v3_4_args \
--define=android_standalone_dexing_tool=d8_compat_dx \
--android_databinding_use_androidx

# Ensure all built Java files treat warnings as errors (similar to the Kotlin configuration) to help
# reduce code smell & potential bugs during development.
build --javacopt="-Werror"

# Note that this doesn't stop 'Werror' from being passed above, but that shouldn't affect most of
# the Oppia Android-specific build.
build:ignore_build_warnings --//tools/kotlin:warn_mode=warning

# Show all test output by default (for better debugging).
test --test_output=all
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ WORKSPACE @oppia/android-app-infrastructure-reviewers
.bazelrc @oppia/android-app-infrastructure-reviewers
.bazelversion @oppia/android-app-infrastructure-reviewers
/tools/android/ @oppia/android-app-infrastructure-reviewers
/tools/kotlin/ @oppia/android-app-infrastructure-reviewers

# Configurations for Bazel-built Android App Bundles.
/bundle_config.pb.json @oppia/android-dev-workflow-reviewers
Expand Down
36 changes: 27 additions & 9 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,22 @@ http_archive(
# Add support for Kotlin: https://github.com/bazelbuild/rules_kotlin.
http_archive(
name = "io_bazel_rules_kotlin",
patches = ["//tools/kotlin:add_kotlinc_optin_support.patch"],
sha256 = HTTP_DEPENDENCY_VERSIONS["rules_kotlin"]["sha"],
urls = ["https://github.com/bazelbuild/rules_kotlin/releases/download/%s/rules_kotlin_release.tgz" % HTTP_DEPENDENCY_VERSIONS["rules_kotlin"]["version"]],
)

load("@io_bazel_rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories")
load("@io_bazel_rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories", "kotlinc_version")

kotlin_repositories()

load("@io_bazel_rules_kotlin//kotlin:core.bzl", "kt_register_toolchains")
# Use the 1.6 compiler since rules_kotlin 1.5 defaults to the 1.5 compiler.
kotlin_repositories(
compiler_release = kotlinc_version(
release = "1.6.10",
sha256 = "432267996d0d6b4b17ca8de0f878e44d4a099b7e9f1587a98edc4d27e76c215a",
),
)

kt_register_toolchains()
register_toolchains("//tools/kotlin:kotlin_16_jdk9_toolchain")

# The proto_compiler and proto_java_toolchain bindings load the protos rules needed for the model
# module while helping us avoid the unnecessary compilation of protoc. Referecences:
Expand Down Expand Up @@ -141,18 +146,18 @@ git_repository(

git_repository(
name = "android-spotlight",
commit = "ebde38335bfb56349eae57e705b611ead9addb15",
commit = "cc23499d37dc8533a2876e45b5063e981a4583f4",
remote = "https://github.com/oppia/android-spotlight",
shallow_since = "1668824029 -0800",
shallow_since = "1680147372 -0700",
)

# A custom fork of KotliTeX that removes resources artifacts that break the build, and updates the
# min target SDK version to be compatible with Oppia.
git_repository(
name = "kotlitex",
commit = "43139c140833c7120f351d63d74b42c253d2b213",
commit = "ccdf4170817fa3b48b8e1e452772dd58ecb71cf2",
remote = "https://github.com/oppia/kotlitex",
shallow_since = "1675741075 -0800",
shallow_since = "1679426649 -0700",
)

bind(
Expand Down Expand Up @@ -199,6 +204,7 @@ maven_install(
maven_install_json = "//third_party:maven_install.json",
override_targets = {
"com.google.guava:guava": "@//third_party:com_google_guava_guava",
"org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm": "@//third_party:kotlinx-coroutines-core-jvm",
},
repositories = DAGGER_REPOSITORIES + MAVEN_REPOSITORIES,
strict_visibility = True,
Expand All @@ -219,3 +225,15 @@ http_jar(
for url_base in DAGGER_REPOSITORIES + MAVEN_REPOSITORIES
],
)

http_jar(
name = "kotlinx-coroutines-core-jvm",
sha256 = HTTP_DEPENDENCY_VERSIONS["kotlinx-coroutines-core-jvm"]["sha"],
urls = [
"{0}/org/jetbrains/kotlinx/kotlinx-coroutines-core-jvm/{1}/kotlinx-coroutines-core-jvm-{1}.jar".format(
url_base,
HTTP_DEPENDENCY_VERSIONS["kotlinx-coroutines-core-jvm"]["version"],
)
for url_base in DAGGER_REPOSITORIES + MAVEN_REPOSITORIES
],
)
19 changes: 9 additions & 10 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ if (project.gradle.startParameter?.taskRequests?.args[0]?.remove("--list-shards"
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation(
'android.arch.lifecycle:extensions:1.1.1',
'androidx.appcompat:appcompat:1.0.2',
'androidx.constraintlayout:constraintlayout:1.1.3',
'androidx.core:core-ktx:1.0.2',
Expand All @@ -166,7 +165,7 @@ dependencies {
'com.github.bumptech.glide:glide:4.11.0',
'com.google.android.flexbox:flexbox:3.0.0',
'com.google.android.material:material:1.3.0',
'com.google.dagger:dagger:2.24',
'com.google.dagger:dagger:2.41',
'com.google.firebase:firebase-analytics:17.5.0',
'com.google.firebase:firebase-analytics-ktx:17.5.0',
'com.google.firebase:firebase-appcheck:16.0.0',
Expand All @@ -180,10 +179,10 @@ dependencies {
'com.google.protobuf:protobuf-javalite:3.17.3',
'nl.dionsegijn:konfetti:1.2.5',
"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version",
'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.1',
'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1',
'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4',
'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4',
'org.mockito:mockito-core:2.7.22',
'com.github.oppia:android-spotlight:ebde38335bfb56349eae57e705b611ead9addb15'
'com.github.oppia:android-spotlight:cc23499d37dc8533a2876e45b5063e981a4583f4'
)
compileOnly(
'jakarta.xml.bind:jakarta.xml.bind-api:2.3.2',
Expand All @@ -203,7 +202,7 @@ dependencies {
'com.google.truth.extensions:truth-liteproto-extension:1.1.3',
'org.robolectric:annotations:4.5',
'org.robolectric:robolectric:4.5',
'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.2.2',
'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4',
"org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version",
'org.mockito:mockito-core:2.7.22',
project(":testing"),
Expand All @@ -219,7 +218,7 @@ dependencies {
'com.google.truth:truth:1.1.3',
'androidx.work:work-testing:2.4.0',
'com.google.truth.extensions:truth-liteproto-extension:1.1.3',
'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.2.2',
'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4',
'org.mockito:mockito-android:2.7.22',
'org.robolectric:annotations:4.5',
)
Expand All @@ -243,13 +242,13 @@ dependencies {
'androidx.test:orchestrator:1.2.0',
)
kapt(
'com.google.dagger:dagger-compiler:2.24'
'com.google.dagger:dagger-compiler:2.41'
)
kaptTest(
'com.google.dagger:dagger-compiler:2.24'
'com.google.dagger:dagger-compiler:2.41'
)
kaptAndroidTest(
'com.google.dagger:dagger-compiler:2.24'
'com.google.dagger:dagger-compiler:2.41'
)
// TODO(#59): Remove this once Bazel is introduced
api project(':data')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ class AppLanguageResourceHandler @Inject constructor(
private fun getLocalizedDisplayName(languageCode: String, regionCode: String = ""): String {
// TODO(#3791): Remove this dependency.
val locale = Locale(languageCode, regionCode)
return locale.getDisplayLanguage(locale).capitalize(locale)
return locale.getDisplayLanguage(locale).replaceFirstChar {
if (it.isLowerCase()) it.titlecase(locale) else it.toString()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,5 @@ kt_android_library(
visibility = ["//visibility:public"],
deps = [
"//third_party:androidx_databinding_databinding-adapters",
"//third_party:androidx_lifecycle_lifecycle-extensions",
],
)
Loading

0 comments on commit 4c7f811

Please sign in to comment.