Skip to content

Fix release CI - 5

Fix release CI - 5 #29

Workflow file for this run

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