Skip to content

Build & Release Bangen #14

Build & Release Bangen

Build & Release Bangen #14

name: Build Bangen (Nuitka)
on:
push:
tags:
- "v*"
workflow_dispatch:
permissions:
contents: write
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
name: linux
- os: macos-latest
name: macos
- os: windows-latest
name: windows
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Build fingerprint + cache key
id: meta
shell: bash
run: |
VERSION=${GITHUB_REF_NAME#v}
SHA=$(git rev-parse --short HEAD)
# sha256sum on Linux, shasum on macOS — both unavailable on Windows
# so we use Python for a cross-platform hash
DEPS_HASH=$(python -c "
import hashlib, pathlib
p = pathlib.Path('pyproject.toml')
print(hashlib.sha256(p.read_bytes()).hexdigest()[:16] if p.exists() else 'nodeps')
")
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
echo "SHA=$SHA" >> $GITHUB_OUTPUT
echo "DEPS=$DEPS_HASH" >> $GITHUB_OUTPUT
echo "CACHE_KEY=${{ runner.os }}-$VERSION-$DEPS_HASH" >> $GITHUB_OUTPUT
- uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: "pip"
- name: Cross-workflow cache (Nuitka + deps)
uses: actions/cache@v4
with:
path: |
~/.cache/pip
~/.cache/Nuitka
~/Library/Caches/Nuitka
~\AppData\Local\Nuitka\Nuitka\Cache
key: nuitka-${{ steps.meta.outputs.CACHE_KEY }}
restore-keys: |
nuitka-${{ runner.os }}-${{ steps.meta.outputs.VERSION }}-
nuitka-${{ runner.os }}-
- name: Install system deps (Linux)
if: runner.os == 'Linux'
# build-essential already pulls in binutils (which provides strip).
# Do NOT list "strip" — it is not a package name and will abort apt.
run: sudo apt-get update && sudo apt-get install -y build-essential patchelf
- name: Install system deps (macOS)
if: runner.os == 'macOS'
run: xcode-select -p || xcode-select --install || true
- name: MSVC setup (Windows)
if: runner.os == 'Windows'
uses: ilammy/msvc-dev-cmd@v1
- name: Install Python deps
run: |
python -m pip install -U pip wheel
# setuptools>=72 removed pkg_resources.DefaultProvider, which
# Nuitka 4.x's bundled Jinja2 copy requires during C code generation.
# Pin below 72 until Nuitka ships its own Jinja2 fix.
pip install "setuptools<72"
pip install nuitka[onefile]
pip install .
- name: Create entrypoint
shell: bash
run: |
cat > _entry.py << 'EOF'
from bangen.app import main
if __name__ == "__main__":
main()
EOF
- name: Build with Nuitka
shell: bash
run: |
python -m nuitka \
--onefile \
--lto=yes \
--jobs=2 \
--assume-yes-for-downloads \
--output-dir=build \
--output-filename=bangen \
--include-package=bangen \
--include-package=rich \
--include-package=pyfiglet \
--include-package=PIL \
--include-package=typer \
--include-package=click \
--nofollow-import-to=tkinter \
--nofollow-import-to=unittest \
--nofollow-import-to=test \
--nofollow-import-to=distutils \
--nofollow-import-to=setuptools \
--nofollow-import-to=pkg_resources \
--python-flag=no_asserts \
--python-flag=no_docstrings \
--python-flag=isolated \
"--onefile-tempdir-spec={CACHE_DIR}/bangen/${{ steps.meta.outputs.VERSION }}" \
_entry.py
- name: Stage fingerprinted artifact
shell: bash
run: |
mkdir -p dist
NAME="bangen-${{ matrix.name }}-${{ steps.meta.outputs.VERSION }}-${{ steps.meta.outputs.SHA }}"
if [[ "$RUNNER_OS" == "Linux" ]]; then
mv build/bangen dist/$NAME
# strip is provided by binutils (part of build-essential)
strip dist/$NAME
elif [[ "$RUNNER_OS" == "macOS" ]]; then
mv build/bangen dist/$NAME
# strip ships with Xcode Command Line Tools
strip dist/$NAME
else
# Nuitka always appends .exe on Windows regardless of --output-filename
mv build/bangen.exe dist/$NAME.exe
fi
- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.name }}-build
path: dist/*
release:
needs: build
runs-on: ubuntu-latest
steps:
# Checkout is required so git log/describe have history to work with
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full history so git describe can find previous tags
- uses: actions/download-artifact@v4
with:
path: artifacts
merge-multiple: true # flatten into artifacts/ instead of artifacts/<name>/
- name: Generate changelog
id: changelog
shell: bash
run: |
PREV=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
{
echo "CHANGELOG<<EOF"
if [[ -n "$PREV" ]]; then
git log "$PREV"..HEAD --pretty=format:"- %s"
else
git log --pretty=format:"- %s"
fi
echo ""
echo "EOF"
} >> $GITHUB_OUTPUT
- name: Create DRAFT release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
name: Bangen ${{ github.ref_name }}
draft: true
body: |
## 🚀 Changes
${{ steps.changelog.outputs.CHANGELOG }}
## 🧬 Build Info
- Commit: `${{ github.sha }}`
- Matrix build: Linux · macOS · Windows
- Nuitka LTO + onefile
files: artifacts/*