Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions .github/workflows/android_windows_sources.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
name: Android native sources on Windows

on:
pull_request:
paths:
- zstandard_android/**
- zstandard_native/**
- scripts/check_android_windows_sources.py
- scripts/check_android_native_sources.py
- scripts/download_android_windows_tools.py
- .github/workflows/android_windows_sources.yml
push:
branches: [develop]
paths:
- zstandard_android/**
- zstandard_native/**
- scripts/check_android_windows_sources.py
- scripts/check_android_native_sources.py
- scripts/download_android_windows_tools.py
- .github/workflows/android_windows_sources.yml

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
reproduce-source-resolution:
name: Android Pub-cache regression on Windows
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
runs-on:
group: vypdev
labels: [self-hosted, Windows, X64]
timeout-minutes: 30
env:
PYTHONDONTWRITEBYTECODE: '1'
PYTHONUTF8: '1'
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Prepare verified job-local Python without a Windows installer
shell: powershell
env:
REPRODUCTION_REPORT: ${{ runner.temp }}/zstandard-android-windows-${{ github.run_id }}-${{ github.run_attempt }}
run: |
$ErrorActionPreference = 'Stop'
$ProgressPreference = 'SilentlyContinue'
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
New-Item -ItemType Directory -Path $env:REPRODUCTION_REPORT -Force | Out-Null
$utf8 = New-Object System.Text.UTF8Encoding($false)
$version = '3.13.17'
$expected = '9e35319bffedab8b36ad44d8f377cb4f1733bcec257a0b6d04d94f01486ddb38'
$url = "https://www.python.org/ftp/python/$version/python-$version-embed-amd64.zip"
[IO.File]::WriteAllText((Join-Path $env:REPRODUCTION_REPORT 'python-bootstrap.txt'), "$url`nSHA256 $expected`n", $utf8)
$directory = Join-Path $env:RUNNER_TEMP "zstandard-python-$env:GITHUB_RUN_ID-$env:GITHUB_RUN_ATTEMPT"
New-Item -ItemType Directory -Path $directory | Out-Null
$archive = Join-Path $directory 'python.zip'
Invoke-WebRequest -UseBasicParsing -Uri $url -OutFile $archive
if ((Get-FileHash -Algorithm SHA256 $archive).Hash.ToLowerInvariant() -ne $expected) {
throw 'The portable Python archive does not match the official release checksum.'
}
$runtime = Join-Path $directory 'runtime'
Expand-Archive -LiteralPath $archive -DestinationPath $runtime
& (Join-Path $runtime 'python.exe') --version
if ($LASTEXITCODE -ne 0) { throw 'The job-local Python runtime could not execute.' }
[IO.File]::AppendAllText($env:GITHUB_PATH, "$runtime`n", $utf8)
- uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
- name: Isolate Gradle state
shell: powershell
run: |
$directory = Join-Path $env:RUNNER_TEMP "zstandard-gradle-$env:GITHUB_RUN_ID-$env:GITHUB_RUN_ATTEMPT"
New-Item -ItemType Directory -Path $directory | Out-Null
$utf8 = New-Object System.Text.UTF8Encoding($false)
[IO.File]::WriteAllText((Join-Path $directory 'gradle.properties'), "org.gradle.daemon=false`norg.gradle.workers.max=2`n", $utf8)
[IO.File]::AppendAllText($env:GITHUB_ENV, "GRADLE_USER_HOME=$directory`n", $utf8)
- uses: gradle/actions/setup-gradle@v4
with:
gradle-version: '8.14.2'
cache-disabled: true
- name: Prepare a private Windows Android SDK
shell: powershell
env:
REPRODUCTION_REPORT: ${{ runner.temp }}/zstandard-android-windows-${{ github.run_id }}-${{ github.run_attempt }}
run: |
$ErrorActionPreference = 'Stop'
$utf8 = New-Object System.Text.UTF8Encoding($false)
$sdk = Join-Path $env:RUNNER_TEMP ("zstandard-android-sdk-{0}-{1}" -f $env:GITHUB_RUN_ID, $env:GITHUB_RUN_ATTEMPT)
python scripts/download_android_windows_tools.py --sdk-root "$sdk" --report-directory "$env:REPRODUCTION_REPORT"
if ($LASTEXITCODE -ne 0) { throw 'The reviewed command-line tools could not be prepared.' }
$env:ANDROID_HOME = $sdk
$env:ANDROID_SDK_ROOT = $sdk
$env:ANDROID_USER_HOME = Join-Path $sdk 'user-state'
New-Item -ItemType Directory -Path $env:ANDROID_USER_HOME | Out-Null
python scripts/download_android_windows_tools.py --sdk-root "$sdk" --report-directory "$env:REPRODUCTION_REPORT" --install-packages
if ($LASTEXITCODE -ne 0) { throw 'The private Windows Android SDK could not be provisioned.' }
Write-Host ("[{0:o}] Private Android SDK provisioning finished" -f (Get-Date))
foreach ($name in @('ANDROID_HOME', 'ANDROID_SDK_ROOT', 'ANDROID_USER_HOME')) {
$value = [Environment]::GetEnvironmentVariable($name)
[IO.File]::AppendAllText($env:GITHUB_ENV, "$name=$value`n", $utf8)
}
- name: Reproduce the published failure and validate the candidate resolver
shell: powershell
env:
REPRODUCTION_REPORT: ${{ runner.temp }}/zstandard-android-windows-${{ github.run_id }}-${{ github.run_attempt }}
run: |
$ErrorActionPreference = 'Stop'
python scripts/check_android_windows_sources.py --baseline-version 1.5.3 --gradle (Get-Command gradle.bat).Source --report-directory "$env:REPRODUCTION_REPORT"
if ($LASTEXITCODE -ne 0) { throw 'Android source resolver regression failed.' }
- name: Retain Windows source resolution and toolchain evidence
if: always()
uses: actions/upload-artifact@v5
with:
name: android-windows-source-reproduction-${{ github.run_attempt }}
path: ${{ runner.temp }}/zstandard-android-windows-${{ github.run_id }}-${{ github.run_attempt }}
if-no-files-found: error
retention-days: 14
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 1.5.5 - Release fix Android native sources from the Windows Pub cache

- Fix Android native-source discovery for consumers using the Windows Pub cache, including paths with spaces, Unicode and correctly resolved package-config URIs.
- Resolve the selected `zstandard_native` dependency from the consumer or workspace package configuration, validate the source tree, and retain explicit `ZSTD_ROOT` overrides.
- Add a real Windows regression that reproduces the published failure, passes 16 Gradle resolver cases and compiles the Android ARM64 library.
- Keep Android runtime coverage in the Linux Flutter/JNI matrix. Windows headless emulator stability is tracked separately in #184 and is not claimed as validated runtime coverage.
- Minimum SDK requirements remain Dart ^3.12.0 and Flutter >=3.44.0. Validation uses Flutter 3.47.2; no public API or SDK minimum changes are introduced by this patch.

## 1.5.4 - Validate complete deployment flow in one pass

- Maintenance patch to validate the complete Copilot-managed deployment flow with the publisher and CI fixes delivered in 1.5.3.
Expand Down
3 changes: 2 additions & 1 deletion docs/development/building.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,11 @@ If you are developing or modifying a platform package’s native code:

### Android

- The plugin builds the native library via `zstandard_android/zstd_build/CMakeLists.txt`, which compiles sources from `zstandard_native/src/zstd/` (resolved from the repo or pub cache).
- The plugin builds the native library via `zstandard_android/zstd_build/CMakeLists.txt`. Gradle reads the consuming app or workspace's `.dart_tool/package_config.json`, resolves the exact `zstandard_native` file URI and passes its `src/zstd` path to CMake. The plugin and native package can both live in a versioned Pub cache outside the consuming app, including Windows paths with spaces.
- The Android plugin uses Built-in Kotlin with AGP 9 and newer. The Android examples exercise this path with Flutter 3.47+.
- Building the Android app (e.g. `flutter build apk` or running from Android Studio) triggers the native build via Gradle/CMake.
- Ensure the NDK is installed and that `zstandard_native` is available (e.g. `flutter pub get` so the canonical `zstandard_native/src/zstd/` is resolved).
- For an explicit source override, set the Gradle property `ZSTD_ROOT` (or its environment variable) to the directory containing `zstd.h`; direct CMake callers use `-DZSTD_ROOT=...`. Overrides take precedence. With no consumer package configuration, a direct repository build can use the sibling native package. A missing or invalid configured dependency fails rather than selecting a different cached package.

### iOS / macOS

Expand Down
6 changes: 6 additions & 0 deletions docs/development/ci-cd.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ They provide Android emulator/instrumentation, Linux desktop, ChromeDriver,
Windows desktop/native, and both SwiftPM and CocoaPods Apple integration. They
also run publish dry-runs and coverage where applicable.

`android_windows_sources.yml` separately verifies Android source discovery on
a Windows host with both packages staged in a versioned cache outside the
consumer and builds ARM64 native code. Android execution coverage remains in
the Linux emulator matrix. See the [Windows Android runner
contract](self-hosted-ci.md#android-builds-hosted-on-windows).

Actions in workflows and composite actions must use version tags such as
`@v1`, `@v2` or `@v3`. Commit SHA references are not permitted. The package
preparation contract checks this policy when workflow or action files change.
Expand Down
28 changes: 28 additions & 0 deletions docs/development/self-hosted-ci.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,34 @@ Windows setup resolves CMake and CTest from the job's current `PATH`, a standalo

The workflow builds `zstandard_windows/example` in Debug mode, runs the generated native test target (including a zstd compression/decompression round trip), runs the Windows package tests with the built DLL on `PATH`, and launches the example for Flutter integration tests. The same sequence is repeated with the current `zstandard_native` package staged outside the checkout and selected through `package_config.json`. A separate federated-example job builds `zstandard/example` and runs its integration suite.

### Android builds hosted on Windows

`android_windows_sources.yml` adds one targeted job for relevant pull requests
and pushes to `develop`. It reproduces the original published Android source
lookup failure, then stages both candidate packages outside the checkout and
outside a separate consuming app. Production Gradle resolver checks cover two
cached native versions, absolute and relative file URIs, Windows drive paths,
spaces, Unicode, workspace ancestors, overrides and invalid dependencies.
NDK 27.0.12077973 with CMake 3.22.1 builds the corrected ARM64/API 21 library.

Linux retains the complete Flutter integration and JNI instrumentation matrix.
The Windows job covers host-specific source discovery and compilation. It does
not claim Android runtime coverage. A Windows emulator requires separate
infrastructure validation: the current runner reported unavailable hardware
virtualization, and API 30 ATD software-emulator trials did not reach a stable
boot. Enabling Windows runtime checks requires a reproducible successful boot
and test execution first.

Portable Python and Android command-line tools use reviewed archive checksums.
The job requires HTTPS access to Python, Google SDK repositories, Gradle
distributions and pub.dev archives.
Java 17 and Gradle 8.14.2 are selected per job. The Android SDK, Gradle state and
test fixtures live in private job directories, including on cancellation. Only
the NDK and CMake packages are provisioned; no system image is downloaded for
the compilation check. The job does not change machine-wide SDK, virtualization
or PATH settings. Missing tools, failed resolution and failed compilation are
explicit errors; diagnostic artifacts are retained for 14 days.

## Web job requirements

Flutter 3.47.2 does not support running `package:integration_test` directly with `flutter test -d chrome`. The workflow therefore uses the supported WebDriver path:
Expand Down
Loading
Loading