CI: compile the Kotlin plugin and run the unit tests - #143
Merged
Conversation
Two gaps found while chasing a compile failure on #142: CI builds Unity players but has never compiled the Android plugin module, and it compiles the test assembly without ever running the tests. android-library compiles unity-plugin with plain gradle. The module is an ordinary Android library, so this needs no Unity and no license seat, and it closes the larger gap of the two -- no AAR is checked in and the existing Unity build never invokes this module, so every Kotlin change so far has reached review unverified. tests runs the EditMode suite through game-ci/unity-test-runner. The tests have existed and been compiled for a while but could not fail a PR. unityVersion defaults to auto, reading ProjectSettings/ProjectVersion.txt, so there is no editor version pinned here. tests is sequenced after ci rather than run alongside it. Every Unity job holds a serial license seat for its duration and the ci matrix already holds two, so running it in parallel would require a third simultaneous seat. This keeps peak concurrency at the two that CI already demonstrates, at the cost of wall-clock. Not covered by this change: the Swift under Assets/Plugins/iOS is still compiled by nothing. That needs macOS plus either a full Unity install or a SwiftPM type-check harness, and belongs in its own change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
First run of android-library failed: JetifyTransform could not find
unity-plugin/libs/unity-classes.jar. The module compiles against it
(compileOnly files('libs/unity-classes.jar')), the jar is gitignored, and
copyUnityClassesJar sources it from $UNITY_CLASSES_JAR or else a macOS Unity Hub path --
the same shape as getUnityExePath() in the root build.gradle. On a bare Linux runner the
Copy task finds nothing, no-ops silently, and Kotlin compilation then fails on a missing
classpath entry.
So my "this needs no Unity" premise was wrong: the jar only exists inside a Unity
install. Run the job in the game-ci editor image to get it. No Unity process is launched,
so this still consumes no license seat, unlike the ci and tests jobs.
The jar is located with find rather than hardcoded, because the
Variations/<backend>/Release/Classes layout has moved between editor versions. The image
tag is pinned and, as in release.yaml, checked against ProjectVersion.txt so it cannot
drift silently.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…owing
First run of the new tests job: 46 tests, 45 passed, 1 failed.
Unhandled log message: '[Error] Airship: unable to parse push message: JSON
parse error: Invalid value.'. Use UnityEngine.TestTools.LogAssert.Expect
The test feeds deliberately malformed JSON, FromJson logs the parse failure before
returning null as designed, and Unity's test runner fails any test that emits an
unexpected error log. A test-authoring bug, not a defect in PushMessage -- and one that
was invisible while nothing ran the suite.
Matched with a regex rather than the full string: the tail of the message is
JsonUtility's own wording and can change between editor versions.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ulrico972
approved these changes
Aug 21, 2026
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two coverage gaps found while chasing a compile failure on #142. Base is
MOBILE-3815so the in-flight release work picks these checks up immediately.What CI missed
AirshipSDK.dll)unity-plugin)Assets/Plugins/iOS)The Kotlin gap is the bigger of the two. No AAR is checked in, and the existing Unity player build never invokes the
unity-plugingradle module, so every Kotlin change to date reached review without a compiler ever looking at it. #142 changes the Android event pump,trackScreen's nullability and the live-update payload shape — none of that is currently verified by anything.The tests have existed and been compiled for a while, they just could not fail a PR.
The two jobs
android-library—./gradlew :unity-plugin:assembleRelease, run inside the game-ci editor image.I first wrote this as a plain ubuntu job on the premise that an Android library needs no Unity. That was wrong, and the first CI run said so:
unity-plugincompiles againstcompileOnly files('libs/unity-classes.jar'), the jar is gitignored, andcopyUnityClassesJarsources it from$UNITY_CLASSES_JARor else a macOS Unity Hub path — the same shape asgetUnityExePath()in the rootbuild.gradle. On a bare Linux runner the Copy task finds nothing, no-ops silently, and Kotlin compilation fails on a missing classpath entry.The job now runs in the editor image purely to obtain that jar, located with
findrather than a hardcodedVariations/<backend>/Release/Classespath since that layout has moved between editor versions. No Unity process is launched, so it still consumes no license seat — unlikeciandtests. The image tag is pinned and checked againstProjectVersion.txt, same asrelease.yaml.tests—game-ci/unity-test-runner@v4,testMode: EditModebecauseTests.asmdefis Editor-only.unityVersiondefaults toauto, which readsProjectSettings/ProjectVersion.txt, so there is no editor version pinned here to drift.Why
testshasneeds: ciA Unity serial has a fixed seat count, and each Unity job holds one for its whole duration. The
cimatrix already holds two concurrently — which is the most this repo has ever demonstrated working. Runningtestsin parallel would need a third simultaneous seat, and the failure mode is ugly: activation fails with an error that reads as a broken workflow rather than a capacity limit.Sequencing keeps peak concurrency at two. The cost is wall-clock —
testswaits for both player legs.Note this does add one more activate/return cycle per PR run. Peak concurrency is unchanged, but it is one more round trip to Unity's licensing service, and one more place a hard-killed runner can leak a seat.
Swift is deliberately out of scope
Assets/Plugins/iOS/*.swiftis still compiled by nothing, and the changes in #142 touch it. Two options, neither a config tweak:xcodebuild. Roughly 30–45 minutes against ~5 for the Linux legs, plus SPM resolution, the post-build script and another license seat. Slow and fragile.Package.swiftdepending onAirshipFrameworkProxythat includes the plugin's Swift sources with a stub forAirshipUnityCBridge. No Unity, no seat, a few minutes, and it gives real type checking. Needs the stub written and maintained, and it would not catch problems in the generated Xcode project or the post-build script.A
swiftc -parsesyntax check is not worth adding: it would miss type errors, which is exactly where the risk in #142 sits, so a green result would be false confidence.I'd suggest the harness as a follow-up ticket rather than blocking on it here.
Suggested order
Merge this before #142, so #142's next run compile-checks its Kotlin and runs its tests.
First-run risks
Neither job has run yet — no way to exercise a
pull_requestworkflow without a PR.android-librarymay needcompileSdk 36downloaded inside the container. The image accepts SDK licences and makes the SDK dir writable, so AGP should handle it, but it's the most likely remaining wrinkle.unity-test-runnerpassescoverageOptionsby default; if the code-coverage package isn't present Unity should ignore the arguments, but that's the second thing to look at.🤖 Generated with Claude Code