From 9a6387c507fc807a11fd140a5883df2437036591 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Fri, 23 Oct 2026 21:42:19 +0200 Subject: [PATCH 01/16] chore(ci): align workflows with shared self-hosted runners --- .../workflows/copilot_credential_health.yml | 32 ++++++++++++++----- .../copilot_pull_request_approval.yml | 4 ++- .../copilot_pull_request_merge_queue.yml | 4 ++- .github/workflows/hotfix_workflow.yml | 4 ++- .github/workflows/pr_check_android.yml | 21 +++++++++--- .github/workflows/pr_check_cli.yml | 16 +++++++--- .github/workflows/pr_check_ios.yml | 21 +++++++++--- .github/workflows/pr_check_linux.yml | 21 +++++++++--- .github/workflows/pr_check_macos.yml | 21 +++++++++--- .../workflows/pr_check_platform_interface.yml | 16 +++++++--- .github/workflows/pr_check_web.yml | 16 +++++++--- .github/workflows/pr_check_windows.yml | 21 +++++++++--- .github/workflows/pr_check_zstandard.yml | 16 +++++++--- .github/workflows/release_workflow.yml | 4 ++- .github/workflows/stale.yaml | 6 ++-- 15 files changed, 168 insertions(+), 55 deletions(-) diff --git a/.github/workflows/copilot_credential_health.yml b/.github/workflows/copilot_credential_health.yml index e87c82a3..58e8f6f9 100644 --- a/.github/workflows/copilot_credential_health.yml +++ b/.github/workflows/copilot_credential_health.yml @@ -51,7 +51,9 @@ jobs: verify-pat: if: ${{ inputs.check_pat }} name: Verify PAT - runs-on: ubuntu-latest + runs-on: + group: vypdev + labels: [self-hosted, codex, Linux] timeout-minutes: 10 steps: - name: Validate PAT without exposing its value @@ -67,7 +69,9 @@ jobs: verify-openai: if: ${{ inputs.check_openai }} name: Verify OPENAI_API_KEY - runs-on: ubuntu-latest + runs-on: + group: vypdev + labels: [self-hosted, codex, Linux] timeout-minutes: 10 steps: - name: Validate OpenAI key without exposing its value @@ -82,7 +86,9 @@ jobs: verify-anthropic: if: ${{ inputs.check_anthropic }} name: Verify ANTHROPIC_API_KEY - runs-on: ubuntu-latest + runs-on: + group: vypdev + labels: [self-hosted, codex, Linux] timeout-minutes: 10 steps: - name: Validate Anthropic key without exposing its value @@ -97,7 +103,9 @@ jobs: verify-google: if: ${{ inputs.check_google }} name: Verify GOOGLE_API_KEY - runs-on: ubuntu-latest + runs-on: + group: vypdev + labels: [self-hosted, codex, Linux] timeout-minutes: 10 steps: - name: Validate Google key without exposing its value @@ -112,7 +120,9 @@ jobs: verify-openrouter: if: ${{ inputs.check_openrouter }} name: Verify OPENROUTER_API_KEY - runs-on: ubuntu-latest + runs-on: + group: vypdev + labels: [self-hosted, codex, Linux] timeout-minutes: 10 steps: - name: Validate OpenRouter key without exposing its value @@ -127,7 +137,9 @@ jobs: verify-cursor: if: ${{ inputs.check_cursor }} name: Verify CURSOR_API_KEY - runs-on: ubuntu-latest + runs-on: + group: vypdev + labels: [self-hosted, codex, Linux] timeout-minutes: 10 steps: - name: Validate Cursor key without exposing its value @@ -142,7 +154,9 @@ jobs: verify-opencode: if: ${{ inputs.check_opencode }} name: Verify OPENCODE_API_KEY - runs-on: ubuntu-latest + runs-on: + group: vypdev + labels: [self-hosted, codex, Linux] timeout-minutes: 10 steps: - name: Validate OpenCode key without exposing its value @@ -157,7 +171,9 @@ jobs: verify-codex-api-key: if: ${{ inputs.check_codex_api_key }} name: Verify CODEX_API_KEY - runs-on: ubuntu-latest + runs-on: + group: vypdev + labels: [self-hosted, codex, Linux] timeout-minutes: 10 steps: - name: Validate Codex API key without exposing its value diff --git a/.github/workflows/copilot_pull_request_approval.yml b/.github/workflows/copilot_pull_request_approval.yml index 3f926e15..672bead8 100644 --- a/.github/workflows/copilot_pull_request_approval.yml +++ b/.github/workflows/copilot_pull_request_approval.yml @@ -15,7 +15,9 @@ on: jobs: observe-approval: name: Copilot - Pull Request Approval - runs-on: ubuntu-latest + runs-on: + group: vypdev + labels: [self-hosted, codex, Linux] timeout-minutes: 15 concurrency: # Some workflow_run payloads omit the PR association. A repository-wide diff --git a/.github/workflows/copilot_pull_request_merge_queue.yml b/.github/workflows/copilot_pull_request_merge_queue.yml index 0be12abd..1ee8335e 100644 --- a/.github/workflows/copilot_pull_request_merge_queue.yml +++ b/.github/workflows/copilot_pull_request_merge_queue.yml @@ -10,7 +10,9 @@ jobs: # GitHub required checks match the job name. Keep this identical to normal # PR analysis while isolating merge-group runs in their own workflow. name: Copilot - Pull Request - runs-on: ubuntu-latest + runs-on: + group: vypdev + labels: [self-hosted, codex, Linux] timeout-minutes: 10 permissions: checks: write diff --git a/.github/workflows/hotfix_workflow.yml b/.github/workflows/hotfix_workflow.yml index aa00184e..844c340d 100644 --- a/.github/workflows/hotfix_workflow.yml +++ b/.github/workflows/hotfix_workflow.yml @@ -159,7 +159,9 @@ jobs: publish: name: Publish accepted production commit if: ${{ inputs.mode == 'publish' }} - runs-on: ubuntu-latest + runs-on: + group: vypdev + labels: [self-hosted, codex, Linux] needs: validate timeout-minutes: 30 permissions: diff --git a/.github/workflows/pr_check_android.yml b/.github/workflows/pr_check_android.yml index 2d991428..207d1c9d 100644 --- a/.github/workflows/pr_check_android.yml +++ b/.github/workflows/pr_check_android.yml @@ -4,7 +4,6 @@ on: pull_request: branches: - '**' - - '!master' push: branches: - develop @@ -19,7 +18,10 @@ env: jobs: check_android_analyze: name: Analyze Android - runs-on: [self-hosted, macOS] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, X64] steps: - uses: actions/checkout@v4 @@ -38,7 +40,10 @@ jobs: check_android_test: name: Test Android - runs-on: [self-hosted, macOS] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, X64] steps: - uses: actions/checkout@v4 @@ -71,7 +76,10 @@ jobs: check_android_test_from_pub_cache: name: Test Android (from pub cache) - runs-on: [self-hosted, macOS] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, X64] steps: - uses: actions/checkout@v4 @@ -115,7 +123,10 @@ jobs: check_android_publish_dry_run: name: Dry Run Publish Android - runs-on: [self-hosted, macOS] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, X64] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/pr_check_cli.yml b/.github/workflows/pr_check_cli.yml index a5d865f4..c2fac608 100644 --- a/.github/workflows/pr_check_cli.yml +++ b/.github/workflows/pr_check_cli.yml @@ -4,7 +4,6 @@ on: pull_request: branches: - '**' - - '!master' push: branches: - develop @@ -19,7 +18,10 @@ env: jobs: check_cli_analyze: name: Analyze CLI - runs-on: [self-hosted, macOS] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 @@ -38,7 +40,10 @@ jobs: check_cli_test: name: Test CLI - runs-on: [self-hosted, macOS] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, ARM64] timeout-minutes: 30 steps: - uses: actions/checkout@v4 @@ -98,7 +103,10 @@ jobs: check_cli_publish_dry_run: name: Dry Run Publish CLI - runs-on: [self-hosted, macOS] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/pr_check_ios.yml b/.github/workflows/pr_check_ios.yml index 3a052ffd..f3dda3cd 100644 --- a/.github/workflows/pr_check_ios.yml +++ b/.github/workflows/pr_check_ios.yml @@ -4,7 +4,6 @@ on: pull_request: branches: - '**' - - '!master' push: branches: - develop @@ -19,7 +18,10 @@ env: jobs: check_ios_analyze: name: Analyze iOS - runs-on: [self-hosted, macOS, X64] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, X64] steps: - uses: actions/checkout@v4 @@ -38,7 +40,10 @@ jobs: check_ios_test: name: Test iOS - runs-on: [self-hosted, macOS, X64] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, X64] steps: - uses: actions/checkout@v4 @@ -63,7 +68,10 @@ jobs: check_ios_test_from_pub_cache: name: Test iOS (from pub cache) - runs-on: [self-hosted, macOS, X64] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, X64] steps: - uses: actions/checkout@v4 @@ -99,7 +107,10 @@ jobs: check_ios_publish_dry_run: name: Dry Run Publish iOS - runs-on: [self-hosted, macOS, X64] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, X64] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/pr_check_linux.yml b/.github/workflows/pr_check_linux.yml index f18dfe2c..ec5f89c3 100644 --- a/.github/workflows/pr_check_linux.yml +++ b/.github/workflows/pr_check_linux.yml @@ -4,7 +4,6 @@ on: pull_request: branches: - '**' - - '!master' push: branches: - develop @@ -19,7 +18,10 @@ env: jobs: check_linux_analyze: name: Analyze Linux - runs-on: [self-hosted, Linux] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, codex, Linux] steps: - uses: actions/checkout@v4 @@ -38,7 +40,10 @@ jobs: check_linux_test: name: Test Linux - runs-on: [self-hosted, Linux] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, codex, Linux] steps: - uses: actions/checkout@v4 @@ -65,7 +70,10 @@ jobs: check_linux_test_from_pub_cache: name: Test Linux (from pub cache) - runs-on: [self-hosted, Linux] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, codex, Linux] steps: - uses: actions/checkout@v4 @@ -95,7 +103,10 @@ jobs: check_linux_publish_dry_run: name: Dry Run Publish Linux - runs-on: [self-hosted, Linux] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, codex, Linux] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/pr_check_macos.yml b/.github/workflows/pr_check_macos.yml index 336e6149..db593ab5 100644 --- a/.github/workflows/pr_check_macos.yml +++ b/.github/workflows/pr_check_macos.yml @@ -4,7 +4,6 @@ on: pull_request: branches: - '**' - - '!master' push: branches: - develop @@ -19,7 +18,10 @@ env: jobs: check_macos_analyze: name: Analyze macOS - runs-on: [self-hosted, macOS, X64] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, X64] steps: - uses: actions/checkout@v4 @@ -38,7 +40,10 @@ jobs: check_macos_test: name: Test macOS - runs-on: [self-hosted, macOS, X64] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, X64] steps: - uses: actions/checkout@v4 @@ -53,7 +58,10 @@ jobs: check_macos_test_from_pub_cache: name: Test macOS (from pub cache) - runs-on: [self-hosted, macOS, X64] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, X64] steps: - uses: actions/checkout@v4 @@ -83,7 +91,10 @@ jobs: check_macos_publish_dry_run: name: Dry Run Publish macOS - runs-on: [self-hosted, macOS, X64] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, X64] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/pr_check_platform_interface.yml b/.github/workflows/pr_check_platform_interface.yml index 44a36364..febea77e 100644 --- a/.github/workflows/pr_check_platform_interface.yml +++ b/.github/workflows/pr_check_platform_interface.yml @@ -4,7 +4,6 @@ on: pull_request: branches: - '**' - - '!master' push: branches: - develop @@ -19,7 +18,10 @@ env: jobs: check_platform_interface_analyze: name: Analyze Platform Interface - runs-on: [self-hosted, macOS] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 @@ -38,7 +40,10 @@ jobs: check_platform_interface_test: name: Test Platform Interface - runs-on: [self-hosted, macOS] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 @@ -78,7 +83,10 @@ jobs: check_platform_interface_publish_dry_run: name: Dry Run Publish Platform Interface - runs-on: [self-hosted, macOS] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/pr_check_web.yml b/.github/workflows/pr_check_web.yml index a67055e3..275dcdb5 100644 --- a/.github/workflows/pr_check_web.yml +++ b/.github/workflows/pr_check_web.yml @@ -4,7 +4,6 @@ on: pull_request: branches: - '**' - - '!master' push: branches: - develop @@ -19,7 +18,10 @@ env: jobs: check_web_analyze: name: Analyze Web - runs-on: [self-hosted, macOS] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 @@ -38,7 +40,10 @@ jobs: check_web_test: name: Test Web - runs-on: [self-hosted, macOS] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 @@ -95,7 +100,10 @@ jobs: check_web_publish_dry_run: name: Dry Run Publish Web - runs-on: [self-hosted, macOS] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/pr_check_windows.yml b/.github/workflows/pr_check_windows.yml index ad49b64d..589abc03 100644 --- a/.github/workflows/pr_check_windows.yml +++ b/.github/workflows/pr_check_windows.yml @@ -4,7 +4,6 @@ on: pull_request: branches: - '**' - - '!master' push: branches: - develop @@ -17,7 +16,10 @@ concurrency: jobs: check_windows_analyze: name: Analyze Windows - runs-on: [self-hosted, 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] steps: - uses: actions/checkout@v4 @@ -33,7 +35,10 @@ jobs: check_windows_test: name: Test Windows - runs-on: [self-hosted, 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] steps: - uses: actions/checkout@v4 @@ -59,7 +64,10 @@ jobs: check_windows_test_from_pub_cache: name: Test Windows (from pub cache) - runs-on: [self-hosted, 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] steps: - uses: actions/checkout@v4 @@ -84,7 +92,10 @@ jobs: check_windows_publish_dry_run: name: Dry Run Publish Windows - runs-on: [self-hosted, 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] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/pr_check_zstandard.yml b/.github/workflows/pr_check_zstandard.yml index 0b7a1408..e53ade65 100644 --- a/.github/workflows/pr_check_zstandard.yml +++ b/.github/workflows/pr_check_zstandard.yml @@ -4,7 +4,6 @@ on: pull_request: branches: - '**' - - '!master' push: branches: - develop @@ -19,7 +18,10 @@ env: jobs: check_zstandard_analyze: name: Analyze Zstandard - runs-on: [self-hosted, macOS] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 @@ -38,7 +40,10 @@ jobs: check_zstandard_test: name: Test Zstandard - runs-on: [self-hosted, macOS] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, ARM64] timeout-minutes: 30 steps: - uses: actions/checkout@v4 @@ -85,7 +90,10 @@ jobs: check_zstandard_publish_dry_run: name: Dry Run Publish Zstandard - runs-on: [self-hosted, macOS] + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: + group: vypdev + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/release_workflow.yml b/.github/workflows/release_workflow.yml index ff13d748..fcdc2d65 100644 --- a/.github/workflows/release_workflow.yml +++ b/.github/workflows/release_workflow.yml @@ -159,7 +159,9 @@ jobs: publish: name: Publish accepted production commit if: ${{ inputs.mode == 'publish' }} - runs-on: ubuntu-latest + runs-on: + group: vypdev + labels: [self-hosted, codex, Linux] needs: validate timeout-minutes: 30 permissions: diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml index a21e3fb1..9a2e8e74 100644 --- a/.github/workflows/stale.yaml +++ b/.github/workflows/stale.yaml @@ -5,12 +5,14 @@ on: jobs: close-issues: - runs-on: ubuntu-latest + runs-on: + group: vypdev + labels: [self-hosted, codex, Linux] permissions: issues: write pull-requests: write steps: - - uses: actions/stale@v5 + - uses: actions/stale@v10 with: operations-per-run: 100 days-before-issue-stale: 30 From dbcb2279d4c88c92081c487915b921ab523acf09 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Fri, 23 Oct 2026 21:46:48 +0200 Subject: [PATCH 02/16] fix(ci): prepare Flutter in every Windows validation job --- .github/workflows/pr_check_windows.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/.github/workflows/pr_check_windows.yml b/.github/workflows/pr_check_windows.yml index 589abc03..42bfad69 100644 --- a/.github/workflows/pr_check_windows.yml +++ b/.github/workflows/pr_check_windows.yml @@ -12,6 +12,8 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +env: + FLUTTER_VERSION: ${{ vars.FLUTTER_VERSION || '3.41.4' }} jobs: check_windows_analyze: @@ -23,6 +25,12 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Prepare Flutter SDK + uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version: ${{ env.FLUTTER_VERSION }} + - name: Get dependencies working-directory: zstandard_windows shell: cmd @@ -42,6 +50,12 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Prepare Flutter SDK + uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version: ${{ env.FLUTTER_VERSION }} + - name: Get dependencies working-directory: zstandard_windows shell: cmd @@ -71,6 +85,12 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Prepare Flutter SDK + uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version: ${{ env.FLUTTER_VERSION }} + - name: Remove zstandard_native to force resolution from pub cache shell: cmd run: rmdir /s /q zstandard_native @@ -99,6 +119,12 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Prepare Flutter SDK + uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version: ${{ env.FLUTTER_VERSION }} + - name: Get dependencies working-directory: zstandard_windows shell: cmd From c5ac2c99e16ef8c11073a1b539f5009da02bec9a Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Fri, 23 Oct 2026 21:51:11 +0200 Subject: [PATCH 03/16] fix(ci): select Git Bash for native Windows Flutter setup --- .../actions/setup-flutter-windows/action.yml | 23 +++++++++++++++++++ .github/workflows/pr_check_windows.yml | 12 ++++------ 2 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 .github/actions/setup-flutter-windows/action.yml diff --git a/.github/actions/setup-flutter-windows/action.yml b/.github/actions/setup-flutter-windows/action.yml new file mode 100644 index 00000000..f4bafc5f --- /dev/null +++ b/.github/actions/setup-flutter-windows/action.yml @@ -0,0 +1,23 @@ +name: Prepare native Windows Flutter +description: Select Git Bash instead of the WSL launcher, then install the reviewed Flutter SDK. +inputs: + flutter-version: + description: Exact Flutter SDK version used by repository validation. + required: true +runs: + using: composite + steps: + - name: Select Git Bash for composite actions + shell: cmd + run: | + @echo off + if not exist "%ProgramFiles%\Git\bin\bash.exe" ( + echo Expected the runner's Git for Windows Bash executable. 1>&2 + exit /b 1 + ) + echo %ProgramFiles%\Git\bin>>"%GITHUB_PATH%" + - name: Prepare Flutter SDK + uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version: ${{ inputs.flutter-version }} diff --git a/.github/workflows/pr_check_windows.yml b/.github/workflows/pr_check_windows.yml index 42bfad69..5579592a 100644 --- a/.github/workflows/pr_check_windows.yml +++ b/.github/workflows/pr_check_windows.yml @@ -26,9 +26,8 @@ jobs: - uses: actions/checkout@v4 - name: Prepare Flutter SDK - uses: subosito/flutter-action@v2 + uses: ./.github/actions/setup-flutter-windows with: - channel: stable flutter-version: ${{ env.FLUTTER_VERSION }} - name: Get dependencies @@ -51,9 +50,8 @@ jobs: - uses: actions/checkout@v4 - name: Prepare Flutter SDK - uses: subosito/flutter-action@v2 + uses: ./.github/actions/setup-flutter-windows with: - channel: stable flutter-version: ${{ env.FLUTTER_VERSION }} - name: Get dependencies @@ -86,9 +84,8 @@ jobs: - uses: actions/checkout@v4 - name: Prepare Flutter SDK - uses: subosito/flutter-action@v2 + uses: ./.github/actions/setup-flutter-windows with: - channel: stable flutter-version: ${{ env.FLUTTER_VERSION }} - name: Remove zstandard_native to force resolution from pub cache @@ -120,9 +117,8 @@ jobs: - uses: actions/checkout@v4 - name: Prepare Flutter SDK - uses: subosito/flutter-action@v2 + uses: ./.github/actions/setup-flutter-windows with: - channel: stable flutter-version: ${{ env.FLUTTER_VERSION }} - name: Get dependencies From 5845ed84ec8c8fc1c595804d583b0e579263870b Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Fri, 23 Oct 2026 21:59:38 +0200 Subject: [PATCH 04/16] fix(ci): provision native Flutter architectures and verified Windows jq --- .github/actions/setup-flutter-windows/action.yml | 14 ++++++++++++++ .github/workflows/pr_check_android.yml | 16 ++++++++++++---- .github/workflows/pr_check_cli.yml | 12 +++++++++--- .github/workflows/pr_check_ios.yml | 16 ++++++++++++---- .github/workflows/pr_check_linux.yml | 16 ++++++++++++---- .github/workflows/pr_check_macos.yml | 16 ++++++++++++---- .../workflows/pr_check_platform_interface.yml | 12 +++++++++--- .github/workflows/pr_check_web.yml | 12 +++++++++--- .github/workflows/pr_check_zstandard.yml | 12 +++++++++--- 9 files changed, 98 insertions(+), 28 deletions(-) diff --git a/.github/actions/setup-flutter-windows/action.yml b/.github/actions/setup-flutter-windows/action.yml index f4bafc5f..5e23317e 100644 --- a/.github/actions/setup-flutter-windows/action.yml +++ b/.github/actions/setup-flutter-windows/action.yml @@ -16,6 +16,20 @@ runs: exit /b 1 ) echo %ProgramFiles%\Git\bin>>"%GITHUB_PATH%" + - name: Prepare verified portable jq + shell: powershell + run: | + $ErrorActionPreference = 'Stop' + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + $toolDirectory = Join-Path $env:RUNNER_TEMP 'zstandard-jq' + New-Item -ItemType Directory -Force -Path $toolDirectory | Out-Null + $executable = Join-Path $toolDirectory 'jq.exe' + Invoke-WebRequest -UseBasicParsing -Uri 'https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-windows-amd64.exe' -OutFile $executable + $expected = '23cb60a1354eed6bcc8d9b9735e8c7b388cd1fdcb75726b93bc299ef22dd9334' + if ((Get-FileHash -Algorithm SHA256 $executable).Hash.ToLowerInvariant() -ne $expected) { + throw 'The downloaded jq executable does not match the reviewed checksum.' + } + Add-Content -Path $env:GITHUB_PATH -Value $toolDirectory - name: Prepare Flutter SDK uses: subosito/flutter-action@v2 with: diff --git a/.github/workflows/pr_check_android.yml b/.github/workflows/pr_check_android.yml index 207d1c9d..34021e0d 100644 --- a/.github/workflows/pr_check_android.yml +++ b/.github/workflows/pr_check_android.yml @@ -25,10 +25,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_android @@ -47,10 +49,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_android/example @@ -83,10 +87,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Remove zstandard_native to force resolution from pub cache run: rm -rf zstandard_native @@ -130,10 +136,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_android diff --git a/.github/workflows/pr_check_cli.yml b/.github/workflows/pr_check_cli.yml index c2fac608..747913b3 100644 --- a/.github/workflows/pr_check_cli.yml +++ b/.github/workflows/pr_check_cli.yml @@ -25,10 +25,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_cli @@ -48,10 +50,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_cli @@ -110,10 +114,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_cli diff --git a/.github/workflows/pr_check_ios.yml b/.github/workflows/pr_check_ios.yml index f3dda3cd..7693611a 100644 --- a/.github/workflows/pr_check_ios.yml +++ b/.github/workflows/pr_check_ios.yml @@ -25,10 +25,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_ios @@ -47,10 +49,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_ios/example @@ -75,10 +79,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Remove zstandard_native to force resolution from pub cache run: rm -rf zstandard_native @@ -114,10 +120,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_ios diff --git a/.github/workflows/pr_check_linux.yml b/.github/workflows/pr_check_linux.yml index ec5f89c3..b0dcff80 100644 --- a/.github/workflows/pr_check_linux.yml +++ b/.github/workflows/pr_check_linux.yml @@ -25,10 +25,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_linux @@ -47,10 +49,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_linux @@ -77,10 +81,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Remove zstandard_native to force resolution from pub cache run: rm -rf zstandard_native @@ -110,10 +116,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_linux diff --git a/.github/workflows/pr_check_macos.yml b/.github/workflows/pr_check_macos.yml index db593ab5..4168471b 100644 --- a/.github/workflows/pr_check_macos.yml +++ b/.github/workflows/pr_check_macos.yml @@ -25,10 +25,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_macos @@ -47,10 +49,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Run integration tests working-directory: zstandard_macos/example @@ -65,10 +69,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Remove zstandard_native to force resolution from pub cache run: rm -rf zstandard_native @@ -98,10 +104,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_macos diff --git a/.github/workflows/pr_check_platform_interface.yml b/.github/workflows/pr_check_platform_interface.yml index febea77e..10111281 100644 --- a/.github/workflows/pr_check_platform_interface.yml +++ b/.github/workflows/pr_check_platform_interface.yml @@ -25,10 +25,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_platform_interface @@ -47,10 +49,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_platform_interface @@ -90,10 +94,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_platform_interface diff --git a/.github/workflows/pr_check_web.yml b/.github/workflows/pr_check_web.yml index 275dcdb5..f463aade 100644 --- a/.github/workflows/pr_check_web.yml +++ b/.github/workflows/pr_check_web.yml @@ -25,10 +25,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_web @@ -47,10 +49,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_web @@ -107,10 +111,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard_web diff --git a/.github/workflows/pr_check_zstandard.yml b/.github/workflows/pr_check_zstandard.yml index e53ade65..f475f2de 100644 --- a/.github/workflows/pr_check_zstandard.yml +++ b/.github/workflows/pr_check_zstandard.yml @@ -25,10 +25,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard @@ -48,10 +50,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard @@ -97,10 +101,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v1 + - uses: subosito/flutter-action@v2 with: channel: 'stable' flutter-version: ${{ env.FLUTTER_VERSION }} + architecture: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' - name: Get dependencies working-directory: zstandard From 675d28ff9e048da40d845c607afeca3f9739cfcc Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Fri, 23 Oct 2026 22:06:19 +0200 Subject: [PATCH 05/16] fix(ci): route modern Flutter and ARM Android emulators to Apple Silicon --- .../actions/prepare-macos-coverage/action.yml | 10 +++++ .github/workflows/pr_check_android.yml | 38 ++++++++++++++++--- .github/workflows/pr_check_cli.yml | 3 ++ .github/workflows/pr_check_ios.yml | 8 ++-- .github/workflows/pr_check_macos.yml | 8 ++-- .../workflows/pr_check_platform_interface.yml | 3 ++ .github/workflows/pr_check_zstandard.yml | 3 ++ 7 files changed, 59 insertions(+), 14 deletions(-) create mode 100644 .github/actions/prepare-macos-coverage/action.yml diff --git a/.github/actions/prepare-macos-coverage/action.yml b/.github/actions/prepare-macos-coverage/action.yml new file mode 100644 index 00000000..029a3f4d --- /dev/null +++ b/.github/actions/prepare-macos-coverage/action.yml @@ -0,0 +1,10 @@ +name: Prepare macOS coverage verification +description: Provide GPG for Codecov signature verification on the self-hosted macOS runner. +runs: + using: composite + steps: + - shell: bash + run: | + if ! command -v gpg >/dev/null 2>&1; then + brew install gnupg + fi diff --git a/.github/workflows/pr_check_android.yml b/.github/workflows/pr_check_android.yml index 34021e0d..f06c4676 100644 --- a/.github/workflows/pr_check_android.yml +++ b/.github/workflows/pr_check_android.yml @@ -21,7 +21,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} runs-on: group: vypdev - labels: [self-hosted, macOS, X64] + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 @@ -45,7 +45,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} runs-on: group: vypdev - labels: [self-hosted, macOS, X64] + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 @@ -66,13 +66,26 @@ jobs: distribution: 'temurin' java-version: '17' + - name: Prepare isolated Android SDK directories + shell: bash + run: | + sdk_root="$RUNNER_TEMP/zstandard-android-$GITHUB_JOB" + mkdir -p "$sdk_root" "$RUNNER_TEMP/zstandard-avd-$GITHUB_JOB" "$RUNNER_TEMP/zstandard-android-user-$GITHUB_JOB" + echo "ANDROID_HOME=$sdk_root" >> "$GITHUB_ENV" + echo "ANDROID_SDK_ROOT=$sdk_root" >> "$GITHUB_ENV" + echo "ANDROID_AVD_HOME=$RUNNER_TEMP/zstandard-avd-$GITHUB_JOB" >> "$GITHUB_ENV" + echo "ANDROID_USER_HOME=$RUNNER_TEMP/zstandard-android-user-$GITHUB_JOB" >> "$GITHUB_ENV" + + - name: Prepare Android command-line tools + uses: android-actions/setup-android@v3 + - name: Run integration tests on emulator uses: reactivecircus/android-emulator-runner@v2 with: api-level: 30 target: google_apis profile: pixel_4 - arch: x86_64 + arch: arm64-v8a avd-name: zstandard_ci_test emulator-port: 5554 script: | @@ -83,7 +96,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} runs-on: group: vypdev - labels: [self-hosted, macOS, X64] + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 @@ -115,13 +128,26 @@ jobs: distribution: 'temurin' java-version: '17' + - name: Prepare isolated Android SDK directories + shell: bash + run: | + sdk_root="$RUNNER_TEMP/zstandard-android-$GITHUB_JOB" + mkdir -p "$sdk_root" "$RUNNER_TEMP/zstandard-avd-$GITHUB_JOB" "$RUNNER_TEMP/zstandard-android-user-$GITHUB_JOB" + echo "ANDROID_HOME=$sdk_root" >> "$GITHUB_ENV" + echo "ANDROID_SDK_ROOT=$sdk_root" >> "$GITHUB_ENV" + echo "ANDROID_AVD_HOME=$RUNNER_TEMP/zstandard-avd-$GITHUB_JOB" >> "$GITHUB_ENV" + echo "ANDROID_USER_HOME=$RUNNER_TEMP/zstandard-android-user-$GITHUB_JOB" >> "$GITHUB_ENV" + + - name: Prepare Android command-line tools + uses: android-actions/setup-android@v3 + - name: Run integration tests on emulator (from pub cache) uses: reactivecircus/android-emulator-runner@v2 with: api-level: 30 target: google_apis profile: pixel_4 - arch: x86_64 + arch: arm64-v8a avd-name: zstandard_ci_test_pubcache emulator-port: 5556 script: | @@ -132,7 +158,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} runs-on: group: vypdev - labels: [self-hosted, macOS, X64] + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/pr_check_cli.yml b/.github/workflows/pr_check_cli.yml index 747913b3..72d412a4 100644 --- a/.github/workflows/pr_check_cli.yml +++ b/.github/workflows/pr_check_cli.yml @@ -83,6 +83,9 @@ jobs: if [ -z "$COVERAGE" ]; then echo "Could not parse coverage"; exit 1; fi if (( $(echo "$COVERAGE < 79" | bc -l) )); then echo "ERROR: Coverage ${COVERAGE}% is below 79%"; exit 1; fi + - name: Prepare coverage signature verification + uses: ./.github/actions/prepare-macos-coverage + - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 with: diff --git a/.github/workflows/pr_check_ios.yml b/.github/workflows/pr_check_ios.yml index 7693611a..ed87c5f6 100644 --- a/.github/workflows/pr_check_ios.yml +++ b/.github/workflows/pr_check_ios.yml @@ -21,7 +21,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} runs-on: group: vypdev - labels: [self-hosted, macOS, X64] + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 @@ -45,7 +45,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} runs-on: group: vypdev - labels: [self-hosted, macOS, X64] + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 @@ -75,7 +75,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} runs-on: group: vypdev - labels: [self-hosted, macOS, X64] + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 @@ -116,7 +116,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} runs-on: group: vypdev - labels: [self-hosted, macOS, X64] + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/pr_check_macos.yml b/.github/workflows/pr_check_macos.yml index 4168471b..9f89e515 100644 --- a/.github/workflows/pr_check_macos.yml +++ b/.github/workflows/pr_check_macos.yml @@ -21,7 +21,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} runs-on: group: vypdev - labels: [self-hosted, macOS, X64] + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 @@ -45,7 +45,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} runs-on: group: vypdev - labels: [self-hosted, macOS, X64] + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 @@ -65,7 +65,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} runs-on: group: vypdev - labels: [self-hosted, macOS, X64] + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 @@ -100,7 +100,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} runs-on: group: vypdev - labels: [self-hosted, macOS, X64] + labels: [self-hosted, macOS, ARM64] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/pr_check_platform_interface.yml b/.github/workflows/pr_check_platform_interface.yml index 10111281..169325b0 100644 --- a/.github/workflows/pr_check_platform_interface.yml +++ b/.github/workflows/pr_check_platform_interface.yml @@ -77,6 +77,9 @@ jobs: if [ -z "$COVERAGE" ]; then echo "Could not parse coverage"; exit 1; fi if (( $(echo "$COVERAGE < 85" | bc -l) )); then echo "ERROR: Coverage ${COVERAGE}% is below 85%"; exit 1; fi + - name: Prepare coverage signature verification + uses: ./.github/actions/prepare-macos-coverage + - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 with: diff --git a/.github/workflows/pr_check_zstandard.yml b/.github/workflows/pr_check_zstandard.yml index f475f2de..fe485c90 100644 --- a/.github/workflows/pr_check_zstandard.yml +++ b/.github/workflows/pr_check_zstandard.yml @@ -84,6 +84,9 @@ jobs: exit 1 fi + - name: Prepare coverage signature verification + uses: ./.github/actions/prepare-macos-coverage + - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 with: From daffb99077b1d59856c63905c459c8620087d970 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Fri, 23 Oct 2026 22:08:42 +0200 Subject: [PATCH 06/16] fix(ci): run Linux desktop integration tests in isolated virtual displays --- .github/workflows/pr_check_linux.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr_check_linux.yml b/.github/workflows/pr_check_linux.yml index b0dcff80..d2460ba4 100644 --- a/.github/workflows/pr_check_linux.yml +++ b/.github/workflows/pr_check_linux.yml @@ -41,6 +41,9 @@ jobs: run: flutter analyze check_linux_test: + env: + GDK_BACKEND: x11 + LIBGL_ALWAYS_SOFTWARE: '1' name: Test Linux if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} runs-on: @@ -70,9 +73,12 @@ jobs: - name: Run integration tests working-directory: zstandard_linux/example - run: flutter test integration_test/ -d linux + run: xvfb-run -a flutter test integration_test/ -d linux check_linux_test_from_pub_cache: + env: + GDK_BACKEND: x11 + LIBGL_ALWAYS_SOFTWARE: '1' name: Test Linux (from pub cache) if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} runs-on: @@ -105,7 +111,7 @@ jobs: - name: Run integration tests (C sources from pub cache) working-directory: zstandard_linux/example - run: flutter test integration_test/ -d linux + run: xvfb-run -a flutter test integration_test/ -d linux check_linux_publish_dry_run: name: Dry Run Publish Linux From e3b8eef4df5bbf0b6c78c33c361f4ba571e0a6a9 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Fri, 23 Oct 2026 22:12:31 +0200 Subject: [PATCH 07/16] fix(ci): isolate Windows Flutter from incomplete legacy tool cache --- .github/actions/setup-flutter-windows/action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/setup-flutter-windows/action.yml b/.github/actions/setup-flutter-windows/action.yml index 5e23317e..81d8b4b5 100644 --- a/.github/actions/setup-flutter-windows/action.yml +++ b/.github/actions/setup-flutter-windows/action.yml @@ -35,3 +35,4 @@ runs: with: channel: stable flutter-version: ${{ inputs.flutter-version }} + cache-path: '${{ runner.tool_cache }}/zstandard-flutter-v2/:channel:-:version:-:arch:' From 6b8cecf5087bbb3fee5489b264e16f58e4408018 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Fri, 23 Oct 2026 22:23:05 +0200 Subject: [PATCH 08/16] fix(ci): prepare headless Linux and align Flutter with declared SDK requirements --- .../actions/prepare-linux-display/action.yml | 27 +++++++++++++++++++ .../actions/setup-flutter-windows/action.yml | 17 ++++++++++++ .github/workflows/pr_check_cli.yml | 2 +- .github/workflows/pr_check_ios.yml | 2 +- .github/workflows/pr_check_linux.yml | 12 ++++++--- .github/workflows/pr_check_macos.yml | 2 +- .../workflows/pr_check_platform_interface.yml | 7 ++--- .github/workflows/pr_check_web.yml | 2 +- .github/workflows/pr_check_windows.yml | 2 +- .github/workflows/pr_check_zstandard.yml | 7 ++--- 10 files changed, 66 insertions(+), 14 deletions(-) create mode 100644 .github/actions/prepare-linux-display/action.yml diff --git a/.github/actions/prepare-linux-display/action.yml b/.github/actions/prepare-linux-display/action.yml new file mode 100644 index 00000000..193a8dcd --- /dev/null +++ b/.github/actions/prepare-linux-display/action.yml @@ -0,0 +1,27 @@ +name: Prepare Linux virtual display +description: Prepare Ubuntu Xvfb tools in the job directory without requiring sudo. +runs: + using: composite + steps: + - name: Prepare job-local Xvfb + shell: bash + run: | + set -euo pipefail + if command -v xvfb-run >/dev/null && command -v Xvfb >/dev/null && command -v xauth >/dev/null; then + exit 0 + fi + display_root="$(mktemp -d "$RUNNER_TEMP/zstandard-xvfb.XXXXXX")" + mkdir -p "$display_root/apt/lists/partial" "$display_root/packages" + apt_options=(-o "Dir::State::Lists=$display_root/apt/lists" -o "Dir::Cache=$display_root/apt/cache") + apt-get "${apt_options[@]}" update + ( + cd "$display_root/packages" + apt-get "${apt_options[@]}" download xvfb xauth libxfont2 libunwind8 + for package in ./*.deb; do + dpkg-deb --extract "$package" "$display_root" + done + ) + library_directory="$(find "$display_root/usr/lib" -name libXfont2.so.2 -printf '%h\n' -quit)" + test -n "$library_directory" + echo "$display_root/usr/bin" >> "$GITHUB_PATH" + echo "LD_LIBRARY_PATH=$library_directory${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" >> "$GITHUB_ENV" diff --git a/.github/actions/setup-flutter-windows/action.yml b/.github/actions/setup-flutter-windows/action.yml index 81d8b4b5..fd464415 100644 --- a/.github/actions/setup-flutter-windows/action.yml +++ b/.github/actions/setup-flutter-windows/action.yml @@ -30,6 +30,23 @@ runs: throw 'The downloaded jq executable does not match the reviewed checksum.' } Add-Content -Path $env:GITHUB_PATH -Value $toolDirectory + - name: Recover interrupted repository SDK extraction + shell: powershell + env: + SDK_TOOL_CACHE: ${{ runner.tool_cache }} + SDK_VERSION: ${{ inputs.flutter-version }} + run: | + $ErrorActionPreference = 'Stop' + if ($env:SDK_VERSION -notmatch '^\d+\.\d+\.\d+$') { + throw 'Expected an exact stable Flutter release version.' + } + $sdkDirectory = Join-Path (Join-Path $env:SDK_TOOL_CACHE 'zstandard-flutter-v2') "stable-$env:SDK_VERSION-x64" + $sdkRoot = Join-Path $sdkDirectory 'flutter' + $requiredFiles = @('bin\flutter.bat', 'bin\cache\dart-sdk\bin\dart.exe', 'packages\flutter_tools\bin\flutter_tools.dart', 'packages\flutter\lib\widgets.dart') + if ((Test-Path -LiteralPath $sdkDirectory) -and ($requiredFiles | Where-Object { -not (Test-Path -LiteralPath (Join-Path $sdkRoot $_)) })) { + Write-Host 'Removing the incomplete repository-specific Flutter installation before preparing the SDK.' + Remove-Item -LiteralPath $sdkDirectory -Recurse -Force + } - name: Prepare Flutter SDK uses: subosito/flutter-action@v2 with: diff --git a/.github/workflows/pr_check_cli.yml b/.github/workflows/pr_check_cli.yml index 72d412a4..98759441 100644 --- a/.github/workflows/pr_check_cli.yml +++ b/.github/workflows/pr_check_cli.yml @@ -13,7 +13,7 @@ concurrency: cancel-in-progress: true env: - FLUTTER_VERSION: ${{ vars.FLUTTER_VERSION || '3.41.4' }} + FLUTTER_VERSION: ${{ vars.FLUTTER_VERSION || '3.47.2' }} jobs: check_cli_analyze: diff --git a/.github/workflows/pr_check_ios.yml b/.github/workflows/pr_check_ios.yml index ed87c5f6..69a324ed 100644 --- a/.github/workflows/pr_check_ios.yml +++ b/.github/workflows/pr_check_ios.yml @@ -13,7 +13,7 @@ concurrency: cancel-in-progress: true env: - FLUTTER_VERSION: ${{ vars.FLUTTER_VERSION || '3.41.4' }} + FLUTTER_VERSION: ${{ vars.FLUTTER_VERSION || '3.47.2' }} jobs: check_ios_analyze: diff --git a/.github/workflows/pr_check_linux.yml b/.github/workflows/pr_check_linux.yml index d2460ba4..6ddf63ef 100644 --- a/.github/workflows/pr_check_linux.yml +++ b/.github/workflows/pr_check_linux.yml @@ -13,7 +13,7 @@ concurrency: cancel-in-progress: true env: - FLUTTER_VERSION: ${{ vars.FLUTTER_VERSION || '3.41.4' }} + FLUTTER_VERSION: ${{ vars.FLUTTER_VERSION || '3.47.2' }} jobs: check_linux_analyze: @@ -71,7 +71,10 @@ jobs: working-directory: zstandard_linux/example run: flutter pub get - - name: Run integration tests + - name: Prepare virtual display + uses: ./.github/actions/prepare-linux-display + + - name: Run integration tests with a virtual display working-directory: zstandard_linux/example run: xvfb-run -a flutter test integration_test/ -d linux @@ -109,7 +112,10 @@ jobs: flutter clean flutter pub get - - name: Run integration tests (C sources from pub cache) + - name: Prepare virtual display + uses: ./.github/actions/prepare-linux-display + + - name: Run integration tests with a virtual display (C sources from pub cache) working-directory: zstandard_linux/example run: xvfb-run -a flutter test integration_test/ -d linux diff --git a/.github/workflows/pr_check_macos.yml b/.github/workflows/pr_check_macos.yml index 9f89e515..f4f6a4a4 100644 --- a/.github/workflows/pr_check_macos.yml +++ b/.github/workflows/pr_check_macos.yml @@ -13,7 +13,7 @@ concurrency: cancel-in-progress: true env: - FLUTTER_VERSION: ${{ vars.FLUTTER_VERSION || '3.41.4' }} + FLUTTER_VERSION: ${{ vars.FLUTTER_VERSION || '3.47.2' }} jobs: check_macos_analyze: diff --git a/.github/workflows/pr_check_platform_interface.yml b/.github/workflows/pr_check_platform_interface.yml index 169325b0..56b02220 100644 --- a/.github/workflows/pr_check_platform_interface.yml +++ b/.github/workflows/pr_check_platform_interface.yml @@ -13,7 +13,7 @@ concurrency: cancel-in-progress: true env: - FLUTTER_VERSION: ${{ vars.FLUTTER_VERSION || '3.41.4' }} + FLUTTER_VERSION: ${{ vars.FLUTTER_VERSION || '3.47.2' }} jobs: check_platform_interface_analyze: @@ -71,8 +71,9 @@ jobs: - name: Check coverage threshold (85% of lib/) working-directory: zstandard_platform_interface run: | - lcov --extract coverage/lcov.info 'lib/*' -o coverage/lcov_lib.info - COVERAGE=$(lcov --summary coverage/lcov_lib.info 2>&1 | grep "lines" | awk '{print $2}' | sed 's/%//') + # Flutter emits line coverage; keep the existing line coverage threshold. + lcov --rc function_coverage=0 --extract coverage/lcov.info 'lib/*' -o coverage/lcov_lib.info + COVERAGE=$(lcov --rc function_coverage=0 --summary coverage/lcov_lib.info 2>&1 | grep "lines" | awk '{print $2}' | sed 's/%//') echo "Coverage (lib/ only): ${COVERAGE}%" if [ -z "$COVERAGE" ]; then echo "Could not parse coverage"; exit 1; fi if (( $(echo "$COVERAGE < 85" | bc -l) )); then echo "ERROR: Coverage ${COVERAGE}% is below 85%"; exit 1; fi diff --git a/.github/workflows/pr_check_web.yml b/.github/workflows/pr_check_web.yml index f463aade..d088e5a4 100644 --- a/.github/workflows/pr_check_web.yml +++ b/.github/workflows/pr_check_web.yml @@ -13,7 +13,7 @@ concurrency: cancel-in-progress: true env: - FLUTTER_VERSION: ${{ vars.FLUTTER_VERSION || '3.41.4' }} + FLUTTER_VERSION: ${{ vars.FLUTTER_VERSION || '3.47.2' }} jobs: check_web_analyze: diff --git a/.github/workflows/pr_check_windows.yml b/.github/workflows/pr_check_windows.yml index 5579592a..926de78e 100644 --- a/.github/workflows/pr_check_windows.yml +++ b/.github/workflows/pr_check_windows.yml @@ -13,7 +13,7 @@ concurrency: cancel-in-progress: true env: - FLUTTER_VERSION: ${{ vars.FLUTTER_VERSION || '3.41.4' }} + FLUTTER_VERSION: ${{ vars.FLUTTER_VERSION || '3.47.2' }} jobs: check_windows_analyze: diff --git a/.github/workflows/pr_check_zstandard.yml b/.github/workflows/pr_check_zstandard.yml index fe485c90..aa629ae6 100644 --- a/.github/workflows/pr_check_zstandard.yml +++ b/.github/workflows/pr_check_zstandard.yml @@ -13,7 +13,7 @@ concurrency: cancel-in-progress: true env: - FLUTTER_VERSION: ${{ vars.FLUTTER_VERSION || '3.41.4' }} + FLUTTER_VERSION: ${{ vars.FLUTTER_VERSION || '3.47.2' }} jobs: check_zstandard_analyze: @@ -72,8 +72,9 @@ jobs: - name: Check coverage threshold (76% of lib/) working-directory: zstandard run: | - lcov --extract coverage/lcov.info 'lib/*' -o coverage/lcov_lib.info - COVERAGE=$(lcov --summary coverage/lcov_lib.info 2>&1 | grep "lines" | awk '{print $2}' | sed 's/%//') + # Flutter emits line coverage; keep the existing line coverage threshold. + lcov --rc function_coverage=0 --extract coverage/lcov.info 'lib/*' -o coverage/lcov_lib.info + COVERAGE=$(lcov --rc function_coverage=0 --summary coverage/lcov_lib.info 2>&1 | grep "lines" | awk '{print $2}' | sed 's/%//') echo "Coverage (lib/ only): ${COVERAGE}%" if [ -z "$COVERAGE" ]; then echo "Could not parse coverage" From 0238bbf1bed84d3ab9fd9e38c83b38036bce953c Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Fri, 23 Oct 2026 22:36:23 +0200 Subject: [PATCH 09/16] fix(ci): resolve complete missing Xvfb runtime dependencies in private package state --- .../actions/prepare-linux-display/action.yml | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/.github/actions/prepare-linux-display/action.yml b/.github/actions/prepare-linux-display/action.yml index 193a8dcd..27b4c42e 100644 --- a/.github/actions/prepare-linux-display/action.yml +++ b/.github/actions/prepare-linux-display/action.yml @@ -10,18 +10,30 @@ runs: if command -v xvfb-run >/dev/null && command -v Xvfb >/dev/null && command -v xauth >/dev/null; then exit 0 fi + # Ubuntu's X server invokes this compiler at an absolute system path. + # It is part of the runner's base X11/GTK desktop toolchain. + if [ ! -x /usr/bin/xkbcomp ] || [ ! -f /usr/share/X11/xkb/rules/evdev ]; then + echo 'The Ubuntu runner needs x11-xkb-utils and xkb-data in its base desktop toolchain.' >&2 + exit 1 + fi display_root="$(mktemp -d "$RUNNER_TEMP/zstandard-xvfb.XXXXXX")" - mkdir -p "$display_root/apt/lists/partial" "$display_root/packages" - apt_options=(-o "Dir::State::Lists=$display_root/apt/lists" -o "Dir::Cache=$display_root/apt/cache") + mkdir -p "$display_root/apt/lists/partial" "$display_root/packages/partial" + cp /var/lib/dpkg/status "$display_root/apt/status" + # Resolve every missing runtime dependency using a private package state + # and cache. Download-only never installs packages or runs maintainer scripts. + apt_options=(-o "Dir::State::status=$display_root/apt/status" -o "Dir::State::Lists=$display_root/apt/lists" -o "Dir::Cache::archives=$display_root/packages") apt-get "${apt_options[@]}" update + apt-get "${apt_options[@]}" --download-only --assume-yes --no-install-recommends install xvfb xauth ( cd "$display_root/packages" - apt-get "${apt_options[@]}" download xvfb xauth libxfont2 libunwind8 for package in ./*.deb; do dpkg-deb --extract "$package" "$display_root" done ) - library_directory="$(find "$display_root/usr/lib" -name libXfont2.so.2 -printf '%h\n' -quit)" - test -n "$library_directory" echo "$display_root/usr/bin" >> "$GITHUB_PATH" - echo "LD_LIBRARY_PATH=$library_directory${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" >> "$GITHUB_ENV" + if [ -d "$display_root/usr/lib" ]; then + library_directories="$(find "$display_root/usr/lib" -mindepth 1 -maxdepth 1 -type d -name '*-linux-gnu' | paste -sd : -)" + if [ -n "$library_directories" ]; then + echo "LD_LIBRARY_PATH=$library_directories${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" >> "$GITHUB_ENV" + fi + fi From 9b3977de99a2d334cd0b713fc9f1e28a7623e047 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Fri, 23 Oct 2026 22:44:14 +0200 Subject: [PATCH 10/16] fix(ci): persist Flutter analyzer migration before publication validation --- zstandard/analysis_options.yaml | 3 +++ zstandard/example/analysis_options.yaml | 9 +++++++++ zstandard_android/analysis_options.yaml | 4 ++++ zstandard_android/example/analysis_options.yaml | 4 ++++ zstandard_ios/analysis_options.yaml | 4 ++++ zstandard_ios/example/analysis_options.yaml | 4 ++++ zstandard_linux/analysis_options.yaml | 4 ++++ zstandard_linux/example/analysis_options.yaml | 4 ++++ zstandard_macos/analysis_options.yaml | 4 ++++ zstandard_macos/example/analysis_options.yaml | 4 ++++ zstandard_web/analysis_options.yaml | 3 +++ zstandard_web/example/analysis_options.yaml | 4 ++++ zstandard_windows/analysis_options.yaml | 4 ++++ zstandard_windows/example/analysis_options.yaml | 4 ++++ 14 files changed, 59 insertions(+) diff --git a/zstandard/analysis_options.yaml b/zstandard/analysis_options.yaml index a5744c1c..e46654b9 100644 --- a/zstandard/analysis_options.yaml +++ b/zstandard/analysis_options.yaml @@ -1,3 +1,6 @@ +analyzer: + exclude: + - build/** include: package:flutter_lints/flutter.yaml # Additional information about this file can be found at diff --git a/zstandard/example/analysis_options.yaml b/zstandard/example/analysis_options.yaml index 0d290213..bf8d4218 100644 --- a/zstandard/example/analysis_options.yaml +++ b/zstandard/example/analysis_options.yaml @@ -7,6 +7,15 @@ # The following line activates a set of recommended lints for Flutter apps, # packages, and plugins designed to encourage good coding practices. +analyzer: + exclude: + - build/** + - android/** + - ios/** + - web/** + - windows/** + - macos/** + - linux/** include: package:flutter_lints/flutter.yaml linter: diff --git a/zstandard_android/analysis_options.yaml b/zstandard_android/analysis_options.yaml index a5744c1c..756c0f49 100644 --- a/zstandard_android/analysis_options.yaml +++ b/zstandard_android/analysis_options.yaml @@ -1,3 +1,7 @@ +analyzer: + exclude: + - build/** + - android/** include: package:flutter_lints/flutter.yaml # Additional information about this file can be found at diff --git a/zstandard_android/example/analysis_options.yaml b/zstandard_android/example/analysis_options.yaml index 0d290213..5671d4c5 100644 --- a/zstandard_android/example/analysis_options.yaml +++ b/zstandard_android/example/analysis_options.yaml @@ -7,6 +7,10 @@ # The following line activates a set of recommended lints for Flutter apps, # packages, and plugins designed to encourage good coding practices. +analyzer: + exclude: + - build/** + - android/** include: package:flutter_lints/flutter.yaml linter: diff --git a/zstandard_ios/analysis_options.yaml b/zstandard_ios/analysis_options.yaml index a5744c1c..1186c2bb 100644 --- a/zstandard_ios/analysis_options.yaml +++ b/zstandard_ios/analysis_options.yaml @@ -1,3 +1,7 @@ +analyzer: + exclude: + - build/** + - ios/** include: package:flutter_lints/flutter.yaml # Additional information about this file can be found at diff --git a/zstandard_ios/example/analysis_options.yaml b/zstandard_ios/example/analysis_options.yaml index 0d290213..a5a2c9f5 100644 --- a/zstandard_ios/example/analysis_options.yaml +++ b/zstandard_ios/example/analysis_options.yaml @@ -7,6 +7,10 @@ # The following line activates a set of recommended lints for Flutter apps, # packages, and plugins designed to encourage good coding practices. +analyzer: + exclude: + - build/** + - ios/** include: package:flutter_lints/flutter.yaml linter: diff --git a/zstandard_linux/analysis_options.yaml b/zstandard_linux/analysis_options.yaml index a5744c1c..612ee4bf 100644 --- a/zstandard_linux/analysis_options.yaml +++ b/zstandard_linux/analysis_options.yaml @@ -1,3 +1,7 @@ +analyzer: + exclude: + - build/** + - linux/** include: package:flutter_lints/flutter.yaml # Additional information about this file can be found at diff --git a/zstandard_linux/example/analysis_options.yaml b/zstandard_linux/example/analysis_options.yaml index 0d290213..cbe5dc5b 100644 --- a/zstandard_linux/example/analysis_options.yaml +++ b/zstandard_linux/example/analysis_options.yaml @@ -7,6 +7,10 @@ # The following line activates a set of recommended lints for Flutter apps, # packages, and plugins designed to encourage good coding practices. +analyzer: + exclude: + - build/** + - linux/** include: package:flutter_lints/flutter.yaml linter: diff --git a/zstandard_macos/analysis_options.yaml b/zstandard_macos/analysis_options.yaml index a5744c1c..5e15f457 100644 --- a/zstandard_macos/analysis_options.yaml +++ b/zstandard_macos/analysis_options.yaml @@ -1,3 +1,7 @@ +analyzer: + exclude: + - build/** + - macos/** include: package:flutter_lints/flutter.yaml # Additional information about this file can be found at diff --git a/zstandard_macos/example/analysis_options.yaml b/zstandard_macos/example/analysis_options.yaml index 0d290213..5d3e697c 100644 --- a/zstandard_macos/example/analysis_options.yaml +++ b/zstandard_macos/example/analysis_options.yaml @@ -7,6 +7,10 @@ # The following line activates a set of recommended lints for Flutter apps, # packages, and plugins designed to encourage good coding practices. +analyzer: + exclude: + - build/** + - macos/** include: package:flutter_lints/flutter.yaml linter: diff --git a/zstandard_web/analysis_options.yaml b/zstandard_web/analysis_options.yaml index a5744c1c..e46654b9 100644 --- a/zstandard_web/analysis_options.yaml +++ b/zstandard_web/analysis_options.yaml @@ -1,3 +1,6 @@ +analyzer: + exclude: + - build/** include: package:flutter_lints/flutter.yaml # Additional information about this file can be found at diff --git a/zstandard_web/example/analysis_options.yaml b/zstandard_web/example/analysis_options.yaml index 0d290213..2a2b57e8 100644 --- a/zstandard_web/example/analysis_options.yaml +++ b/zstandard_web/example/analysis_options.yaml @@ -7,6 +7,10 @@ # The following line activates a set of recommended lints for Flutter apps, # packages, and plugins designed to encourage good coding practices. +analyzer: + exclude: + - build/** + - web/** include: package:flutter_lints/flutter.yaml linter: diff --git a/zstandard_windows/analysis_options.yaml b/zstandard_windows/analysis_options.yaml index a5744c1c..ba427235 100644 --- a/zstandard_windows/analysis_options.yaml +++ b/zstandard_windows/analysis_options.yaml @@ -1,3 +1,7 @@ +analyzer: + exclude: + - build/** + - windows/** include: package:flutter_lints/flutter.yaml # Additional information about this file can be found at diff --git a/zstandard_windows/example/analysis_options.yaml b/zstandard_windows/example/analysis_options.yaml index 0d290213..6bd848b7 100644 --- a/zstandard_windows/example/analysis_options.yaml +++ b/zstandard_windows/example/analysis_options.yaml @@ -7,6 +7,10 @@ # The following line activates a set of recommended lints for Flutter apps, # packages, and plugins designed to encourage good coding practices. +analyzer: + exclude: + - build/** + - windows/** include: package:flutter_lints/flutter.yaml linter: From 5879061539d8a14633b48f8c86cd9f5f8908f3c1 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Fri, 23 Oct 2026 22:48:11 +0200 Subject: [PATCH 11/16] fix(ci): request supported Android tools and retain Dart line coverage gates --- .github/workflows/pr_check_android.yml | 4 ++++ .github/workflows/pr_check_cli.yml | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr_check_android.yml b/.github/workflows/pr_check_android.yml index f06c4676..7399e3cc 100644 --- a/.github/workflows/pr_check_android.yml +++ b/.github/workflows/pr_check_android.yml @@ -78,6 +78,8 @@ jobs: - name: Prepare Android command-line tools uses: android-actions/setup-android@v3 + with: + packages: platform-tools - name: Run integration tests on emulator uses: reactivecircus/android-emulator-runner@v2 @@ -140,6 +142,8 @@ jobs: - name: Prepare Android command-line tools uses: android-actions/setup-android@v3 + with: + packages: platform-tools - name: Run integration tests on emulator (from pub cache) uses: reactivecircus/android-emulator-runner@v2 diff --git a/.github/workflows/pr_check_cli.yml b/.github/workflows/pr_check_cli.yml index 98759441..a8d605a7 100644 --- a/.github/workflows/pr_check_cli.yml +++ b/.github/workflows/pr_check_cli.yml @@ -76,9 +76,10 @@ jobs: - name: Check coverage threshold (79% of lib/) working-directory: zstandard_cli run: | - lcov --extract coverage/lcov.info '*zstandard_cli/lib/*' -o coverage/lcov_lib.info - lcov --remove coverage/lcov_lib.info '*bindings_generated*' -o coverage/lcov_lib.info --ignore-errors unused - COVERAGE=$(lcov --summary coverage/lcov_lib.info 2>&1 | grep "lines" | awk '{print $2}' | sed 's/%//') + # Dart emits line coverage; keep the existing line coverage threshold. + lcov --rc function_coverage=0 --extract coverage/lcov.info '*zstandard_cli/lib/*' -o coverage/lcov_lib.info + lcov --rc function_coverage=0 --remove coverage/lcov_lib.info '*bindings_generated*' -o coverage/lcov_lib.info --ignore-errors unused + COVERAGE=$(lcov --rc function_coverage=0 --summary coverage/lcov_lib.info 2>&1 | grep "lines" | awk '{print $2}' | sed 's/%//') echo "Coverage (lib/ excluding generated): ${COVERAGE}%" if [ -z "$COVERAGE" ]; then echo "Could not parse coverage"; exit 1; fi if (( $(echo "$COVERAGE < 79" | bc -l) )); then echo "ERROR: Coverage ${COVERAGE}% is below 79%"; exit 1; fi From c46b05a38335686eb43a4568132414894d8751a2 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Fri, 23 Oct 2026 22:56:30 +0200 Subject: [PATCH 12/16] fix(ci): pair Chrome for Testing with its native driver and isolate the service port --- .github/scripts/run-web-integration.sh | 36 +++++++++++++++++++++ .github/workflows/pr_check_web.yml | 44 ++++++-------------------- 2 files changed, 46 insertions(+), 34 deletions(-) create mode 100644 .github/scripts/run-web-integration.sh diff --git a/.github/scripts/run-web-integration.sh b/.github/scripts/run-web-integration.sh new file mode 100644 index 00000000..cb84cc8f --- /dev/null +++ b/.github/scripts/run-web-integration.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -euo pipefail + +driver_log="$(mktemp "$RUNNER_TEMP/zstandard-chromedriver.XXXXXX")" +"$CHROMEDRIVER_EXECUTABLE" --port=0 > "$driver_log" 2>&1 & +driver_pid=$! +cleanup() { + kill "$driver_pid" 2>/dev/null || true + wait "$driver_pid" 2>/dev/null || true +} +trap cleanup EXIT + +driver_port='' +for attempt in {1..100}; do + driver_port="$(sed -nE 's/.*ChromeDriver was started successfully on port ([0-9]+).*/\1/p' "$driver_log" | tail -n 1)" + if [ -n "$driver_port" ]; then + break + fi + if ! kill -0 "$driver_pid" 2>/dev/null; then + cat "$driver_log" >&2 + exit 1 + fi + sleep 0.1 +done +if [ -z "$driver_port" ]; then + cat "$driver_log" >&2 + echo 'ChromeDriver did not become ready within 10 seconds.' >&2 + exit 1 +fi + +flutter drive \ + --driver=test_driver/integration_test.dart \ + --target=integration_test/zstandard_web_integration_test.dart \ + --driver-port="$driver_port" \ + --chrome-binary="$CHROME_EXECUTABLE" \ + -d web-server diff --git a/.github/workflows/pr_check_web.yml b/.github/workflows/pr_check_web.yml index d088e5a4..c8b9a291 100644 --- a/.github/workflows/pr_check_web.yml +++ b/.github/workflows/pr_check_web.yml @@ -64,43 +64,19 @@ jobs: working-directory: zstandard_web/example run: flutter pub get - - name: Update Google Chrome (match ChromeDriver) - run: | - if brew list --cask google-chrome &>/dev/null; then - brew upgrade --cask google-chrome - else - echo "Chrome not installed via Homebrew, skipping upgrade" - fi - - - name: Install ChromeDriver - run: brew install chromedriver - - - name: Remove ChromeDriver quarantine (macOS) - run: | - CHROMEDRIVER_BIN=$(command -v chromedriver) - while [[ -L "$CHROMEDRIVER_BIN" ]]; do - NEXT=$(readlink "$CHROMEDRIVER_BIN") - [[ "$NEXT" != /* ]] && NEXT="$(dirname "$CHROMEDRIVER_BIN")/$NEXT" - CHROMEDRIVER_BIN=$NEXT - done - if [[ -f "$CHROMEDRIVER_BIN" ]] && xattr "$CHROMEDRIVER_BIN" 2>/dev/null | grep -q com.apple.quarantine; then - xattr -d com.apple.quarantine "$CHROMEDRIVER_BIN" 2>/dev/null || true - fi - - - name: Start ChromeDriver - run: | - chromedriver --port=4444 & - sleep 3 - lsof -i:4444 || (echo "ChromeDriver failed to start"; exit 1) + - name: Prepare matching Chrome for Testing and ChromeDriver + id: browser + uses: browser-actions/setup-chrome@v2 + with: + chrome-version: stable + install-chromedriver: true - name: Run integration tests (flutter drive + ChromeDriver) working-directory: zstandard_web/example - run: | - flutter drive \ - --driver=test_driver/integration_test.dart \ - --target=integration_test/zstandard_web_integration_test.dart \ - -d web-server \ - --web-port=8080 + env: + CHROME_EXECUTABLE: ${{ steps.browser.outputs.chrome-path }} + CHROMEDRIVER_EXECUTABLE: ${{ steps.browser.outputs.chromedriver-path }} + run: bash "$GITHUB_WORKSPACE/.github/scripts/run-web-integration.sh" check_web_publish_dry_run: name: Dry Run Publish Web From eaedec772359ae92c018c4ba93392774712e5687 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Fri, 23 Oct 2026 23:43:24 +0200 Subject: [PATCH 13/16] fix(ci): give each iOS job an isolated simulator and exact cleanup --- .github/scripts/.gitignore | 1 + .github/scripts/start_ios_simulator.py | 43 +++++++++++++++++ .github/scripts/tests/test_ios_simulator.py | 53 +++++++++++++++++++++ .github/workflows/pr_check_ios.yml | 42 +++++++++++----- .github/workflows/simulator_contract.yml | 24 ++++++++++ 5 files changed, 151 insertions(+), 12 deletions(-) create mode 100644 .github/scripts/.gitignore create mode 100644 .github/scripts/start_ios_simulator.py create mode 100644 .github/scripts/tests/test_ios_simulator.py create mode 100644 .github/workflows/simulator_contract.yml diff --git a/.github/scripts/.gitignore b/.github/scripts/.gitignore new file mode 100644 index 00000000..c18dd8d8 --- /dev/null +++ b/.github/scripts/.gitignore @@ -0,0 +1 @@ +__pycache__/ diff --git a/.github/scripts/start_ios_simulator.py b/.github/scripts/start_ios_simulator.py new file mode 100644 index 00000000..d6dbef3e --- /dev/null +++ b/.github/scripts/start_ios_simulator.py @@ -0,0 +1,43 @@ +"""Create a fresh CI simulator without reusing or stopping personal devices.""" + +import json +import os +import subprocess +import uuid + + +def start(): + result = subprocess.run( + ["xcrun", "simctl", "list", "devices", "available", "--json"], + check=True, capture_output=True, text=True, timeout=30, + ) + candidates = [] + for runtime, devices in json.loads(result.stdout).get("devices", {}).items(): + if not runtime.startswith("com.apple.CoreSimulator.SimRuntime.iOS-"): + continue + for device in devices: + kind = device.get("deviceTypeIdentifier", "") + if device.get("isAvailable") and kind.startswith("com.apple.CoreSimulator.SimDeviceType.iPhone-"): + candidates.append((runtime, kind, device.get("name"))) + if not candidates: + raise RuntimeError("Xcode needs an available iPhone simulator and its installed iOS runtime.") + preferred = os.environ.get("ZSTANDARD_IOS_DEVICE", "iPhone 16") + runtime, kind, _ = next((item for item in candidates if item[2] == preferred), candidates[0]) + name = "zstandard-{}-{}-{}-{}".format( + os.environ["GITHUB_RUN_ID"], os.environ["GITHUB_RUN_ATTEMPT"], + os.environ["GITHUB_JOB"], uuid.uuid4().hex[:8], + ) + created = subprocess.run( + ["xcrun", "simctl", "create", name, kind, runtime], + check=True, capture_output=True, text=True, timeout=30, + ) + device_id = str(uuid.UUID(created.stdout.strip())).upper() + # Record ownership before boot so an interrupted boot can still be cleaned up. + with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as output: + output.write(f"device-id={device_id}\n") + subprocess.run(["xcrun", "simctl", "boot", device_id], check=True, timeout=30) + subprocess.run(["xcrun", "simctl", "bootstatus", device_id, "-b"], check=True, timeout=120) + + +if __name__ == "__main__": + start() diff --git a/.github/scripts/tests/test_ios_simulator.py b/.github/scripts/tests/test_ios_simulator.py new file mode 100644 index 00000000..78dde505 --- /dev/null +++ b/.github/scripts/tests/test_ios_simulator.py @@ -0,0 +1,53 @@ +import importlib.util +import json +import os +import pathlib +import subprocess +import tempfile +import unittest +from unittest.mock import Mock, patch + + +path = pathlib.Path(__file__).parents[1] / "start_ios_simulator.py" +spec = importlib.util.spec_from_file_location("start_ios_simulator", path) +simulator = importlib.util.module_from_spec(spec) +spec.loader.exec_module(simulator) +RUNTIME = "com.apple.CoreSimulator.SimRuntime.iOS-27-0" +KIND = "com.apple.CoreSimulator.SimDeviceType.iPhone-16" +EXISTING = "AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA" +CREATED = "BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB" + + +class SimulatorTests(unittest.TestCase): + def prepare(self, folder): + return patch.dict(os.environ, {"GITHUB_RUN_ID": "12", "GITHUB_RUN_ATTEMPT": "1", "GITHUB_JOB": "ios", "GITHUB_OUTPUT": str(pathlib.Path(folder) / "output")}) + + @patch.object(simulator.subprocess, "run") + def test_booted_personal_device_is_only_used_as_type_metadata(self, command): + devices = {"devices": {RUNTIME: [{"name": "iPhone 16", "deviceTypeIdentifier": KIND, "isAvailable": True, "state": "Booted", "udid": EXISTING}]}} + command.side_effect = [Mock(stdout=json.dumps(devices)), Mock(stdout=CREATED), Mock(), Mock()] + with tempfile.TemporaryDirectory() as folder, self.prepare(folder): + simulator.start() + self.assertEqual((pathlib.Path(folder) / "output").read_text(), f"device-id={CREATED}\n") + self.assertEqual(command.call_args_list[1].args[0][-2:], [KIND, RUNTIME]) + self.assertEqual(command.call_args_list[2].args[0], ["xcrun", "simctl", "boot", CREATED]) + self.assertNotIn(EXISTING, str(command.call_args_list)) + + @patch.object(simulator.subprocess, "run", return_value=Mock(stdout='{"devices": {}}')) + def test_missing_ios_runtime_fails_before_creating_a_device(self, command): + with self.assertRaisesRegex(RuntimeError, "installed iOS runtime"): + simulator.start() + self.assertEqual(command.call_count, 1) + + @patch.object(simulator.subprocess, "run") + def test_failed_boot_preserves_created_device_id_for_cleanup(self, command): + devices = {"devices": {RUNTIME: [{"name": "iPhone 16", "deviceTypeIdentifier": KIND, "isAvailable": True}]}} + command.side_effect = [Mock(stdout=json.dumps(devices)), Mock(stdout=CREATED), subprocess.CalledProcessError(1, "boot")] + with tempfile.TemporaryDirectory() as folder, self.prepare(folder): + with self.assertRaises(subprocess.CalledProcessError): + simulator.start() + self.assertEqual((pathlib.Path(folder) / "output").read_text(), f"device-id={CREATED}\n") + + +if __name__ == "__main__": + unittest.main() diff --git a/.github/workflows/pr_check_ios.yml b/.github/workflows/pr_check_ios.yml index 69a324ed..e47b3e56 100644 --- a/.github/workflows/pr_check_ios.yml +++ b/.github/workflows/pr_check_ios.yml @@ -60,15 +60,24 @@ jobs: working-directory: zstandard_ios/example run: flutter pub get - - name: Boot iOS simulator - run: | - chmod +x scripts/manage_ios_simulator.sh - ./scripts/manage_ios_simulator.sh start + - name: Boot an isolated iOS simulator + id: ios-simulator + timeout-minutes: 4 + run: python3 .github/scripts/start_ios_simulator.py - name: Run integration tests + working-directory: zstandard_ios/example + env: + DEVICE_ID: ${{ steps.ios-simulator.outputs.device-id }} + run: flutter test integration_test/ -d "$DEVICE_ID" + + - name: Remove this job's iOS simulator + if: ${{ always() && steps.ios-simulator.outputs.device-id != '' }} + env: + DEVICE_ID: ${{ steps.ios-simulator.outputs.device-id }} run: | - DEVICE_ID=$(./scripts/manage_ios_simulator.sh device-id) - cd zstandard_ios/example && flutter test integration_test/ -d "$DEVICE_ID" + xcrun simctl shutdown "$DEVICE_ID" 2>/dev/null || true + xcrun simctl delete "$DEVICE_ID" check_ios_test_from_pub_cache: name: Test iOS (from pub cache) @@ -101,15 +110,24 @@ jobs: flutter clean flutter pub get - - name: Boot iOS simulator - run: | - chmod +x scripts/manage_ios_simulator.sh - ./scripts/manage_ios_simulator.sh start + - name: Boot an isolated iOS simulator + id: ios-simulator + timeout-minutes: 4 + run: python3 .github/scripts/start_ios_simulator.py - name: Run integration tests (C sources from pub cache) + working-directory: zstandard_ios/example + env: + DEVICE_ID: ${{ steps.ios-simulator.outputs.device-id }} + run: flutter test integration_test/ -d "$DEVICE_ID" + + - name: Remove this job's iOS simulator + if: ${{ always() && steps.ios-simulator.outputs.device-id != '' }} + env: + DEVICE_ID: ${{ steps.ios-simulator.outputs.device-id }} run: | - DEVICE_ID=$(./scripts/manage_ios_simulator.sh device-id) - cd zstandard_ios/example && flutter test integration_test/ -d "$DEVICE_ID" + xcrun simctl shutdown "$DEVICE_ID" 2>/dev/null || true + xcrun simctl delete "$DEVICE_ID" check_ios_publish_dry_run: name: Dry Run Publish iOS diff --git a/.github/workflows/simulator_contract.yml b/.github/workflows/simulator_contract.yml new file mode 100644 index 00000000..8591dcb7 --- /dev/null +++ b/.github/workflows/simulator_contract.yml @@ -0,0 +1,24 @@ +name: iOS simulator contract +on: + pull_request: + paths: + - '.github/scripts/start_ios_simulator.py' + - '.github/scripts/tests/test_ios_simulator.py' + - '.github/workflows/pr_check_ios.yml' + - '.github/workflows/simulator_contract.yml' +jobs: + simulator-contract: + if: github.event.pull_request.head.repo.full_name == github.repository + runs-on: + group: vypdev + labels: [self-hosted, codex, Linux] + permissions: + contents: read + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - uses: actions/setup-python@v6 + with: + python-version: '3.11' + - run: python -m unittest discover -s .github/scripts/tests -p test_ios_simulator.py -v From 9f28cf39908cc84cd7590427a65f8a5088bfee99 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Sat, 24 Oct 2026 00:32:18 +0200 Subject: [PATCH 14/16] fix(ci): preserve the macOS Chrome bundle layout for WebDriver sessions --- .github/scripts/run-web-integration.sh | 44 ++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/.github/scripts/run-web-integration.sh b/.github/scripts/run-web-integration.sh index cb84cc8f..cd02eb9f 100644 --- a/.github/scripts/run-web-integration.sh +++ b/.github/scripts/run-web-integration.sh @@ -1,15 +1,42 @@ #!/usr/bin/env bash set -euo pipefail -driver_log="$(mktemp "$RUNNER_TEMP/zstandard-chromedriver.XXXXXX")" -"$CHROMEDRIVER_EXECUTABLE" --port=0 > "$driver_log" 2>&1 & -driver_pid=$! +driver_pid='' +browser_directory='' cleanup() { - kill "$driver_pid" 2>/dev/null || true - wait "$driver_pid" 2>/dev/null || true + if [ -n "$driver_pid" ]; then + kill "$driver_pid" 2>/dev/null || true + wait "$driver_pid" 2>/dev/null || true + fi + if [ -n "$browser_directory" ]; then + rm -rf -- "$browser_directory" + fi } trap cleanup EXIT +# setup-chrome strips the .app suffix from its macOS cache directory. Chrome +# prints its version there but cannot create the instrumented WebDriver session. +# Keep the shared cache untouched and restore the bundle name in a private copy. +if [ "$(uname -s)" = Darwin ]; then + chrome_bundle="${CHROME_EXECUTABLE%/Contents/MacOS/*}" + if [ ! -d "$chrome_bundle/Contents" ]; then + echo 'Expected a macOS Chrome app bundle.' >&2 + exit 1 + fi + case "$chrome_bundle" in + *.app) ;; + *) + browser_directory="$(mktemp -d "$RUNNER_TEMP/zstandard-chrome.XXXXXX")" + /bin/cp -R "$chrome_bundle" "$browser_directory/Chrome for Testing.app" + CHROME_EXECUTABLE="$browser_directory/Chrome for Testing.app/Contents/MacOS/${CHROME_EXECUTABLE##*/}" + ;; + esac +fi + +driver_log="$(mktemp "$RUNNER_TEMP/zstandard-chromedriver.XXXXXX")" +"$CHROMEDRIVER_EXECUTABLE" --port=0 > "$driver_log" 2>&1 & +driver_pid=$! + driver_port='' for attempt in {1..100}; do driver_port="$(sed -nE 's/.*ChromeDriver was started successfully on port ([0-9]+).*/\1/p' "$driver_log" | tail -n 1)" @@ -28,9 +55,14 @@ if [ -z "$driver_port" ]; then exit 1 fi +result=0 flutter drive \ --driver=test_driver/integration_test.dart \ --target=integration_test/zstandard_web_integration_test.dart \ --driver-port="$driver_port" \ --chrome-binary="$CHROME_EXECUTABLE" \ - -d web-server + -d web-server || result=$? +if [ "$result" -ne 0 ]; then + tail -n 50 "$driver_log" >&2 +fi +exit "$result" From f400feb818d98470ad38fb88040b7cc90cba87c2 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Sat, 24 Oct 2026 01:01:34 +0200 Subject: [PATCH 15/16] fix(ci): isolate Android JDK profiles and bound Gradle processes per job --- .../prepare-android-integration/action.yml | 34 +++++++++++++++++++ .github/workflows/pr_check_android.yml | 30 ++++++---------- 2 files changed, 44 insertions(+), 20 deletions(-) create mode 100644 .github/actions/prepare-android-integration/action.yml diff --git a/.github/actions/prepare-android-integration/action.yml b/.github/actions/prepare-android-integration/action.yml new file mode 100644 index 00000000..7ab869e7 --- /dev/null +++ b/.github/actions/prepare-android-integration/action.yml @@ -0,0 +1,34 @@ +name: Prepare isolated Android integration +description: Keep SDK, Flutter settings and bounded Gradle processes local to this job. +runs: + using: composite + steps: + - name: Prepare private Android build state and select the job JDK + shell: bash + run: | + set -euo pipefail + build_directory="$(mktemp -d "$RUNNER_TEMP/zstandard-android-build.XXXXXX")" + sdk_root="$build_directory/sdk" + gradle_root="$build_directory/gradle" + flutter_profile="$build_directory/flutter-profile" + mkdir -p "$sdk_root" "$gradle_root" "$flutter_profile" "$build_directory/avd" "$build_directory/android-user" + cat > "$gradle_root/gradle.properties" <<'PROPERTIES' + org.gradle.daemon=false + org.gradle.parallel=false + org.gradle.workers.max=2 + org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=1g -Dfile.encoding=UTF-8 + kotlin.compiler.execution.strategy=in-process + PROPERTIES + { + echo "ANDROID_HOME=$sdk_root" + echo "ANDROID_SDK_ROOT=$sdk_root" + echo "ANDROID_AVD_HOME=$build_directory/avd" + echo "ANDROID_USER_HOME=$build_directory/android-user" + echo "ANDROID_EMULATOR_HOME=$build_directory/android-user" + echo "GRADLE_USER_HOME=$gradle_root" + echo "ZSTANDARD_FLUTTER_PROFILE=$flutter_profile" + } >> "$GITHUB_ENV" + # Flutter otherwise prefers the host Android Studio JBR over JAVA_HOME. + # Configure a private child profile; never rewrite the operator's config. + env HOME="$flutter_profile" XDG_CONFIG_HOME="$flutter_profile/config" \ + flutter config --jdk-dir="$JAVA_HOME" diff --git a/.github/workflows/pr_check_android.yml b/.github/workflows/pr_check_android.yml index 7399e3cc..1d2b976c 100644 --- a/.github/workflows/pr_check_android.yml +++ b/.github/workflows/pr_check_android.yml @@ -66,15 +66,8 @@ jobs: distribution: 'temurin' java-version: '17' - - name: Prepare isolated Android SDK directories - shell: bash - run: | - sdk_root="$RUNNER_TEMP/zstandard-android-$GITHUB_JOB" - mkdir -p "$sdk_root" "$RUNNER_TEMP/zstandard-avd-$GITHUB_JOB" "$RUNNER_TEMP/zstandard-android-user-$GITHUB_JOB" - echo "ANDROID_HOME=$sdk_root" >> "$GITHUB_ENV" - echo "ANDROID_SDK_ROOT=$sdk_root" >> "$GITHUB_ENV" - echo "ANDROID_AVD_HOME=$RUNNER_TEMP/zstandard-avd-$GITHUB_JOB" >> "$GITHUB_ENV" - echo "ANDROID_USER_HOME=$RUNNER_TEMP/zstandard-android-user-$GITHUB_JOB" >> "$GITHUB_ENV" + - name: Prepare isolated Android build tools + uses: ./.github/actions/prepare-android-integration - name: Prepare Android command-line tools uses: android-actions/setup-android@v3 @@ -88,10 +81,12 @@ jobs: target: google_apis profile: pixel_4 arch: arm64-v8a + ndk: 28.2.13676358 avd-name: zstandard_ci_test emulator-port: 5554 script: | - cd zstandard_android/example && flutter test integration_test/ -d emulator-${EMULATOR_PORT} + cd zstandard_android/example + env HOME="$ZSTANDARD_FLUTTER_PROFILE" XDG_CONFIG_HOME="$ZSTANDARD_FLUTTER_PROFILE/config" flutter test integration_test/ -d emulator-${EMULATOR_PORT} check_android_test_from_pub_cache: name: Test Android (from pub cache) @@ -130,15 +125,8 @@ jobs: distribution: 'temurin' java-version: '17' - - name: Prepare isolated Android SDK directories - shell: bash - run: | - sdk_root="$RUNNER_TEMP/zstandard-android-$GITHUB_JOB" - mkdir -p "$sdk_root" "$RUNNER_TEMP/zstandard-avd-$GITHUB_JOB" "$RUNNER_TEMP/zstandard-android-user-$GITHUB_JOB" - echo "ANDROID_HOME=$sdk_root" >> "$GITHUB_ENV" - echo "ANDROID_SDK_ROOT=$sdk_root" >> "$GITHUB_ENV" - echo "ANDROID_AVD_HOME=$RUNNER_TEMP/zstandard-avd-$GITHUB_JOB" >> "$GITHUB_ENV" - echo "ANDROID_USER_HOME=$RUNNER_TEMP/zstandard-android-user-$GITHUB_JOB" >> "$GITHUB_ENV" + - name: Prepare isolated Android build tools + uses: ./.github/actions/prepare-android-integration - name: Prepare Android command-line tools uses: android-actions/setup-android@v3 @@ -152,10 +140,12 @@ jobs: target: google_apis profile: pixel_4 arch: arm64-v8a + ndk: 28.2.13676358 avd-name: zstandard_ci_test_pubcache emulator-port: 5556 script: | - cd zstandard_android/example && flutter test integration_test/ -d emulator-${EMULATOR_PORT} + cd zstandard_android/example + env HOME="$ZSTANDARD_FLUTTER_PROFILE" XDG_CONFIG_HOME="$ZSTANDARD_FLUTTER_PROFILE/config" flutter test integration_test/ -d emulator-${EMULATOR_PORT} check_android_publish_dry_run: name: Dry Run Publish Android From 49cadc4925afb5fa595481e739c29f7ff7e3f828 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Sat, 24 Oct 2026 11:15:42 +0200 Subject: [PATCH 16/16] fix: keep Android emulator test command in its project directory --- .github/workflows/pr_check_android.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pr_check_android.yml b/.github/workflows/pr_check_android.yml index 1d2b976c..77a1a1e8 100644 --- a/.github/workflows/pr_check_android.yml +++ b/.github/workflows/pr_check_android.yml @@ -85,8 +85,7 @@ jobs: avd-name: zstandard_ci_test emulator-port: 5554 script: | - cd zstandard_android/example - env HOME="$ZSTANDARD_FLUTTER_PROFILE" XDG_CONFIG_HOME="$ZSTANDARD_FLUTTER_PROFILE/config" flutter test integration_test/ -d emulator-${EMULATOR_PORT} + cd zstandard_android/example && env HOME="$ZSTANDARD_FLUTTER_PROFILE" XDG_CONFIG_HOME="$ZSTANDARD_FLUTTER_PROFILE/config" flutter test integration_test/ -d emulator-${EMULATOR_PORT} check_android_test_from_pub_cache: name: Test Android (from pub cache) @@ -144,8 +143,7 @@ jobs: avd-name: zstandard_ci_test_pubcache emulator-port: 5556 script: | - cd zstandard_android/example - env HOME="$ZSTANDARD_FLUTTER_PROFILE" XDG_CONFIG_HOME="$ZSTANDARD_FLUTTER_PROFILE/config" flutter test integration_test/ -d emulator-${EMULATOR_PORT} + cd zstandard_android/example && env HOME="$ZSTANDARD_FLUTTER_PROFILE" XDG_CONFIG_HOME="$ZSTANDARD_FLUTTER_PROFILE/config" flutter test integration_test/ -d emulator-${EMULATOR_PORT} check_android_publish_dry_run: name: Dry Run Publish Android