Fix release CI - 5 #29
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. | |
| - name: Setup MSVC SDK (Windows targets) | |
| if: endsWith(matrix.target, '-windows-msvc') | |
| run: | | |
| set -euo pipefail | |
| zig build msvcup-setup | |
| # MSI extraction on Linux preserves the original mixed-case filenames from | |
| # the SDK packages (kernel32.Lib, AdvAPI32.Lib, ...) — fine on macOS/Windows | |
| # which are case-insensitive, but on Linux's case-sensitive FS the gen | |
| # script (and later the linker) can't find kernel32.lib. Symlink each *.Lib | |
| # to a lowercase sibling so any consumer requesting *.lib resolves it. | |
| # Upstream bug in velopack-zig's tools/gen_zig_libc_msvc.zig + MSI extractor. | |
| - name: Fix MSVC SDK case-sensitivity (Linux + Windows targets) | |
| if: endsWith(matrix.target, '-windows-msvc') | |
| run: | | |
| set -euo pipefail | |
| n=0 | |
| while IFS= read -r -d '' f; do | |
| lower="${f%.Lib}.lib" | |
| if [[ ! -e "$lower" ]]; then | |
| ln -s "$(basename "$f")" "$lower" | |
| n=$((n + 1)) | |
| fi | |
| done < <(find .velopack-msvc -type f -name "*.Lib" -print0) | |
| echo "Created $n lowercase symlinks for *.Lib -> *.lib" | |
| - 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 |