-
Notifications
You must be signed in to change notification settings - Fork 23
ci: add Android Java API compatibility checks #165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,6 +25,7 @@ hs_err_pid* | |
|
|
||
| # Ignore Gradle | ||
| /.gradle/ | ||
| /build-logic/.gradle | ||
| build/ | ||
| local.properties | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| // Copyright 2026 The Terasology Foundation | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| plugins { | ||
| `kotlin-dsl` | ||
| } | ||
|
|
||
| repositories { | ||
| gradlePluginPortal() | ||
| } | ||
|
|
||
| dependencies { | ||
| implementation("ru.vyarus:gradle-animalsniffer-plugin:2.0.1") | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ | |
| plugins { | ||
| id("com.android.library") | ||
| id("maven-publish") | ||
| id("ru.vyarus.animalsniffer") version "2.0.1" | ||
| } | ||
|
|
||
| android { | ||
|
|
@@ -30,7 +31,14 @@ android { | |
| lintOptions { | ||
| lintConfig file("lintconfig.xml") | ||
| } | ||
| lint { | ||
| // Somehow, AndroidAssetsFileSource.java breaks this lint. | ||
| disable "BidiSpoofing" | ||
|
Comment on lines
+34
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | rg '(^|/)build\.gradle$|AndroidAssetsFileSource\.java$' || true
echo "== gestalt-android/build.gradle context =="
if [ -f gestalt-android/build.gradle ]; then
nl -ba gestalt-android/build.gradle | sed -n '1,90p'
echo "== BidiSpoofing occurrences =="
rg -n 'BidiSpoofing|lint|disable|baseline|SuppressWarnings' gestalt-android/build.gradle gestalt-android || true
fi
echo "== AndroidAssetsFileSource.java context =="
if [ -f gestalt-android/AndroidAssetsFileSource.java ]; then
nl -ba gestalt-android/AndroidAssetsFileSource.java | sed -n '1,220p'
fi
echo "== repo-wide occurrences =="
rg -n 'BidiSpoofing|AndroidAssetsFileSource|class AndroidAssetsFileSource' . || trueRepository: MovingBlocks/gestalt Length of output: 594 🏁 Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
import json, re, pathlib
# Read-only behavioral/deterministic parser-like probe: locate BidiSpoofing disable and any narrower suppression references in relevant files.
files = ["gestalt-android/build.gradle", "gestalt-android/AndroidAssetsFileSource.java"]
for f in files:
p = pathlib.Path(f)
if not p.exists():
print(f"MISSING {f}")
continue
s = p.read_text()
print(f"\n== {f} ==")
for i, line in enumerate(s.splitlines(), 1):
if 'BidiSpoofing' in line or '`@SuppressLint`' in line or 'lintOptions' in line or 'disable ' in line:
print(f"{i}: {line.strip()}")
PYRepository: MovingBlocks/gestalt Length of output: 292 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== gestalt-android/build.gradle =="
awk '{print NR":"$0}' gestalt-android/build.gradle | sed -n '1,120p'
echo "== gestalt-android/src/main/java/org/terasology/gestalt/android/AndroidAssetsFileSource.java =="
awk '{print NR":"$0}' gestalt-android/src/main/java/org/terasology/gestalt/android/AndroidAssetsFileSource.java | sed -n '1,260p'
echo "== relevant repo occurrences =="
rg -n 'BidiSpoofing|AndroidAssetsFileSource|`@SuppressLint`|lintOptions|baseline.*Bidi|AndroidAssetsFileSource' .
echo "== android gradle plugins and versions =="
rg -n 'com\.android\.(library|application)|android\.lint|lintOptions' -g '*.gradle' .Repository: MovingBlocks/gestalt Length of output: 12244 Do not disable
🤖 Prompt for AI Agents |
||
| } | ||
|
Comment on lines
+34
to
+37
|
||
| } | ||
|
|
||
| tasks.withType(AnimalSniffer) { | ||
|
|
||
| ignoreFailures = false | ||
| } | ||
|
|
||
| dependencies { | ||
|
|
@@ -46,6 +54,8 @@ dependencies { | |
| testImplementation(libs.junit) | ||
| androidTestImplementation("androidx.test:runner:1.6.2") | ||
| androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1") | ||
|
|
||
| signature("com.toasttab.android:gummy-bears-api-24:0.15.0:coreLib2@signature") | ||
| } | ||
|
|
||
| task androidJavadocs(type: Javadoc) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,10 @@ dependencyResolutionManagement { | |
| } | ||
| } | ||
|
|
||
| pluginManagement { | ||
| includeBuild("build-logic") | ||
| } | ||
|
|
||
|
Comment on lines
+19
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf 'Files:\n'
git ls-files | sed -n '1,120p'
printf '\nsettings.gradle.kts:\n'
cat -n settings.gradle.kts 2>/dev/null || true
printf '\nGradle wrapper/version files:\n'
fd -a 'gradle/wrapper|gradle.properties|gradlew' . | sed -n '1,80p'
printf '\nBuild logic presence:\n'
test -d build-logic && find build-logic -maxdepth 3 -type f | sort || trueRepository: MovingBlocks/gestalt Length of output: 11027 🌐 Web query:
💡 Result: In a Gradle settings file (settings.gradle or settings.gradle.kts), the pluginManagement block must be the first block in the file [1][2]. This requirement exists because Gradle must compile and evaluate pluginManagement before the rest of the settings script can be processed, as it dictates how plugins used in the build are resolved [3]. In contrast, the dependencyResolutionManagement block does not have the same strict requirement to be the first block [4][5]. It is typically placed after pluginManagement and other initial settings, following standard Gradle documentation examples, but it is not technically constrained to be the first block like pluginManagement [4][6][7]. In practice, both are commonly declared in the settings file to centralize repositories and version management for the entire build [5][8]. A standard order found in official documentation is [4][6][7]: 1. pluginManagement {... } 2. plugins {... } 3. rootProject.name = "..." 4. dependencyResolutionManagement {... } 5. include(...) This structure ensures that plugins are configured first, followed by project-wide dependency resolution strategies [4][5]. Citations:
Move Gradle requires Proposed fix+pluginManagement {
+ includeBuild("build-logic")
+}
+
dependencyResolutionManagement {
// ...
}
-pluginManagement {
- includeBuild("build-logic")
-}🤖 Prompt for AI Agents |
||
| include( | ||
| "gestalt-util", | ||
| "gestalt-di", | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: MovingBlocks/gestalt
Length of output: 5553
🌐 Web query:
gradle animalsniffer plugin AnimalSnifferExtension ignore class level suppression java.io.File💡 Result:
The Gradle AnimalSniffer plugin (by xvik) does not provide a direct configuration option in AnimalSnifferExtension to "ignore" or suppress violations specifically for a java.io.File or any other arbitrary class type via the extension itself. Instead, Animal Sniffer handles suppression through standard mechanism provided by the underlying Animal Sniffer library [1][2]. To suppress violations at the code level, you should use the
@IgnoreJRERequirementannotation [3]. This annotation is part of the animal-sniffer-annotations artifact [4]. By adding this annotation to a class or a specific method, you instruct the Animal Sniffer checker to ignore compatibility violations for the annotated code block [3]. If you need to suppress violations for a broader set of classes or files that you cannot annotate, the common practice—as seen in large-scale projects like Kotlinx Coroutines—is to use Gradle's built-in task configuration to exclude specific files from the check tasks [5]. You can achieve this by configuring the AnimalSniffer tasks in your build.gradle.kts file: tasks.withType<ru.vyarus.gradle.plugin.animalsniffer.task.AnimalSnifferTask>.configureEach { exclude("/path/to/your/class/") } This approach allows you to filter out specific files or packages from being analyzed by the plugin [5]. The AnimalSnifferExtension is primarily used to define signatures, source sets, and general plugin behavior [6][7][8], rather than granular, per-class violation management.Citations:
🌐 Web query:
github.com xvik gradle-animalsniffer-plugin AnimalSnifferExtension ignore Groovy source💡 Result:
The gradle-animalsniffer-plugin does not provide a direct configuration option to ignore individual source files or specific Groovy files within a source set [1][2]. The plugin operates at the level of "targets" (such as source sets, Android variants, or Kotlin multiplatform compilations) rather than granular file filtering [2][3]. To exclude specific Groovy (or other) source files from being checked by the plugin, the recommended approach is to isolate those files into a separate source set and exclude that source set from the plugin's configuration [4]. If you need to manage which source sets are checked, you can configure the plugin using the
defaultTargetsproperty [2][3]: animalsniffer { // Only check the 'main' source set, excluding others defaultTargets = ['main'] } If you have specific classes or packages that are causing issues and do not need to be checked, consider the following options: 1. Use Cache Exclusions: If you are encountering issues with specific packages (such as internal Gradle or third-party classes), you can use theanimalsniffer.cache.excludeconfiguration [5]: animalsniffer { cache { exclude 'com.example.package.*' } } 2. Isolate Sources: As noted in the documentation for quality plugins, the cleanest way to exclude specific files is to move them into a dedicated source set and not include that source set in yourdefaultTargetslist [4]. Note: The plugin supports Groovy source sets only when they use@CompileStatic[1][6]. If your Groovy code is not compiled statically, it may not be correctly analyzed or may require different handling. Direct "exclude file" patterns (like those found in other quality plugins) are generally not supported by the animalsniffer plugin [4][7].Citations:
🌐 Web query:
AnimalSniffer extension ignore "ignores property" JavaSourceSetProcessor ignore signatures animal sniffer💡 Result:
In Animal Sniffer, there are two primary ways to ignore signature violations: using the ignores configuration parameter or using source code annotations [1][2]. 1. Configuration Parameter (ignores): You can specify class names to ignore in the plugin configuration. This parameter supports wildcards [1][3]. In Maven, this is defined within the block of the animal-sniffer-maven-plugin [2]: com.example.SomeClass com.example.package.* In Gradle, if you are using the common ru.vyarus:gradle-animalsniffer-plugin, specific ignore behavior may depend on your configuration (such as cache exclusions) [4][5]. 2. Source Annotations: You can use the
@IgnoreJRERequirementannotation to mark specific methods, classes, or fields that should be ignored during signature checking [6][1]. Animal Sniffer automatically recognizes this annotation by default [1]. You need to include the animal-sniffer-annotations dependency in your project (typically with scope provided or optional) to use this annotation [6]. Regarding your mention of JavaSourceSetProcessor: While this is a class name found in some build tool internal APIs, it is not a standard configuration property for Animal Sniffer. Animal Sniffer itself uses the ignores parameter [3][7] and standard annotation-based suppression [6][1] to handle exceptions to signature checks. top_results: [6][1][3][2][4][5]Citations:
🏁 Script executed:
Repository: MovingBlocks/gestalt
Length of output: 4286
🌐 Web query:
site:github.com/xvik/gradle-animalsniffer-plugin src/main/groovy ru.vyarus.gradle.plugin.animalsniffer CheckTaskHelper groovy💡 Result:
In the context of the ru.vyarus.gradle.plugin.animalsniffer plugin, there is no public API class named CheckTaskHelper documented in the official repository [1][2]. The plugin is a Gradle tool used to check API compatibility against AnimalSniffer signatures for Java, Kotlin, Groovy, and Scala projects [1]. While the plugin internally manages tasks for checking compatibility and building signatures, configuration and customization are typically performed through the animalsniffer extension and specific task types exposed by the plugin, such as ru.vyarus.gradle.plugin.animalsniffer.signature.BuildSignatureTask or ru.vyarus.gradle.plugin.animalsniffer.info.SignatureInfoTask [1][3][2]. If you encounter references to a CheckTaskHelper, it is likely an internal class within the plugin's source code not intended for public use or configuration [4]. You can manage check tasks and performance (such as enabling caching) via the animalsniffer block in your build.gradle file: animalsniffer { cache { enabled = true } } For debugging or inspecting task registration, the plugin provides utility tasks like printAnimalsnifferTasks and printAnimalsnifferSourceInfo [1][5].
Citations:
🌐 Web query:
site:github.com/xvik/gradle-animalsniffer-plugin src/main/groovy AnimalSnifferExtension groovy💡 Result:
The file src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/AnimalSnifferExtension.groovy is a core component of the gradle-animalsniffer-plugin [1], a popular Gradle plugin developed by xvik (Vyarus) used to verify API compatibility of Java, Kotlin, Groovy, Scala, and Android projects against specific signatures (such as JDK or Android SDK versions) [2]. In the plugin's source code, AnimalSnifferExtension.groovy defines the configuration extension for the plugin [2]. This extension allows users to configure the plugin's behavior within their build.gradle or build.gradle.kts files [2]. Key details regarding the plugin and its extension include: 1. Functionality: The plugin ensures that the code being built does not accidentally use APIs that are not available in the target environment (e.g., ensuring a library meant for Java 8 doesn't use Java 11 APIs) [2]. 2. Usage with Groovy: The plugin supports Groovy projects, though it is specifically noted that Groovy projects should use
@CompileStaticfor optimal compatibility checking [2]. 3. Configuration: Users interact with the extension to define signatures, check configurations, and manage other plugin settings [2]. The wiki documentation provides further details on how to configure tasks and custom signatures [3]. 4. Development: The file is located in the plugin's source repository at src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/ [1]. The plugin is actively maintained, with recent versions (such as 2.0.1) released as of early 2025 [4][5]. For detailed usage, you can refer to the official repository at https://github.com/xvik/gradle-animalsniffer-plugin [2].Citations:
🌐 Web query:
"com.toasttab.android:gummy-bears-api-24" "java.io.File" "toPath" Android signature💡 Result:
The com.toasttab.android:gummy-bears-api-24 artifact is part of the Gummy Bears project, which provides Animal Sniffer signatures for Android APIs [1][2]. These signatures help developers ensure their code does not accidentally use APIs that are unavailable on their minimum supported Android version, while accounting for APIs made available through core library desugaring [1][3]. Regarding java.io.File.toPath, here is the context for its usage with Android and Gummy Bears: 1. Availability in Android: The java.io.File.toPath method was added to the Android platform in API level 26 [4]. It allows for obtaining a java.nio.file.Path object from a java.io.File instance [5][6]. 2. Role of Gummy Bears: Because java.io.File.toPath is not natively available on Android devices below API level 26, developers using core library desugaring may be able to use this method on older API levels [7]. Gummy Bears provides specialized Animal Sniffer signatures (such as those with the coreLib2 classifier) that include these desugared APIs [1][2]. 3. Usage in Animal Sniffer: If you are using Gummy Bears to prevent the accidental use of unavailable APIs, you would include the appropriate signature in your build configuration [1][2]. For projects utilizing core library desugaring, you would specifically reference the signature artifact that includes those desugared methods [1][2]: // Example using core library desugaring signatures dependencies { signature('com.toasttab.android:gummy-bears-api-24:0.14.0:coreLib2@signature') } Note: When using signatures with classifiers (like coreLib2), some versions of the animal-sniffer-maven-plugin may have difficulty consuming the artifact directly due to how classifiers are handled [8]. You may need to ensure your plugin configuration is set up correctly or consider the workarounds documented by the community [8].
Citations:
🌐 Web query:
Gummy Bears 0.15.0 coreLib2 java.util.zip.ZipOutputStream API level signature💡 Result:
The Gummy Bears library (com.toasttab.android:gummy-bears) is a tool that provides Animal Sniffer signatures to validate that Android code does not use APIs unavailable on specific Android versions [1][2]. The 0.15.0 version, released on July 15, 2026, continues to provide these signatures [3][4]. Regarding the coreLib2 classifier and java.util.zip.ZipOutputStream: 1. Purpose of coreLib2: The coreLib2 classifier in Gummy Bears provides experimental sets of signatures for APIs made available to older Android versions via Android's core library desugaring (desugar_jdk_libs version 2.1.5 or above) [1][2]. These are used to ensure that libraries are compatible with projects that enable this desugaring at build time [1]. 2. java.util.zip.ZipOutputStream API level: - The java.util.zip.ZipOutputStream class has been part of the Android SDK since API level 1 [5]. - Consequently, basic constructors and methods for ZipOutputStream are available from API level 1 [5]. - If you are specifically looking for signatures related to ZipOutputStream within Gummy Bears, note that because it is a standard Java API available since the beginning of Android, it does not typically require "desugaring" (which is used for bringing newer Java APIs like java.time to older Android versions) [1][5]. If you are using the coreLib2 classifier to validate your project, it is designed to account for these backported/desugared APIs [1]. Since java.util.zip.ZipOutputStream is not a desugared API in the same category as java.time or ConcurrentHashMap, its standard usage is governed by the base Android API level signatures rather than the coreLib2 desugared signatures [1][5].
Citations:
🌐 Web query:
"gummy-bears-api-24" "java.io.File" "open" "newFile" signature💡 Result:
The identifier gummy-bears-api-24 refers to a library provided by open-toast that supplies Animal Sniffer signatures for Android API level 24 [1][2]. These signatures are used to ensure code compatibility by detecting the use of APIs that are not available on specific Android versions, taking into account desugared APIs [1][3]. There is no "open newFile" method or signature in the java.io.File class. The java.io.File class in the standard Java API (JDK) provides the following constructor signatures for creating a new File instance [4][5]: public File(String pathname) public File(String parent, String child) public File(File parent, String child) public File(URI uri) The gummy-bears library does not modify the standard Java File class or its constructors; it merely provides signature files (based on the Animal Sniffer format) used to validate your code against the Android SDK's surface area [1][2]. If you are encountering an error related to java.io.File while using gummy-bears, it is likely due to your code attempting to use a constructor or method signature that does not exist in the Java API or is not permitted by the API level you are targeting [1][3].
Citations:
Exclude only
File.toPath()from AnimalSniffer.ignore = listOf("java.io.File")suppresses validation across the entirejava.io.FileAPI, not just theFile.toPath()call referenced by the comment. Confine the exception to the Android-facing code path, or target the narrowest supported suppression mechanism so future incompatibleFileAPIs remain caught.🤖 Prompt for AI Agents