Build and Release Storybook iOS App #6
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: Build and Release Storybook iOS App | |
| on: | |
| workflow_call: | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| jobs: | |
| build: | |
| name: Build and upload IPA | |
| runs-on: macos-26 | |
| permissions: | |
| contents: read | |
| env: | |
| CERTIFICATE_FILE: build_certificate.p12 | |
| PROVISIONING_PROFILE_FILE: build_pp.mobileprovision | |
| KEYCHAIN_FILE: app-signing.keychain-db | |
| steps: | |
| - name: Set Xcode version | |
| uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 | |
| with: | |
| xcode-version: "26.2" | |
| - name: Set build number | |
| id: set-build-number | |
| run: | | |
| build_number="$(date +'%Y%m%d').${{ github.run_number }}" | |
| echo "BUILD_NUMBER=$build_number" >> $GITHUB_ENV | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Install Apple certificate and provisioning profile | |
| env: | |
| BUILD_CERTIFICATE_BASE64: ${{ secrets.P12SECRET }} | |
| P12_PASSWORD: ${{ secrets.P12PASSWORD }} | |
| BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.PROVISIONING_PROFILE_BASE64 }} | |
| KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} | |
| run: | | |
| CERTIFICATE_PATH="$RUNNER_TEMP/$CERTIFICATE_FILE" | |
| PROVISIONING_PROFILE_PATH="$RUNNER_TEMP/$PROVISIONING_PROFILE_FILE" | |
| KEYCHAIN_PATH="$RUNNER_TEMP/$KEYCHAIN_FILE" | |
| echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH | |
| echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PROVISIONING_PROFILE_PATH | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| security set-keychain-settings -lut 21600 $KEYCHAIN_PATH | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH | |
| security list-keychain -d user -s $KEYCHAIN_PATH login.keychain | |
| mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles | |
| cp "$PROVISIONING_PROFILE_PATH" "$HOME/Library/MobileDevice/Provisioning Profiles/build_pp.mobileprovision" | |
| - name: Debug provisioning profile | |
| run: | | |
| PROFILE_PATH="$RUNNER_TEMP/$PROVISIONING_PROFILE_FILE" | |
| INSTALLED="$HOME/Library/MobileDevice/Provisioning Profiles/build_pp.mobileprovision" | |
| echo "Temp file size: $(wc -c < "$PROFILE_PATH") bytes" | |
| echo "Installed file size: $(wc -c < "$INSTALLED") bytes" | |
| file "$INSTALLED" | |
| - name: Extract UUID from provisioning profile | |
| run: | | |
| PROFILE="$HOME/Library/MobileDevice/Provisioning Profiles/build_pp.mobileprovision" | |
| UUID=$(grep -aEo '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}' "$PROFILE" | head -1) | |
| echo "UUID=$UUID" >> $GITHUB_ENV | |
| echo "Extracted UUID: $UUID" | |
| - name: Generate ExportOptions.plist | |
| working-directory: apps/storybook | |
| run: | | |
| FILE=ExportOptions.plist | |
| /usr/libexec/PlistBuddy -c "add :method string app-store" $FILE | |
| /usr/libexec/PlistBuddy -c "add :provisioningProfiles dict" $FILE | |
| /usr/libexec/PlistBuddy -c "add :provisioningProfiles:${{ vars.APPLE_BUNDLE_IDENTIFIER }} string ${{ env.UUID }}" $FILE | |
| /usr/libexec/PlistBuddy -c "add :signingStyle string manual" $FILE | |
| /usr/libexec/PlistBuddy -c "add :teamId string ${{ vars.APPLE_TEAM_ID }}" $FILE | |
| cat $FILE | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22.x | |
| cache: pnpm | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Patch app.json | |
| uses: onlyutkarsh/patch-files-action@21f4ae5a9e27243ba04757e4082c7cd9518cec47 | |
| with: | |
| fail-if-no-files-patched: true | |
| fail-if-error: true | |
| files: ./apps/storybook/app.json | |
| patch-syntax: | | |
| = /expo/ios/buildNumber => "${{ env.BUILD_NUMBER }}" | |
| - name: Prebuild Expo project | |
| run: pnpm build:storybook | |
| - name: Xcode archive | |
| working-directory: apps/storybook | |
| run: | | |
| /usr/bin/xcodebuild archive \ | |
| -workspace ios/EDSMobile.xcworkspace \ | |
| -scheme EDSMobile \ | |
| -destination 'generic/platform=iOS' \ | |
| -archivePath build/EDSMobile.xcarchive \ | |
| CODE_SIGN_STYLE="Manual" \ | |
| CODE_SIGN_IDENTITY="${{ vars.APPLE_CODE_SIGN_IDENTITY }}" \ | |
| PROVISIONING_PROFILE="${{ env.UUID }}" | |
| - name: Export IPA | |
| working-directory: apps/storybook | |
| run: | | |
| /usr/bin/xcodebuild -exportArchive \ | |
| -archivePath build/EDSMobile.xcarchive \ | |
| -exportOptionsPlist ExportOptions.plist \ | |
| -exportPath build | |
| - name: Upload IPA artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: EDSMobile-${{ env.BUILD_NUMBER }} | |
| path: apps/storybook/build/*.ipa | |
| - name: Upload to TestFlight | |
| uses: apple-actions/upload-testflight-build@v5 | |
| with: | |
| app-path: ${{ github.workspace }}/apps/storybook/build/EDSMobile.ipa | |
| issuer-id: ${{ secrets.APPSTORE_ISSUER_ID }} | |
| api-key-id: ${{ secrets.APPSTORE_API_KEY_ID }} | |
| api-private-key: ${{ secrets.APPSTORE_API_PRIVATE_KEY }} | |
| - name: Clean up signing artifacts | |
| if: ${{ always() }} | |
| run: | | |
| PROVISIONING_PROFILE_PATH="$RUNNER_TEMP/$PROVISIONING_PROFILE_FILE" | |
| KEYCHAIN_PATH="$RUNNER_TEMP/$KEYCHAIN_FILE" | |
| security delete-keychain "$KEYCHAIN_PATH" || true | |
| rm -f "$PROVISIONING_PROFILE_PATH" | |
| rm -f "$HOME/Library/MobileDevice/Provisioning Profiles/build_pp.mobileprovision" |