work on app selection building #23
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: iOS CI/CD | |
| on: | |
| push: | |
| branches: ["ci-cd"] | |
| workflow_dispatch: | |
| jobs: | |
| build-web: | |
| name: Build web bundle (www) | |
| runs-on: macos-15 | |
| # Ensure manual runs only proceed on the ci-cd branch | |
| if: github.ref == 'refs/heads/ci-cd' | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| cache: npm | |
| - name: Create empty .env | |
| run: touch .env | |
| - name: Make envfile (override with secrets) | |
| run: | | |
| set -euo pipefail | |
| [ -n "${{ secrets.COLLAB_API_CLIENT_ID }}" ] && echo "COLLAB_API_CLIENT_ID=${{ secrets.COLLAB_API_CLIENT_ID }}" >> .env || true | |
| [ -n "${{ secrets.COLLAB_API_CLIENT_SECRET }}" ] && echo "COLLAB_API_CLIENT_SECRET=${{ secrets.COLLAB_API_CLIENT_SECRET }}" >> .env || true | |
| [ -n "${{ secrets.BASE_AUTH_URL }}" ] && echo "BASE_AUTH_URL=${{ secrets.BASE_AUTH_URL }}" >> .env || true | |
| [ -n "${{ secrets.QLF_COLLAB_API_CLIENT_ID }}" ] && echo "QLF_COLLAB_API_CLIENT_ID=${{ secrets.QLF_COLLAB_API_CLIENT_ID }}" >> .env || true | |
| [ -n "${{ secrets.QLF_COLLAB_API_CLIENT_SECRET }}" ] && echo "QLF_COLLAB_API_CLIENT_SECRET=${{ secrets.QLF_COLLAB_API_CLIENT_SECRET }}" >> .env || true | |
| [ -n "${{ secrets.QLF_BASE_AUTH_URL }}" ] && echo "QLF_BASE_AUTH_URL=${{ secrets.QLF_BASE_AUTH_URL }}" >> .env || true | |
| [ -n "${{ secrets.BASE_API_URL }}" ] && echo "BASE_API_URL=${{ secrets.BASE_API_URL }}" >> .env || true | |
| [ -n "${{ secrets.SECRET }}" ] && echo "SECRET=${{ secrets.SECRET }}" >> .env || true | |
| # App selection/name identifiers (optional overrides, defined in the config.js files) | |
| [ -n "${{ secrets.APPLI }}" ] && echo "APPLI=${{ secrets.APPLI }}" >> .env || true | |
| [ -n "${{ secrets.APPLI_ID }}" ] && echo "APPLI_ID=${{ secrets.APPLI_ID }}" >> .env || true | |
| [ -n "${{ secrets.APPLI_NAME }}" ] && echo "APPLI_NAME=${{ secrets.APPLI_NAME }}" >> .env || true | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Build web bundle | |
| run: npm run build | |
| - name: Generate Capacitor assets (iOS) | |
| run: npx @capacitor/assets generate --ios | |
| - name: Capacitor sync (iOS) | |
| run: npx cap sync ios | |
| - name: Detect selected app and iOS signing params | |
| id: detect_ios_app | |
| shell: bash | |
| env: | |
| SELECTED_APP_FILE: scripts/.selected-app | |
| # ESPACECO_DEPLOY_PROFILE: ${{ secrets.DEPLOY_PROVISION_PROFILE_BASE64_ESPACECO }} | |
| ESPACECO_APPSTORE_PROFILE: ${{ secrets.DEPLOY_PROVISION_PROFILE_BASE64_ESPACECO }} | |
| ESPACECO_EXPORT_PLIST: ${{ secrets.IOS_EXPORT_PRODUCTION_ESPACECO }} | |
| # NAVIFOREST_DEPLOY_PROFILE: ${{ secrets.DEPLOY_PROVISION_PROFILE_BASE64_NAVIFOREST }} | |
| NAVIFOREST_APPSTORE_PROFILE: ${{ secrets.DEPLOY_PROVISION_PROFILE_BASE64_NAVIFOREST }} | |
| NAVIFOREST_EXPORT_PLIST: ${{ secrets.IOS_EXPORT_PRODUCTION_NAVIFOREST }} | |
| run: | | |
| set -euo pipefail | |
| app="EspaceCo" | |
| if [[ -f "$SELECTED_APP_FILE" ]]; then | |
| candidate=$(tr -d '\r\n' < "$SELECTED_APP_FILE") | |
| if [[ "$candidate" == "NaviForest" || "$candidate" == "EspaceCo" ]]; then | |
| app="$candidate" | |
| else | |
| echo "Unknown app '$candidate' in $SELECTED_APP_FILE, defaulting to EspaceCo" >&2 | |
| fi | |
| fi | |
| if [[ "$app" == "NaviForest" ]]; then | |
| profile="$NAVIFOREST_DEPLOY_PROFILE" | |
| appstore_profile="$NAVIFOREST_APPSTORE_PROFILE" | |
| export_plist="$NAVIFOREST_EXPORT_PLIST" | |
| if [[ -z "$profile" || -z "$appstore_profile" || -z "$export_plist" ]]; then | |
| echo "Missing NaviForest secrets; using EspaceCo configuration" >&2 | |
| app="EspaceCo" | |
| fi | |
| fi | |
| if [[ "$app" == "EspaceCo" ]]; then | |
| appstore_profile="$ESPACECO_APPSTORE_PROFILE" | |
| export_plist="$ESPACECO_EXPORT_PLIST" | |
| fi | |
| if [[ -z "${profile}" ]]; then | |
| echo "Missing provisioning profile secret for $app" >&2 | |
| exit 1 | |
| fi | |
| if [[ -z "${export_plist}" ]]; then | |
| echo "Missing export options plist secret for $app" >&2 | |
| exit 1 | |
| fi | |
| if [[ -z "${appstore_profile}" ]]; then | |
| appstore_profile="$profile" | |
| fi | |
| echo "Selected app: $app" | |
| { | |
| printf 'SELECTED_APP=%s\n' "$app" | |
| printf 'APPSTORE_PROFILE_BASE64<<EOF\n%s\nEOF\n' "$appstore_profile" | |
| printf 'IOS_EXPORT_PRODUCTION<<EOF\n%s\nEOF\n' "$export_plist" | |
| } >> "$GITHUB_ENV" | |
| - name: Install Apple distribution cert & App Store profile | |
| env: | |
| DISTRIBUTION_CERTIFICATE_P12: ${{ secrets.DISTRIBUTION_CERTIFICATE_P12 }} | |
| P12_PASSWORD_DISTR: ${{ secrets.P12_PASSWORD_DISTR }} | |
| APPSTORE_PROFILE_BASE64: ${{ env.APPSTORE_PROFILE_BASE64 }} | |
| KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} | |
| run: | | |
| set -euo pipefail | |
| CERT_P12=$RUNNER_TEMP/dist.p12 | |
| PROFILE=$RUNNER_TEMP/appstore.mobileprovision | |
| KEYCHAIN=$RUNNER_TEMP/app-signing.keychain-db | |
| echo -n "$DISTRIBUTION_CERTIFICATE_P12" | base64 --decode > "$CERT_P12" | |
| echo -n "$APPSTORE_PROFILE_BASE64" | base64 --decode > "$PROFILE" | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN" | |
| security set-keychain-settings -lut 21600 "$KEYCHAIN" | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN" | |
| security import "$CERT_P12" -P "$P12_PASSWORD_DISTR" -A -t cert -f pkcs12 -k "$KEYCHAIN" | |
| security list-keychain -d user -s "$KEYCHAIN" | |
| mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles" | |
| cp "$PROFILE" "$HOME/Library/MobileDevice/Provisioning Profiles/" | |
| - name: Show build settings | |
| run: | | |
| cd ios/App | |
| xcodebuild -showBuildSettings \ | |
| -workspace "App.xcworkspace" \ | |
| -scheme "App" \ | |
| -configuration "Release Production" | egrep "CODE_SIGN|PROVISION|PRODUCT_BUNDLE_IDENTIFIER|DEVELOPMENT_TEAM" | |
| # - name: Show code signing identities | |
| # run: | | |
| # security find-identity -v -p codesigning | |
| # - name: Inspect provisioning profile | |
| # run: | | |
| # PROFILE=$(ls "$HOME/Library/MobileDevice/Provisioning Profiles"/*.mobileprovision | head -n1) | |
| # security cms -D -i "$PROFILE" > $RUNNER_TEMP/profile.plist | |
| # echo "Profile Name: $(/usr/libexec/PlistBuddy -c 'Print Name' $RUNNER_TEMP/profile.plist)" | |
| # echo "Bundle ID: $(/usr/libexec/PlistBuddy -c 'Print Entitlements:application-identifier' $RUNNER_TEMP/profile.plist)" | |
| # # Print SHA-1 fingerprints of DeveloperCertificates embedded in the profile | |
| # python3 - <<'PY' | |
| # import plistlib, base64, subprocess, os | |
| # p=plistlib.load(open(os.environ['RUNNER_TEMP']+'/profile.plist','rb')) | |
| # for i, der_b64 in enumerate(p.get('DeveloperCertificates', [])): | |
| # der = base64.b64decode(der_b64) | |
| # path = f"{os.environ['RUNNER_TEMP']}/cert{i}.cer" | |
| # open(path,'wb').write(der) | |
| # out = subprocess.check_output(['openssl','x509','-inform','DER','-in',path,'-noout','-subject','-serial','-fingerprint','-sha1']).decode() | |
| # print(f"Profile cert[{i}]:\n{out}") | |
| # PY | |
| - name: Build archive | |
| env: | |
| TEAM_ID: ${{ secrets.APPSTORE_TEAM_ID }} | |
| run: | | |
| set -euo pipefail | |
| cd ios/App | |
| xcodebuild \ | |
| -workspace "App.xcworkspace" \ | |
| -scheme "App" \ | |
| -configuration "Release Production" \ | |
| -archivePath "$GITHUB_WORKSPACE/App.xcarchive" \ | |
| -destination "generic/platform=iOS" \ | |
| DEVELOPMENT_TEAM="$TEAM_ID" \ | |
| CODE_SIGN_STYLE=Manual \ | |
| CODE_SIGNING_ALLOWED=NO \ | |
| CODE_SIGNING_REQUIRED=NO \ | |
| CODE_SIGN_IDENTITY="" \ | |
| PROVISIONING_PROFILE_SPECIFIER="" \ | |
| PROVISIONING_PROFILE="" \ | |
| clean archive | |
| - name: Export IPA | |
| env: | |
| EXPORT_PLIST_B64: ${{ env.IOS_EXPORT_PRODUCTION }} | |
| run: | | |
| set -euo pipefail | |
| EXPORT_PLIST=$RUNNER_TEMP/ExportOptions.plist | |
| echo -n "$EXPORT_PLIST_B64" | base64 --decode > "$EXPORT_PLIST" | |
| cd ios/App | |
| xcodebuild -exportArchive \ | |
| -archivePath "$GITHUB_WORKSPACE/App.xcarchive" \ | |
| -exportOptionsPlist "$EXPORT_PLIST" \ | |
| -exportPath "$RUNNER_TEMP/export" | |
| # - name: Save App Store Connect API key (.p8) | |
| # env: | |
| # API_KEY_B64: ${{ secrets.APPSTORE_API_PRIVATE_KEY }} # base64 of AuthKey_XXXXXX.p8 | |
| # run: | | |
| # set -euo pipefail | |
| # mkdir -p ~/private_keys | |
| # echo -n "$API_KEY_B64" | base64 --decode \ | |
| # > ~/private_keys/AuthKey_${{ secrets.APPSTORE_API_KEY_ID }}.p8 | |
| # - name: Upload to TestFlight | |
| # env: | |
| # API_KEY_ID: ${{ secrets.APPSTORE_API_KEY_ID }} | |
| # API_ISSUER_ID: ${{ secrets.APPSTORE_ISSUER_ID }} | |
| # run: | | |
| # set -euo pipefail | |
| # IPA=$(ls $RUNNER_TEMP/export/*.ipa | head -n 1) | |
| # xcrun iTMSTransporter -m upload \ | |
| # -assetFile "$IPA" \ | |
| # -apiKey "$API_KEY_ID" \ | |
| # -apiIssuer "$API_ISSUER_ID" |