Skip to content

Build & Release Bangen #23

Build & Release Bangen

Build & Release Bangen #23

name: Build & Release Bangen
on:
workflow_dispatch:
push:
branches:
- main
paths:
- "pyproject.toml"
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: true
jobs:
tag:
name: Extract version & create tag
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
version: ${{ steps.extract.outputs.version }}
tag: ${{ steps.extract.outputs.tag }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Extract version from pyproject.toml
id: extract
run: |
VERSION=$(python - <<'EOF'
import tomllib
with open("pyproject.toml", "rb") as f:
print(tomllib.load(f)["project"]["version"])
EOF
)
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "tag=$VERSION" >> "$GITHUB_OUTPUT"
- name: Abort if tag already exists
run: |
if git rev-parse "refs/tags/${{ steps.extract.outputs.tag }}" &>/dev/null; then
echo "Tag ${{ steps.extract.outputs.tag }} already exists β€” skipping release."
exit 1
fi
- name: Create and push tag
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag "${{ steps.extract.outputs.tag }}"
git push origin "${{ steps.extract.outputs.tag }}"
build:
name: Build (${{ matrix.name }})
needs: tag
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
name: linux
binary: bangen
- os: windows-latest
name: windows
binary: bangen.exe
- os: macos-latest
name: macos
binary: bangen
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Cache pip
uses: actions/cache@v4
with:
path: |
~/.cache/pip
~/AppData/Local/pip/Cache
key: pip-${{ runner.os }}-${{ hashFiles('pyproject.toml') }}
restore-keys: pip-${{ runner.os }}-
- name: Install Python deps
shell: bash
run: |
python -m pip install -U pip wheel pyinstaller
pip install ".[all]"
- name: Build with PyInstaller
shell: bash
env:
VERSION: ${{ needs.tag.outputs.version }}
run: |
printf 'from bangen.app import main\nif __name__ == "__main__":\n main()\n' > _entry.py
python -m PyInstaller \
--onefile \
--noconfirm \
--name bangen \
--distpath dist \
--workpath build \
--collect-all bangen \
--collect-all pyfiglet \
--collect-all rich \
--collect-all PIL \
--collect-all typer \
--exclude-module tkinter \
--exclude-module unittest \
--exclude-module test \
--exclude-module distutils \
--exclude-module setuptools \
--exclude-module pkg_resources \
--exclude-module email \
--exclude-module http \
--exclude-module html \
--exclude-module xml \
--exclude-module xmlrpc \
--optimize 2 \
_entry.py
- name: Package artifact
shell: bash
env:
VERSION: ${{ needs.tag.outputs.version }}
BINARY: ${{ matrix.binary }}
run: |
mkdir -p release
NAME="bangen-${{ matrix.name }}-$VERSION"
if [[ "$RUNNER_OS" == "Windows" ]]; then
mv "dist/$BINARY" "release/$NAME.exe"
powershell -Command "Compress-Archive -Path release\\$NAME.exe -DestinationPath release\\$NAME.zip"
rm "release/$NAME.exe"
else
mv "dist/$BINARY" "release/$NAME"
(cd release && tar -czf "$NAME.tar.gz" "$NAME" && rm "$NAME")
fi
- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.name }}-build
path: release/*
retention-days: 1
release:
name: Publish Release
needs: [tag, build]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/download-artifact@v4
with:
path: artifacts
merge-multiple: true
- name: Generate checksums
run: |
cd artifacts
sha256sum * > SHA256SUMS.txt
- name: Build release notes
id: notes
env:
VERSION: ${{ needs.tag.outputs.version }}
run: |
PREV_TAG=$(git tag --sort=-version:refname | grep -v "^$VERSION$" | head -1)
if [[ -n "$PREV_TAG" ]]; then
COMMITS=$(git log "$PREV_TAG"..HEAD --pretty=format:"- %s (%h)" --no-merges)
COMPARE_URL="https://github.com/${{ github.repository }}/compare/$PREV_TAG...$VERSION"
SINCE_LINE="> Changes since \`$PREV_TAG\` Β· [Full diff]($COMPARE_URL)"
else
COMMITS=$(git log --pretty=format:"- %s (%h)" --no-merges)
SINCE_LINE="> Initial release"
fi
FEATS=$(echo "$COMMITS" | grep -E "^- feat" | sed 's/^- feat[^:]*: /- /' || true)
FIXES=$(echo "$COMMITS" | grep -E "^- fix" | sed 's/^- fix[^:]*: /- /' || true)
CHORES=$(echo "$COMMITS" | grep -E "^- (chore|refactor|perf|build|ci)" | sed 's/^- [^:]*: /- /' || true)
OTHER=$(echo "$COMMITS" | grep -vE "^- (feat|fix|chore|refactor|perf|build|ci)" || true)
LINUX_SHA=$(grep "bangen-linux-$VERSION.tar.gz" artifacts/SHA256SUMS.txt | awk '{print $1}' || true)
WINDOWS_SHA=$(grep "bangen-windows-$VERSION.zip" artifacts/SHA256SUMS.txt | awk '{print $1}' || true)
MACOS_SHA=$(grep "bangen-macos-$VERSION.tar.gz" artifacts/SHA256SUMS.txt | awk '{print $1}' || true)
{
echo "body<<NOTES_EOF"
echo "# ✨ Bangen $VERSION"
echo ""
echo "$SINCE_LINE"
echo ""
echo "---"
echo ""
if [[ -n "$FEATS" ]]; then
echo "## πŸš€ What's New"
echo "$FEATS"
echo ""
fi
if [[ -n "$FIXES" ]]; then
echo "## πŸ› Bug Fixes"
echo "$FIXES"
echo ""
fi
if [[ -n "$CHORES" ]]; then
echo "## πŸ”§ Maintenance"
echo "$CHORES"
echo ""
fi
if [[ -n "$OTHER" ]]; then
echo "## πŸ“ Other Changes"
echo "$OTHER"
echo ""
fi
echo "---"
echo ""
echo "## πŸ“¦ Downloads"
echo ""
echo "Pre-built native binaries are available for all major platforms β€” no Python installation required."
echo ""
echo "| Platform | Architecture | File | SHA-256 |"
echo "|----------|-------------|------|---------|"
echo "| 🐧 Linux | x86_64 | \`bangen-linux-$VERSION.tar.gz\` | \`$LINUX_SHA\` |"
echo "| πŸͺŸ Windows | x86_64 | \`bangen-windows-$VERSION.zip\` | \`$WINDOWS_SHA\` |"
echo "| 🍎 macOS | arm64 | \`bangen-macos-$VERSION.tar.gz\` | \`$MACOS_SHA\` |"
echo ""
echo "### πŸš€ Quick Install"
echo ""
echo "\`\`\`bash"
echo "# Linux / macOS"
echo "tar -xzf bangen-<platform>-$VERSION.tar.gz"
echo "chmod +x bangen-<platform>-$VERSION"
echo "sudo mv bangen-<platform>-$VERSION /usr/local/bin/bangen"
echo ""
echo "# Windows (PowerShell)"
echo "Expand-Archive bangen-windows-$VERSION.zip ."
echo "\`\`\`"
echo ""
echo "### πŸ”’ Verify Your Download"
echo ""
echo "\`\`\`bash"
echo "sha256sum -c SHA256SUMS.txt"
echo "\`\`\`"
echo ""
echo "> Full checksums for all artifacts are in \`SHA256SUMS.txt\`, included in the release assets below."
echo "NOTES_EOF"
} >> "$GITHUB_OUTPUT"
- uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.tag.outputs.tag }}
name: "✨ Bangen ${{ needs.tag.outputs.version }}"
body: ${{ steps.notes.outputs.body }}
files: artifacts/*