773da6800b
iCloud sync: - Fix: deploy CloudKit schema to production so exports work - Fix: PredictionCache marked syncable=NO (binary attr caused partial failures) - Fix: forceExportToiCloud uses createdAt+1ms for guaranteed persistent history - Fix: auto-deduplication on CloudKit import (processRemoteChanges) - Add: NSPersistentHistoryTrackingKey always enabled regardless of CloudKit state - Add: cloudKitForceReload notification so repositories re-fetch on remote changes Sources UI: - Add: horizontal category filter chips in SourceListView - Add: search toggle button with animated TextField Other: - Add: ITSAppUsesNonExemptEncryption=NO in Info.plist (skip manual compliance) - Add: fastlane submit lane with run_precheck_before_submit=false - Update: release notes all locales for 1.3.1 - Update: fastlane API key via pass Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
164 lines
4.4 KiB
Bash
Executable File
164 lines
4.4 KiB
Bash
Executable File
#!/bin/zsh
|
|
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
PROJECT_PATH="${PROJECT_PATH:-$ROOT_DIR/PortfolioJournal.xcodeproj}"
|
|
SCHEME="${SCHEME:-PortfolioJournal}"
|
|
CONFIGURATION="${CONFIGURATION:-Release}"
|
|
ARCHIVE_DIR="${ARCHIVE_DIR:-$ROOT_DIR/build/appstore}"
|
|
ARCHIVE_PATH="${ARCHIVE_PATH:-$ARCHIVE_DIR/${SCHEME}.xcarchive}"
|
|
EXPORT_PATH="${EXPORT_PATH:-$ARCHIVE_DIR/export}"
|
|
EXPORT_OPTIONS_PLIST="${EXPORT_OPTIONS_PLIST:-$ARCHIVE_DIR/ExportOptions.plist}"
|
|
# Credenciales desde pass (GPG store). Se puede sobreescribir con variables de entorno.
|
|
_pass_or_env() {
|
|
local env_val="$1" pass_key="$2"
|
|
if [[ -n "$env_val" ]]; then
|
|
echo "$env_val"
|
|
elif command -v pass >/dev/null 2>&1; then
|
|
pass show "$pass_key" 2>/dev/null || fail "No se encontro la credencial en pass: $pass_key"
|
|
else
|
|
fail "pass no esta disponible y la variable de entorno no esta definida para: $pass_key"
|
|
fi
|
|
}
|
|
|
|
KEY_ID="$(_pass_or_env "${APPSTORE_KEY_ID:-}" appstore/api-key-id)"
|
|
ISSUER_ID="$(_pass_or_env "${APPSTORE_ISSUER_ID:-}" appstore/issuer-id)"
|
|
TEAM_ID="$(_pass_or_env "${DEVELOPMENT_TEAM_ID:-}" appstore/team-id)"
|
|
P8_PATH="${APPSTORE_P8_PATH:-}"
|
|
P8_DIR=""
|
|
|
|
fail() {
|
|
echo "Error: $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
find_p8_file() {
|
|
# 1. Variable de entorno explícita
|
|
if [[ -n "$P8_PATH" ]]; then
|
|
[[ -f "$P8_PATH" ]] || fail "No existe el fichero APPSTORE_P8_PATH=$P8_PATH"
|
|
echo "$P8_PATH"
|
|
return
|
|
fi
|
|
|
|
# 2. Extraer de pass y escribir en fichero temporal
|
|
if command -v pass >/dev/null 2>&1 && pass show appstore/api-key-p8 &>/dev/null; then
|
|
local tmp_p8
|
|
tmp_p8="$(mktemp /tmp/AuthKey_XXXXXX.p8)"
|
|
pass show appstore/api-key-p8 > "$tmp_p8"
|
|
chmod 600 "$tmp_p8"
|
|
# Registrar para limpieza al salir
|
|
trap "rm -f '$tmp_p8'" EXIT
|
|
echo "$tmp_p8"
|
|
return
|
|
fi
|
|
|
|
# 3. Fichero por defecto en HOME
|
|
local default_path="$HOME/AuthKey_${KEY_ID}.p8"
|
|
if [[ -f "$default_path" ]]; then
|
|
echo "$default_path"
|
|
return
|
|
fi
|
|
|
|
# 4. Único .p8 en HOME
|
|
local matches=("${HOME}"/*.p8(N))
|
|
if (( ${#matches[@]} == 1 )); then
|
|
echo "${matches[1]}"
|
|
return
|
|
fi
|
|
|
|
if (( ${#matches[@]} > 1 )); then
|
|
fail "Hay varios ficheros .p8 en $HOME. Define APPSTORE_P8_PATH o inserta la clave en pass: appstore/api-key-p8"
|
|
fi
|
|
|
|
fail "No se encontro la clave .p8. Insértala con: cat AuthKey.p8 | pass insert -f -e appstore/api-key-p8"
|
|
}
|
|
|
|
create_export_options() {
|
|
mkdir -p "$ARCHIVE_DIR"
|
|
cat > "$EXPORT_OPTIONS_PLIST" <<EOF
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>destination</key>
|
|
<string>export</string>
|
|
<key>manageAppVersionAndBuildNumber</key>
|
|
<false/>
|
|
<key>method</key>
|
|
<string>app-store-connect</string>
|
|
<key>signingStyle</key>
|
|
<string>automatic</string>
|
|
<key>stripSwiftSymbols</key>
|
|
<true/>
|
|
<key>teamID</key>
|
|
<string>${TEAM_ID}</string>
|
|
<key>uploadSymbols</key>
|
|
<true/>
|
|
</dict>
|
|
</plist>
|
|
EOF
|
|
}
|
|
|
|
archive_app() {
|
|
echo "==> Archivando ${SCHEME}"
|
|
xcodebuild \
|
|
-project "$PROJECT_PATH" \
|
|
-scheme "$SCHEME" \
|
|
-configuration "$CONFIGURATION" \
|
|
-archivePath "$ARCHIVE_PATH" \
|
|
-destination "generic/platform=iOS" \
|
|
clean archive
|
|
}
|
|
|
|
export_ipa() {
|
|
echo "==> Exportando IPA"
|
|
xcodebuild \
|
|
-exportArchive \
|
|
-archivePath "$ARCHIVE_PATH" \
|
|
-exportPath "$EXPORT_PATH" \
|
|
-exportOptionsPlist "$EXPORT_OPTIONS_PLIST" \
|
|
-allowProvisioningUpdates \
|
|
-authenticationKeyPath "$P8_PATH" \
|
|
-authenticationKeyID "$KEY_ID" \
|
|
-authenticationKeyIssuerID "$ISSUER_ID"
|
|
}
|
|
|
|
upload_ipa() {
|
|
local ipa
|
|
ipa="$(find "$EXPORT_PATH" -maxdepth 1 -name '*.ipa' -print -quit)"
|
|
[[ -n "$ipa" ]] || fail "No se encontro ningun .ipa en $EXPORT_PATH"
|
|
|
|
echo "==> Subiendo $(basename "$ipa") a App Store Connect"
|
|
API_PRIVATE_KEYS_DIR="$P8_DIR" \
|
|
xcrun altool \
|
|
--upload-app \
|
|
--type ios \
|
|
--file "$ipa" \
|
|
--apiKey "$KEY_ID" \
|
|
--apiIssuer "$ISSUER_ID"
|
|
}
|
|
|
|
main() {
|
|
command -v xcodebuild >/dev/null 2>&1 || fail "xcodebuild no esta disponible"
|
|
command -v xcrun >/dev/null 2>&1 || fail "xcrun no esta disponible"
|
|
|
|
P8_PATH="$(find_p8_file)"
|
|
P8_DIR="$(dirname "$P8_PATH")"
|
|
|
|
echo "Usando proyecto: $PROJECT_PATH"
|
|
echo "Usando scheme: $SCHEME"
|
|
echo "Usando clave API: $KEY_ID"
|
|
echo "Usando fichero .p8: $P8_PATH"
|
|
|
|
rm -rf "$ARCHIVE_PATH" "$EXPORT_PATH"
|
|
create_export_options
|
|
archive_app
|
|
export_ipa
|
|
upload_ipa
|
|
|
|
echo "==> Proceso completado"
|
|
}
|
|
|
|
main "$@"
|