crossmate

A collaborative crossword app for iOS
Log | Files | Refs | LICENSE

publish-ios.sh (4687B)


      1 #!/bin/bash
      2 set -euo pipefail
      3 
      4 REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
      5 SECRETS="$REPO_ROOT/.asc/secrets.sh"
      6 
      7 if [[ ! -f "$SECRETS" ]]; then
      8     echo "Error: $SECRETS not found. See Scripts/secrets.sh.example for the required format."
      9     exit 1
     10 fi
     11 
     12 source "$SECRETS"
     13 
     14 SCHEME="Crossmate"
     15 # Archive into the Xcode Archives library at a unique per-build path so
     16 # Organizer indexes every build and TestFlight crashes symbolicate
     17 # automatically. A fixed/volatile path (e.g. /tmp) makes each publish
     18 # overwrite the previous build's dSYM, leaving superseded builds' crashes
     19 # permanently unsymbolicatable. One timestamp drives both the date dir
     20 # and the archive name so they can't disagree across a midnight boundary.
     21 ARCHIVE_STAMP="$(date '+%Y-%m-%d %H.%M.%S')"
     22 ARCHIVE_DIR="$HOME/Library/Developer/Xcode/Archives/${ARCHIVE_STAMP%% *}"
     23 ARCHIVE_PATH="$ARCHIVE_DIR/$SCHEME $ARCHIVE_STAMP.xcarchive"
     24 EXPORT_PATH="/tmp/Crossmate-export"
     25 EXPORT_PLIST="/tmp/Crossmate-ExportOptions.plist"
     26 IPA_PATH="$EXPORT_PATH/Crossmate.ipa"
     27 DEV_P12="$REPO_ROOT/.asc/dev.p12"
     28 DIST_P12="$REPO_ROOT/.asc/ios-signing/dist-headless.p12"
     29 TMP_KEYCHAIN="$REPO_ROOT/.asc/build.keychain-db"
     30 
     31 CHECK_ONLY=false
     32 if [[ "${1:-}" == "--check" ]]; then
     33     CHECK_ONLY=true
     34 fi
     35 
     36 cd "$REPO_ROOT"
     37 
     38 if ! git diff --quiet || ! git diff --cached --quiet; then
     39     echo "Error: Git repository is dirty. Commit or stash changes before publishing."
     40     exit 1
     41 fi
     42 
     43 echo "==> Setting up temporary keychain..."
     44 security delete-keychain "$TMP_KEYCHAIN" 2>/dev/null || true
     45 security create-keychain -p "$TMP_KEYCHAIN_PASS" "$TMP_KEYCHAIN"
     46 security unlock-keychain -p "$TMP_KEYCHAIN_PASS" "$TMP_KEYCHAIN"
     47 security set-keychain-settings -lut 21600 "$TMP_KEYCHAIN"
     48 security import "$DEV_P12" -k "$TMP_KEYCHAIN" -P "$DEV_P12_PASS" \
     49     -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild
     50 security import "$DIST_P12" -k "$TMP_KEYCHAIN" -P "$DIST_P12_PASS" \
     51     -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild
     52 security set-key-partition-list -S apple-tool:,apple:,codesign:,productbuild: \
     53     -s -k "$TMP_KEYCHAIN_PASS" "$TMP_KEYCHAIN"
     54 security list-keychains -d user -s "$TMP_KEYCHAIN" ~/Library/Keychains/login.keychain-db
     55 
     56 cleanup_keychain() {
     57     echo "==> Restoring keychain search list..."
     58     security list-keychains -d user -s ~/Library/Keychains/login.keychain-db
     59     security default-keychain -d user -s ~/Library/Keychains/login.keychain-db
     60     security delete-keychain "$TMP_KEYCHAIN" 2>/dev/null || true
     61     rm -f "$REPO_ROOT/private_keys/AuthKey_${KEY_ID}.p8"
     62     rmdir "$REPO_ROOT/private_keys" 2>/dev/null || true
     63 }
     64 trap cleanup_keychain EXIT
     65 
     66 mkdir -p "$ARCHIVE_DIR"
     67 echo "==> Archiving $SCHEME to $ARCHIVE_PATH..."
     68 xcodebuild \
     69     -scheme "$SCHEME" \
     70     -project Crossmate.xcodeproj \
     71     -configuration Release \
     72     -destination 'generic/platform=iOS' \
     73     -archivePath "$ARCHIVE_PATH" \
     74     archive
     75 
     76 echo "==> Writing export options..."
     77 cat > "$EXPORT_PLIST" <<PLIST
     78 <?xml version="1.0" encoding="UTF-8"?>
     79 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
     80   "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
     81 <plist version="1.0">
     82 <dict>
     83     <key>method</key>
     84     <string>app-store-connect</string>
     85     <key>signingStyle</key>
     86     <string>manual</string>
     87     <key>teamID</key>
     88     <string>$TEAM_ID</string>
     89     <key>signingCertificate</key>
     90     <string>iPhone Distribution</string>
     91     <key>provisioningProfiles</key>
     92     <dict>
     93         <key>net.inqk.crossmate</key>
     94         <string>Crossmate iOS Distribution</string>
     95         <key>net.inqk.crossmate.notificationservice</key>
     96         <string>Crossmate Notification Service iOS Distribution</string>
     97     </dict>
     98     <key>destination</key>
     99     <string>export</string>
    100     <key>stripSwiftSymbols</key>
    101     <true/>
    102     <key>manageAppVersionAndBuildNumber</key>
    103     <false/>
    104 </dict>
    105 </plist>
    106 PLIST
    107 
    108 echo "==> Exporting IPA..."
    109 xcodebuild \
    110     -exportArchive \
    111     -archivePath "$ARCHIVE_PATH" \
    112     -exportPath "$EXPORT_PATH" \
    113     -exportOptionsPlist "$EXPORT_PLIST"
    114 
    115 echo "==> Checking entitlements in exported IPA..."
    116 CHECK_DIR="/tmp/Crossmate-ipa-check"
    117 rm -rf "$CHECK_DIR"
    118 unzip -q "$IPA_PATH" -d "$CHECK_DIR"
    119 echo "--- iOS app entitlements ---"
    120 codesign -d --entitlements - "$CHECK_DIR/Payload/Crossmate.app"
    121 rm -rf "$CHECK_DIR"
    122 
    123 if $CHECK_ONLY; then
    124     echo "==> Check complete. Skipping upload."
    125     exit 0
    126 fi
    127 
    128 echo "==> Uploading to App Store Connect..."
    129 mkdir -p "$REPO_ROOT/private_keys"
    130 cp "$REPO_ROOT/.asc/AuthKey_${KEY_ID}.p8" "$REPO_ROOT/private_keys/"
    131 xcrun iTMSTransporter \
    132     -m upload \
    133     -assetFile "$IPA_PATH" \
    134     -apiKey "$KEY_ID" \
    135     -apiIssuer "$ISSUER_ID" \
    136     -v informational
    137 
    138 echo "==> Done!"