Files
Tarnax/scripts/release.sh
T
2026-11-04 14:59:42 +00:00

69 lines
3.5 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
METHOD=release-testing
PROVISIONING=()
while (($#)); do
case "$1" in
--method)
[[ $# -ge 2 ]] || { echo '--method needs a value' >&2; exit 2; }
METHOD="$2"; shift ;;
--allow-provisioning-updates) PROVISIONING=(-allowProvisioningUpdates) ;;
-h|--help)
echo 'Usage: scripts/release.sh [--method release-testing|debugging] [--allow-provisioning-updates]'
echo 'Always archives Release configuration. Default: registered-device distribution IPA.'
exit 0 ;;
*) echo "Unknown option: $1" >&2; exit 2 ;;
esac
shift
done
case "$METHOD" in release-testing|debugging) ;; *) echo 'Supported methods: release-testing, debugging' >&2; exit 2 ;; esac
TEAM="${DEVELOPMENT_TEAM:-39R6U3437D}"
BASE="${RELEASE_OUTPUT_DIR:-$ROOT/build/releases}"
mkdir -p "$BASE"
OUTPUT="$(mktemp -d "$BASE/$(date +%Y%m%d-%H%M%S)-$METHOD.XXXXXX")"
ARCHIVE="$OUTPUT/Tarnax.xcarchive"
EXPORT="$OUTPUT/export"
echo "Release output: $OUTPUT"
python3 - "$OUTPUT/ExportOptions.plist" "$METHOD" "$TEAM" <<'PY'
import plistlib, sys
with open(sys.argv[1], 'wb') as f:
plistlib.dump({'method':sys.argv[2], 'teamID':sys.argv[3], 'signingStyle':'automatic',
'destination':'export', 'stripSwiftSymbols':True, 'thinning':'<none>',
'manageAppVersionAndBuildNumber':False}, f)
PY
xcodebuild -project "$ROOT/Tarnax.xcodeproj" -scheme Tarnax \
-configuration Release -destination 'generic/platform=iOS' \
-derivedDataPath "$OUTPUT/DerivedData" -archivePath "$ARCHIVE" \
DEVELOPMENT_TEAM="$TEAM" CODE_SIGN_STYLE=Automatic \
${PROVISIONING[@]+"${PROVISIONING[@]}"} archive 2>&1 | tee "$OUTPUT/archive.log"
xcodebuild -exportArchive -archivePath "$ARCHIVE" -exportPath "$EXPORT" \
-exportOptionsPlist "$OUTPUT/ExportOptions.plist" \
${PROVISIONING[@]+"${PROVISIONING[@]}"} 2>&1 | tee "$OUTPUT/export.log"
IPA="$EXPORT/Tarnax.ipa"
[[ -f "$IPA" ]] || { echo 'Export finished without Tarnax.ipa' >&2; exit 1; }
VERIFY="$(mktemp -d "$OUTPUT/verify.XXXXXX")"
trap 'rm -rf "$VERIFY"' EXIT
unzip -q "$IPA" -d "$VERIFY"
APP="$VERIFY/Payload/Tarnax.app"
codesign --verify --deep --strict "$APP"
[[ -f "$APP/embedded.mobileprovision" ]] || { echo 'No embedded provisioning profile' >&2; exit 1; }
security cms -D -i "$APP/embedded.mobileprovision" > "$VERIFY/profile.plist"
python3 - "$APP/Info.plist" "$VERIFY/profile.plist" "$METHOD" <<'PY'
import plistlib, sys, datetime
with open(sys.argv[1],'rb') as f: app=plistlib.load(f)
with open(sys.argv[2],'rb') as f: profile=plistlib.load(f)
assert app['CFBundleIdentifier']=='net.absdev.Tarnax', 'Unexpected app identifier'
assert profile.get('ProvisionedDevices'), 'Profile does not include registered devices'
assert profile['ExpirationDate']>datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None), 'Profile expired'
assert profile['Entitlements']['application-identifier'].endswith('.'+app['CFBundleIdentifier']), 'Profile/app mismatch'
if sys.argv[3]=='release-testing':
assert not profile['Entitlements'].get('get-task-allow',False), 'Distribution IPA has debugging enabled'
print('Verified:', app['CFBundleDisplayName'], app['CFBundleShortVersionString'], 'build', app['CFBundleVersion'])
print('Registered devices:',len(profile['ProvisionedDevices']))
print('Profile expiry:',profile['ExpirationDate'].isoformat()+'Z')
PY
(cd "$EXPORT" && shasum -a 256 Tarnax.ipa > Tarnax.ipa.sha256)
echo "Verified IPA: $IPA"
echo "SHA-256: $EXPORT/Tarnax.ipa.sha256"