Compilar en CI con GitHub Actions
Como cada sistema compila su propia app, la forma más fácil de publicarlas todas es dejar que GitHub las compile en sus propias máquinas Windows, macOS y Linux (“runners”), en x64 y ARM, cada vez que publicas una versión.
Escribir el flujo
Sección titulada «Escribir el flujo»uv run pyzed build --workflowpyzed build --workflow # o: python -m pyzed build --workflowpyzed build --workflow # o: py -m pyzed build --workflowEscribe .github/workflows/build.yml, con un trabajo por cada destino de targets en [tool.pyzed.build] (por
defecto Windows x64, macOS en Apple silicon y Linux x64). En Pyzed Design, marca las plataformas en
Archivo → Exportar aplicación… → Plataformas y pulsa Escribir workflow de CI
(Exportar tu app).
name: Build
# Builds the app for each target with `pyzed build` and keeps the result as an# artifact (Actions -> this run -> Artifacts). The backends cannot cross-compile, so# every platform and architecture builds on its own runner.on: push: tags: ["v*"] workflow_dispatch:
jobs: build: name: Build ${{ matrix.target }} runs-on: ${{ matrix.runner }} strategy: fail-fast: false matrix: include: - { target: windows-x64, runner: windows-latest } - { target: macos-arm64, runner: macos-latest } - { target: linux-x64, runner: ubuntu-22.04 } steps: - uses: actions/checkout@v4 - uses: astral-sh/setup-uv@v6 - run: uv sync --locked - run: uv run pyzed build --target ${{ matrix.target }} - uses: actions/upload-artifact@v4 with: name: shop-${{ matrix.target }} path: dist/--target hace que cada trabajo compruebe que su máquina compila lo que dice la matriz. El empaquetador, el icono, la
pantalla de inicio y el resto de ajustes salen de pyproject.toml, igual que en tu equipo.
Ejecutarlo
Sección titulada «Ejecutarlo»-
Haz commit del flujo y de tu
uv.lock(la compilación usauv sync --locked, así que el archivo de bloqueo tiene que estar al día). -
Sube una etiqueta de versión:
Ventana de terminal git tag v1.0.0git push origin v1.0.0O lánzalo a mano: Actions → Build → Run workflow.
-
Cuando termine, descarga las compilaciones desde la página de la ejecución, en Artifacts.
Qué máquinas
Sección titulada «Qué máquinas»| Destino | Runner | Compila para |
|---|---|---|
windows-x64 |
windows-latest |
Windows 10 y 11 en Intel y AMD |
windows-arm64 |
windows-11-arm |
Windows 11 en ARM |
macos-arm64 |
macos-latest |
Macs con Apple silicon |
macos-x64 |
macos-15-intel |
Macs con Intel |
linux-x64 |
ubuntu-22.04 |
Linux en Intel y AMD |
linux-arm64 |
ubuntu-22.04-arm |
Linux en ARM |
Los runners de Linux son a propósito el Ubuntu más antiguo que ofrece GitHub: la app funciona con la glibc del runner
o una más nueva (Linux). Con backend = "nuitka" todos los
runners ya tienen el compilador de C que necesita Nuitka.
Publicar una GitHub Release
Sección titulada «Publicar una GitHub Release»Los artifacts caducan pasado un tiempo y piden iniciar sesión en GitHub para descargarlos. Para dar a la gente una
página de descarga permanente, fija archive antes de escribir el flujo:
[tool.pyzed.build]archive = "zip"Cada compilación empaqueta entonces la app como <app>-<sistema>-<arq>.zip (shop-windows-x86_64.zip,
shop-macos-arm64.zip, shop-linux-x86_64.zip), los nombres que busca la
autoactualización, y el flujo gana un último paso que lo adjunta a la Release de la
etiqueta (y el permiso para crearla):
jobs: build: permissions: contents: write steps: # ... la compilación, y luego: - name: Attach to the GitHub Release if: startsWith(github.ref, 'refs/tags/v') shell: bash env: GH_TOKEN: ${{ github.token }} run: | # the first build to get here creates the release; the others only upload gh release create "$GITHUB_REF_NAME" --title "$GITHUB_REF_NAME" --verify-tag || true gh release upload "$GITHUB_REF_NAME" dist/*.zip --clobberEn macOS el zip se crea con ditto, que conserva los enlaces simbólicos y la firma del paquete. Si
firmas la app, fírmala antes de comprimirla: fija archive solo después de añadir el paso de firma, o
comprime tú tras firmar.
Firmar en CI
Sección titulada «Firmar en CI»Guarda los certificados en secretos de GitHub (Settings → Secrets and variables → Actions), nunca en el repositorio. Luego decodifícalos en un paso antes de firmar. Es lo que hace el flujo de versiones de Pyzed para Pyzed Design:
Guarda el archivo .pfx en base64 en WINDOWS_CERTIFICATE y su contraseña en WINDOWS_CERTIFICATE_PASSWORD:
- name: Sign if: runner.os == 'Windows' shell: bash env: CERT: ${{ secrets.WINDOWS_CERTIFICATE }} PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }} run: | echo "$CERT" | base64 --decode > "$RUNNER_TEMP/cert.pfx" signtool=$(ls "/c/Program Files (x86)/Windows Kits/10/bin/"*/x64/signtool.exe | tail -1) "$signtool" sign /f "$RUNNER_TEMP/cert.pfx" /p "$PASSWORD" /fd sha256 \ /tr http://timestamp.digicert.com /td sha256 dist/Shop/Shop.exeGuarda el certificado Developer ID (.p12) en base64 en MACOS_CERTIFICATE con su contraseña, y los datos de tu
Apple ID para la notarización:
- name: Sign and notarize if: runner.os == 'macOS' env: CERT: ${{ secrets.MACOS_CERTIFICATE }} CERT_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }} IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }} APPLE_ID: ${{ secrets.APPLE_ID }} APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }} run: | keychain="$RUNNER_TEMP/signing.keychain-db" echo "$CERT" | base64 --decode > "$RUNNER_TEMP/cert.p12" security create-keychain -p "" "$keychain" security unlock-keychain -p "" "$keychain" security import "$RUNNER_TEMP/cert.p12" -P "$CERT_PASSWORD" -A -t cert -f pkcs12 -k "$keychain" security set-key-partition-list -S apple-tool:,apple: -k "" "$keychain" >/dev/null security list-keychains -d user -s "$keychain" codesign --force --deep --options runtime --timestamp --sign "$IDENTITY" dist/Shop.app ditto -c -k --keepParent dist/Shop.app notarize.zip xcrun notarytool submit notarize.zip --wait \ --apple-id "$APPLE_ID" --team-id "$APPLE_TEAM_ID" --password "$APPLE_APP_PASSWORD" xcrun stapler staple dist/Shop.appPon el paso de firma después de uv run pyzed build y antes de comprimir. Mira
Windows y macOS para saber
qué hace cada comando.