Files
iKeyMon/scripts/build_release.sh
2025-11-25 16:21:07 +01:00

164 lines
5.0 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
BUILD_DIR="$ROOT_DIR/build"
ARTIFACTS_DIR="$ROOT_DIR/dist"
SCHEME="iKeyMon"
PROJECT="iKeyMon.xcodeproj"
CREDENTIALS_FILE="$ROOT_DIR/.signing.env"
VERSION_FILE="$ROOT_DIR/version.json"
DERIVED_DATA_ROOT="${DERIVED_DATA_ROOT:-$HOME/Library/Developer/Xcode/DerivedData}"
find_generate_appcast() {
if [[ -n "${SPARKLE_GENERATE_APPCAST:-}" && -x "${SPARKLE_GENERATE_APPCAST}" ]]; then
echo "$SPARKLE_GENERATE_APPCAST"
return
fi
if [[ -d "$DERIVED_DATA_ROOT" ]]; then
local candidate
candidate="$(find "$DERIVED_DATA_ROOT" -path "*/SourcePackages/artifacts/sparkle/Sparkle/bin/generate_appcast" -type f 2>/dev/null | head -n 1 || true)"
if [[ -n "$candidate" ]]; then
echo "$candidate"
return
fi
fi
}
generate_appcast() {
local generator
generator="$(find_generate_appcast)"
local download_prefix=""
if [[ -n "${SPARKLE_DOWNLOAD_BASE_TEMPLATE:-}" ]]; then
download_prefix="${SPARKLE_DOWNLOAD_BASE_TEMPLATE//\{\{VERSION\}\}/$VERSION}"
else
download_prefix="${SPARKLE_DOWNLOAD_BASE_URL:-}"
fi
if [[ -z "$generator" || -z "${SPARKLE_EDDSA_KEY_FILE:-}" || -z "$download_prefix" ]]; then
echo " Skipping Sparkle appcast generation (generator/key/download prefix not configured)."
return
fi
local output="$SPARKLE_APPCAST_OUTPUT"
mkdir -p "$(dirname "$output")"
local staging_dir
staging_dir="$(mktemp -d)"
cp "$ARTIFACTS_DIR"/*.zip "$staging_dir"/ 2>/dev/null || true
echo "🧾 Generating Sparkle appcast at $output"
if ! "$generator" \
--download-url-prefix "$download_prefix" \
--ed-key-file "$SPARKLE_EDDSA_KEY_FILE" \
-o "$output" \
"$staging_dir"; then
echo "⚠️ Sparkle appcast generation failed."
fi
rm -rf "$staging_dir"
}
sign_update_artifacts() {
local signer
signer="$(find "$DERIVED_DATA_ROOT" -path "*/SourcePackages/artifacts/sparkle/Sparkle/bin/sign_update" -type f 2>/dev/null | head -n 1 || true)"
if [[ -z "$signer" || -z "${SPARKLE_EDDSA_KEY_FILE:-}" ]]; then
echo " Skipping Sparkle signing (sign_update or SPARKLE_EDDSA_KEY_FILE missing)."
return
fi
echo "🔑 Signing ${ZIP_NAME} for Sparkle feed"
if ! "$signer" "${ARTIFACTS_DIR}/${ZIP_NAME}" --ed-key-file "${SPARKLE_EDDSA_KEY_FILE}"; then
echo "⚠️ sign_update failed (continuing without signature)"
fi
}
if [[ -f "$CREDENTIALS_FILE" ]]; then
set -a
# shellcheck disable=SC1090
source "$CREDENTIALS_FILE"
set +a
fi
: "${SPARKLE_APPCAST_OUTPUT:=$ROOT_DIR/Sparkle/appcast.xml}"
export SPARKLE_APPCAST_OUTPUT
"$ROOT_DIR/scripts/sync_version.sh"
rm -rf "$BUILD_DIR" "$ARTIFACTS_DIR"
mkdir -p "$ARTIFACTS_DIR"
xcodebuild \
-project "$ROOT_DIR/$PROJECT" \
-scheme "$SCHEME" \
-configuration Release \
-derivedDataPath "$BUILD_DIR" \
CODE_SIGNING_ALLOWED=NO \
clean build
APP_PATH="$BUILD_DIR/Build/Products/Release/iKeyMon.app"
if [[ ! -d "$APP_PATH" ]]; then
echo "❌ Failed to find built app at $APP_PATH"
exit 1
fi
if [[ -n "${CODESIGN_IDENTITY:-}" ]]; then
echo "🔏 Codesigning app with identity: $CODESIGN_IDENTITY"
codesign \
--deep \
--force \
--options runtime \
--timestamp \
--entitlements "$ROOT_DIR/iKeyMon.entitlements" \
--sign "$CODESIGN_IDENTITY" \
"$APP_PATH"
else
echo "⚠️ Skipping codesign (CODESIGN_IDENTITY not set)."
fi
STAGING_DIR=$(mktemp -d)
mkdir -p "$STAGING_DIR"
cp -R "$APP_PATH" "$STAGING_DIR/"
ln -s /Applications "$STAGING_DIR/Applications"
mkdir -p "$STAGING_DIR/.background"
cp "$ROOT_DIR/Assets/dmg_background.png" "$STAGING_DIR/.background/background.png"
VERSION="$(python3 - <<'PY' "$VERSION_FILE"
import json, sys
with open(sys.argv[1], "r", encoding="utf-8") as handle:
data = json.load(handle)
print(data.get("marketing_version", "dev"))
PY
)"
ZIP_NAME="iKeyMon-${VERSION}.zip"
pushd "$(dirname "$APP_PATH")" >/dev/null
zip -r "$ARTIFACTS_DIR/$ZIP_NAME" "$(basename "$APP_PATH")"
popd >/dev/null
DMG_NAME="iKeyMon-${VERSION}.dmg"
hdiutil create -volname "iKeyMon" -srcfolder "$STAGING_DIR" -ov -format UDZO "$ARTIFACTS_DIR/$DMG_NAME"
sign_update_artifacts
if [[ -n "${NOTARY_APPLE_ID:-}" && -n "${NOTARY_TEAM_ID:-}" && -n "${NOTARY_PASSWORD:-}" ]]; then
echo "📝 Submitting DMG for notarization..."
xcrun notarytool submit "$ARTIFACTS_DIR/$DMG_NAME" \
--apple-id "$NOTARY_APPLE_ID" \
--team-id "$NOTARY_TEAM_ID" \
--password "$NOTARY_PASSWORD" \
--wait
xcrun stapler staple "$ARTIFACTS_DIR/$DMG_NAME"
else
echo "⚠️ Skipping notarization (NOTARY_* variables not set)."
fi
rm -rf "$STAGING_DIR"
generate_appcast
if [[ -n "${GITEA_TOKEN:-}" && -n "${GITEA_OWNER:-}" && -n "${GITEA_REPO:-}" ]]; then
"$ROOT_DIR/scripts/publish_release.sh" "$VERSION" "$ARTIFACTS_DIR/$ZIP_NAME" "$ARTIFACTS_DIR/$DMG_NAME"
else
echo " Skipping Gitea release publishing (GITEA_* variables not fully set)."
fi
echo "✅ Build complete. Artifacts:"
echo " - $ARTIFACTS_DIR/$ZIP_NAME"
echo " - $ARTIFACTS_DIR/$DMG_NAME"