mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-18 02:57:29 +00:00
refactor(ios): derive app version from package.json
This commit is contained in:
@@ -17,9 +17,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2026.3.9</string>
|
||||
<string>$(OPENCLAW_MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>20260308</string>
|
||||
<string>$(OPENCLAW_BUILD_VERSION)</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
// Shared iOS signing defaults for local development + CI.
|
||||
#include "Version.xcconfig"
|
||||
|
||||
OPENCLAW_IOS_DEFAULT_TEAM = Y5PE65HELJ
|
||||
OPENCLAW_IOS_SELECTED_TEAM = $(OPENCLAW_IOS_DEFAULT_TEAM)
|
||||
OPENCLAW_APP_BUNDLE_ID = ai.openclaw.client
|
||||
|
||||
8
apps/ios/Config/Version.xcconfig
Normal file
8
apps/ios/Config/Version.xcconfig
Normal file
@@ -0,0 +1,8 @@
|
||||
// Shared iOS version defaults.
|
||||
// Generated overrides live in build/Version.xcconfig (git-ignored).
|
||||
|
||||
OPENCLAW_GATEWAY_VERSION = 0.0.0
|
||||
OPENCLAW_MARKETING_VERSION = 0.0.0
|
||||
OPENCLAW_BUILD_VERSION = 0
|
||||
|
||||
#include? "../build/Version.xcconfig"
|
||||
@@ -63,26 +63,27 @@ Release behavior:
|
||||
- Local development keeps using unique per-developer bundle IDs from `scripts/ios-configure-signing.sh`.
|
||||
- Beta release uses canonical `ai.openclaw.client*` bundle IDs through a temporary generated xcconfig in `apps/ios/build/BetaRelease.xcconfig`.
|
||||
- The beta flow does not modify `apps/ios/.local-signing.xcconfig` or `apps/ios/LocalSigning.xcconfig`.
|
||||
- Version input `2026.3.9-beta.1` becomes:
|
||||
- Root `package.json.version` is the only version source for iOS.
|
||||
- A root version like `2026.3.9-beta.1` becomes:
|
||||
- `CFBundleShortVersionString = 2026.3.9`
|
||||
- `CFBundleVersion = next TestFlight build number for 2026.3.9`
|
||||
|
||||
Archive without upload:
|
||||
|
||||
```bash
|
||||
pnpm ios:beta:archive -- --version 2026.3.9-beta.1
|
||||
pnpm ios:beta:archive
|
||||
```
|
||||
|
||||
Archive and upload to TestFlight:
|
||||
|
||||
```bash
|
||||
pnpm ios:beta -- --version 2026.3.9-beta.1
|
||||
pnpm ios:beta
|
||||
```
|
||||
|
||||
If you need to force a specific build number:
|
||||
|
||||
```bash
|
||||
pnpm ios:beta -- --version 2026.3.9-beta.1 --build-number 7
|
||||
pnpm ios:beta -- --build-number 7
|
||||
```
|
||||
|
||||
## APNs Expectations For Local/Manual Builds
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2026.3.9</string>
|
||||
<string>$(OPENCLAW_MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>20260308</string>
|
||||
<string>$(OPENCLAW_BUILD_VERSION)</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionAttributes</key>
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// Auto-selected local team overrides live in .local-signing.xcconfig (git-ignored).
|
||||
// Manual local overrides can go in LocalSigning.xcconfig (git-ignored).
|
||||
|
||||
#include "Config/Version.xcconfig"
|
||||
|
||||
OPENCLAW_CODE_SIGN_STYLE = Manual
|
||||
OPENCLAW_DEVELOPMENT_TEAM = Y5PE65HELJ
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2026.3.9</string>
|
||||
<string>$(OPENCLAW_MARKETING_VERSION)</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -36,7 +36,7 @@
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>20260308</string>
|
||||
<string>$(OPENCLAW_BUILD_VERSION)</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2026.3.9</string>
|
||||
<string>$(OPENCLAW_MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>20260308</string>
|
||||
<string>$(OPENCLAW_BUILD_VERSION)</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2026.3.9</string>
|
||||
<string>$(OPENCLAW_MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>20260308</string>
|
||||
<string>$(OPENCLAW_BUILD_VERSION)</string>
|
||||
<key>WKCompanionAppBundleIdentifier</key>
|
||||
<string>$(OPENCLAW_APP_BUNDLE_ID)</string>
|
||||
<key>WKWatchKitApp</key>
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2026.3.9</string>
|
||||
<string>$(OPENCLAW_MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>20260308</string>
|
||||
<string>$(OPENCLAW_BUILD_VERSION)</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionAttributes</key>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
require "shellwords"
|
||||
require "open3"
|
||||
require "json"
|
||||
|
||||
default_platform(:ios)
|
||||
|
||||
@@ -94,18 +95,28 @@ def ios_root
|
||||
File.expand_path("..", __dir__)
|
||||
end
|
||||
|
||||
def normalize_beta_version(raw_value)
|
||||
def normalize_release_version(raw_value)
|
||||
version = raw_value.to_s.strip.sub(/\Av/, "")
|
||||
UI.user_error!("Missing IOS_BETA_VERSION. Example: IOS_BETA_VERSION=2026.3.9-beta.1 fastlane ios beta") unless env_present?(version)
|
||||
UI.user_error!("Missing root package.json version.") unless env_present?(version)
|
||||
unless version.match?(/\A\d+\.\d+\.\d+(?:[.-]?beta[.-]\d+)?\z/i)
|
||||
UI.user_error!("Invalid IOS_BETA_VERSION '#{raw_value}'. Expected 2026.3.9 or 2026.3.9-beta.1.")
|
||||
UI.user_error!("Invalid package.json version '#{raw_value}'. Expected 2026.3.9 or 2026.3.9-beta.1.")
|
||||
end
|
||||
|
||||
version
|
||||
end
|
||||
|
||||
def short_beta_version(version)
|
||||
normalize_beta_version(version).sub(/([.-]?beta[.-]\d+)\z/i, "")
|
||||
def read_root_package_version
|
||||
package_json_path = File.join(repo_root, "package.json")
|
||||
UI.user_error!("Missing package.json at #{package_json_path}.") unless File.exist?(package_json_path)
|
||||
|
||||
parsed = JSON.parse(File.read(package_json_path))
|
||||
normalize_release_version(parsed["version"])
|
||||
rescue JSON::ParserError => e
|
||||
UI.user_error!("Invalid package.json at #{package_json_path}: #{e.message}")
|
||||
end
|
||||
|
||||
def short_release_version(version)
|
||||
normalize_release_version(version).sub(/([.-]?beta[.-]\d+)\z/i, "")
|
||||
end
|
||||
|
||||
def shell_join(parts)
|
||||
@@ -120,7 +131,7 @@ def resolve_beta_build_number(api_key:, version:)
|
||||
return explicit
|
||||
end
|
||||
|
||||
short_version = short_beta_version(version)
|
||||
short_version = short_release_version(version)
|
||||
latest_build = latest_testflight_build_number(
|
||||
api_key: api_key,
|
||||
app_identifier: BETA_APP_IDENTIFIER,
|
||||
@@ -135,7 +146,7 @@ end
|
||||
def prepare_beta_release!(version:, build_number:)
|
||||
script_path = File.join(repo_root, "scripts", "ios-beta-prepare.sh")
|
||||
UI.message("Preparing iOS beta release #{version} (build #{build_number}).")
|
||||
sh(shell_join(["bash", script_path, "--version", version, "--build-number", build_number]))
|
||||
sh(shell_join(["bash", script_path, "--build-number", build_number]))
|
||||
|
||||
beta_xcconfig = File.join(ios_root, "build", "BetaRelease.xcconfig")
|
||||
UI.user_error!("Missing beta xcconfig at #{beta_xcconfig}.") unless File.exist?(beta_xcconfig)
|
||||
@@ -226,7 +237,7 @@ platform :ios do
|
||||
|
||||
private_lane :prepare_beta_context do
|
||||
api_key = asc_api_key
|
||||
version = normalize_beta_version(ENV["IOS_BETA_VERSION"])
|
||||
version = read_root_package_version
|
||||
build_number = resolve_beta_build_number(api_key: api_key, version: version)
|
||||
beta_xcconfig = prepare_beta_release!(version: version, build_number: build_number)
|
||||
|
||||
@@ -234,7 +245,7 @@ platform :ios do
|
||||
api_key: api_key,
|
||||
beta_xcconfig: beta_xcconfig,
|
||||
build_number: build_number,
|
||||
short_version: short_beta_version(version),
|
||||
short_version: short_release_version(version),
|
||||
version: version
|
||||
}
|
||||
end
|
||||
|
||||
@@ -63,25 +63,26 @@ fastlane ios auth_check
|
||||
Archive locally without upload:
|
||||
|
||||
```bash
|
||||
pnpm ios:beta:archive -- --version 2026.3.9-beta.1
|
||||
pnpm ios:beta:archive
|
||||
```
|
||||
|
||||
Upload to TestFlight:
|
||||
|
||||
```bash
|
||||
pnpm ios:beta -- --version 2026.3.9-beta.1
|
||||
pnpm ios:beta
|
||||
```
|
||||
|
||||
Direct Fastlane entry point:
|
||||
|
||||
```bash
|
||||
cd apps/ios
|
||||
IOS_BETA_VERSION=2026.3.9-beta.1 fastlane ios beta
|
||||
fastlane ios beta
|
||||
```
|
||||
|
||||
Versioning rules:
|
||||
|
||||
- Input release version uses CalVer beta format: `YYYY.M.D-beta.N`
|
||||
- Root `package.json.version` is the single source of truth for iOS
|
||||
- Use `YYYY.M.D` for stable versions and `YYYY.M.D-beta.N` for beta versions
|
||||
- Fastlane stamps `CFBundleShortVersionString` to `YYYY.M.D`
|
||||
- Fastlane resolves `CFBundleVersion` as the next integer TestFlight build number for that short version
|
||||
- The beta flow regenerates `apps/ios/OpenClaw.xcodeproj` from `apps/ios/project.yml` before archiving
|
||||
|
||||
@@ -107,8 +107,8 @@ targets:
|
||||
- CFBundleURLName: ai.openclaw.ios
|
||||
CFBundleURLSchemes:
|
||||
- openclaw
|
||||
CFBundleShortVersionString: "2026.3.9"
|
||||
CFBundleVersion: "20260308"
|
||||
CFBundleShortVersionString: "$(OPENCLAW_MARKETING_VERSION)"
|
||||
CFBundleVersion: "$(OPENCLAW_BUILD_VERSION)"
|
||||
UILaunchScreen: {}
|
||||
UIApplicationSceneManifest:
|
||||
UIApplicationSupportsMultipleScenes: false
|
||||
@@ -168,8 +168,8 @@ targets:
|
||||
path: ShareExtension/Info.plist
|
||||
properties:
|
||||
CFBundleDisplayName: OpenClaw Share
|
||||
CFBundleShortVersionString: "2026.3.9"
|
||||
CFBundleVersion: "20260308"
|
||||
CFBundleShortVersionString: "$(OPENCLAW_MARKETING_VERSION)"
|
||||
CFBundleVersion: "$(OPENCLAW_BUILD_VERSION)"
|
||||
NSExtension:
|
||||
NSExtensionPointIdentifier: com.apple.share-services
|
||||
NSExtensionPrincipalClass: "$(PRODUCT_MODULE_NAME).ShareViewController"
|
||||
@@ -205,8 +205,8 @@ targets:
|
||||
path: ActivityWidget/Info.plist
|
||||
properties:
|
||||
CFBundleDisplayName: OpenClaw Activity
|
||||
CFBundleShortVersionString: "2026.3.9"
|
||||
CFBundleVersion: "20260308"
|
||||
CFBundleShortVersionString: "$(OPENCLAW_MARKETING_VERSION)"
|
||||
CFBundleVersion: "$(OPENCLAW_BUILD_VERSION)"
|
||||
NSSupportsLiveActivities: true
|
||||
NSExtension:
|
||||
NSExtensionPointIdentifier: com.apple.widgetkit-extension
|
||||
@@ -232,8 +232,8 @@ targets:
|
||||
path: WatchApp/Info.plist
|
||||
properties:
|
||||
CFBundleDisplayName: OpenClaw
|
||||
CFBundleShortVersionString: "2026.3.9"
|
||||
CFBundleVersion: "20260308"
|
||||
CFBundleShortVersionString: "$(OPENCLAW_MARKETING_VERSION)"
|
||||
CFBundleVersion: "$(OPENCLAW_BUILD_VERSION)"
|
||||
WKCompanionAppBundleIdentifier: "$(OPENCLAW_APP_BUNDLE_ID)"
|
||||
WKWatchKitApp: true
|
||||
|
||||
@@ -257,8 +257,8 @@ targets:
|
||||
path: WatchExtension/Info.plist
|
||||
properties:
|
||||
CFBundleDisplayName: OpenClaw
|
||||
CFBundleShortVersionString: "2026.3.9"
|
||||
CFBundleVersion: "20260308"
|
||||
CFBundleShortVersionString: "$(OPENCLAW_MARKETING_VERSION)"
|
||||
CFBundleVersion: "$(OPENCLAW_BUILD_VERSION)"
|
||||
NSExtension:
|
||||
NSExtensionAttributes:
|
||||
WKAppBundleIdentifier: "$(OPENCLAW_WATCH_APP_BUNDLE_ID)"
|
||||
@@ -294,8 +294,8 @@ targets:
|
||||
path: Tests/Info.plist
|
||||
properties:
|
||||
CFBundleDisplayName: OpenClawTests
|
||||
CFBundleShortVersionString: "2026.3.9"
|
||||
CFBundleVersion: "20260308"
|
||||
CFBundleShortVersionString: "$(OPENCLAW_MARKETING_VERSION)"
|
||||
CFBundleVersion: "$(OPENCLAW_BUILD_VERSION)"
|
||||
|
||||
OpenClawLogicTests:
|
||||
type: bundle.unit-test
|
||||
@@ -320,5 +320,5 @@ targets:
|
||||
path: Tests/Info.plist
|
||||
properties:
|
||||
CFBundleDisplayName: OpenClawLogicTests
|
||||
CFBundleShortVersionString: "2026.3.9"
|
||||
CFBundleVersion: "20260308"
|
||||
CFBundleShortVersionString: "$(OPENCLAW_MARKETING_VERSION)"
|
||||
CFBundleVersion: "$(OPENCLAW_BUILD_VERSION)"
|
||||
|
||||
@@ -265,10 +265,10 @@
|
||||
"ios:beta": "bash scripts/ios-beta-release.sh",
|
||||
"ios:beta:archive": "bash scripts/ios-beta-archive.sh",
|
||||
"ios:beta:prepare": "bash scripts/ios-beta-prepare.sh",
|
||||
"ios:build": "bash -lc './scripts/ios-configure-signing.sh && cd apps/ios && xcodegen generate && xcodebuild -project OpenClaw.xcodeproj -scheme OpenClaw -destination \"${IOS_DEST:-platform=iOS Simulator,name=iPhone 17}\" -configuration Debug build'",
|
||||
"ios:gen": "bash -lc './scripts/ios-configure-signing.sh && cd apps/ios && xcodegen generate'",
|
||||
"ios:open": "bash -lc './scripts/ios-configure-signing.sh && cd apps/ios && xcodegen generate && open OpenClaw.xcodeproj'",
|
||||
"ios:run": "bash -lc './scripts/ios-configure-signing.sh && cd apps/ios && xcodegen generate && xcodebuild -project OpenClaw.xcodeproj -scheme OpenClaw -destination \"${IOS_DEST:-platform=iOS Simulator,name=iPhone 17}\" -configuration Debug build && xcrun simctl boot \"${IOS_SIM:-iPhone 17}\" || true && xcrun simctl launch booted ai.openclaw.ios'",
|
||||
"ios:build": "bash -lc './scripts/ios-configure-signing.sh && ./scripts/ios-write-version-xcconfig.sh && cd apps/ios && xcodegen generate && xcodebuild -project OpenClaw.xcodeproj -scheme OpenClaw -destination \"${IOS_DEST:-platform=iOS Simulator,name=iPhone 17}\" -configuration Debug build'",
|
||||
"ios:gen": "bash -lc './scripts/ios-configure-signing.sh && ./scripts/ios-write-version-xcconfig.sh && cd apps/ios && xcodegen generate'",
|
||||
"ios:open": "bash -lc './scripts/ios-configure-signing.sh && ./scripts/ios-write-version-xcconfig.sh && cd apps/ios && xcodegen generate && open OpenClaw.xcodeproj'",
|
||||
"ios:run": "bash -lc './scripts/ios-configure-signing.sh && ./scripts/ios-write-version-xcconfig.sh && cd apps/ios && xcodegen generate && xcodebuild -project OpenClaw.xcodeproj -scheme OpenClaw -destination \"${IOS_DEST:-platform=iOS Simulator,name=iPhone 17}\" -configuration Debug build && xcrun simctl boot \"${IOS_SIM:-iPhone 17}\" || true && xcrun simctl launch booted ai.openclaw.ios'",
|
||||
"lint": "oxlint --type-aware",
|
||||
"lint:agent:ingress-owner": "node scripts/check-ingress-agent-owner-context.mjs",
|
||||
"lint:all": "pnpm lint && pnpm lint:swift",
|
||||
|
||||
@@ -4,13 +4,12 @@ set -euo pipefail
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
scripts/ios-beta-archive.sh --version 2026.3.9-beta.1 [--build-number 7]
|
||||
scripts/ios-beta-archive.sh [--build-number 7]
|
||||
|
||||
Archives and exports a beta-release IPA locally without uploading.
|
||||
EOF
|
||||
}
|
||||
|
||||
VERSION="${IOS_BETA_VERSION:-}"
|
||||
BUILD_NUMBER="${IOS_BETA_BUILD_NUMBER:-}"
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
@@ -19,10 +18,6 @@ while [[ $# -gt 0 ]]; do
|
||||
--)
|
||||
shift
|
||||
;;
|
||||
--version)
|
||||
VERSION="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
--build-number)
|
||||
BUILD_NUMBER="${2:-}"
|
||||
shift 2
|
||||
@@ -39,15 +34,7 @@ while [[ $# -gt 0 ]]; do
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "${VERSION}" ]]; then
|
||||
echo "Missing required --version (or IOS_BETA_VERSION)." >&2
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
(
|
||||
cd "${ROOT_DIR}/apps/ios"
|
||||
IOS_BETA_VERSION="${VERSION}" \
|
||||
IOS_BETA_BUILD_NUMBER="${BUILD_NUMBER}" \
|
||||
fastlane ios beta_archive
|
||||
IOS_BETA_BUILD_NUMBER="${BUILD_NUMBER}" fastlane ios beta_archive
|
||||
)
|
||||
|
||||
@@ -4,10 +4,10 @@ set -euo pipefail
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
scripts/ios-beta-prepare.sh --version 2026.3.9-beta.1 --build-number 7 [--team-id TEAMID]
|
||||
scripts/ios-beta-prepare.sh --build-number 7 [--team-id TEAMID]
|
||||
|
||||
Prepares local beta-release inputs without touching local signing overrides:
|
||||
- stamps apps/ios/project.yml with the short version + build number
|
||||
- reads package.json.version and writes apps/ios/build/Version.xcconfig
|
||||
- writes apps/ios/build/BetaRelease.xcconfig with canonical bundle IDs
|
||||
- regenerates apps/ios/OpenClaw.xcodeproj via xcodegen
|
||||
EOF
|
||||
@@ -17,20 +17,17 @@ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
IOS_DIR="${ROOT_DIR}/apps/ios"
|
||||
BETA_XCCONFIG="${IOS_DIR}/build/BetaRelease.xcconfig"
|
||||
TEAM_HELPER="${ROOT_DIR}/scripts/ios-team-id.sh"
|
||||
VERSION_HELPER="${ROOT_DIR}/scripts/ios-write-version-xcconfig.sh"
|
||||
|
||||
VERSION=""
|
||||
BUILD_NUMBER=""
|
||||
TEAM_ID="${IOS_DEVELOPMENT_TEAM:-}"
|
||||
PACKAGE_VERSION="$(cd "${ROOT_DIR}" && node -p "require('./package.json').version" 2>/dev/null || true)"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--)
|
||||
shift
|
||||
;;
|
||||
--version)
|
||||
VERSION="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
--build-number)
|
||||
BUILD_NUMBER="${2:-}"
|
||||
shift 2
|
||||
@@ -51,8 +48,8 @@ while [[ $# -gt 0 ]]; do
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "${VERSION}" || -z "${BUILD_NUMBER}" ]]; then
|
||||
echo "Missing required --version or --build-number." >&2
|
||||
if [[ -z "${BUILD_NUMBER}" ]]; then
|
||||
echo "Missing required --build-number." >&2
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
@@ -64,10 +61,7 @@ fi
|
||||
mkdir -p "${IOS_DIR}/build"
|
||||
|
||||
(
|
||||
cd "${ROOT_DIR}"
|
||||
node --import tsx scripts/ios-sync-version.ts \
|
||||
--version "${VERSION}" \
|
||||
--build-number "${BUILD_NUMBER}"
|
||||
bash "${VERSION_HELPER}" --build-number "${BUILD_NUMBER}"
|
||||
)
|
||||
|
||||
cat >"${BETA_XCCONFIG}" <<EOF
|
||||
@@ -90,5 +84,5 @@ EOF
|
||||
xcodegen generate
|
||||
)
|
||||
|
||||
echo "Prepared iOS beta release: version=${VERSION} build=${BUILD_NUMBER} team=${TEAM_ID}"
|
||||
echo "Prepared iOS beta release: version=${PACKAGE_VERSION} build=${BUILD_NUMBER} team=${TEAM_ID}"
|
||||
echo "XCODE_XCCONFIG_FILE=${BETA_XCCONFIG}"
|
||||
|
||||
@@ -4,13 +4,12 @@ set -euo pipefail
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
scripts/ios-beta-release.sh --version 2026.3.9-beta.1 [--build-number 7]
|
||||
scripts/ios-beta-release.sh [--build-number 7]
|
||||
|
||||
Archives and uploads a beta-release IPA to TestFlight locally.
|
||||
EOF
|
||||
}
|
||||
|
||||
VERSION="${IOS_BETA_VERSION:-}"
|
||||
BUILD_NUMBER="${IOS_BETA_BUILD_NUMBER:-}"
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
@@ -19,10 +18,6 @@ while [[ $# -gt 0 ]]; do
|
||||
--)
|
||||
shift
|
||||
;;
|
||||
--version)
|
||||
VERSION="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
--build-number)
|
||||
BUILD_NUMBER="${2:-}"
|
||||
shift 2
|
||||
@@ -39,15 +34,7 @@ while [[ $# -gt 0 ]]; do
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "${VERSION}" ]]; then
|
||||
echo "Missing required --version (or IOS_BETA_VERSION)." >&2
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
(
|
||||
cd "${ROOT_DIR}/apps/ios"
|
||||
IOS_BETA_VERSION="${VERSION}" \
|
||||
IOS_BETA_BUILD_NUMBER="${BUILD_NUMBER}" \
|
||||
fastlane ios beta
|
||||
IOS_BETA_BUILD_NUMBER="${BUILD_NUMBER}" fastlane ios beta
|
||||
)
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
#!/usr/bin/env -S node --import tsx
|
||||
|
||||
import { readFileSync, writeFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
type CliOptions = {
|
||||
buildNumber: string;
|
||||
version: string;
|
||||
};
|
||||
|
||||
function parseArgs(argv: string[]): CliOptions {
|
||||
const options = new Map<string, string>();
|
||||
|
||||
for (let i = 0; i < argv.length; i += 1) {
|
||||
const arg = argv[i];
|
||||
if (!arg.startsWith("--")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const key = arg.slice(2);
|
||||
const value = argv[i + 1];
|
||||
if (!value || value.startsWith("--")) {
|
||||
throw new Error(`Missing value for --${key}`);
|
||||
}
|
||||
options.set(key, value);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
const version = options.get("version")?.trim();
|
||||
const buildNumber = options.get("build-number")?.trim();
|
||||
|
||||
if (!version) {
|
||||
throw new Error("Missing required --version");
|
||||
}
|
||||
if (!buildNumber) {
|
||||
throw new Error("Missing required --build-number");
|
||||
}
|
||||
if (!/^[0-9]+$/.test(buildNumber)) {
|
||||
throw new Error(`Invalid --build-number '${buildNumber}'; expected digits only.`);
|
||||
}
|
||||
|
||||
return { buildNumber, version };
|
||||
}
|
||||
|
||||
function toShortVersion(input: string): string {
|
||||
const trimmed = input.trim().replace(/^v/, "");
|
||||
const shortVersion = trimmed.replace(/([.-]?beta[.-]\d+)$/i, "");
|
||||
if (!/^\d+\.\d+\.\d+$/.test(shortVersion)) {
|
||||
throw new Error(
|
||||
`Invalid --version '${input}'; expected CalVer like 2026.3.9 or 2026.3.9-beta.1.`,
|
||||
);
|
||||
}
|
||||
return shortVersion;
|
||||
}
|
||||
|
||||
function replaceAllExact(params: { content: string; pattern: RegExp; replacement: string }) {
|
||||
const { content, pattern, replacement } = params;
|
||||
const matches = [...content.matchAll(pattern)];
|
||||
if (matches.length === 0) {
|
||||
throw new Error(`Pattern not found: ${pattern}`);
|
||||
}
|
||||
return content.replace(pattern, replacement);
|
||||
}
|
||||
|
||||
function main() {
|
||||
const options = parseArgs(process.argv.slice(2));
|
||||
const shortVersion = toShortVersion(options.version);
|
||||
const projectPath = resolve("apps/ios/project.yml");
|
||||
const original = readFileSync(projectPath, "utf8");
|
||||
|
||||
let updated = original;
|
||||
updated = replaceAllExact({
|
||||
content: updated,
|
||||
pattern: /(CFBundleShortVersionString:\s*")[^"]+(")/g,
|
||||
replacement: `$1${shortVersion}$2`,
|
||||
});
|
||||
updated = replaceAllExact({
|
||||
content: updated,
|
||||
pattern: /(CFBundleVersion:\s*")[^"]+(")/g,
|
||||
replacement: `$1${options.buildNumber}$2`,
|
||||
});
|
||||
|
||||
if (updated === original) {
|
||||
console.log(`iOS version already set: short=${shortVersion} build=${options.buildNumber}`);
|
||||
return;
|
||||
}
|
||||
|
||||
writeFileSync(projectPath, updated);
|
||||
console.log(`Updated iOS project version: short=${shortVersion} build=${options.buildNumber}`);
|
||||
}
|
||||
|
||||
try {
|
||||
main();
|
||||
} catch (error) {
|
||||
console.error(`ios-sync-version: ${(error as Error).message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
75
scripts/ios-write-version-xcconfig.sh
Executable file
75
scripts/ios-write-version-xcconfig.sh
Executable file
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
scripts/ios-write-version-xcconfig.sh [--build-number 7]
|
||||
|
||||
Writes apps/ios/build/Version.xcconfig from root package.json.version:
|
||||
- OPENCLAW_GATEWAY_VERSION = exact package.json version
|
||||
- OPENCLAW_MARKETING_VERSION = short iOS/App Store version
|
||||
- OPENCLAW_BUILD_VERSION = explicit build number or local numeric fallback
|
||||
EOF
|
||||
}
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
IOS_DIR="${ROOT_DIR}/apps/ios"
|
||||
VERSION_XCCONFIG="${IOS_DIR}/build/Version.xcconfig"
|
||||
PACKAGE_VERSION="$(cd "${ROOT_DIR}" && node -p "require('./package.json').version" 2>/dev/null || true)"
|
||||
BUILD_NUMBER=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--)
|
||||
shift
|
||||
;;
|
||||
--build-number)
|
||||
BUILD_NUMBER="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument: $1" >&2
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
PACKAGE_VERSION="$(printf '%s' "${PACKAGE_VERSION}" | tr -d '\n' | xargs)"
|
||||
if [[ -z "${PACKAGE_VERSION}" ]]; then
|
||||
echo "Unable to read package.json.version from ${ROOT_DIR}/package.json." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${PACKAGE_VERSION}" =~ ^([0-9]{4}\.[0-9]{1,2}\.[0-9]{1,2})([.-]?beta[.-][0-9]+)?$ ]]; then
|
||||
MARKETING_VERSION="${BASH_REMATCH[1]}"
|
||||
else
|
||||
echo "Unsupported package.json.version '${PACKAGE_VERSION}'. Expected 2026.3.9 or 2026.3.9-beta.1." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${BUILD_NUMBER}" ]]; then
|
||||
BUILD_NUMBER="$(cd "${ROOT_DIR}" && git rev-list --count HEAD 2>/dev/null || printf '0')"
|
||||
fi
|
||||
|
||||
if [[ ! "${BUILD_NUMBER}" =~ ^[0-9]+$ ]]; then
|
||||
echo "Invalid build number '${BUILD_NUMBER}'. Expected digits only." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "${IOS_DIR}/build"
|
||||
|
||||
cat >"${VERSION_XCCONFIG}" <<EOF
|
||||
// Auto-generated by scripts/ios-write-version-xcconfig.sh.
|
||||
// Local version override; do not commit.
|
||||
OPENCLAW_GATEWAY_VERSION = ${PACKAGE_VERSION}
|
||||
OPENCLAW_MARKETING_VERSION = ${MARKETING_VERSION}
|
||||
OPENCLAW_BUILD_VERSION = ${BUILD_NUMBER}
|
||||
EOF
|
||||
|
||||
echo "Prepared iOS version settings: gateway=${PACKAGE_VERSION} marketing=${MARKETING_VERSION} build=${BUILD_NUMBER}"
|
||||
Reference in New Issue
Block a user