Files
security-game/docs/RELEASING.md
T
zwitschi 2dba562c52
Full build / Import + headless tests (push) Successful in 26s
Full build / Full desktop build + optional release (push) Skipped
Publish v0.2.11 and document the host disk limit
- Pruned the superseded v0.2.0 and v0.2.9 releases through the API (~565 MB of
  assets) after the host root filesystem hit 100%, which blocked release uploads
  (HTTP 500 "no space left on device") and even git push ("unpacker error").
- Published v0.2.11 locally with the fixed script: all five artifacts verified on
  the release (Linux/Windows/macOS ports, NSIS installer, AppImage).
- TODO records the remaining ~150 MB headroom and the exact host cleanup commands;
  MEMORY and RELEASING describe the disk failure mode and the pruning.
2026-10-31 21:39:15 +01:00

6.7 KiB

Releasing Step Line

This guide describes how to produce downloadable executables and publish them so the README "Downloads" links always point at the latest release.

1. Install export templates

Godot needs platform export templates to build standalone binaries. The first time you export, either:

  • Open the editor and use Editor → Manage Export Templates (downloads the matching templates), or
  • Install them manually from the Godot downloads page by placing the Godot_v4.3-stable_export_templates.tpz contents into ~/.local/share/godot/export_templates/4.3.stable/.

Verify with:

godot --headless --export-release "Linux" build/step-line-smoke.x86_64

2. Bump the version

project.godot sets config/version. Keep it in sync with the release tag (e.g. v0.3.0 → config/version="0.3.0", plus a git tag v0.3.0).

3. CI (Gitea Actions)

The repository ships a Gitea Actions workflow (.gitea/workflows/build.yml):

  • Every push/PR runs the checks job: Godot 4.3 install, project import, and the full headless test suite. This is the fast safety net.
  • Tags (v*) and manual workflow_dispatch runs additionally execute the build job: export templates install, import, tools/build_releases.sh for Linux/Windows/macOS, artifact upload, and — on tags — release publication via tools/publish_release.sh.

tools/publish_release.sh picks the first available credential, in order:

  1. GITEA_TOKEN (repo secret, write:repository scope),
  2. GITEA_AUTH_HEADER (a ready-made Authorization: ... header),
  3. ~/.git-credentials for the host,
  4. the local git extraheader that actions/checkout configures on the CI job.

Option 4 is what makes tag builds publish without any repo secret: the runner already injects basic-auth credentials for the checkout, and the script reuses that header for the API (same server). github.token is not available in this Gitea setup, so do not rely on it.

Disk space: Gitea stores release assets under /var/lib/gitea/data/attachments on the host root filesystem (7.8 GB here). When it is full, asset uploads fail with HTTP 500 … no space left on device and even git push can fail with "unpacker error". publish_release.sh now verifies the asset count and exits non-zero, so this is visible.

Incident (2026-10-31): tools/publish_release.sh never set AUTH in its ~/.git-credentials branch, so every API call failed silently (AUTH[@] was unbound under set -u). Combined with no GITEA_TOKEN secret on the repo, tag builds from v0.2.2 to v0.2.8 produced installers but published nothing. The script is fixed (AUTH=(-u "$CRED")) and v0.2.9 was published locally with all five artifacts. If CI publishing fails again, run ./tools/publish_release.sh <version> from a checkout with ~/.git-credentials.

No actions/cache for now: the runner has no local actions-cache service, so actions/cache times out against GitHub's cache API. We dropped it (Godot import is only ~4s). If a host admin later enables Gitea [cache.actions] with a cache server, the step can be reintroduced.

The workflow lives in .gitea/workflows/ (Gitea's canonical path). The old .github/workflows/ci.yml was removed to avoid double runs on hosts that scan both directories.

4. Local build (alternative to CI)

godot --headless --path . --script res://src/test/test_runner.gd   # all tests
godot --headless --path . --quit-after 120                        # boot smoke test
./tools/build_releases.sh

Artifacts are written to build/ (all exports embed the PCK — single files):

  • build/step-line-linux-<version>.x86_64
  • build/step-line-windows-<version>.exe
  • build/step-line-macos-<version>.zip

When run in CI (tags/dispatch), the build job also packages:

  • build/step-line-setup-<version>.exe — Windows installer (NSIS, incl. shortcuts + uninstaller; apt nsis on the runner)
  • build/step-line-<version>-x86_64.AppImage — Linux AppImage (packaging/linux/build_appimage.sh, appimagetool via APPIMAGE_EXTRACT_AND_RUN)

Locally you can build the AppImage with bash packaging/linux/build_appimage.sh <version>; the NSIS installer requires makensis (covered by CI).

macOS builds are unsigned and will need xattr -dr com.apple.quarantine guidance or notarization for production releases.

5. Publish on the repository host (Gitea/Forgejo)

The repository lives at https://git.allucanget.biz/zwitschi/security-game.

Preferred path — use the helper script. It needs either a token or the same credentials used by git push (it falls back to ~/.git-credentials):

GITEA_TOKEN=your_api_token ./tools/publish_release.sh 0.2.1
# or simply: ./tools/publish_release.sh 0.2.1   (uses ~/.git-credentials)

The script creates (or reuses) the release from project.godot's config/version, uploads the three portable artifacts plus the NSIS installer and AppImage when present, and prints the release URL. If CI already published the release, re-running the script only adds missing assets.

Host note: the release is fully built by CI, but anonymous users can only browse and download when the instance sets [service] REQUIRE_SIGNIN_VIEW=false in app.ini (the repo itself is public). See the TODO for the exact steps.

Manual alternative:

Via the web UI

  1. Create a New Release with tag v<version>.
  2. Attach all three build/ artifacts.
  3. Write release notes (see checklist below).

Via the API

TOKEN="your_api_token"
REPO="zwitschi/security-game"
VERSION="0.3.0"
API="https://git.allucanget.biz/api/v1/repos/$REPO/releases"

# Create the release
RELEASE_JSON=$(curl -s -X POST "$API" \
  -H "Authorization: token $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"tag_name\":\"v$VERSION\",\"name\":\"v$VERSION\",\"body\":\"Playable prototype release.\"}")

RELEASE_ID=$(echo "$RELEASE_JSON" | python3 -c "import sys,json;print(json.load(sys.stdin)['id'])")

for f in build/step-line-*"$VERSION"*; do
  curl -s -X POST "$API/$RELEASE_ID/assets" \
    -H "Authorization: token $TOKEN" \
    -F "attachment=@$f"
done

6. Update the README

The Downloads section links to the host releases page (https://git.allucanget.biz/zwitschi/security-game/releases), so no README edit is needed when the page follows the naming pattern. If artifact names change, update tools/build_releases.sh first.

Release notes checklist

  • All headless tests pass (exit code 0).
  • Game boots cleanly in a smoke test.
  • Controls documented in README.md match the build.
  • Version in project.godot matches the tag.
  • Export templates used are the official ones for the pinned engine.
  • Artifacts uploaded; README downloads page shows them.