Skip to main content

Official Action

The rudrankriyam/setup-asc action provides:
  • Automatic version detection and caching
  • Support for all platforms (macOS, Linux, Windows)
  • Matrix build support for multiple app configurations
  • Integration with GitHub Secrets for credential management
Repository: github.com/rudrankriyam/setup-asc

Quick Start

Basic Workflow

.github/workflows/testflight.yml
name: Deploy to TestFlight

on:
  push:
    tags:
      - 'v*'

jobs:
  deploy:
    runs-on: macos-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      
      - name: Setup App Store Connect CLI
        uses: rudrankriyam/setup-asc@v1
        with:
          version: latest
      
      - name: Verify installation
        run: asc --version
      
      - name: Upload to TestFlight
        env:
          ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
          ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
          ASC_PRIVATE_KEY_B64: ${{ secrets.ASC_PRIVATE_KEY_B64 }}
        run: |
          asc builds upload \
            --app "${{ secrets.APP_ID }}" \
            --file "MyApp.ipa"

Setup Action Configuration

Inputs

InputDescriptionRequiredDefault
versionVersion to install (latest, 1.2.3, etc.)Nolatest
tokenGitHub token for API rate limitingNo${{ github.token }}

Example: Pin to Specific Version

- uses: rudrankriyam/setup-asc@v1
  with:
    version: '1.0.0'

Complete Workflows

TestFlight Distribution

.github/workflows/testflight-release.yml
name: TestFlight Release

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  build-and-deploy:
    runs-on: macos-latest
    timeout-minutes: 30
    
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      
      - name: Setup Xcode
        uses: maxim-lobanov/setup-xcode@v1
        with:
          xcode-version: latest-stable
      
      - name: Setup App Store Connect CLI
        uses: rudrankriyam/setup-asc@v1
        with:
          version: latest
      
      - name: Build IPA
        run: |
          xcodebuild -workspace MyApp.xcworkspace \
            -scheme MyApp \
            -configuration Release \
            -archivePath build/MyApp.xcarchive \
            archive
          
          xcodebuild -exportArchive \
            -archivePath build/MyApp.xcarchive \
            -exportPath build \
            -exportOptionsPlist ExportOptions.plist
      
      - name: Upload to TestFlight
        env:
          ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
          ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
          ASC_PRIVATE_KEY_B64: ${{ secrets.ASC_PRIVATE_KEY_B64 }}
          ASC_APP_ID: ${{ secrets.APP_ID }}
        run: |
          asc builds upload \
            --app "$ASC_APP_ID" \
            --file build/MyApp.ipa
      
      - name: Wait for processing
        env:
          ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
          ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
          ASC_PRIVATE_KEY_B64: ${{ secrets.ASC_PRIVATE_KEY_B64 }}
          ASC_APP_ID: ${{ secrets.APP_ID }}
        run: |
          # Wait for build to process (simplified example)
          sleep 120
          
          # Get latest build
          BUILD_ID=$(asc testflight builds list \
            --app "$ASC_APP_ID" \
            --output json \
            --limit 1 | jq -r '.[0].id')
          
          # Add to external testers
          asc testflight builds add-to-group \
            --build "$BUILD_ID" \
            --group "External Testers"

App Store Submission

.github/workflows/app-store-submit.yml
name: Submit to App Store

on:
  workflow_dispatch:
    inputs:
      version:
        description: 'Version to submit'
        required: true
        type: string

jobs:
  submit:
    runs-on: macos-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      
      - name: Setup App Store Connect CLI
        uses: rudrankriyam/setup-asc@v1
      
      - name: Validate version
        env:
          ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
          ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
          ASC_PRIVATE_KEY_B64: ${{ secrets.ASC_PRIVATE_KEY_B64 }}
          ASC_APP_ID: ${{ secrets.APP_ID }}
        run: |
          asc validate \
            --app "$ASC_APP_ID" \
            --version "${{ inputs.version }}"
      
      - name: Submit for review
        env:
          ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
          ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
          ASC_PRIVATE_KEY_B64: ${{ secrets.ASC_PRIVATE_KEY_B64 }}
          ASC_APP_ID: ${{ secrets.APP_ID }}
        run: |
          asc submit \
            --app "$ASC_APP_ID" \
            --version "${{ inputs.version }}"
      
      - name: Notify on success
        if: success()
        run: |
          echo "::notice::Version ${{ inputs.version }} submitted successfully"

Metadata Sync

.github/workflows/metadata-sync.yml
name: Sync App Metadata

on:
  push:
    paths:
      - 'metadata/**'
    branches: [main]

jobs:
  sync:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      
      - name: Setup App Store Connect CLI
        uses: rudrankriyam/setup-asc@v1
      
      - name: Update app description
        env:
          ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
          ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
          ASC_PRIVATE_KEY_B64: ${{ secrets.ASC_PRIVATE_KEY_B64 }}
          ASC_APP_ID: ${{ secrets.APP_ID }}
        run: |
          # Update en-US description
          asc app-info update \
            --app "$ASC_APP_ID" \
            --locale en-US \
            --description "$(cat metadata/en-US/description.txt)"
      
      - name: Upload screenshots
        env:
          ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
          ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
          ASC_PRIVATE_KEY_B64: ${{ secrets.ASC_PRIVATE_KEY_B64 }}
          ASC_APP_ID: ${{ secrets.APP_ID }}
        run: |
          # Upload iPhone 6.7" screenshots
          for screenshot in metadata/en-US/screenshots/iphone67/*.png; do
            asc screenshots upload \
              --app "$ASC_APP_ID" \
              --version "1.0" \
              --locale en-US \
              --display-type APP_IPHONE_67 \
              --file "$screenshot"
          done

Crash Monitoring

.github/workflows/crash-monitor.yml
name: Monitor Crashes

on:
  schedule:
    # Run daily at 9 AM UTC
    - cron: '0 9 * * *'
  workflow_dispatch:

jobs:
  monitor:
    runs-on: ubuntu-latest
    
    steps:
      - name: Setup App Store Connect CLI
        uses: rudrankriyam/setup-asc@v1
      
      - name: Fetch recent crashes
        env:
          ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
          ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
          ASC_PRIVATE_KEY_B64: ${{ secrets.ASC_PRIVATE_KEY_B64 }}
          ASC_APP_ID: ${{ secrets.APP_ID }}
        run: |
          asc crashes \
            --app "$ASC_APP_ID" \
            --sort -createdDate \
            --limit 10 \
            --output json > crashes.json
      
      - name: Upload crash report
        uses: actions/upload-artifact@v4
        with:
          name: crash-report-${{ github.run_number }}
          path: crashes.json
      
      - name: Check for critical crashes
        run: |
          CRASH_COUNT=$(jq 'length' crashes.json)
          echo "Found $CRASH_COUNT recent crashes"
          
          if [ "$CRASH_COUNT" -gt 5 ]; then
            echo "::warning::High crash count detected: $CRASH_COUNT"
          fi

Matrix Builds

Multiple Apps

.github/workflows/multi-app-deploy.yml
name: Deploy Multiple Apps

on:
  workflow_dispatch:

jobs:
  deploy:
    runs-on: macos-latest
    strategy:
      matrix:
        app:
          - name: MyApp
            id: 123456789
            scheme: MyApp
          - name: MyAppPro
            id: 987654321
            scheme: MyAppPro
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      
      - name: Setup App Store Connect CLI
        uses: rudrankriyam/setup-asc@v1
      
      - name: Build ${{ matrix.app.name }}
        run: |
          xcodebuild -scheme ${{ matrix.app.scheme }} \
            -archivePath build/${{ matrix.app.name }}.xcarchive \
            archive
          
          xcodebuild -exportArchive \
            -archivePath build/${{ matrix.app.name }}.xcarchive \
            -exportPath build \
            -exportOptionsPlist ExportOptions.plist
      
      - name: Upload ${{ matrix.app.name }}
        env:
          ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
          ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
          ASC_PRIVATE_KEY_B64: ${{ secrets.ASC_PRIVATE_KEY_B64 }}
        run: |
          asc builds upload \
            --app "${{ matrix.app.id }}" \
            --file build/${{ matrix.app.name }}.ipa

Authentication Setup

GitHub Secrets Configuration

  1. Navigate to your repository Settings > Secrets and variables > Actions
  2. Click New repository secret
  3. Add the following secrets:
Secret NameValue
ASC_KEY_IDYour App Store Connect Key ID
ASC_ISSUER_IDYour App Store Connect Issuer ID
ASC_PRIVATE_KEY_B64Base64-encoded .p8 private key
APP_IDYour app’s ID (optional, for convenience)

Base64 Encoding Private Key

# macOS/Linux
base64 -i AuthKey_ABC123.p8 | pbcopy

# Alternative (output to file)
base64 -i AuthKey_ABC123.p8 > key.txt

Using Private Key File (Alternative)

If you prefer not to use base64 encoding:
steps:
  - name: Write private key
    run: |
      echo "${{ secrets.ASC_PRIVATE_KEY }}" > /tmp/AuthKey.p8
      chmod 600 /tmp/AuthKey.p8
  
  - name: Run asc command
    env:
      ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
      ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
      ASC_PRIVATE_KEY_PATH: /tmp/AuthKey.p8
    run: asc apps list
  
  - name: Cleanup
    if: always()
    run: rm -f /tmp/AuthKey.p8

Environment Variables

Set default environment variables for all jobs:
env:
  ASC_DEFAULT_OUTPUT: json
  ASC_TIMEOUT: 2m
  ASC_UPLOAD_TIMEOUT: 10m

jobs:
  deploy:
    runs-on: macos-latest
    env:
      ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
      ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
      ASC_PRIVATE_KEY_B64: ${{ secrets.ASC_PRIVATE_KEY_B64 }}
    # ...

Caching

The setup-asc action automatically caches the asc binary. You can also cache build artifacts:
steps:
  - name: Cache build artifacts
    uses: actions/cache@v4
    with:
      path: |
        build/
        DerivedData/
      key: ${{ runner.os }}-build-${{ hashFiles('**/*.swift') }}
      restore-keys: |
        ${{ runner.os }}-build-

Conditional Workflows

Deploy only on tags

on:
  push:
    tags:
      - 'v[0-9]+.[0-9]+.[0-9]+'

Manual approval for production

jobs:
  deploy-staging:
    runs-on: macos-latest
    # ... deploy to TestFlight
  
  deploy-production:
    runs-on: macos-latest
    needs: deploy-staging
    environment: production  # Requires manual approval
    # ... submit to App Store

Troubleshooting

Enable Debug Logging

- name: Upload with debug logging
  env:
    ASC_DEBUG: api
    ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
    ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
    ASC_PRIVATE_KEY_B64: ${{ secrets.ASC_PRIVATE_KEY_B64 }}
  run: asc builds upload --app "$APP_ID" --file MyApp.ipa

Verify Credentials

- name: Test authentication
  env:
    ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
    ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
    ASC_PRIVATE_KEY_B64: ${{ secrets.ASC_PRIVATE_KEY_B64 }}
  run: |
    echo "Testing App Store Connect authentication..."
    asc apps list --limit 1

Common Issues

  • Verify all three secrets are set correctly
  • Check that private key is properly base64-encoded
  • Ensure API key has not been revoked in App Store Connect
  • Verify Key ID and Issuer ID match the API key
The setup-asc action failed to find the specified version:
  • Check releases for available versions
  • Use latest for the most recent release
  • Ensure version format is correct (e.g., 1.0.0, not v1.0.0)
  • Increase ASC_UPLOAD_TIMEOUT environment variable
  • Check network connectivity from GitHub runner
  • Verify IPA file is not corrupted
  • Add delays between API calls
  • Use pagination wisely with --limit
  • Consider spreading operations across multiple jobs

Best Practices

Use explicit versions

Pin action versions for reproducibility:
uses: rudrankriyam/setup-asc@v1

Set timeouts

Prevent hanging workflows:
jobs:
  deploy:
    timeout-minutes: 30

Separate build and deploy

Use separate jobs for build and deployment:
jobs:
  build:
    # Build IPA
  deploy:
    needs: build
    # Upload to TestFlight

Use environments

Leverage GitHub Environments for approvals:
environment: production

Examples Repository

For more complete examples, see: github.com/rudrankriyam/setup-asc