Fix release CI - 7 #31
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| # Triggered when a tag like v0.0.4 is pushed. Six parallel package jobs (one Velopack | |
| # channel each; some runners use Zig cross-compile to the target triple), then a final job | |
| # stages assets and uploads a draft GitHub release via scripts/release.sh. | |
| # | |
| # Flow: | |
| # 1. Operator edits VERSION, commits, tags v<VERSION>, pushes the tag. | |
| # 2. Matrix builds (Linux ×2, Windows ×2 cross-compiled from Linux, macOS ×2): | |
| # prefetch with retries, then package per target. Windows targets run on | |
| # ubuntu-latest with a `zig build msvcup-setup` pre-step (downloads MSVC + | |
| # Windows SDK to .velopack-msvc/) followed by a small case-sensitivity fix | |
| # (lowercase *.Lib symlinks). Cross-compiling from a non-Windows host avoids | |
| # Zig's MSVC auto-discovery leaking the runner's newer system SDK headers | |
| # (which translate-c can't parse and break SDL3 linking). | |
| # 3. The assemble job downloads zig-out/<channel>/ from each artifact, runs | |
| # FIZZY_RELEASE_SKIP_BUILD=1 ./scripts/release.sh (staging + gh release create). | |
| # 4. Operator reviews the draft and publishes when ready (auto-update only after publish). | |
| # | |
| # Signing (optional macOS builds when secrets unset): | |
| # FIZZY_MACOS_CERT_P12_BASE64 / FIZZY_MACOS_CERT_PASSWORD | |
| # FIZZY_MACOS_SIGN_APP / FIZZY_MACOS_SIGN_INSTALLER | |
| # FIZZY_APPLE_ID / FIZZY_APPLE_APP_PASSWORD / FIZZY_APPLE_TEAM_ID | |
| # | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Existing tag to release (e.g. v0.0.4)" | |
| required: true | |
| concurrency: | |
| group: release-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: false | |
| env: | |
| ZIG_VERSION: "0.16.0" | |
| jobs: | |
| # Linux + Windows: no fizzy_release environment (no signing secrets needed). | |
| package: | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - channel: x86-64-linux | |
| target: x86_64-linux-gnu | |
| runner: ubuntu-latest | |
| - channel: arm64-linux | |
| target: aarch64-linux-gnu | |
| runner: ubuntu-latest | |
| # Windows targets cross-compile from Linux. Cannot use windows-latest: | |
| # Zig's MSVC auto-discovery on a Windows host leaks the runner's system | |
| # SDK into both translate-c (newer headers with ui64 / NEON intrinsics | |
| # translate-c can't parse) and SDL3 link (which expects gameinput.h | |
| # from a newer SDK than msvcup downloads). The only configuration where | |
| # the .velopack-msvc/ SDK wins cleanly is a non-Windows host. | |
| # macOS-latest also works (and is what the old monolithic build used); | |
| # Linux is cheaper but needs the case-sensitivity workaround below for | |
| # the kernel32.Lib vs .lib casing in velopack-zig's MSI extraction. | |
| - channel: x86-64-windows | |
| target: x86_64-windows-msvc | |
| runner: ubuntu-latest | |
| - channel: arm64-windows | |
| target: aarch64-windows-msvc | |
| runner: ubuntu-latest | |
| defaults: | |
| run: | |
| shell: bash | |
| env: | |
| ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache-${{ github.run_id }}-${{ matrix.channel }} | |
| ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache-${{ github.run_id }}-${{ matrix.channel }}-local | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.inputs.tag || github.ref }} | |
| fetch-tags: true | |
| fetch-depth: 0 | |
| - uses: mlugg/setup-zig@v2 | |
| with: | |
| version: ${{ env.ZIG_VERSION }} | |
| use-cache: false | |
| - name: Pre-create Zig cache tmp/ | |
| run: | | |
| mkdir -p "$ZIG_GLOBAL_CACHE_DIR/tmp" | |
| [[ "$ZIG_LOCAL_CACHE_DIR" != "$ZIG_GLOBAL_CACHE_DIR" ]] && mkdir -p "$ZIG_LOCAL_CACHE_DIR/tmp" || true | |
| - uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: "8.0" | |
| # Prefetch before msvcup/package so lazy deps (e.g. zigwin32 from GitHub) get retry | |
| # backoff; zig build msvcup-setup alone can hit HttpConnectionClosing with no retries. | |
| - name: Fetch deps with retries | |
| run: | | |
| fetch() { | |
| local args="$1" | |
| local n=0 | |
| until [ "$n" -ge 5 ]; do | |
| zig build --fetch $args && return 0 | |
| n=$((n+1)) | |
| echo "Fetch attempt $n ($args) failed, sleeping $((n*10))s..." | |
| sleep $((n*10)) | |
| done | |
| return 1 | |
| } | |
| fetch "" || exit 1 | |
| fetch "-Dtarget=${{ matrix.target }}" || exit 1 | |
| # MSVC SDK has to materialize on disk BEFORE `zig build package` configures, | |
| # because applyMsvcIncludesToReachableTranslateC reads zig-libc-*.ini during | |
| # build() to add -isystem paths to DVUI's translate-c steps. -Dfetch-msvc only | |
| # schedules msvcup as a build-step dependency, which is too late. Same reason | |
| # scripts/release.sh runs msvcup-setup as its own pre-step. | |
| # MSI extraction on Linux preserves the SDK packages' mixed-case filenames | |
| # (kernel32.Lib, AdvAPI32.Lib, …) — fine on macOS/Windows (case-insensitive | |
| # FS), but on Linux velopack-zig's gen_zig_libc_msvc.zig + the linker need | |
| # lowercase. The fix has to interleave with msvcup-setup itself: the gen | |
| # check runs inside setup-msvc.sh right after MSI extraction. Two passes: | |
| # the first downloads + extracts (then fails on the .lib check); we add | |
| # lowercase symlinks; the second skips the install (its needs_install check | |
| # also keys on kernel32.Lib so it passes) and just runs the gen step. | |
| - name: Setup MSVC SDK (Windows targets) | |
| if: endsWith(matrix.target, '-windows-msvc') | |
| run: | | |
| set -euo pipefail | |
| # First pass: extract SDK; gen step is expected to fail on Linux. | |
| zig build msvcup-setup || echo "first msvcup-setup failed (expected on Linux); fixing case-sensitivity" | |
| # The SDK ships hundreds of mixed-case filenames (Windows.h, kernel32.Lib, | |
| # ADSIid.h, AccCtrl.h, …) but downstream C code includes them lowercase. | |
| # Symlink every file whose basename has uppercase letters to an | |
| # all-lowercase sibling so case-insensitive lookups resolve. | |
| python3 - <<'PY' | |
| import os | |
| n = 0 | |
| for dirpath, _dirnames, filenames in os.walk('.velopack-msvc'): | |
| for name in filenames: | |
| lower = name.lower() | |
| if lower == name: | |
| continue | |
| dst = os.path.join(dirpath, lower) | |
| if os.path.lexists(dst): | |
| continue | |
| os.symlink(name, dst) | |
| n += 1 | |
| print(f"Created {n} lowercase filename symlinks") | |
| PY | |
| # Second pass: install check passes (kernel32.Lib exists), gen step | |
| # finds kernel32.lib via our symlinks and writes zig-libc-*.ini. | |
| zig build msvcup-setup | |
| - name: Package (${{ matrix.channel }}) | |
| run: | | |
| set -euo pipefail | |
| zig build package -Doptimize=ReleaseFast "-Dtarget=${{ matrix.target }}" | |
| - name: Upload zig-out-${{ matrix.channel }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: zig-out-${{ matrix.channel }} | |
| path: zig-out/${{ matrix.channel }} | |
| if-no-files-found: error | |
| package-macos: | |
| runs-on: ${{ matrix.runner }} | |
| environment: fizzy_release | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - channel: x86-64-macos | |
| target: x86_64-macos | |
| runner: macos-latest | |
| - channel: arm64-macos | |
| target: aarch64-macos | |
| runner: macos-latest | |
| env: | |
| ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache-${{ github.run_id }}-${{ matrix.channel }} | |
| ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache-${{ github.run_id }}-${{ matrix.channel }}-local | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.inputs.tag || github.ref }} | |
| fetch-tags: true | |
| fetch-depth: 0 | |
| - uses: mlugg/setup-zig@v2 | |
| with: | |
| version: ${{ env.ZIG_VERSION }} | |
| use-cache: false | |
| - name: Pre-create Zig cache tmp/ | |
| shell: bash | |
| run: | | |
| mkdir -p "$ZIG_GLOBAL_CACHE_DIR/tmp" | |
| [[ "$ZIG_LOCAL_CACHE_DIR" != "$ZIG_GLOBAL_CACHE_DIR" ]] && mkdir -p "$ZIG_LOCAL_CACHE_DIR/tmp" || true | |
| - uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: "8.0" | |
| - name: Fetch deps with retries | |
| shell: bash | |
| run: | | |
| fetch() { | |
| local args="$1" | |
| local n=0 | |
| until [ "$n" -ge 5 ]; do | |
| zig build --fetch $args && return 0 | |
| n=$((n+1)) | |
| echo "Fetch attempt $n ($args) failed, sleeping $((n*10))s..." | |
| sleep $((n*10)) | |
| done | |
| return 1 | |
| } | |
| fetch "" || exit 1 | |
| fetch "-Dtarget=${{ matrix.target }}" || exit 1 | |
| - name: Check signing config | |
| id: signing_config | |
| env: | |
| HAS_CERT: ${{ secrets.FIZZY_MACOS_CERT_P12_BASE64 != '' }} | |
| HAS_NOTARY: ${{ secrets.FIZZY_APPLE_ID != '' }} | |
| run: | | |
| echo "cert=$HAS_CERT" >> "$GITHUB_OUTPUT" | |
| echo "notary=$HAS_NOTARY" >> "$GITHUB_OUTPUT" | |
| if [[ "$HAS_CERT" == "true" ]]; then echo "macOS signing: ENABLED"; else echo "macOS signing: disabled"; fi | |
| - name: Import signing certificate | |
| if: steps.signing_config.outputs.cert == 'true' | |
| uses: apple-actions/import-codesign-certs@v3 | |
| with: | |
| p12-file-base64: ${{ secrets.FIZZY_MACOS_CERT_P12_BASE64 }} | |
| p12-password: ${{ secrets.FIZZY_MACOS_CERT_PASSWORD }} | |
| keychain: fizzy-release-${{ matrix.channel }} | |
| create-keychain: true | |
| - name: Configure notarytool credentials | |
| if: steps.signing_config.outputs.notary == 'true' | |
| env: | |
| APPLE_ID: ${{ secrets.FIZZY_APPLE_ID }} | |
| APPLE_APP_PASSWORD: ${{ secrets.FIZZY_APPLE_APP_PASSWORD }} | |
| APPLE_TEAM_ID: ${{ secrets.FIZZY_APPLE_TEAM_ID }} | |
| run: | | |
| set -euo pipefail | |
| xcrun notarytool store-credentials "fizzy-ci-notary-${{ matrix.channel }}" \ | |
| --apple-id "$APPLE_ID" \ | |
| --password "$APPLE_APP_PASSWORD" \ | |
| --team-id "$APPLE_TEAM_ID" | |
| echo "FIZZY_MACOS_NOTARY_PROFILE=fizzy-ci-notary-${{ matrix.channel }}" >> "$GITHUB_ENV" | |
| - name: Package (${{ matrix.channel }}) | |
| env: | |
| FIZZY_MACOS_SIGN_APP: ${{ secrets.FIZZY_MACOS_SIGN_APP }} | |
| FIZZY_MACOS_SIGN_INSTALLER: ${{ secrets.FIZZY_MACOS_SIGN_INSTALLER }} | |
| run: | | |
| set -euo pipefail | |
| zig build package -Doptimize=ReleaseFast "-Dtarget=${{ matrix.target }}" | |
| - name: Upload zig-out-${{ matrix.channel }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: zig-out-${{ matrix.channel }} | |
| path: zig-out/${{ matrix.channel }} | |
| if-no-files-found: error | |
| assemble: | |
| needs: [package, package-macos] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.inputs.tag || github.ref }} | |
| fetch-tags: true | |
| fetch-depth: 0 | |
| # Each package job uploads zig-out/<channel>; merge into zig-out/<channel>/ for release.sh. | |
| - name: Download all channel outputs | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: zig-out-* | |
| path: _artifacts | |
| merge-multiple: false | |
| - name: Layout zig-out for release script | |
| run: | | |
| set -euo pipefail | |
| mkdir -p zig-out | |
| for d in _artifacts/zig-out-*; do | |
| [[ -d "$d" ]] || continue | |
| base="$(basename "$d")" | |
| ch="${base#zig-out-}" | |
| mkdir -p "zig-out/$ch" | |
| mv "$d"/* "zig-out/$ch/" | |
| done | |
| ls -la zig-out/*/ | |
| - name: Run release script (stage + gh release) | |
| shell: bash | |
| env: | |
| FIZZY_RELEASE_SKIP_BUILD: "1" | |
| FIZZY_RELEASE_PUBLISH: "0" | |
| run: ./scripts/release.sh |