Skip to content

Upgrade to .NET 10 and harden CI reliability - #74

Merged
mattleibow merged 44 commits into
mainfrom
best56/f2-2-workflows
Feb 22, 2026
Merged

mattleibow merged 44 commits into
mainfrom
best56/f2-2-workflows

Conversation

@mattleibow

@mattleibow mattleibow commented Feb 18, 2026 •

Copy link
Copy Markdown
Collaborator

Why

The project was still on .NET 9 with older GitHub Actions versions, and emulator CI runs were flaky enough that macOS matrix legs couldn't be trusted. This PR upgrades everything to .NET 10 and fixes the specific reliability gaps that were causing intermittent failures — so we ship a modern baseline with a CI pipeline that actually stays green.

What's in this PR

.NET 10 target frameworks

  • AndroidSdk (core library) — added net10.0 alongside existing targets (netstandard2.0, net6.0, net8.0); no compatibility change
  • AndroidRepository — added net10.0 alongside existing targets
  • AndroidSdk.Tool — added net10.0 alongside existing targets
  • AndroidSdk.Tests — moved from net9.0 to net10.0
  • AndroidSdk.Adbd.Tests — moved from net9.0 to net10.0

Workflow modernization (build-publish.yml)

  • Bumped actions/checkout to v4, actions/setup-dotnet to v4, actions/download-artifact to v4
  • Updated .NET SDK from 9.0.x to 10.0.x

Test workflow overhaul (test.yml)

  • Expanded from single macOS runner to Ubuntu + macOS matrix with fail-fast: false
  • Added KVM setup for Linux emulator support
  • Updated all actions to v4 and .NET to 10.0.x
  • TRX results now uploaded as artifacts per matrix leg
  • Added a dedicated Publish Test Results job that downloads artifacts and publishes via EnricoMi/publish-unit-test-result-action@v2
  • Upload and publish both use always() && !cancelled() so results are never lost on failed test runs

Emulator run workflow overhaul (run.yml)

  • Expanded from Ubuntu-only to Ubuntu + macOS matrix with per-OS GPU and image config
  • All commands switched from dotnet run --framework net9.0 --project AndroidSdk.Tool -- to dotnet $TOOL using the pre-built DLL
  • Centralized job-level constants: AVD_NAME, TEST_APP_PACKAGE, APP_START_MARKER — no more magic strings scattered through steps
  • KVM step now conditional on Linux only
  • AVD start uses --cpu-threshold 3.0 to wait for the guest CPU to settle before proceeding
  • Install validation retries package visibility up to 12 times (the install itself is a single Do step)
  • Launch validation consolidated into one step that polls logcat for APP_START_MARKER
  • Artifact names now include ${{ matrix.os }}

CLI improvements (AvdStartCommand.cs)

  • Renamed --disable-animations to --no-animations|--no-anim to match the --no-window/--no-audio/--no-boot-anim naming convention
  • CPU threshold timeout now exits with code 1 (matching boot timeout behavior) instead of silently proceeding
  • Boot wait and CPU wait now log elapsed time and final values for CI diagnostics

Process output reliability (ProcessRunner.cs)

  • Added TaskCompletionSource signals for stdout/stderr stream closure
  • WaitForExit() now waits up to 5 seconds for both streams to close after the process exits, preventing a race where output lines were silently lost

App launch reliability (Adb.cs)

  • LaunchApp now retries monkey up to 3 times with a 1-second delay between attempts
  • Added --pct-syskeys 0 to prevent random HOME/BACK key events during launch
  • Returns early on Events injected success; on exhausted retries, returns the last attempt output (never throws)
  • Catches SdkToolFailedExitException on intermediate attempts and preserves StdOut for the return value

Emulator lifecycle reliability (Emulator.cs)

  • FindRunningEmulatorSerialByAvdName catches transient SdkToolFailedExitException from adb.GetDevices() and returns null — the caller's polling loop retries naturally
  • StopAvd polling and final check now also catch transient SdkToolFailedExitException from adb.GetDevices() instead of crashing during emulator shutdown
  • WaitForCpuLoadBelow now exposes the last observed load value for diagnostic reporting

Test fixture reliability (EmulatorTestsBase.cs)

  • Increased EmulatorBootFixture boot timeout from 15 to 20 minutes — macOS CI runners show boot times ranging from 4 to 14+ minutes

Breaking changes

  • --disable-animations CLI flag removed; use --no-animations or --no-anim instead
  • --cpu-threshold timeout now returns exit code 1 (previously returned 0 with a warning)

Explicitly excluded

  • API 36 / logcat fallback behaviour changes that have repeatedly been reverted

Validation

  • dotnet build --configuration Release ✅
  • Focused test runs for process-runner, emulator, and launch paths ✅
  • Full CI matrix (Ubuntu + macOS) for Tests, Run, and Build workflows ✅

@github-actions

github-actions Bot commented Feb 18, 2026 •

Copy link
Copy Markdown

Test Results

  4 files    4 suites   21m 19s ⏱️
103 tests 100 ✅ 3 💤 0 ❌
206 runs  200 ✅ 6 💤 0 ❌

Results for commit 0bfaf17.

♻️ This comment has been updated with latest results.

@mattleibow mattleibow changed the title Consolidate CI workflow modernization into a single follow-up PR Unify .NET 10 target upgrades and CI workflow modernization Feb 18, 2026
@mattleibow
mattleibow changed the base branch from best56/f2-1-net10-all to main February 18, 2026 12:58
@mattleibow
mattleibow requested a review from Copilot February 18, 2026 19:02

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Consolidates the repo’s modernization track by moving project targets to .NET 10 and refreshing CI workflows, while also improving emulator/device command robustness (process output draining, adb transient handling, and app launch retries).

Changes:

  • Add/advance .NET 10 target frameworks across tool/library/test projects.
  • Modernize GitHub Actions workflows (actions versions, .NET 10 baselines, OS matrices, artifact-based TRX publishing, and dotnet $TOOL invocation).
  • Improve runtime reliability around adb/emulator operations (transient adb failures, app launch retries, and process output completion).

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
AndroidSdk/ProcessRunner.cs Waits briefly for stdout/stderr close events after process exit to reduce truncated output.
AndroidSdk/Emulator/Emulator.cs Treats transient adb failures as “not found” during emulator serial discovery.
AndroidSdk/Adb/Adb.cs Adds retry logic and syskey suppression for monkey-based app launches.
AndroidSdk.Tool/Commands/Device/DeviceLaunchCommand.cs Adjusts CLI launch handling when no activity is specified.
AndroidSdk.Tool/AndroidSdk.Tool.csproj Adds net10.0 to tool multi-targeting.
AndroidSdk.Tests/EmulatorOperations_Tests.cs Updates emulator launch assertion to match new launch behavior.
AndroidSdk.Tests/AndroidSdk.Tests.csproj Moves tests to net10.0.
AndroidSdk.Adbd.Tests/AndroidSdk.Adbd.Tests.csproj Moves tests to net10.0.
AndroidRepository/AndroidRepository.csproj Adds net10.0 to library multi-targeting.
.github/workflows/test.yml Adds Linux+macOS matrix, uploads TRX artifacts, and separates publishing into a follow-up job.
.github/workflows/run.yml Updates to .NET 10 and modernizes command execution (dotnet $TOOL), plus matrix coverage and more validations.
.github/workflows/build-publish.yml Updates actions and .NET baseline to .NET 10.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread AndroidSdk/ProcessRunner.cs
Comment thread AndroidSdk/Adb/Adb.cs
Comment thread AndroidSdk.Tool/Commands/Device/DeviceLaunchCommand.cs Outdated
Comment thread .github/workflows/test.yml
Comment thread .github/workflows/test.yml Outdated
mattleibow and others added 17 commits February 18, 2026 22:27
This aligns project targets with the deferred net10 modernization from #56 while keeping the scope intentionally mechanical and low risk. The change only updates target framework declarations and avoids behavioral churn so it can be reviewed independently from workflow changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…r updates

This is PR 2 of 2 in the follow-up plan: all workflow modernization lands in one place after the net10 framework PR. It upgrades workflow tooling to .NET 10, adopts matrix-based CI coverage, and switches run workflow invocations to the built tool DLL while preserving strict launch-marker checks and avoiding API36/logcat fallback pivots.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reruns on the previous workflow run IDs kept producing a stale failing Test Results check due mixed-attempt artifacts. This empty commit triggers fresh pull_request runs with clean artifacts for reliable status.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ases

The Ubuntu matrix leg was repeatedly failing on emulator-boot dependent tests while the macOS leg remained the full integration signal. This keeps broad test coverage in place, preserves full macOS validation, and makes Linux CI deterministic by filtering only the known flaky emulator-dependent cases.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- restore full test matrix execution in workflow test job
- handle transient adb device-list failures during emulator startup
- improve ProcessRunner stream-drain reliability before returning
- harden LaunchApp monkey invocation with syskey filtering and retries

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The macOS emulator job can hang in the AVD start step when boot detection stalls. This caps wait time with --timeout 300 so the step is bounded and can recover on rerun instead of hanging indefinitely.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The macOS emulator run intermittently fails with PackageInstaller storage NPE during app install. Add a bounded retry loop that rechecks package presence to make install robust without weakening validation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Change app launch logic to check for output success.
@mattleibow
mattleibow force-pushed the best56/f2-2-workflows branch from b34eef1 to 3963894 Compare February 18, 2026 20:28
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread AndroidRepository/AndroidRepository.csproj
Comment thread AndroidSdk/Emulator/Emulator.cs
Comment thread AndroidSdk/ProcessRunner.cs
Comment thread AndroidSdk/Emulator/Emulator.cs
Comment thread AndroidSdk/Adb/Adb.cs
@mattleibow mattleibow changed the title Unify .NET 10 target upgrades and CI workflow modernization Modernize .NET 10 + CI workflows with reliability fixes Feb 18, 2026
mattleibow and others added 14 commits February 18, 2026 22:52
Adds net10.0 to the multi-target list while preserving all existing
targets (netstandard2.0, net6.0, net8.0) for broad compatibility.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
macOS CI runners have variable boot times (4–14+ min observed).
The 15-minute cap was too tight for slower runs, causing the
EmulatorBootFixture to fail and skipping all EmulatorOperations tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Boot wait now logs elapsed time. CPU threshold wait logs elapsed
time, last observed load, and threshold on both success and timeout.
This makes CI logs actionable when tuning --cpu-threshold values.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace --disable-animations with --no-animations|--no-anim to match
  the --no-window/--no-audio/--no-boot-anim naming convention.
- CPU threshold timeout now sets exit code 1 (matching boot timeout
  behavior) instead of silently proceeding.
- WaitForCpuLoadBelow now exposes last observed load value via out
  parameter for diagnostic reporting.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When --timeout is not set, WaitForBootComplete correctly treats
TimeSpan.Zero as 'wait forever', but GetStepTimeout was returning
a 120s fallback for the CPU threshold wait. Now both treat
TimeSpan.Zero consistently as no timeout.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Restore GetStepTimeout fallback parameter (120s) so WaitForCpuLoadBelow
  never receives TimeSpan.Zero (= infinite loop) when --timeout is omitted
- Revert CPU threshold timeout to warn-and-proceed (remove ok = false):
  CPU is naturally high post-boot on macOS CI (~38 vs 3.0 threshold);
  the emulator is functional so unsettled CPU should warn, not fail
- Extract DefaultCpuSettleTimeoutSeconds constant for clarity
- Add EmulatorStartOptions.Cores (int?) mapped to emulator -cores flag
- Add --cores CLI option to AvdStartCommand (int?, consistent type)
- Wire Cores through AvdStartCommand.ExecuteAsync -> EmulatorStartOptions
- Add --cores ${{ matrix.cores }} to run.yml avd start step (cores: 2)
  so macOS/Ubuntu runners use 2 virtual cores instead of the default 1
- Add AvdStartCommandSettingsAllowCores validation test

Co-authored-by: mattleibow <1096616+mattleibow@users.noreply.github.com>
- Remove DefaultCpuSettleTimeoutSeconds: WaitForCpuLoadBelow now waits
  until --timeout budget expires or the step is cancelled externally
- Revert GetStepTimeout back to 2-parameter signature (no fallback)
- Add timeout-minutes: 30 to the Do Start AVD workflow step so the CI
  job times out cleanly instead of hanging indefinitely
- Move cpu_threshold into the matrix: 30 for macos-15-intel (high post-
  boot load), 3 for ubuntu-latest (KVM stays consistently low)

Co-authored-by: mattleibow <1096616+mattleibow@users.noreply.github.com>
Replace the GitHub Actions timeout-minutes: 30 property with the tool's
own --timeout flag (1800 seconds = 30 min). Add timeout_seconds to the
matrix so each OS entry controls its own boot timeout independently.

Co-authored-by: mattleibow <1096616+mattleibow@users.noreply.github.com>
Fix avd start infinite hang + add --cores and per-OS cpu-threshold
Copilot AI and others added 6 commits February 22, 2026 01:27
…ng on macOS

Co-authored-by: mattleibow <1096616+mattleibow@users.noreply.github.com>
…low emulators

Co-authored-by: mattleibow <1096616+mattleibow@users.noreply.github.com>
Co-authored-by: mattleibow <1096616+mattleibow@users.noreply.github.com>
Fix macOS emulator boot hang: remove launcher focus check, unify --timeout budget
Copilot AI and others added 5 commits February 22, 2026 06:29
…t markers

Co-authored-by: mattleibow <1096616+mattleibow@users.noreply.github.com>
…ring

Co-authored-by: mattleibow <1096616+mattleibow@users.noreply.github.com>
…r-issue

Restore launcher readiness check after boot; require dual logcat markers for launch validation
@mattleibow
mattleibow merged commit ace23a8 into main Feb 22, 2026
9 of 10 checks passed
@mattleibow
mattleibow deleted the best56/f2-2-workflows branch February 22, 2026 17:54
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.

3 participants