Skip to content

Build

Build #7

Workflow file for this run

# Required repository secrets for the Android (Meta Quest) job:
# ANDROID_KEYSTORE_BASE64 - release.keystore encoded as base64 (base64 -w 0 release.keystore)
# ANDROID_KEY_ALIAS - key alias chosen when the keystore was created
# ANDROID_KEYSTORE_PASSWORD - password for both the keystore and the key
# If these secrets are absent the Android job will fail; Windows and Linux builds are unaffected.
# IMPORTANT: keep the original release.keystore file safe - losing it prevents updating existing installs.
#
# Required repository secret for the itch-release job:
# BUTLER_API_KEY - itch.io API key with permission to push builds, from
# https://itch.io/user/settings/api-keys
# If this secret is absent the itch-release job will fail; the GitHub Release is unaffected.
# This job pushes to https://benmclean.itch.io/wolfsharp using itch.io's "butler" CLI, one
# channel per platform (windows-x64, linux-x64, android-meta-quest). It only runs on tag pushes,
# same as the GitHub Release job, and only after all builds succeed.
#
# The Linux job also wraps its export into a portable .AppImage (no extra secrets needed).
# It's built with appimagetool alone, not linuxdeploy, so it does NOT bundle system shared
# libraries (Vulkan/Mesa/GL, libc, X11/Wayland, audio) - deliberately, since bundling GPU driver
# libraries would break hardware acceleration on the host. This assumes those libraries are
# present on the target system, which holds for SteamOS and any current mainstream distro, but
# hasn't been verified on real hardware from this environment - test on an actual Steam Deck (or
# a fresh distro VM) before relying on it.
#
# HOW TO CUT A RELEASE:
# Push (or create, in the GitHub web UI under Releases -> Tags) a tag whose name starts with a
# lowercase "v", e.g. "v0.1.0". Everything after the "v" becomes the release version number, so
# the tag "v0.1.0" produces version "0.1.0" and a release named "v0.1.0".
# git tag v0.1.0
# git push origin v0.1.0
# That push triggers this workflow automatically: it builds Windows, Linux, and Android, then
# the "release" job downloads all three build artifacts, creates a GitHub Release for that tag,
# and attaches the build files. Nothing further is needed - the Release goes up as soon as all
# three builds finish. To add hand-written release notes afterward, edit the published release
# in the GitHub web UI.
#
# HOW TO GET A PREVIEW BUILD (no release, no tag):
# 1. In the GitHub web UI, go to Actions -> "Build" (this workflow) in the left sidebar.
# 2. Click "Run workflow" (top right of the runs list).
# 3. Pick the branch to build from, enter a throwaway version string (e.g. "0.0.0-preview" or a
# date/commit stamp) in the "Version number" field, and click the green "Run workflow" button.
# 4. Wait for both the "Export <platform>" jobs and "Export Android (Meta Quest)" to finish
# (green checks). Each produces one artifact: BenMcLean.Wolf3D.VR_windows-x64_v<version>.zip,
# ..._linux-x64_v<version>.tar.gz, and ..._android-meta-quest_v<version>.apk.
# 5. Open the completed run's summary page and download each artifact under "Artifacts".
# GitHub Actions artifacts are zipped again on download, so unzip once to get the real file.
# Manually running the workflow this way never creates a GitHub Release (that only happens from
# a "v*" tag push, per the "release" job's `if:` condition) - it's just the build outputs to
# download and test locally. Old preview artifacts expire automatically (GitHub's default
# artifact retention period) and never need cleanup.
name: Build
on:
workflow_dispatch:
inputs:
version:
description: "Version number (e.g. 0.1.0)"
required: true
type: string
push:
tags:
- "v*"
env:
GODOT_VERSION: "4.5.1"
jobs:
determine-version:
name: Determine version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Determine version
id: version
run: |
if [ "${{ github.event_name }}" = "push" ]; then
VERSION="${GITHUB_REF_NAME#v}"
else
VERSION="${{ inputs.version }}"
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
export:
name: Export ${{ matrix.name }}
needs: determine-version
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- preset: "Windows Desktop"
name: windows-x64
output_dir: build/windows
release_dir: build/windows
output_file: BenMcLean.Wolf3D.VR.exe
archive_ext: zip
- preset: "Linux"
name: linux-x64
output_dir: build/linux
release_dir: build/linux-release
output_file: BenMcLean.Wolf3D.VR.x86_64
archive_ext: tar.gz
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: "8.0.x"
- name: Download Godot
run: |
wget -q "https://github.com/godotengine/godot/releases/download/${{ env.GODOT_VERSION }}-stable/Godot_v${{ env.GODOT_VERSION }}-stable_mono_linux_x86_64.zip" -O godot.zip
unzip -q godot.zip
sudo install -m 755 "Godot_v${{ env.GODOT_VERSION }}-stable_mono_linux_x86_64/Godot_v${{ env.GODOT_VERSION }}-stable_mono_linux.x86_64" /usr/local/bin/godot
sudo cp -r "Godot_v${{ env.GODOT_VERSION }}-stable_mono_linux_x86_64/GodotSharp" /usr/local/bin/GodotSharp
- name: Install export templates
run: |
wget -q "https://github.com/godotengine/godot/releases/download/${{ env.GODOT_VERSION }}-stable/Godot_v${{ env.GODOT_VERSION }}-stable_mono_export_templates.tpz" -O templates.tpz
mkdir -p "$HOME/.local/share/godot/export_templates/${{ env.GODOT_VERSION }}.stable.mono"
unzip -q templates.tpz -d /tmp/godot_tpl
mv /tmp/godot_tpl/templates/* "$HOME/.local/share/godot/export_templates/${{ env.GODOT_VERSION }}.stable.mono/"
- name: Import project resources
working-directory: godot/BenMcLean.Wolf3D.VR
run: godot --headless --import
- name: Build C# assemblies
working-directory: godot/BenMcLean.Wolf3D.VR
run: dotnet build
- name: Export "${{ matrix.preset }}"
working-directory: godot/BenMcLean.Wolf3D.VR
run: |
mkdir -p "$GITHUB_WORKSPACE/${{ matrix.output_dir }}"
godot --headless --export-release "${{ matrix.preset }}" "$GITHUB_WORKSPACE/${{ matrix.output_dir }}/${{ matrix.output_file }}"
- name: Bundle games folder and README (Windows only)
if: matrix.name == 'windows-x64'
run: |
mkdir -p "$GITHUB_WORKSPACE/${{ matrix.output_dir }}/games"
cp "$GITHUB_WORKSPACE/games/GAMES.md" "$GITHUB_WORKSPACE/${{ matrix.output_dir }}/games/GAMES.md"
if [ -f "$GITHUB_WORKSPACE/README.md" ]; then
cp "$GITHUB_WORKSPACE/README.md" "$GITHUB_WORKSPACE/${{ matrix.output_dir }}/README.md"
fi
- name: Assemble AppDir
if: matrix.name == 'linux-x64'
run: |
APPDIR="$GITHUB_WORKSPACE/build/AppDir"
mkdir -p "$APPDIR/usr/bin"
cp -r "$GITHUB_WORKSPACE/${{ matrix.output_dir }}/." "$APPDIR/usr/bin/"
cat > "$APPDIR/AppRun" <<'EOF'
#!/bin/sh
HERE="$(dirname "$(readlink -f "$0")")"
exec "$HERE/usr/bin/BenMcLean.Wolf3D.VR.x86_64" "$@"
EOF
chmod +x "$APPDIR/AppRun"
cp "$GITHUB_WORKSPACE/promo/icon/icon256.png" "$APPDIR/net.benmclean.wolf3d.png"
cat > "$APPDIR/net.benmclean.wolf3d.desktop" <<'EOF'
[Desktop Entry]
Type=Application
Name=Wolfenstein 3-D
Exec=AppRun
Icon=net.benmclean.wolf3d
Categories=Game;ActionGame;
Terminal=false
EOF
- name: Build AppImage
if: matrix.name == 'linux-x64'
run: |
wget -q "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" -O appimagetool
chmod +x appimagetool
mkdir -p "$GITHUB_WORKSPACE/${{ matrix.release_dir }}/games"
# --appimage-extract-and-run avoids needing FUSE, which isn't available on GH-hosted runners
ARCH=x86_64 ./appimagetool --appimage-extract-and-run \
"$GITHUB_WORKSPACE/build/AppDir" \
"$GITHUB_WORKSPACE/${{ matrix.release_dir }}/BenMcLean.Wolf3D.VR-x86_64.AppImage"
cp "$GITHUB_WORKSPACE/games/GAMES.md" "$GITHUB_WORKSPACE/${{ matrix.release_dir }}/games/GAMES.md"
if [ -f "$GITHUB_WORKSPACE/README.md" ]; then
cp "$GITHUB_WORKSPACE/README.md" "$GITHUB_WORKSPACE/${{ matrix.release_dir }}/README.md"
fi
- name: Package release archive
env:
ARCHIVE_NAME: BenMcLean.Wolf3D.VR_${{ matrix.name }}_v${{ needs.determine-version.outputs.version }}
run: |
cd "$GITHUB_WORKSPACE/${{ matrix.release_dir }}"
if [ "${{ matrix.archive_ext }}" = "zip" ]; then
zip -qr "$GITHUB_WORKSPACE/$ARCHIVE_NAME.zip" .
else
tar -czf "$GITHUB_WORKSPACE/$ARCHIVE_NAME.tar.gz" .
fi
- uses: actions/upload-artifact@v4
with:
name: BenMcLean.Wolf3D.VR_${{ matrix.name }}_v${{ needs.determine-version.outputs.version }}
path: BenMcLean.Wolf3D.VR_${{ matrix.name }}_v${{ needs.determine-version.outputs.version }}.${{ matrix.archive_ext }}
export-android:
name: Export Android (Meta Quest)
needs: determine-version
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: "8.0.x"
- name: Install Android SDK components
run: |
echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager \
"ndk;28.1.13356709" \
"build-tools;35.0.0" \
"platforms;android-35"
- name: Download Godot
run: |
wget -q "https://github.com/godotengine/godot/releases/download/${{ env.GODOT_VERSION }}-stable/Godot_v${{ env.GODOT_VERSION }}-stable_mono_linux_x86_64.zip" -O godot.zip
unzip -q godot.zip
sudo install -m 755 "Godot_v${{ env.GODOT_VERSION }}-stable_mono_linux_x86_64/Godot_v${{ env.GODOT_VERSION }}-stable_mono_linux.x86_64" /usr/local/bin/godot
sudo cp -r "Godot_v${{ env.GODOT_VERSION }}-stable_mono_linux_x86_64/GodotSharp" /usr/local/bin/GodotSharp
- name: Install export templates
run: |
wget -q "https://github.com/godotengine/godot/releases/download/${{ env.GODOT_VERSION }}-stable/Godot_v${{ env.GODOT_VERSION }}-stable_mono_export_templates.tpz" -O templates.tpz
mkdir -p "$HOME/.local/share/godot/export_templates/${{ env.GODOT_VERSION }}.stable.mono"
unzip -q templates.tpz -d /tmp/godot_tpl
mv /tmp/godot_tpl/templates/* "$HOME/.local/share/godot/export_templates/${{ env.GODOT_VERSION }}.stable.mono/"
- name: Import project resources
working-directory: godot/BenMcLean.Wolf3D.VR
run: godot --headless --import
- name: Build C# assemblies
working-directory: godot/BenMcLean.Wolf3D.VR
run: dotnet build
- name: Download OpenXR Vendors plugin
working-directory: godot/BenMcLean.Wolf3D.VR
run: bash setup-openxr-vendors.sh
- name: Install Android build template
working-directory: godot/BenMcLean.Wolf3D.VR
run: |
mkdir -p android/build
unzip -q "$HOME/.local/share/godot/export_templates/${{ env.GODOT_VERSION }}.stable.mono/android_source.zip" -d android/build
echo "${{ env.GODOT_VERSION }}.stable.mono" > android/.build_version
- name: Write keystore
run: echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > "$GITHUB_WORKSPACE/release.keystore"
- name: Configure export credentials
env:
KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
run: |
cat > "godot/BenMcLean.Wolf3D.VR/.godot/export_credentials.cfg" <<EOF
[preset.0]
script_encryption_key=""
[preset.0.options]
keystore/debug=""
keystore/debug_user=""
keystore/debug_password=""
keystore/release="$GITHUB_WORKSPACE/release.keystore"
keystore/release_user="$KEY_ALIAS"
keystore/release_password="$KEYSTORE_PASSWORD"
[preset.1]
script_encryption_key=""
[preset.1.options]
codesign/identity_type=0
codesign/identity=""
codesign/password=""
EOF
- name: Export Android
working-directory: godot/BenMcLean.Wolf3D.VR
run: |
mkdir -p "$GITHUB_WORKSPACE/build/android"
godot --headless --export-release "Android" "$GITHUB_WORKSPACE/build/android/BenMcLean.Wolf3D.VR.apk"
- uses: actions/upload-artifact@v4
with:
name: BenMcLean.Wolf3D.VR_android-meta-quest_v${{ needs.determine-version.outputs.version }}
path: build/android/BenMcLean.Wolf3D.VR.apk
release:
name: Create Release
needs: [determine-version, export, export-android]
if: github.event_name == 'push'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download all build artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
name: ${{ github.ref_name }}
files: artifacts/*/*
itch-release:
name: Push to itch.io
needs: [determine-version, export, export-android]
if: github.event_name == 'push'
runs-on: ubuntu-latest
env:
VERSION: ${{ needs.determine-version.outputs.version }}
BUTLER_API_KEY: ${{ secrets.BUTLER_API_KEY }}
ITCH_TARGET: benmclean/wolfsharp
steps:
- name: Download all build artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Install butler
run: |
curl -sL -o butler.zip https://broth.itch.zone/butler/linux-amd64/LATEST/archive/default
unzip -q butler.zip -d butler
chmod +x butler/butler
./butler/butler -V
- name: Push Windows build
run: |
mkdir -p push/windows-x64
unzip -q "artifacts/BenMcLean.Wolf3D.VR_windows-x64_v${VERSION}/BenMcLean.Wolf3D.VR_windows-x64_v${VERSION}.zip" -d push/windows-x64
./butler/butler push push/windows-x64 "$ITCH_TARGET:windows-x64" --userversion "$VERSION"
- name: Push Linux build
run: |
mkdir -p push/linux-x64
tar -xzf "artifacts/BenMcLean.Wolf3D.VR_linux-x64_v${VERSION}/BenMcLean.Wolf3D.VR_linux-x64_v${VERSION}.tar.gz" -C push/linux-x64
./butler/butler push push/linux-x64 "$ITCH_TARGET:linux-x64" --userversion "$VERSION"
- name: Push Android build
run: |
./butler/butler push "artifacts/BenMcLean.Wolf3D.VR_android-meta-quest_v${VERSION}/BenMcLean.Wolf3D.VR.apk" "$ITCH_TARGET:android-meta-quest" --userversion "$VERSION"