YAML 96 lines
name: Release build
# Builds the player-facing launcher binaries (Windows + macOS) and attaches them to the
# GitHub Release for the tag. The launcher is the seed build: a full export with boot.tscn as
# its main scene, so it runs offline out of the box and then self-updates by pulling game.pck
# from the rolling `playtest` pre-release (published by ci.yml). Testers download a launcher
# ONCE; new builds arrive as pck updates. Re-run this only when the launcher contract changes
# (the engine line, the autoload/class set) and min_client is bumped — not every release.
#
# Unlike the pck export, full executable exports need the Godot export templates, so this job
# downloads them. The macOS app is unsigned (codesign disabled in export_presets.cfg); testers
# clear the Gatekeeper quarantine per the README. macOS exports fine from a Linux runner.
on:
push:
tags: ["v*"]
workflow_dispatch: # allow a manual launcher build without cutting a new tag
jobs:
launchers:
name: build launchers
runs-on: ubuntu-latest
permissions:
contents: write
env:
GODOT_VERSION: "4.6.3"
steps:
- uses: actions/checkout@v5
with:
# The .glb models and .png textures are Git LFS objects; without this the
# launcher seed and its embedded pck ship without art and crash on match start.
lfs: true
- name: Download Godot ${{ env.GODOT_VERSION }} + export templates
run: |
base="https://github.com/godotengine/godot-builds/releases/download"
ver="${GODOT_VERSION}-stable"
wget -q "${base}/${ver}/Godot_v${ver}_linux.x86_64.zip" -O godot.zip
unzip -q godot.zip
mv "Godot_v${ver}_linux.x86_64" godot
chmod +x godot
wget -q "${base}/${ver}/Godot_v${ver}_export_templates.tpz" -O templates.tpz
mkdir -p "$HOME/.local/share/godot/export_templates/${GODOT_VERSION}.stable"
unzip -q templates.tpz
mv templates/* "$HOME/.local/share/godot/export_templates/${GODOT_VERSION}.stable/"
- name: Import project
run: ./godot --headless --import
- name: Export launchers
run: |
mkdir -p build
./godot --headless --export-release "Windows Desktop" build/Theria.exe
./godot --headless --export-release "macOS" build/Theria-macos.zip
test -s build/Theria.exe
test -s build/Theria-macos.zip
ls -la build
- name: Export game.pck
run: |
# The Stable channel pulls game.pck + manifest.json from the TAGGED release (the Beta
# channel pulls them from the rolling playtest pre-release, published by ci.yml). A
# tagged release that carried only launchers would leave Stable with nothing to pull,
# so it ships the same payload pair the rolling channel does — exported the same way.
./godot --headless --export-pack "Windows Desktop" build/game.pck
test -s build/game.pck
- name: Write manifest.json
run: |
# min_client is the OLDEST launcher that can load this pck. Bump it ONLY when the
# launcher contract breaks (the engine line or the autoload/class set changes) — never
# per release — or testers would have to re-download the launcher on every build. Kept
# in lockstep with the same literal in ci.yml's publish-pck job.
MIN_CLIENT="0.1.0"
VERSION="$(cat VERSION)"
cat > build/manifest.json <<EOF
{
"version": "${VERSION#v}",
"sha": "${GITHUB_SHA}",
"pck": "game.pck",
"min_client": "${MIN_CLIENT}"
}
EOF
cat build/manifest.json
- name: Package the Windows launcher
run: |
# embed_pck is on, so Theria.exe is the whole launcher — zip it for a clean download.
cd build && zip -j Theria-windows.zip Theria.exe
- name: Attach launchers and the Stable payload to the release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
tag="${GITHUB_REF_NAME}"
# workflow_dispatch has no tag ref name; fall back to the latest release tag.
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
tag="$(gh release list --limit 1 --json tagName --jq '.[0].tagName')"
fi
gh release upload "$tag" \
build/Theria-windows.zip build/Theria-macos.zip \
build/game.pck build/manifest.json --clobber