313 lines
9.8 KiB
YAML
313 lines
9.8 KiB
YAML
# Multi-platform build + packaging workflow
|
|
# Thin GitHub Actions wrapper around Prefect + Dagger pipeline.
|
|
#
|
|
# Architecture:
|
|
# - Windows build runs natively on windows-latest (cannot containerize)
|
|
# - Linux builds run via Dagger containers orchestrated by Prefect
|
|
# - Signing, release creation, and R2 upload handled by Prefect tasks
|
|
# - Container runtime: Podman (Dagger connects via Podman socket)
|
|
#
|
|
# Local equivalent:
|
|
# poetry run python -m ci.prefect_flow full \
|
|
# --gpg-passphrase "$GPG_PASSPHRASE" \
|
|
# --github-token "$GITHUB_TOKEN"
|
|
name: Build Multi-Platform Binaries
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
|
|
concurrency:
|
|
group: release-workflow
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
CI_CD: true
|
|
CI_CD_PAT: ${{ secrets.CI_CD_PAT }}
|
|
|
|
jobs:
|
|
|
|
# ── Windows Build (native runner — cannot containerize) ──────────────
|
|
build-windows:
|
|
runs-on: windows-latest
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: main
|
|
|
|
- name: Set up Python 3.13
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: '3.13'
|
|
|
|
- name: Install Poetry
|
|
uses: snok/install-poetry@v1
|
|
with:
|
|
version: latest
|
|
virtualenvs-create: true
|
|
virtualenvs-in-project: true
|
|
|
|
- name: Ensure Poetry is on PATH
|
|
shell: pwsh
|
|
run: |
|
|
$poetryPath = Join-Path $env:USERPROFILE ".local\bin"
|
|
Write-Output $poetryPath >> $Env:GITHUB_PATH
|
|
|
|
- name: Install dependencies
|
|
run: poetry install
|
|
|
|
- name: Build Windows executable
|
|
run: poetry run pyinstaller scripts/spec_scripts/android-file-handler-windows.spec
|
|
|
|
- name: Install Inno Setup 6.7.1
|
|
shell: pwsh
|
|
run: |
|
|
choco install innosetup --version 6.7.1 -y --no-progress
|
|
# Refresh PATH so ISCC.exe is available immediately
|
|
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
|
|
|
- name: Build Windows installer (Inno Setup)
|
|
shell: pwsh
|
|
run: |
|
|
$version = (poetry version -s).Trim()
|
|
Write-Output "Building installer for version $version"
|
|
& "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" `
|
|
"scripts\windows\android-file-handler-setup.iss" `
|
|
"/DMyAppVersion=$version"
|
|
|
|
- name: Import GPG key
|
|
shell: pwsh
|
|
run: |
|
|
$env:GPG_TTY = "not a tty"
|
|
echo "${{ secrets.GPG_PRIVATE_KEY }}" | gpg --batch --import
|
|
gpg --list-secret-keys
|
|
|
|
- name: Sign and hash Windows artifacts
|
|
shell: pwsh
|
|
run: |
|
|
$passphraseFile = New-TemporaryFile
|
|
try {
|
|
"${{ secrets.GPG_PASSPHRASE }}" | Out-File -FilePath $passphraseFile -Encoding ASCII -NoNewline
|
|
|
|
# Sign and hash standalone executable
|
|
$exePath = Get-ChildItem -Path dist -Filter "android-file-handler-windows.exe" |
|
|
Select-Object -First 1 -ExpandProperty FullName
|
|
if (-not $exePath) { Write-Error "Standalone executable not found"; exit 1 }
|
|
gpg --batch --yes --passphrase-file "$passphraseFile" --detach-sign --armor "$exePath"
|
|
$hash = (Get-FileHash -Path "$exePath" -Algorithm SHA256).Hash.ToLower()
|
|
"$hash $(Split-Path -Leaf $exePath)" |
|
|
Out-File -FilePath "dist/android-file-handler-windows.sha256" -Encoding ASCII -NoNewline
|
|
|
|
# Sign and hash installer
|
|
$setupPath = Get-ChildItem -Path dist -Filter "android-file-handler-setup.exe" |
|
|
Select-Object -First 1 -ExpandProperty FullName
|
|
if (-not $setupPath) { Write-Error "Installer not found"; exit 1 }
|
|
gpg --batch --yes --passphrase-file "$passphraseFile" --detach-sign --armor "$setupPath"
|
|
$setupHash = (Get-FileHash -Path "$setupPath" -Algorithm SHA256).Hash.ToLower()
|
|
"$setupHash $(Split-Path -Leaf $setupPath)" |
|
|
Out-File -FilePath "dist/android-file-handler-setup.sha256" -Encoding ASCII -NoNewline
|
|
}
|
|
finally {
|
|
if (Test-Path $passphraseFile) { Remove-Item $passphraseFile -Force }
|
|
}
|
|
|
|
- name: Upload Windows artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: windows-binary
|
|
path: |
|
|
dist/android-file-handler-windows.exe
|
|
dist/android-file-handler-windows.exe.asc
|
|
dist/android-file-handler-windows.sha256
|
|
dist/android-file-handler-setup.exe
|
|
dist/android-file-handler-setup.exe.asc
|
|
dist/android-file-handler-setup.sha256
|
|
|
|
# ── Linux Builds (Prefect + Dagger with Podman backend) ─────────────
|
|
build-linux:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: main
|
|
|
|
- name: Set up Python 3.13
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: '3.13'
|
|
|
|
- name: Install Poetry
|
|
uses: snok/install-poetry@v1
|
|
with:
|
|
version: latest
|
|
virtualenvs-create: true
|
|
virtualenvs-in-project: true
|
|
|
|
- name: Install project + CI dependencies
|
|
run: poetry install --with ci
|
|
|
|
- name: Set up Podman
|
|
run: |
|
|
sudo apt-get update -qq
|
|
sudo apt-get install -y -qq podman
|
|
# Start rootful Podman socket for Dagger compatibility
|
|
sudo systemctl enable --now podman.socket
|
|
echo "DOCKER_HOST=unix:///run/podman/podman.sock" >> "$GITHUB_ENV"
|
|
|
|
- name: Install Dagger CLI
|
|
uses: dagger/dagger-for-github@v7
|
|
with:
|
|
verb: version
|
|
|
|
- name: Log in to GHCR (Podman)
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" |
|
|
podman login ghcr.io -u "${{ github.actor }}" --password-stdin
|
|
|
|
- name: Build all Linux distros (Prefect + Dagger)
|
|
run: poetry run python -m ci.prefect_flow build-linux
|
|
|
|
- name: Import GPG key
|
|
run: |
|
|
echo "${{ secrets.GPG_PRIVATE_KEY }}" | gpg --batch --import
|
|
|
|
- name: Sign Linux artifacts
|
|
run: |
|
|
poetry run python -m ci.prefect_flow sign \
|
|
--gpg-passphrase "${{ secrets.GPG_PASSPHRASE }}"
|
|
|
|
- name: Upload Debian package
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: debian-package
|
|
path: |
|
|
dist/android-file-handler_*.deb
|
|
dist/android-file-handler_*.deb.asc
|
|
dist/android-file-handler-debian.sha256
|
|
pkg_dist_debian/**
|
|
|
|
- name: Upload Arch package
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: arch-package
|
|
path: |
|
|
dist/*.pkg.tar.*
|
|
dist/android-file-handler-arch.sha256
|
|
pkg_dist_arch/**
|
|
|
|
- name: Upload RHEL package
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: rhel-package
|
|
path: |
|
|
dist/*.rpm
|
|
dist/*.rpm.asc
|
|
dist/android-file-handler-rhel.sha256
|
|
pkg_dist_rhel/**
|
|
|
|
# ── Release + R2 Upload (Prefect) ───────────────────────────────────
|
|
do-release:
|
|
needs: [build-windows, build-linux]
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: main
|
|
|
|
- name: Set up Python 3.13
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: '3.13'
|
|
|
|
- name: Install Poetry
|
|
uses: snok/install-poetry@v1
|
|
with:
|
|
version: latest
|
|
virtualenvs-create: true
|
|
virtualenvs-in-project: true
|
|
|
|
- name: Install project + CI dependencies
|
|
run: poetry install --with ci
|
|
|
|
- name: Download all artifacts
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
merge-multiple: true
|
|
path: ./dist
|
|
|
|
- name: Create GitHub release (Prefect)
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
poetry run python -m ci.prefect_flow release \
|
|
--github-token "$GITHUB_TOKEN"
|
|
|
|
upload-r2:
|
|
runs-on: ubuntu-latest
|
|
needs: do-release
|
|
if: needs.do-release.result == 'success'
|
|
permissions:
|
|
contents: read
|
|
id-token: write
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: main
|
|
|
|
- name: Set up Python 3.13
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: '3.13'
|
|
|
|
- name: Install Poetry
|
|
uses: snok/install-poetry@v1
|
|
with:
|
|
version: latest
|
|
virtualenvs-create: true
|
|
virtualenvs-in-project: true
|
|
|
|
- name: Install project + CI dependencies
|
|
run: poetry install --with ci
|
|
|
|
- name: Download build artifacts
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
merge-multiple: true
|
|
path: ./release-files
|
|
|
|
- name: Authenticate to GCP
|
|
uses: google-github-actions/auth@v2
|
|
with:
|
|
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
|
|
service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }}
|
|
|
|
- name: Upload artifacts to Cloudflare R2
|
|
run: |
|
|
poetry run python -m ci.prefect_flow upload-r2 \
|
|
--gcp-project-id "${{ secrets.GCP_PROJECT_ID }}" \
|
|
--run-id "${{ github.run_id }}" \
|
|
--release-dir "./release-files"
|
|
|
|
sync-wiki:
|
|
needs: do-release
|
|
if: needs.do-release.result == 'success'
|
|
permissions:
|
|
contents: write
|
|
pull-requests: write
|
|
uses: ./.github/workflows/sync-wiki.yml
|
|
with:
|
|
branch: main
|
|
secrets: inherit
|