refactor(version): derive Apple build numbers

This commit is contained in:
2026-07-28 11:27:45 +02:00
parent 2d7982bbb9
commit c6655da7db
17 changed files with 248 additions and 55 deletions

View File

@@ -40,6 +40,12 @@ make build-apple-ios # unsigned iOS simulator app
make check-apple # iOS simulator tests
```
`make apple-project` also generates ignored Store and Direct version xcconfig
files. Their `CURRENT_PROJECT_VERSION` values come from the central version
resolver as UTC `YYYYMMDD.HHMM.SS` build identifiers. Regenerate the project
before creating another App Store archive so it receives a fresh build number;
direct DMG builds refresh their own value automatically.
### macOS shipping channels
The macOS app ships through two targets that build identical sources:

View File

@@ -1,6 +1,3 @@
// Product and build versions are shared by every platform.
#include "../version.properties"
// VniDrop development and CI builds are intentionally unsigned.
CODE_SIGNING_ALLOWED = NO
CODE_SIGNING_REQUIRED = NO

View File

@@ -1,9 +1,11 @@
# XcodeGen spec for the native SwiftUI VniDrop app (iOS/iPadOS/macOS).
# Regenerate the project with: xcodegen generate (run from apple/)
# Requires two generated inputs first (both gitignored), before xcodegen:
# Requires three generated inputs first (all gitignored), before xcodegen:
# - Rust core: apple/scripts/build-core.sh debug
# - Localization: (cd localization && bun run src/cli.ts generate)
# -> VniDrop/Resources/Localizable.xcstrings, VniDrop/Generated/L10n.swift
# - Versions: packaging/version/generate-apple-xcconfig.sh all
# -> Generated/StoreVersion.xcconfig, Generated/DirectVersion.xcconfig
name: VniDrop
options:
bundleIdPrefix: com.vnidrop
@@ -50,10 +52,6 @@ packages:
targetTemplates:
AppBase:
type: application
configFiles:
Debug: Signing.xcconfig
Release: Signing.xcconfig
Release-Direct: Signing.xcconfig
sources:
- path: VniDrop
excludes:
@@ -66,7 +64,6 @@ targetTemplates:
PRODUCT_NAME: VniDrop
PRODUCT_BUNDLE_IDENTIFIER: com.vnidrop.app
MARKETING_VERSION: "$(PRODUCT_VERSION)"
CURRENT_PROJECT_VERSION: "$(APPLE_BUILD_NUMBER)"
GENERATE_INFOPLIST_FILE: NO
INFOPLIST_FILE: VniDrop/Resources/Info.plist
CODE_SIGN_ENTITLEMENTS: VniDrop/Resources/VniDrop.entitlements
@@ -114,6 +111,10 @@ targets:
VniDrop:
templates: [AppBase]
supportedDestinations: [iOS, macOS]
configFiles:
Debug: Generated/StoreVersion.xcconfig
Release: Generated/StoreVersion.xcconfig
Release-Direct: Generated/StoreVersion.xcconfig
# Direct-download macOS target: Developer ID signed, notarized, ships in a .dmg
# and self-updates via Sparkle. DIRECT_DISTRIBUTION gates all Sparkle code so the
@@ -121,6 +122,10 @@ targets:
VniDropDirect:
templates: [AppBase]
supportedDestinations: [macOS]
configFiles:
Debug: Generated/DirectVersion.xcconfig
Release: Generated/DirectVersion.xcconfig
Release-Direct: Generated/DirectVersion.xcconfig
settings:
base:
SWIFT_ACTIVE_COMPILATION_CONDITIONS: "$(inherited) DIRECT_DISTRIBUTION"

View File

@@ -29,10 +29,13 @@ SCHEME="VniDropDirect"
CONFIG="Release-Direct"
APP_NAME="VniDrop"
VERSION_RESOLVER="$REPO_ROOT/packaging/version/resolve-version.sh"
VERSION_CONFIG_GENERATOR="$REPO_ROOT/packaging/version/generate-apple-xcconfig.sh"
VERSION="$("$VERSION_RESOLVER" product)"
BUILD_NUMBER="$("$VERSION_RESOLVER" apple-build)"
export VNIDROP_BUILD_TIME_UTC="${VNIDROP_BUILD_TIME_UTC:-$(date -u +%Y%m%d%H%M%S)}"
BUILD_NUMBER="$("$VERSION_RESOLVER" apple-direct-build)"
"$VERSION_RESOLVER" verify >/dev/null
BUILD_METADATA="$DIST_DIR/$APP_NAME-$VERSION.build-info.json"
# --- Resolve signing identity ------------------------------------------------
if [ -z "${DEVELOPER_ID_APP:-}" ]; then
@@ -57,6 +60,7 @@ echo " team: ${DEVELOPMENT_TEAM:-<unknown>}"
echo "==> Building Rust core (release)"
CARGO_PROFILE_RELEASE_LTO=false "$SCRIPT_DIR/build-core.sh" release
echo "==> Regenerating Xcode project"
"$VERSION_CONFIG_GENERATOR" all
( cd "$APPLE_DIR" && xcodegen generate >/dev/null )
rm -rf "$BUILD_DIR" && mkdir -p "$BUILD_DIR" "$DIST_DIR"
@@ -88,6 +92,18 @@ xcodebuild -exportArchive \
-exportOptionsPlist "$EXPORT_OPTS"
APP="$EXPORT_DIR/$APP_NAME.app"
[ -d "$APP" ] || { echo "error: export failed" >&2; exit 1; }
ACTUAL_VERSION="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' \
"$APP/Contents/Info.plist")"
ACTUAL_BUILD="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleVersion' \
"$APP/Contents/Info.plist")"
[ "$ACTUAL_VERSION" = "$VERSION" ] || {
echo "error: exported app version $ACTUAL_VERSION does not match $VERSION" >&2
exit 1
}
[ "$ACTUAL_BUILD" = "$BUILD_NUMBER" ] || {
echo "error: exported app build $ACTUAL_BUILD does not match $BUILD_NUMBER" >&2
exit 1
}
# --- Build the DMG -----------------------------------------------------------
DMG="$DIST_DIR/$APP_NAME-$VERSION.dmg"
@@ -133,7 +149,18 @@ else
fi
SIZE="$(stat -f%z "$DMG")"
jq -n \
--arg productVersion "$VERSION" \
--arg directBuildNumber "$BUILD_NUMBER" \
--arg artifact "$(basename "$DMG")" \
'{
productVersion: $productVersion,
directBuildNumber: $directBuildNumber,
distribution: "direct",
artifact: $artifact
}' > "$BUILD_METADATA"
echo "==> Done."
echo " dmg: $DMG"
echo " version: $VERSION"
echo " build: $BUILD_NUMBER"
echo " size: $SIZE bytes"