Files
android-assistant/.github/workflows/release-prefect-dagger.yml
T

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