Machine-translated draft — terminology + flow still being reviewed.

Keel × GitHub Actions

Operator-facing guide for the workflow templates in keel/templates/github-actions/. Covers secrets setup, self-hosted runner decisions, and Actions cost notes.

Available templates

TemplateWhat it doesTriggerTypical runtime
keel-ota-publish.ymlBuild JS bundles + publish OTA update to both platformspush to main3–6 min
keel-submit-stores.ymlNative build (.ipa + .aab) + submit to App Store, Google Play, Huawei, Xiaomi, OPPO, vivo, Tencent MyApppush tag v*.*.*30–60 min
keel-pr-check.ymlTypecheck + lint + dry-run build (fast feedback)pull_request2–4 min
keel-cert-healthcheck.ymlWeekly probe of CDN/Update endpoints + TLS expirycron + manual< 1 min

To install a template, copy it into .github/workflows/ of your project repo and populate the required secrets. See the directory’s README.md for one-line install commands.

Setting up GitHub Secrets

Repo Settings → Secrets and variablesActionsNew repository secret. Use Environments for tag-triggered deploys so you can require manual approval before store submission.

Per-template required secrets

keel-ota-publish.yml

SecretSourceHow to obtain
KEEL_API_KEYKeel CloudCreate on the dashboard’s “API tokens” page; copy the keel_live_... string into the secret. In the workflow, keel login --ci picks it up from this env var.
KEEL_PROJECTKeel Cloud<team-slug>/<project-slug> from keel.json

keel-pr-check.yml — same two as above.

keel-submit-stores.ymlKEEL_API_KEY + KEEL_PROJECT plus:

SecretSourceFormatNotes
ASC_KEY_IDApp Store Connect → Users and Access → Keys10-char string
ASC_ISSUER_IDSame page, top of the tableUUID
ASC_KEY_P8_B64.p8 download from ASCbase64 of the filebase64 < AuthKey_XXX.p8 | pbcopy
GOOGLE_PLAY_JSON_B64GCP service account with Play Console rolebase64 of the JSON
HUAWEI_CLIENT_ID / HUAWEI_CLIENT_SECRETAppGallery Connect → API clientstrings
XIAOMI_USERNAME / XIAOMI_PASSWORDdev.mi.com publisher accountstringsRecommend dedicated CI sub-account
OPPO_CLIENT_ID / OPPO_CLIENT_SECRETopen.oppomobile.com consolestrings
VIVO_ACCESS_KEY / VIVO_ACCESS_SECRETdev.vivo.com.cn → API configstrings
YYB_USERNAME / YYB_PASSWORDTencent MyApp publisherstrings

P8 keys and service-account JSON must be base64-encoded before storing. GitHub’s secret editor preserves the bytes, but downstream shell interpolation can mangle embedded newlines; base64 sidesteps that. The template decodes them with printf … | base64 -d at the start of the submit job.

keel-cert-healthcheck.yml

SecretSource
KEEL_PROJECTSame as above
SLACK_WEBHOOK_URLSlack workspace → Apps → Incoming Webhooks

Credential schema cross-reference

The names and shapes above match the keys keel submit looks up in ~/.keel/credentials.yml. Authoritative schema lives in submit §11. If you find a mismatch, that doc is the source of truth — file an issue against the template.

Self-hosted runners

GitHub-hosted runners cover most needs. Use self-hosted when:

  • iOS native builds (keel-submit-stores.yml’s build job): the template uses the macos-14 (Apple Silicon) GitHub-hosted runner. Self-host only if you need a non-public provisioning profile setup or your codebase pulls private CocoaPods from inside a corporate VPN.
  • China-region network access: domestic-market submission endpoints (Huawei, Xiaomi, etc.) are usually reachable from ubuntu-latest. If you hit TLS / rate-limit issues from GitHub’s US/EU IPs, run an ECS / Aliyun self-hosted runner in mainland China.
  • Long native builds (> 60 min wall time): pre-warmed self-hosted runners avoid the cold pod install + Gradle dependency download.

Self-hosted setup is out of scope here; see GitHub’s docs. Tag the runner with self-hosted, macOS, arm64 (or self-hosted, linux, cn) and change runs-on: in the template accordingly.

Cost notes

GitHub Actions free tier (public repos: unlimited; private repos: 2,000 min/month on Free plan, 3,000 on Pro, 50,000 on Team/Enterprise):

RunnerMultiplierEffective cost
ubuntu-latestcheapest — use for everything except iOS native build
windows-latestnot needed for Keel
macos-13 (Intel)10×avoid — Apple Silicon is faster and same cost-per-minute
macos-1410×required for iOS native build, ~2× faster than Intel
macos-14-large12×only if pod install truly bottlenecks

Typical monthly burn for a small team:

  • 50 PRs × 3 min × ubuntu-latest = 150 min
  • 30 main-branch pushes × 5 min × ubuntu-latest = 150 min
  • 4 releases × 40 min, of which 15 min on macos-14 = 4 × 25 ubuntu + 4 × 15 × 10 = 100 + 600 = 700 min
  • Weekly healthcheck: negligible

→ comfortably under the 3,000-min Pro plan. The macOS multiplier is the single biggest lever; minimize macos-14 job duration by doing all non-Xcode work on ubuntu-latest (the template already does this — only the build job lands on macOS).

See also

  • submitkeel submit CLI surface + market list
  • submit §11 — authoritative credential schema (keys + types + where the CLI reads them)
  • update — OTA pipeline that keel publish writes to
  • deployment-sop — human-checklist version of the same release flow (for the “no GHA” case)