Skip to content

vuon9/gh-workflows

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gh-workflows

Reusable GitHub Actions workflows and release tooling.

The goal is to keep product repositories clean: app repos keep small workflow wrappers and app-specific config, while common CI/release behavior lives here.

Workflows

ios-testflight.yml

Caller repositories can trigger TestFlight upload with a thin wrapper:

name: TestFlight

on:
  workflow_dispatch:

jobs:
  testflight:
    uses: vuon9/gh-workflows/.github/workflows/ios-testflight.yml@v0.1.5
    with:
      project-path: MyApp.xcodeproj
      scheme: MyApp
      team-id: ABCDE12345
      dry-run: true
      skip-cert-check: false
      runner-label: macos-26
    secrets: inherit

For workspace-based apps, use workspace-path instead of project-path.

Required caller secrets when dry-run is false:

  • APP_STORE_CONNECT_API_KEY_P8: App Store Connect API private key content.
  • APP_STORE_CONNECT_API_KEY_ID: App Store Connect API key ID.
  • APP_STORE_CONNECT_API_ISSUER_ID: App Store Connect issuer ID.

Optional caller secrets when signing-style: manual:

  • APPLE_DISTRIBUTION_CERTIFICATE_P12_BASE64: base64-encoded Apple Distribution .p12.
  • APPLE_DISTRIBUTION_CERTIFICATE_PASSWORD: .p12 password.
  • APPLE_PROVISIONING_PROFILE_BASE64: base64-encoded App Store provisioning profile.

Preparing Manual Signing Secrets

Use manual signing when a clean GitHub-hosted macOS runner should sign without asking Xcode to create certificates or profiles.

  1. Export an Apple Distribution certificate from a trusted Mac:
security find-identity -v -p codesigning

Pick the Apple Distribution: ... (TEAMID) identity, then export it to a temporary .p12. This may show a macOS Keychain approval prompt:

P12_PASSWORD="$(openssl rand -base64 24)"
security export \
  -k "$HOME/Library/Keychains/login.keychain-db" \
  -t identities \
  -f pkcs12 \
  -o /tmp/apple-distribution.p12 \
  -P "$P12_PASSWORD"
base64 -i /tmp/apple-distribution.p12 -o /tmp/apple-distribution.p12.b64
  1. Base64-encode the App Store provisioning profile for the app:
base64 -i "$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles/<UUID>.mobileprovision" \
  -o /tmp/app-store-profile.mobileprovision.b64
  1. Set repository secrets:
gh secret set APPLE_DISTRIBUTION_CERTIFICATE_P12_BASE64 \
  --repo owner/app-repo \
  < /tmp/apple-distribution.p12.b64

printf '%s' "$P12_PASSWORD" | gh secret set APPLE_DISTRIBUTION_CERTIFICATE_PASSWORD \
  --repo owner/app-repo

gh secret set APPLE_PROVISIONING_PROFILE_BASE64 \
  --repo owner/app-repo \
  < /tmp/app-store-profile.mobileprovision.b64
  1. Delete local temporary signing files:
rm -f /tmp/apple-distribution.p12 /tmp/apple-distribution.p12.b64 /tmp/app-store-profile.mobileprovision.b64
unset P12_PASSWORD

Never commit .p12, .mobileprovision, .p8, archives, IPAs, or base64 secret files.

Useful inputs:

  • dry-run: print commands without running archive/export.
  • skip-tests: skip simulator tests before archive.
  • skip-archive: skip archive and export an archive downloaded from a previous release artifact.
  • export-destination: upload for TestFlight/App Store Connect upload, export for a reusable IPA/archive artifact.
  • upload-artifact-name: upload build/TestFlight as a GitHub Actions artifact after archive/export.
  • download-artifact-name: download a prior build/TestFlight artifact before export.
  • skip-cert-check: skip the local Apple Distribution identity preflight check. This is useful when testing whether xcodebuild -allowProvisioningUpdates can handle signing on a clean GitHub-hosted macOS runner.
  • runner-label: runner used for the release job. Defaults to macos-26 because App Store Connect requires the iOS 26 SDK or newer for uploads.
  • signing-style: defaults to automatic; use manual with bundle-id and provisioning-profile when running on clean hosted runners.
  • bundle-id / provisioning-profile: required with manual signing so archive/export can use an installed profile instead of creating signing assets.

Recommended caller controls:

  • Protect the workflow with a GitHub Environment such as testflight.
  • Use a tag-triggered workflow named Release to build and export the release artifact.
  • Gate the dependent TestFlight upload through a regular approval job with a GitHub Environment such as testflight; configure required reviewers on that environment so the upload is actually manual.
  • Reference a version tag such as @v0.1.3 for pilots or @v1 after the workflow is proven, not @main.

Recommended release wrapper shape:

name: Release

on:
  push:
    tags:
      - 'ios/myapp/v*'

jobs:
  release:
    uses: vuon9/gh-workflows/.github/workflows/ios-testflight.yml@v0.1.6
    with:
      project-path: MyApp.xcodeproj
      scheme: MyApp
      team-id: ABCDE12345
      export-destination: export
      upload-artifact-name: myapp-ios-release-${{ github.run_id }}
      runner-label: macos-26
    secrets: inherit

  approve-testflight:
    needs: release
    runs-on: ubuntu-latest
    environment: testflight
    steps:
      - run: echo "TestFlight upload approved for $GITHUB_REF_NAME"

  testflight:
    needs: approve-testflight
    uses: vuon9/gh-workflows/.github/workflows/ios-testflight.yml@v0.1.6
    with:
      project-path: MyApp.xcodeproj
      scheme: MyApp
      team-id: ABCDE12345
      skip-tests: true
      skip-archive: true
      archive-path: build/TestFlight/MyApp.xcarchive
      download-artifact-name: myapp-ios-release-${{ github.run_id }}
      runner-label: macos-26
    secrets: inherit

Local Development

Run the Go tests:

go test ./...

Build the iOS TestFlight CLI:

go build ./ios/testflight/cmd/ios-testflight

Example dry run from an iOS app repository:

go run /path/to/gh-workflows/ios/testflight/cmd/ios-testflight \
  --project MyApp.xcodeproj \
  --scheme MyApp \
  --team-id ABCDE12345 \
  --skip-tests \
  --dry-run

Local Preflight With act

act can catch basic workflow wiring problems before pushing:

act workflow_dispatch \
  --validate \
  -W .github/workflows/testflight.yml \
  --input dry-run=true \
  --input skip-tests=true

It can also dry-run the job graph:

act workflow_dispatch \
  --dryrun \
  -W .github/workflows/testflight.yml \
  --input dry-run=true \
  --input skip-tests=true

Use act as a preflight only. iOS release workflows still need a real GitHub-hosted macOS runner to verify Xcode, signing, Keychain behavior, and App Store Connect upload.

Versioning

Use the pilot tag while validating the first app migration:

uses: vuon9/gh-workflows/.github/workflows/ios-testflight.yml@v0.1.5

After one real TestFlight upload succeeds, create a major tag for the stable workflow contract:

git tag v1
git push origin v1

Breaking changes should use a new major tag. Additive inputs can stay under the current major tag after testing.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages