Find a file
2026-05-02 11:43:16 +10:00
cmd/wails-release Apply final review fixes: deterministic outputs, abs path, failure-path test, go.mod pin 2026-05-02 10:57:32 +10:00
docs/superpowers Add implementation plan for Wails Release Action 2026-05-02 09:36:52 +10:00
internal Add Forgejo Actions output + masking helpers 2026-05-02 10:24:36 +10:00
.gitignore Gitignore go.sum files inside testdata directories 2026-05-02 10:58:50 +10:00
action.yml Fixed the action 2026-05-02 11:43:16 +10:00
go.mod Apply final review fixes: deterministic outputs, abs path, failure-path test, go.mod pin 2026-05-02 10:57:32 +10:00
go.sum Apply final review fixes: deterministic outputs, abs path, failure-path test, go.mod pin 2026-05-02 10:57:32 +10:00
README.md Document inputs, outputs, and usage 2026-05-02 10:49:05 +10:00

Wails Release Action

Build, sign, notarize, and (optionally) upload a Wails macOS app from a Forgejo Actions workflow on a self-hosted macOS runner.

The action produces a notarized, stapled <AppName>-<version>.app.zip and exposes its local path and (if uploaded) its s3:// URL as outputs.

Requirements

  • A self-hosted macOS runner.
  • go on PATH (Wails requires it).
  • Network access to Apple's notary service and (if uploading) your S3 endpoint.

Quick start

name: Release

on:
  push:
    tags: ['v*']

jobs:
  release:
    runs-on: macos
    steps:
      - uses: actions/checkout@v4

      - uses: leonmika/wails-release@v1
        with:
          developer-id-cert-base64:    ${{ secrets.MAC_DEVELOPER_ID_CERT_BASE64 }}
          developer-id-cert-password:  ${{ secrets.MAC_DEVELOPER_ID_CERT_PASSWORD }}
          notarization-api-key-base64: ${{ secrets.AC_API_KEY_BASE64 }}
          notarization-api-key-id:     ${{ secrets.AC_API_KEY_ID }}
          notarization-api-issuer-id:  ${{ secrets.AC_API_ISSUER_ID }}
          s3-bucket:                   my-releases
          s3-key:                      myapp/{version}/{filename}
        env:
          AWS_ACCESS_KEY_ID:     ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

Inputs

Name Required Default Description
working-directory no . Directory containing wails.json
app-name no wails.json name Override for the app name in artifact filenames
version no derived Override; otherwise: matching semver tag → strip v, else 7-char short SHA
wails-version no from go.mod Override the Wails CLI version
extra-build-flags no "" Additional flags appended to wails build (shell-quoted)
developer-id-cert-base64 yes Base64-encoded Developer ID .p12
developer-id-cert-password yes .p12 password
notarization-method no auto api-key, apple-id, or auto (auto picks whichever group is fully populated)
notarization-api-key-base64 conditional Base64-encoded App Store Connect .p8
notarization-api-key-id conditional API key ID
notarization-api-issuer-id conditional Issuer ID
notarization-apple-id conditional Apple ID (email)
notarization-apple-password conditional App-specific password
notarization-team-id conditional Developer Team ID
s3-bucket no Bucket name. If unset, upload is skipped.
s3-key conditional Object key. Required if s3-bucket is set. Supports {version} and {filename} placeholders.
s3-endpoint-url no Custom endpoint for S3-compatible storage (MinIO, R2, etc.)
s3-region no us-east-1 AWS region

AWS credentials (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, optionally AWS_SESSION_TOKEN) are read from the standard environment, not from action inputs.

Outputs

Name Description
version Resolved version string
app-name Resolved app name
artifact-path Local absolute path to the .app.zip
artifact-filename Just the filename (e.g. MyApp-1.2.3.app.zip)
s3-url s3://bucket/key/... if uploaded, else empty

Versioning rule

  • A git ref of the form refs/tags/vX.Y.Z (no pre-release suffix) → version becomes X.Y.Z.
  • Anything else → 7-character short SHA from HEAD.
  • Override via the version input.

Notarization credentials

You can use either:

  • App Store Connect API key (recommended). Generate one in App Store Connect → Users and Access → Keys. You need the .p8 file, the Key ID, and the Issuer ID.
  • Apple ID + app-specific password + team ID. Generate the app-specific password at appleid.apple.com → Sign-In and Security → App-Specific Passwords.

If both groups are populated and notarization-method is auto, the action errors with an ambiguity message — set notarization-method explicitly to disambiguate.

S3-compatible storage

Set s3-endpoint-url to point at your storage:

- uses: leonmika/wails-release@v1
  with:
    # …
    s3-bucket:        releases
    s3-key:           myapp/{version}/{filename}
    s3-endpoint-url:  https://my-minio.example.com
    s3-region:        auto
  env:
    AWS_ACCESS_KEY_ID:     ${{ secrets.MINIO_KEY }}
    AWS_SECRET_ACCESS_KEY: ${{ secrets.MINIO_SECRET }}

For Cloudflare R2, set the endpoint to https://<account>.r2.cloudflarestorage.com and s3-region to auto.

How it works

  1. Resolve config from INPUT_* env, validate, and mask secrets in logs.
  2. Resolve version (tag → strip v, else short SHA) and app name (from wails.json).
  3. Ensure the Wails CLI matches the version pinned in your project's go.mod (or the wails-version override).
  4. Run wails build -platform darwin/universal -clean -trimpath plus your extra-build-flags.
  5. Create a temporary keychain, import the .p12, and codesign the .app with the hardened runtime and a secure timestamp. Verify the signature.
  6. ditto the .app into a zip for notary submission.
  7. xcrun notarytool submit --wait (API key or Apple ID, whichever was supplied). On rejection, fetch the per-submission log and embed it in the error.
  8. xcrun stapler staple the bundle and re-zip so the on-disk artifact is offline-verifiable.
  9. Optionally upload via the AWS SDK (custom endpoint supported).
  10. Always run cleanup: delete the temp keychain and remove decoded .p12 / .p8 files.

Local development

go test ./...

Smoke-testing real signing requires real credentials and is documented inline in cmd/wails-release/integration_test.go. The integration test itself uses fake external binaries on PATH and runs hermetically.