Amore's release-action runs the full release on a GitHub-hosted Mac runner: it archives, code signs, notarizes, signs the update for Sparkle, updates your appcast.xml and publishes, no local Mac required.
Push a version tag like v1.2.0 and a signed, notarized release ships automatically. Tag a prerelease like v1.2.0-beta.1 and it goes out on your beta channel instead.
Video
The full CI release: a version tag triggers archive, code signing, notarization and publishing on a GitHub-hosted Mac runner, no local Mac. About seven and a half minutes.
The workflow file
Create .github/workflows/release.yml in your app's repo. Set the scheme to yours and pin xcode-path/runs-on to the toolchain your app builds with; the rest works as-is:
name: Amore Release
run-name: Release ${{ github.ref_name }}
on:
push:
tags: ['v*']
concurrency:
group: amore-release
cancel-in-progress: true
jobs:
release:
runs-on: macos-26
steps:
- uses: actions/checkout@v4
- name: Read version from tag
id: version
run: |
ref="${GITHUB_REF_NAME#v}"
echo "number=${ref%%-*}" >> "$GITHUB_OUTPUT"
- uses: AmoreComputer/release-action@v1
with:
# Pin Xcode to the version your project builds with, so a runner
# default drifting can't silently break your build.
scheme: Pomodoro
codesign-identity: ${{ secrets.CODESIGN_IDENTITY }}
dev-id-cert-p12: ${{ secrets.DEV_ID_CERT_P12 }}
dev-id-cert-password: ${{ secrets.DEV_ID_CERT_PASSWORD }}
sparkle-private-key: ${{ secrets.SPARKLE_PRIVATE_KEY }}
asc-api-key-id: ${{ secrets.ASC_API_KEY_ID }}
asc-api-issuer: ${{ secrets.ASC_API_ISSUER }}
asc-api-key: ${{ secrets.ASC_API_KEY }}
amore-token: ${{ secrets.AMORE_TOKEN }}
channel: ${{ contains(github.ref_name, '-') && 'beta' || '' }}
marketing-version: ${{ steps.version.outputs.number }}
The release-action builds a DMG installer, which carries a Built with amore.computer watermark. It is not removed automatically: with Amore+ you can turn it off (see DMG watermark).
Add your secrets
Add each of the values below in your repo under Settings → Secrets and variables → Actions → New repository secret. See using secrets in GitHub Actions for the details.
App Store Connect API key (notarization)
Notarization uses an App Store Connect API key. It gives you three secrets in one go.
- Open App Store Connect → Users and Access → Integrations and select the
App Store Connect APItab. - Click the
+to generate a key. Name it (e.g.Amore CI) and give it theDeveloperrole. - Copy the
Issuer IDshown above the table →ASC_API_ISSUER. - Copy the
Key IDfrom the new row →ASC_API_KEY_ID. - Click
Downloadto get theAuthKey_XXXXXXXX.p8file. You can only download it once. Base64-encode it and paste the result intoASC_API_KEY:
base64 -i AuthKey_XXXXXXXX.p8 | pbcopy
Apple's guide to creating API keys.
Developer ID certificate (code signing)
Signing uses your Developer ID Application certificate. If you don't have one yet, create it first (see Codesigning).
Export it straight from Xcode, no Keychain Access needed:
- In Xcode, open
Settings→Accounts, select your Apple ID, then pick your team and clickManage Certificates. - Control-click your
Developer ID Applicationcertificate →Export Certificate. Save it as a.p12and set a password. That password isDEV_ID_CERT_PASSWORD. - Base64-encode the
.p12and paste it intoDEV_ID_CERT_P12:
base64 -i Certificate.p12 | pbcopy
Your CODESIGN_IDENTITY is the full Developer ID Application: Your Name (TEAMID) string. List yours in Terminal and copy it from the output:
security find-identity -v -p codesigning | grep "Developer ID Application"
Sparkle signing key (updates)
SPARKLE_PRIVATE_KEY is the base64 Ed25519 private key that signs your updates so existing installs trust them. It is the same key Amore stores in your keychain, do not generate a new one or users won't be able to update.
Get it either way and paste the result into the secret:
-
From the CLI:
amore export sparkle-key --bundle-id com.example.YourApp -
From the app: copy the base64 private key from Key Management.
Amore token (publishing)
AMORE_TOKEN is a scoped API key that lets CI publish releases to your Amore-hosted app.
Create it in the app: open Amore → Settings… (⌘,) and scroll to API Keys. Click New Key, name it (e.g. GitHub Actions), pick the Release scope (best for CI), and click Create. Copy the secret token and paste it into AMORE_TOKEN.
Running a release
Tag a commit and push the tag:
git tag v1.2.0
git push origin v1.2.0
v1.2.0→ stable release, published as version 1.2.0.v1.2.0-beta.1→ beta release on your beta channel.
The version comes from the tag and the build number is assigned automatically, one past your last release, so there is nothing to bump by hand.
Self-hosted S3 storage
By default your releases are hosted by Amore. To publish to your own S3-compatible bucket (AWS S3, Cloudflare R2, MinIO) instead, add these inputs to the release-action step:
s3-bucket: my-app-releases
s3-region: us-east-1
s3-public-url: https://cdn.example.com
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
Add AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY as repository secrets, and keep amore-token; it stays required in S3 mode.
For Cloudflare R2 or MinIO, set s3-region: auto and add s3-endpoint: https://<account-id>.r2.cloudflarestorage.com. See Self-Managed S3-Bucket for the full bucket setup.