Skip to content

ci: add version bump verification and fix bump-version.sh test-app coverage#402

Merged
Kobikg78 merged 55 commits into
masterfrom
development
May 19, 2026
Merged

ci: add version bump verification and fix bump-version.sh test-app coverage#402
Kobikg78 merged 55 commits into
masterfrom
development

Conversation

@Kobikg78
Copy link
Copy Markdown
Collaborator

Summary

  • rc-release.yml: adds Verify version bump step after bumping — fails fast if mainTemplate.gradle, ios-pod-install.sh, or AppsFlyer.cs don't contain the requested versions. Also stages the two newly-patched files in the release commit.
  • scripts/bump-version.sh: now patches test-app/Assets/Plugins/Android/mainTemplate.gradle and scripts/ios-pod-install.sh — previously these were hardcoded and E2E ran against the old SDK versions regardless of pipeline inputs.

Test plan

  • Trigger rc-release.yml — verify step should pass and E2E logs should show the requested SDK versions

🤖 Generated with Claude Code

Kobikg78 and others added 30 commits May 17, 2026 12:52
- Unity test-app with QA scene, scripts and logging (AFQALogger, QATestScript)
- Android: custom activity for deep link onNewIntent, mainTemplate.gradle,
  unitywrapper.aar, AndroidManifest with singleTask launch mode
- iOS: UnityAppControllerDeepLink for deep link handling, AppsFlyerOpenURL.mm
- .af-e2e/test-plan.json: 6-phase E2E plan covering cold launch, deep links,
  custom events, identity APIs, and SDK stop/start (38 checks)
- scripts/: af-scenario-runner.sh, bump-version.sh, ios-pod-install.sh
- .github/workflows/: rc-e2e-android, rc-e2e-ios, rc-release CI workflows
- .claude/: project agents and skills for Unity plugin and E2E testing
- CLAUDE.md: project architecture and workflow documentation
- .gitignore: exclude reports, build artifacts and per-developer settings
- test-app/ProjectSettings/: full Unity project settings for CI builds

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Allows running rc-e2e-android and rc-e2e-ios independently on any branch
without triggering the full rc-release pipeline.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Runs Android and iOS E2E automatically on every push to
plugins-effort-reduction-workflow1, bypassing the default-branch
requirement for workflow_dispatch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Android: add allowDirtyBuild=true to fix game-ci dirty branch error.
iOS: game-ci Docker actions (unity-activate, unity-return-license) only
run on Linux. Split into two jobs — Unity build on ubuntu-latest,
then pod install + xcodebuild + E2E on macos-14.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…OS-only guard

- Set unityVersion to 2020.3.41f1 in both rc-e2e-android and rc-e2e-ios workflows
- Revert test-app/ProjectSettings/ProjectVersion.txt from 6000.3.1f1 to 2020.3.41f1
- Guard iOSBuildPostProcess.cs with UNITY_EDITOR && UNITY_IOS to prevent
  UnityEditor.iOS.Xcode compile error on Android CI image

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…compile error

- Set unityVersion to 6000.3.5f1 in both E2E workflows (matches local build)
- Update ProjectVersion.txt to 6000.3.5f1 accordingly
- Fix UnityAppControllerDeepLink.mm: replace __strong typeof() with explicit
  type to resolve 'undeclared identifier strongSelf' clang error on CI

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Android: remove redundant cp in Locate APK — game-ci already writes
  APK to the expected path, copying to itself caused exit code 1
- iOS: add ARCHS=arm64 VALID_ARCHS=arm64 to xcodebuild — macOS-14 runners
  are Apple Silicon; building x86_64 hit missing Swift overlay libs in Xcode 15+
- iOS: remove || true from xcodebuild so build failures surface properly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Unity on Linux (game-ci Docker) compiles UnityRuntime.framework and baselib.a
as x86_64 only. Must build for x86_64 (Rosetta on M1) — arm64 causes
_UnityAutorotationStatusChanged undefined because the pre-compiled Unity libs
are ignored. Previous x86_64 failures were with Unity 2020, not 6000.3.5f1.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…o.plist

Unity leaves $(CURRENT_PROJECT_VERSION) unresolved in Xcode project;
simulator rejects install without a numeric CFBundleVersion value.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eleration

Without KVM permissions the emulator runs in TCG software mode and never
finishes booting — adb stays offline indefinitely. Standard udev rule fix
grants the runner user access to /dev/kvm before launching the emulator.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rlays

- BuildScript: set AndroidArchitecture.X86_64 so APK installs on x86_64
  emulator (Unity defaults to ARM64 only)
- iOS xcodebuild: add -allow_missing_module_imported_lib to suppress
  auto-linked Swift overlay errors (swift_Builtin_float etc removed in Xcode 15+)
- iOS xcodebuild: add set -o pipefail so build failures surface through xcpretty

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Android: android-emulator-runner runs each script line as a separate
sh -c, so backslash continuations don't work — flatten adb push and
af-scenario-runner.sh onto single lines.

iOS: remove unsupported -allow_missing_module_imported_lib flag (unknown
on Xcode 15/macOS-14); add ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES=YES,
tee raw xcodebuild output so actual linker errors are visible on failure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PurchaseConnector 6.17.9 ships a Pods target
'PurchaseConnector-PurchaseConnector_Privacy' that references a source
file 'PurchaseConnector_Privacy' which does not exist on disk, causing
simulator xcodebuild to abort with "Build input file cannot be found".

Add a post_install hook that strips all build phases from this target,
making it a no-op so the rest of the build proceeds normally.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two bugs prevented any log collection on Android:

1. QATestScript read .env from Application.persistentDataPath (internal
   storage) but the workflow was pushing to external storage — wrong path,
   config never loaded. Fix: use UnityWebRequest to read .env from
   StreamingAssets (already baked into the APK by the CI 'Write .env'
   step). Start() becomes a coroutine (InitAsync) to allow the async read.

2. AFQALogger only wrote af_qa_logs.txt on iOS. On Android only Debug.Log
   was called; after 240s the logcat buffer was overrun by Unity engine
   output and all [AF_QA] lines were lost. Fix: enable file logging on
   Android under the same (UNITY_IOS || UNITY_ANDROID) guard.

Also remove the now-redundant adb mkdir + adb push .env lines from the
workflow — the APK carries .env in its StreamingAssets bundle.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ases

Removing build phases from PurchaseConnector-PurchaseConnector_Privacy
was not enough — Xcode's implicit bundle machinery still runs and fails
looking for the compiled privacy manifest 'PurchaseConnector_Privacy'.

The target must be removed entirely: delete all dependency edges pointing
to it from every other Pods target, then remove it from the root project
target list and the objects map.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All pod privacy bundle targets (AppsFlyerLib_Privacy, PurchaseConnector_Privacy,
etc.) have the same broken compiled-manifest reference. Remove every target
whose name ends with _Privacy, along with all dependency edges pointing to them.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…acos-13

Android log collection broke in two independent ways:

1. run-as fails when adb shell runs as root (Android 10+ CI emulators
   disable run-as for root callers). Result: platform_peek_qa_log always
   returned empty, so the marker wait ran the full 240s every phase.
   Fix: add direct `cat /data/data/<pkg>/files/af_qa_logs.txt` fallback
   in both platform_peek_qa_log and android_collect_logs.

2. `adb logcat -d -t 2000` only captures the last 2000 raw lines. Unity
   generates hundreds of lines/sec, so after the 240s wait the [AF_QA]
   lines (written in the first ~4s) are outside the window. Collected 0
   matching lines even when the app ran correctly.
   Fix: remove the -t limit; the grep filter keeps the output file small.

iOS: switch e2e-ios runner from macos-14 to macos-13. Xcode 15 (macos-14)
dropped x86_64 simulator Swift overlay libraries (swift_DarwinFoundation*,
swift_Builtin_float, SwiftUICore, UIUtilities) that AppsFlyerFramework
6.17.9's x86_64 slice auto-links against. macos-13 uses Xcode 14.3.1
which still ships them.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The root-cat fallback introduced in the previous commit used plain
variable assignments (not local) for the command substitution result.
With `set -euo pipefail`, when `adb shell "cat <path>"` returns non-zero
(file absent or inaccessible), the assignment propagates exit code 1 and
the script exits immediately after printing "Collecting logs...".

Fix: append `|| true` to every fallback `content=$(...)` / `file_content=$(...)
assignment in both platform_peek_qa_log and android_collect_logs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two related bugs caused 0 log lines even when the app ran correctly:

1. Ring buffer overflow: Unity generates ~100-200 logcat lines/sec;
   after a 240s wait the 2M buffer (set by android-emulator-runner) holds
   only the last ~10-20s of output, so [AF_QA] lines written in the first
   ~4s are gone by collection time.
   Fix: call `adb logcat -G 32m` in android_launch() before clearing the
   buffer. 32M holds >5 minutes of typical Unity output.

2. Marker never found early: platform_peek_qa_log only tried run-as and
   root-cat; when both are unavailable the full 240s timeout always fires,
   delaying log collection and wasting CI minutes.
   Fix: add `adb logcat -d | grep AF_QA` as the last-resort peek so the
   marker is found within the first 10s poll and collection runs while
   the buffer is definitely still fresh.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
macos-13 runners are deprecated and have poor availability, causing 20+
minute queue waits. The reason macos-13 was needed: Xcode 15 dropped
x86_64 Swift overlay libs (swift_DarwinFoundation*, SwiftUICore, etc.)
that AppsFlyerFramework 6.17.9 auto-links against, causing linker errors.

Switch to macos-14 (M1) and build arm64 simulator instead. Unity's iOS
simulator framework libraries are fat binaries; the IL2CPP C++ source
is compiled by Xcode on the target machine and is arch-agnostic.
arm64 avoids the missing Swift overlay issue entirely since those
overlays were only dropped for the x86_64 slice.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause of all Android CI failures: the test plan had the wrong
activity name (com.unity3d.player.UnityPlayerActivity). The Unity
AppsFlyer plugin generates AppsFlyerUnityActivity as the launcher
activity. adb shell am start silently failed on every run, the app
never launched, and there were zero logs.

Confirmed locally: with the correct activity the app launches and all
[AF_QA] logs appear correctly within 5 seconds.

Also add ARM64 to the Android build targets alongside x86_64 so the
APK installs on both CI x86_64 emulators and local ARM64 (Apple Silicon)
emulators.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…simulator libs

Replaces the Ubuntu Unity build + macOS xcodebuild two-job approach that
failed because Linux game-ci ships x86_64-only prebuilt libs (baselib.a,
UnityRuntime.framework). Building Unity on macos-14 produces arm64 libs
that match the arm64 xcodebuild target, matching the local setup where
38/38 E2E checks pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…lays

- Add e2e-ios-only.yml: push-triggered, iOS only, no Android
- Remove push trigger from e2e-manual.yml (manual dispatch only)
- Delete rc-e2e-ios-macos.yml (game-ci is container/Linux only, fails on macOS)
- rc-e2e-ios.yml: pin Xcode 15.4 + ARCHS=x86_64 to match Ubuntu Unity libs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…allbacks

Add e2e-android-only.yml (workflow_dispatch, Android only).
Add post_marker_wait_sec: 30 to phases 1/3/5 in test plan so the runner
waits 30s after the auto-run-complete marker before collecting logs —
giving onInstallConversionData time to arrive from AppsFlyer servers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…build

game-ci is Docker/container-only so it can't run on macOS. Linux game-ci
produces x86_64-only prebuilt libs (baselib.a, UnityRuntime.framework).
AppsFlyerFramework 6.17.9 (Swift 6) has no x86_64 simulator support so
x86_64 builds fail on any Xcode. arm64 builds fail because Unity libs
are x86_64-only. Installing Unity directly on macos-14 produces arm64
libs matching the local setup where 38/38 E2E checks pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both workflows are now independent and only run when explicitly triggered.
No automatic runs on push.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Hub CLI requires --changeset for versions not yet in its release catalog.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ctively

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Kobikg78 and others added 25 commits May 18, 2026 11:55
…dless prompt

Unity Hub --headless install uses a TUI architecture prompt that ignores stdin.
Download Editor and iOS module pkgs directly from Unity CDN instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…EYCODE_HOME

On CI emulators, Unity is killed under memory pressure when backgrounded via
KEYCODE_HOME. onNewIntent + performOnDeepLinking then fires before the Unity
runtime is ready → no callback. Force-stopping and cold-launching with the
VIEW intent gives a clean start: SDK initializes fully before processing the
deep link. Verified 38/38 locally.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ources scripts

Unity on ARM64 Mac generates x86_64 simulator baselib.a and UnityRuntime.framework
by default. Copy the arm64 variants from Unity's PlaybackEngines after the build.

CocoaPods resources scripts reference _Privacy.bundle targets that don't exist in
simulator builds — replace those install_resource calls with : (no-op) to prevent
"Build input file cannot be found" failures without breaking bash 3.2 if/fi blocks.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…h Hub and direct pkg install

The direct pkg install puts PlaybackEngines alongside Unity.app, not inside
Unity.app/Contents/. Using find resolves the path correctly in both cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…th __has_include

PurchaseConnector 6.17.9 was compiled with SDK 26.0 which is incompatible with
CI runners on Xcode 16.x. The E2E test app does not exercise purchase connector
functionality, so remove it from the test Podfile.

Also fix AppsFlyeriOSWrapper to compile without PurchaseConnector:
- Move PurchaseConnector-Swift.h import inside the __has_include guard in the header
- Make @interface protocol conformances conditional on PC availability
- Wrap all PC function bodies in #if __has_include guards with no-op stubs
- Wrap PC @implementation methods in the same guard
- Add explicit AppsFlyerLib-Swift.h import so AppsFlyerConsent is fully defined

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
matrix: [1,2,3] with max-parallel:1 avoids Unity license conflicts
(serial can only be active on one machine at a time). fail-fast:false
so all 3 runs complete even if one fails.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
macos-15 runner ships Xcode 26.x. PurchaseConnector 6.17.9 was compiled
with SDK 26.0 and requires it. No conditional compile workarounds needed.

Changes:
- runs-on: macos-14 → macos-15
- Add "Select Xcode 26" step (xcode-select -s Xcode_26.3.app)
- Update cache key to macos15-arm64
- Simulator boot targets iOS-19 (Xcode 26 default runtime)
- Restore PurchaseConnector 6.17.9 in Podfile
- Revert AppsFlyeriOSWrapper.h/.mm to original (no conditional PC guards)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… Podfile

Both binaries compiled with iOS 17.x SDK (no iOS 26 restricted frameworks).
PC 6.18.1 requires AFLib 6.18.0 per podspec dependency.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ards

Reverts to the state of the successful run 26033290223:
- macos-14 runner (no Xcode 26 step)
- AppsFlyerFramework 6.17.9 only in E2E Podfile (no PurchaseConnector)
- __has_include guards in wrapper .h/.mm so PC absence compiles cleanly
- Explicit AppsFlyerLib-Swift.h import for AppsFlyerConsent

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… contract

- rc-release.yml: add RC-PUBLISH job (GitHub pre-release + Jira check + Slack notify)
  after the pre-publish gate; fires only when dry_run=false and both E2E gates pass
- promote-release.yml: new RC-PROMOTE workflow triggered by 'pass QA ready for deploy'
  label on the release PR; strips -rcN from all version surfaces and pushes
- .af-release/rc-plan.json: Unity plugin machine-readable RC plan mapping all
  RC-* stages to workflow files per the tooling contract

RC-RELEASE is handled by the existing release_production_workflow.yml (PR merge → master).
RC-SMOKE deferred (no published-artifact smoke app yet).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Strips the workflow down to the three core steps:
1. Take plugin/android/ios version inputs
2. Cut release branch and apply version bumps
3. Run iOS E2E then Android E2E on that branch

Publish, promote, and release stages come later as separate workflows.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rkflow1

ci: iOS & Android E2E pipeline + RC release workflow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… on Ubuntu

Removes legacy Unity 2019 licensing (game-ci) which uses a deprecated
license server that times out on return. Mirrors the iOS approach:
direct install, entitlement-based activate/return.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Android support is bundled in the base Unity Linux installer.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…dle it

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
game-ci/unity-builder does not return the license on exit.
Run returnlicense explicitly in the same Docker image.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
mainTemplate.gradle and ios-pod-install.sh had native SDK versions
hardcoded — the bump script only updated AppsFlyerDependencies.xml which
is not what the E2E builds actually use. E2E was running against the old
SDK versions regardless of what was passed to the pipeline.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fails fast before Unity builds if bump-version.sh did not correctly
update mainTemplate.gradle, ios-pod-install.sh, or AppsFlyer.cs.
Also stages the two newly-bumped files in the release commit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rkflow1

fix: bump-version.sh must also patch test-app gradle and ios-pod-install
- rc-e2e-ios.yml: bring in retry logic + credentials on license return
- rc-release.yml: fix \d regex to [0-9]+ for Linux grep compatibility

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rkflow1

ci: align workflow files with master — iOS retry, regex fix
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@al-af al-af left a comment

Choose a reason for hiding this comment

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

Approved

@Kobikg78 Kobikg78 merged commit b61f940 into master May 19, 2026
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