Skip to content

Build and Release Storybook iOS App #12

Build and Release Storybook iOS App

Build and Release Storybook iOS App #12

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: 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 ${{ vars.APPLE_PROVISIONING_PROFILE_NAME }}" $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"