Skip to content

Release Build

Release Build #32

Workflow file for this run

name: Release Build
on:
workflow_dispatch:
inputs:
release_type:
description: 'Release type'
required: true
type: choice
options:
- stable
- prerelease
- development
default: 'stable'
permissions:
contents: write
jobs:
prepare_release:
name: Prepare Release
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
version: ${{ steps.version.outputs.version }}
upload_url: ${{ steps.create_release.outputs.upload_url }}
is_prerelease: ${{ steps.version.outputs.is_prerelease }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.14'
- name: Generate Version
id: version
run: python .github/scripts/generate_release_version.py --type ${{ github.event.inputs.release_type }}
- name: Update Version in Files
run: |
VERSION="${{ steps.version.outputs.version }}"
echo "Updating version to $VERSION"
# Update pyproject.toml
sed -i "s/version = \".*\"/version = \"$VERSION\"/" pyproject.toml
# Update __init__.py
sed -i "s/__version__ = \".*\"/__version__ = \"$VERSION\"/" src/switchcraft/__init__.py
# Update file_version_info.txt
python .github/scripts/update_version_info.py "$VERSION"
- name: Generate Changelog
id: changelog
run: |
python .github/scripts/generate_changelog.py --output changelog.md --type ${{ github.event.inputs.release_type }}
# Read changelog content into a variable safely (multiline)
{
echo 'CHANGELOG_BODY<<EOF'
cat changelog.md
echo ""
echo 'EOF'
} >> "$GITHUB_ENV"
- name: Generate Summary Table
id: summary
run: |
VERSION="${{ steps.version.outputs.version }}"
REPO_URL="${{ github.server_url }}/${{ github.repository }}"
python .github/scripts/release_summary.py "$VERSION" "$REPO_URL" > summary.md
# Read summary content into a variable safely (multiline)
{
echo 'SUMMARY_BODY<<EOF'
cat summary.md
echo ""
echo 'EOF'
} >> "$GITHUB_ENV"
- name: Commit and Tag
run: |
VERSION="${{ steps.version.outputs.version }}"
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git add pyproject.toml src/switchcraft/__init__.py file_version_info.txt
# Only commit if there are changes
if ! git diff --cached --quiet; then
echo "Changes detected, committing version bump..."
git commit -m "chore(release): bump version to $VERSION [skip ci]"
git push origin main
else
echo "No changes detected, version files are already up to date."
fi
# Always tag and push the tag
git tag "v$VERSION"
git push origin "v$VERSION"
- name: Create GitHub Release
id: create_release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ steps.version.outputs.version }}
name: ${{ github.event.inputs.release_type == 'stable' && format('Release v{0}', steps.version.outputs.version) || github.event.inputs.release_type == 'prerelease' && format('Pre-release v{0}', steps.version.outputs.version) || format('Development Build v{0}', steps.version.outputs.version) }}
body: |
[![GitHub all releases](https://img.shields.io/github/downloads/${{ github.repository }}/total?color=blue&style=flat-square&logo=github&label=Total%20Downloads)](https://github.com/${{ github.repository }}/releases)
![Downloads](https://img.shields.io/github/downloads/${{ github.repository }}/v${{ steps.version.outputs.version }}/total?color=blue&style=flat-square)
${{ env.CHANGELOG_BODY }}
---
${{ env.SUMMARY_BODY }}
draft: false
prerelease: ${{ github.event.inputs.release_type != 'stable' }}
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Update Main Branch to Dev Version
if: ${{ github.event.inputs.release_type == 'stable' }}
run: |
VERSION="${{ steps.version.outputs.version }}"
# Calculate next dev version (increment patch and add -dev)
MAJOR=$(echo $VERSION | cut -d. -f1)
MINOR=$(echo $VERSION | cut -d. -f2)
PATCH=$(echo $VERSION | cut -d. -f3)
NEXT_PATCH=$((PATCH + 1))
DEV_VERSION="${MAJOR}.${MINOR}.${NEXT_PATCH}-dev"
echo "Setting development version to $DEV_VERSION"
# Update version files
sed -i "s/version = \".*\"/version = \"$DEV_VERSION\"/" pyproject.toml
sed -i "s/__version__ = \".*\"/__version__ = \"$DEV_VERSION\"/" src/switchcraft/__init__.py
python .github/scripts/update_version_info.py "$DEV_VERSION"
# Commit
git add pyproject.toml src/switchcraft/__init__.py file_version_info.txt
git commit -m "chore: bump version to $DEV_VERSION for development [skip ci]"
git push origin main
build:
name: Build Artifacts
needs: prepare_release
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: windows-latest
build_flags: "-All"
asset_path: "dist/SwitchCraft-windows.exe"
asset_name: "SwitchCraft-windows.exe"
- os: ubuntu-latest
build_flags: "-Modern"
asset_path: "dist/SwitchCraft-linux"
asset_name: "SwitchCraft-linux"
- os: macos-latest
build_flags: "-Modern"
asset_path: "dist/SwitchCraft"
asset_name: "SwitchCraft-macos"
steps:
- uses: actions/checkout@v6
with:
ref: v${{ needs.prepare_release.outputs.version }}
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.14'
# Cache PyInstaller
- uses: actions/cache@v5
with:
path: build
key: ${{ matrix.os }}-build-${{ hashFiles('**/pyproject.toml') }}
restore-keys: |
${{ matrix.os }}-build-
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install ".[modern,gui]"
pip install pyinstaller build
- name: Build with Script
run: |
# Call the unified build script
pwsh ./scripts/build_release.ps1 ${{ matrix.build_flags }}
env:
TERM: xterm
- name: Rename MacOS Artifact (if needed)
if: matrix.os == 'macos-latest'
run: |
# Script produces 'dist/SwitchCraft' on Mac.
# We might want to rename it to match asset_name expected
mv dist/SwitchCraft dist/${{ matrix.asset_name }} || true
shell: bash
# --- Windows Specific Signing & Uploads ---
- name: Decode Signing Certificate
if: matrix.os == 'windows-latest'
env:
SIGNING_CERT: ${{ secrets.SIGNING_CERT }}
run: |
if ($env:SIGNING_CERT) {
$certBytes = [System.Convert]::FromBase64String($env:SIGNING_CERT)
[System.IO.File]::WriteAllBytes("cert.pfx", $certBytes)
}
shell: pwsh
- name: Sign Windows Artifacts
if: matrix.os == 'windows-latest'
env:
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
run: |
if (Test-Path "cert.pfx") {
$signtool = Get-ChildItem -Path "C:\Program Files (x86)\Windows Kits" -Include signtool.exe -Recurse | Select-Object -Last 1
if ($signtool) {
# Sign everything executable in dist
Get-ChildItem dist\*.exe | ForEach-Object {
Write-Host "Signing $_..."
& $signtool.FullName sign /f "cert.pfx" /p "$env:SIGNING_PASSWORD" /tr http://timestamp.digicert.com /td sha256 /fd sha256 $_.FullName
}
}
}
shell: pwsh
- name: Upload Core Assets
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ needs.prepare_release.outputs.version }}
files: |
dist/${{ matrix.asset_name }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload Windows Extras (Legacy, CLIs, Installers, Addons)
if: matrix.os == 'windows-latest'
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ needs.prepare_release.outputs.version }}
files: |
dist/SwitchCraft-Legacy.exe
dist/SwitchCraft-CLI-windows.exe
dist/SwitchCraft-Setup.exe
dist/SwitchCraft-Legacy-Setup.exe
dist/*.zip
dist/*.whl
dist/*.tar.gz
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Cleanup Certificate
if: always() && matrix.os == 'windows-latest'
run: |
if (Test-Path "cert.pfx") { Remove-Item "cert.pfx" -Force }
shell: pwsh
winget_manifests:
name: Generate Winget Manifests
needs: [prepare_release, build]
if: github.event.inputs.release_type == 'stable'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install Dependencies
run: pip install requests pyyaml
- name: Generate Manifests
run: |
VERSION="${{ needs.prepare_release.outputs.version }}"
python .github/scripts/generate_winget_manifests.py --version "$VERSION" >> "$GITHUB_STEP_SUMMARY"