Build & Release Bangen #23
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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/* |