Submit App Store Review #9
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Submit App Store Review | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: Release tag to submit | |
| required: true | |
| type: string | |
| dry_run: | |
| description: Exercise the release workflow without submitting to App Review | |
| required: true | |
| type: boolean | |
| default: false | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: app-store-review-submission | |
| cancel-in-progress: false | |
| env: | |
| FASTLANE_SKIP_UPDATE_CHECK: "1" | |
| jobs: | |
| find-build: | |
| name: Find matching TestFlight build | |
| runs-on: ${{ fromJSON(vars.RUNNER_LABELS_LINUX || '["ubuntu-latest"]') }} | |
| outputs: | |
| build_number: ${{ steps.find.outputs.build_number }} | |
| build_version: ${{ steps.find.outputs.build_version }} | |
| upload_time: ${{ steps.find.outputs.upload_time }} | |
| tag: ${{ steps.resolve-tag.outputs.tag }} | |
| version: ${{ steps.resolve-tag.outputs.version }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Resolve tag and version | |
| id: resolve-tag | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| TAG="${{ inputs.tag }}" | |
| VERSION="${TAG#app/v}" | |
| VERSION="${VERSION#v}" | |
| VERSION="${VERSION%%-rc.*}" | |
| echo "tag=$TAG" >> "$GITHUB_OUTPUT" | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| - name: Write App Store Connect credentials | |
| shell: bash | |
| env: | |
| ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }} | |
| ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }} | |
| ASC_PRIVATE_KEY: ${{ secrets.ASC_PRIVATE_KEY }} | |
| run: | | |
| set -euo pipefail | |
| : "${ASC_KEY_ID:?ASC_KEY_ID secret is required}" | |
| : "${ASC_ISSUER_ID:?ASC_ISSUER_ID secret is required}" | |
| : "${ASC_PRIVATE_KEY:?ASC_PRIVATE_KEY secret is required}" | |
| mkdir -p "$HOME/.appstoreconnect/private_keys" | |
| p8_path="$HOME/.appstoreconnect/private_keys/AuthKey_${ASC_KEY_ID}.p8" | |
| printf '%s' "$ASC_PRIVATE_KEY" > "$p8_path" | |
| chmod 600 "$p8_path" | |
| jq -n \ | |
| --arg key_id "$ASC_KEY_ID" \ | |
| --arg issuer_id "$ASC_ISSUER_ID" \ | |
| --arg key "$ASC_PRIVATE_KEY" \ | |
| '{ | |
| key_id: $key_id, | |
| issuer_id: $issuer_id, | |
| key: $key, | |
| in_house: false | |
| }' > /tmp/asc_api_key.json | |
| chmod 600 /tmp/asc_api_key.json | |
| { | |
| echo "ASC_KEY_ID=$ASC_KEY_ID" | |
| echo "ASC_ISSUER_ID=$ASC_ISSUER_ID" | |
| } >> "$GITHUB_ENV" | |
| - name: Install Python dependencies | |
| run: | | |
| python3 -m venv .venv-release | |
| .venv-release/bin/python -m pip install --upgrade pip --quiet | |
| .venv-release/bin/python -m pip install PyJWT requests cryptography --quiet | |
| - name: Find build matching release version | |
| id: find | |
| shell: bash | |
| env: | |
| VERSION: ${{ steps.resolve-tag.outputs.version }} | |
| run: | | |
| set +e | |
| .venv-release/bin/python scripts/release/find_qualifying_build.py \ | |
| --key-id "$ASC_KEY_ID" \ | |
| --issuer-id "$ASC_ISSUER_ID" \ | |
| --private-key-path "$HOME/.appstoreconnect/private_keys/AuthKey_${ASC_KEY_ID}.p8" \ | |
| --app-id "${{ vars.APPLE_APP_ID }}" \ | |
| --latest \ | |
| --version "$VERSION" \ | |
| --output-format github-output 2> /tmp/find-build.err | |
| status=$? | |
| set -e | |
| if [ "$status" -ne 0 ]; then | |
| echo "::error::No valid TestFlight build found for version $VERSION." | |
| cat /tmp/find-build.err | |
| exit "$status" | |
| fi | |
| approve-release: | |
| name: Approve App Store submission | |
| needs: find-build | |
| runs-on: ${{ fromJSON(vars.RUNNER_LABELS_LINUX || '["ubuntu-latest"]') }} | |
| environment: ${{ vars.APPROVAL_ENVIRONMENT || 'app-store-release' }} | |
| steps: | |
| - name: Release candidate summary | |
| run: | | |
| { | |
| echo "## Release candidate ready for approval" | |
| echo "" | |
| echo "- Version: ${{ needs.find-build.outputs.build_version }}" | |
| echo "- Build: #${{ needs.find-build.outputs.build_number }}" | |
| echo "- Tag: ${{ needs.find-build.outputs.tag }}" | |
| echo "- Uploaded: ${{ needs.find-build.outputs.upload_time }}" | |
| echo "- Dry run: ${{ inputs.dry_run }}" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| submit: | |
| name: Submit build for App Store review | |
| needs: | |
| - find-build | |
| - approve-release | |
| if: ${{ !inputs.dry_run }} | |
| runs-on: ${{ fromJSON(vars.RUNNER_LABELS_LINUX || '["ubuntu-latest"]') }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Write App Store Connect credentials | |
| shell: bash | |
| env: | |
| ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }} | |
| ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }} | |
| ASC_PRIVATE_KEY: ${{ secrets.ASC_PRIVATE_KEY }} | |
| run: | | |
| set -euo pipefail | |
| : "${ASC_KEY_ID:?ASC_KEY_ID secret is required}" | |
| : "${ASC_ISSUER_ID:?ASC_ISSUER_ID secret is required}" | |
| : "${ASC_PRIVATE_KEY:?ASC_PRIVATE_KEY secret is required}" | |
| jq -n \ | |
| --arg key_id "$ASC_KEY_ID" \ | |
| --arg issuer_id "$ASC_ISSUER_ID" \ | |
| --arg key "$ASC_PRIVATE_KEY" \ | |
| '{ | |
| key_id: $key_id, | |
| issuer_id: $issuer_id, | |
| key: $key, | |
| in_house: false | |
| }' > /tmp/asc_api_key.json | |
| chmod 600 /tmp/asc_api_key.json | |
| - name: Set up Ruby and Bundler | |
| if: ${{ !contains(fromJSON(vars.RUNNER_LABELS_LINUX || '["ubuntu-latest"]'), 'self-hosted') }} | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: '3.3' | |
| bundler-cache: true | |
| working-directory: ${{ vars.IOS_WORKDIR || 'ios' }} | |
| - name: Install Ruby bundle | |
| if: ${{ contains(fromJSON(vars.RUNNER_LABELS_LINUX || '["ubuntu-latest"]'), 'self-hosted') }} | |
| working-directory: ${{ vars.IOS_WORKDIR || 'ios' }} | |
| run: | | |
| export BUNDLE_VERSION=system | |
| echo "BUNDLE_VERSION=system" >> "$GITHUB_ENV" | |
| bundle config set path vendor/bundle | |
| bundle install --jobs 4 --retry 3 | |
| - name: Submit build for App Store review | |
| working-directory: ${{ vars.IOS_WORKDIR || 'ios' }} | |
| run: | | |
| if [ -f fastlane/Deliverfile ]; then | |
| mv -f fastlane/Deliverfile fastlane/Deliverfile.release | |
| trap 'mv -f fastlane/Deliverfile.release fastlane/Deliverfile' EXIT | |
| fi | |
| bundle exec fastlane run deliver \ | |
| api_key_path:/tmp/asc_api_key.json \ | |
| app_identifier:${{ vars.BUNDLE_ID }} \ | |
| team_id:${{ vars.TEAM_ID }} \ | |
| skip_binary_upload:true \ | |
| skip_screenshots:true \ | |
| skip_metadata:true \ | |
| submit_for_review:true \ | |
| run_precheck_before_submit:false \ | |
| precheck_include_in_app_purchases:false \ | |
| force:true \ | |
| phased_release:true \ | |
| automatic_release:false \ | |
| build_number:"${{ needs.find-build.outputs.build_number }}" | |
| - name: Summary | |
| run: | | |
| { | |
| echo "## App Store submission complete" | |
| echo "" | |
| echo "- Version: ${{ needs.find-build.outputs.build_version }}" | |
| echo "- Build: #${{ needs.find-build.outputs.build_number }}" | |
| echo "- Tag: ${{ needs.find-build.outputs.tag }}" | |
| echo "- Status: Submitted for review" | |
| echo "- Automatic release: disabled" | |
| } >> "$GITHUB_STEP_SUMMARY" |