mirror of https://github.com/openclaw/openclaw.git
fix(release): unify sparkle build policy and defaults
This commit is contained in:
parent
3e55cc5811
commit
af9edc98e4
|
|
@ -38,7 +38,6 @@ Notes:
|
||||||
# Default is auto-derived from APP_VERSION when omitted.
|
# Default is auto-derived from APP_VERSION when omitted.
|
||||||
BUNDLE_ID=ai.openclaw.mac \
|
BUNDLE_ID=ai.openclaw.mac \
|
||||||
APP_VERSION=2026.2.27 \
|
APP_VERSION=2026.2.27 \
|
||||||
APP_BUILD="$(git rev-list --count HEAD)" \
|
|
||||||
BUILD_CONFIG=release \
|
BUILD_CONFIG=release \
|
||||||
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
|
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
|
||||||
scripts/package-mac-app.sh
|
scripts/package-mac-app.sh
|
||||||
|
|
@ -56,7 +55,6 @@ scripts/create-dmg.sh dist/OpenClaw.app dist/OpenClaw-2026.2.27.dmg
|
||||||
NOTARIZE=1 NOTARYTOOL_PROFILE=openclaw-notary \
|
NOTARIZE=1 NOTARYTOOL_PROFILE=openclaw-notary \
|
||||||
BUNDLE_ID=ai.openclaw.mac \
|
BUNDLE_ID=ai.openclaw.mac \
|
||||||
APP_VERSION=2026.2.27 \
|
APP_VERSION=2026.2.27 \
|
||||||
APP_BUILD="$(git rev-list --count HEAD)" \
|
|
||||||
BUILD_CONFIG=release \
|
BUILD_CONFIG=release \
|
||||||
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
|
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
|
||||||
scripts/package-mac-dist.sh
|
scripts/package-mac-dist.sh
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ BUILD_TS=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||||
GIT_COMMIT=$(cd "$ROOT_DIR" && git rev-parse --short HEAD 2>/dev/null || echo "unknown")
|
GIT_COMMIT=$(cd "$ROOT_DIR" && git rev-parse --short HEAD 2>/dev/null || echo "unknown")
|
||||||
GIT_BUILD_NUMBER=$(cd "$ROOT_DIR" && git rev-list --count HEAD 2>/dev/null || echo "0")
|
GIT_BUILD_NUMBER=$(cd "$ROOT_DIR" && git rev-list --count HEAD 2>/dev/null || echo "0")
|
||||||
APP_VERSION="${APP_VERSION:-$PKG_VERSION}"
|
APP_VERSION="${APP_VERSION:-$PKG_VERSION}"
|
||||||
|
APP_BUILD="${APP_BUILD:-}"
|
||||||
BUILD_CONFIG="${BUILD_CONFIG:-debug}"
|
BUILD_CONFIG="${BUILD_CONFIG:-debug}"
|
||||||
BUILD_ARCHS_VALUE="${BUILD_ARCHS:-$(uname -m)}"
|
BUILD_ARCHS_VALUE="${BUILD_ARCHS:-$(uname -m)}"
|
||||||
if [[ "${BUILD_ARCHS_VALUE}" == "all" ]]; then
|
if [[ "${BUILD_ARCHS_VALUE}" == "all" ]]; then
|
||||||
|
|
@ -29,42 +30,17 @@ if [[ "$BUNDLE_ID" == *.debug ]]; then
|
||||||
AUTO_CHECKS=false
|
AUTO_CHECKS=false
|
||||||
fi
|
fi
|
||||||
|
|
||||||
canonical_build_from_version() {
|
sparkle_canonical_build_from_version() {
|
||||||
local version="$1"
|
node --import tsx "$ROOT_DIR/scripts/sparkle-build.ts" canonical-build "$1"
|
||||||
if [[ "$version" =~ ^([0-9]{4})\.([0-9]{1,2})\.([0-9]{1,2})([.-].*)?$ ]]; then
|
|
||||||
local year="${BASH_REMATCH[1]}"
|
|
||||||
local month="${BASH_REMATCH[2]}"
|
|
||||||
local day="${BASH_REMATCH[3]}"
|
|
||||||
local month_dec=$((10#$month))
|
|
||||||
local day_dec=$((10#$day))
|
|
||||||
local suffix="${BASH_REMATCH[4]:-}"
|
|
||||||
local lane=90
|
|
||||||
# Keep stable releases above same-day prereleases so Sparkle can advance beta -> stable.
|
|
||||||
if [[ -n "$suffix" ]]; then
|
|
||||||
if [[ "$suffix" =~ ([0-9]+)$ ]]; then
|
|
||||||
lane=$((10#${BASH_REMATCH[1]}))
|
|
||||||
if (( lane > 89 )); then
|
|
||||||
lane=89
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
lane=1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
printf "%d%02d%02d%02d" "$year" "$month_dec" "$day_dec" "$lane"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if [[ -z "${APP_BUILD:-}" ]]; then
|
if [[ -z "${APP_BUILD:-}" ]]; then
|
||||||
APP_BUILD="$GIT_BUILD_NUMBER"
|
APP_BUILD="$GIT_BUILD_NUMBER"
|
||||||
if CANONICAL_BUILD="$(canonical_build_from_version "$APP_VERSION")"; then
|
if CANONICAL_BUILD="$(sparkle_canonical_build_from_version "$APP_VERSION" 2>/dev/null)"; then
|
||||||
if [[ "$CANONICAL_BUILD" =~ ^[0-9]+$ ]] && (( CANONICAL_BUILD > APP_BUILD )); then
|
if [[ "$CANONICAL_BUILD" =~ ^[0-9]+$ ]] && (( CANONICAL_BUILD > APP_BUILD )); then
|
||||||
APP_BUILD="$CANONICAL_BUILD"
|
APP_BUILD="$CANONICAL_BUILD"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
APP_BUILD="${APP_BUILD}"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$AUTO_CHECKS" == "true" && ! "$APP_BUILD" =~ ^[0-9]+$ ]]; then
|
if [[ "$AUTO_CHECKS" == "true" && ! "$APP_BUILD" =~ ^[0-9]+$ ]]; then
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
import { execSync } from "node:child_process";
|
import { execSync } from "node:child_process";
|
||||||
import { readdirSync, readFileSync } from "node:fs";
|
import { readdirSync, readFileSync } from "node:fs";
|
||||||
import { join, resolve } from "node:path";
|
import { join, resolve } from "node:path";
|
||||||
|
import { sparkleBuildFloorsFromShortVersion, type SparkleBuildFloors } from "./sparkle-build.ts";
|
||||||
|
|
||||||
type PackFile = { path: string };
|
type PackFile = { path: string };
|
||||||
type PackResult = { files?: PackFile[] };
|
type PackResult = { files?: PackFile[] };
|
||||||
|
|
@ -22,12 +23,6 @@ type PackageJson = {
|
||||||
version?: string;
|
version?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type CalverSparkleFloors = {
|
|
||||||
dateKey: number;
|
|
||||||
legacyFloor: number;
|
|
||||||
laneFloor: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
function normalizePluginSyncVersion(version: string): string {
|
function normalizePluginSyncVersion(version: string): string {
|
||||||
const normalized = version.trim().replace(/^v/, "");
|
const normalized = version.trim().replace(/^v/, "");
|
||||||
const base = /^([0-9]+\.[0-9]+\.[0-9]+)/.exec(normalized)?.[1];
|
const base = /^([0-9]+\.[0-9]+\.[0-9]+)/.exec(normalized)?.[1];
|
||||||
|
|
@ -94,45 +89,6 @@ function checkPluginVersions() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function sparkleFloorsFromShortVersion(shortVersion: string): CalverSparkleFloors | null {
|
|
||||||
const match = /^([0-9]{4})\.([0-9]{1,2})\.([0-9]{1,2})([.-].*)?$/.exec(shortVersion.trim());
|
|
||||||
if (!match) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const year = Number(match[1]);
|
|
||||||
const month = Number(match[2]);
|
|
||||||
const day = Number(match[3]);
|
|
||||||
if (
|
|
||||||
!Number.isInteger(year) ||
|
|
||||||
!Number.isInteger(month) ||
|
|
||||||
!Number.isInteger(day) ||
|
|
||||||
month < 1 ||
|
|
||||||
month > 12 ||
|
|
||||||
day < 1 ||
|
|
||||||
day > 31
|
|
||||||
) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dateKey = Number(`${year}${String(month).padStart(2, "0")}${String(day).padStart(2, "0")}`);
|
|
||||||
const legacyFloor = Number(`${dateKey}0`);
|
|
||||||
|
|
||||||
// Must stay aligned with canonical_build_from_version in scripts/package-mac-app.sh.
|
|
||||||
const suffix = match[4] ?? "";
|
|
||||||
let lane = 90;
|
|
||||||
if (suffix.length > 0) {
|
|
||||||
const numericSuffix = /([0-9]+)$/.exec(suffix)?.[1];
|
|
||||||
if (numericSuffix) {
|
|
||||||
lane = Math.min(Number.parseInt(numericSuffix, 10), 89);
|
|
||||||
} else {
|
|
||||||
lane = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const laneFloor = Number(`${dateKey}${String(lane).padStart(2, "0")}`);
|
|
||||||
return { dateKey, legacyFloor, laneFloor };
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractTag(item: string, tag: string): string | null {
|
function extractTag(item: string, tag: string): string | null {
|
||||||
const escapedTag = tag.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
const escapedTag = tag.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||||
const regex = new RegExp(`<${escapedTag}>([^<]+)</${escapedTag}>`);
|
const regex = new RegExp(`<${escapedTag}>([^<]+)</${escapedTag}>`);
|
||||||
|
|
@ -143,7 +99,7 @@ function checkAppcastSparkleVersions() {
|
||||||
const xml = readFileSync(appcastPath, "utf8");
|
const xml = readFileSync(appcastPath, "utf8");
|
||||||
const itemMatches = [...xml.matchAll(/<item>([\s\S]*?)<\/item>/g)];
|
const itemMatches = [...xml.matchAll(/<item>([\s\S]*?)<\/item>/g)];
|
||||||
const errors: string[] = [];
|
const errors: string[] = [];
|
||||||
const calverItems: Array<{ title: string; sparkleBuild: number; floors: CalverSparkleFloors }> =
|
const calverItems: Array<{ title: string; sparkleBuild: number; floors: SparkleBuildFloors }> =
|
||||||
[];
|
[];
|
||||||
|
|
||||||
if (itemMatches.length === 0) {
|
if (itemMatches.length === 0) {
|
||||||
|
|
@ -167,13 +123,12 @@ function checkAppcastSparkleVersions() {
|
||||||
if (!shortVersion) {
|
if (!shortVersion) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const floors = sparkleFloorsFromShortVersion(shortVersion);
|
const floors = sparkleBuildFloorsFromShortVersion(shortVersion);
|
||||||
if (floors === null) {
|
if (floors === null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sparkleBuild = Number(sparkleVersion);
|
calverItems.push({ title, sparkleBuild: Number(sparkleVersion), floors });
|
||||||
calverItems.push({ title, sparkleBuild, floors });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const adoptionDateKey = calverItems
|
const adoptionDateKey = calverItems
|
||||||
|
|
@ -186,7 +141,6 @@ function checkAppcastSparkleVersions() {
|
||||||
item.sparkleBuild >= 1_000_000_000 ||
|
item.sparkleBuild >= 1_000_000_000 ||
|
||||||
(typeof adoptionDateKey === "number" && item.floors.dateKey >= adoptionDateKey);
|
(typeof adoptionDateKey === "number" && item.floors.dateKey >= adoptionDateKey);
|
||||||
const floor = expectLaneFloor ? item.floors.laneFloor : item.floors.legacyFloor;
|
const floor = expectLaneFloor ? item.floors.laneFloor : item.floors.legacyFloor;
|
||||||
|
|
||||||
if (item.sparkleBuild < floor) {
|
if (item.sparkleBuild < floor) {
|
||||||
const floorLabel = expectLaneFloor ? "lane floor" : "legacy floor";
|
const floorLabel = expectLaneFloor ? "lane floor" : "legacy floor";
|
||||||
errors.push(
|
errors.push(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
#!/usr/bin/env -S node --import tsx
|
||||||
|
|
||||||
|
import { pathToFileURL } from "node:url";
|
||||||
|
|
||||||
|
export type SparkleBuildFloors = {
|
||||||
|
dateKey: number;
|
||||||
|
legacyFloor: number;
|
||||||
|
laneFloor: number;
|
||||||
|
lane: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const CALVER_REGEX = /^([0-9]{4})\.([0-9]{1,2})\.([0-9]{1,2})([.-].*)?$/;
|
||||||
|
|
||||||
|
export function sparkleBuildFloorsFromShortVersion(
|
||||||
|
shortVersion: string,
|
||||||
|
): SparkleBuildFloors | null {
|
||||||
|
const match = CALVER_REGEX.exec(shortVersion.trim());
|
||||||
|
if (!match) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const year = Number.parseInt(match[1], 10);
|
||||||
|
const month = Number.parseInt(match[2], 10);
|
||||||
|
const day = Number.parseInt(match[3], 10);
|
||||||
|
if (
|
||||||
|
!Number.isInteger(year) ||
|
||||||
|
!Number.isInteger(month) ||
|
||||||
|
!Number.isInteger(day) ||
|
||||||
|
month < 1 ||
|
||||||
|
month > 12 ||
|
||||||
|
day < 1 ||
|
||||||
|
day > 31
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dateKey = Number(`${year}${String(month).padStart(2, "0")}${String(day).padStart(2, "0")}`);
|
||||||
|
const legacyFloor = Number(`${dateKey}0`);
|
||||||
|
|
||||||
|
let lane = 90;
|
||||||
|
const suffix = match[4] ?? "";
|
||||||
|
if (suffix.length > 0) {
|
||||||
|
const numericSuffix = /([0-9]+)$/.exec(suffix)?.[1];
|
||||||
|
if (numericSuffix) {
|
||||||
|
lane = Math.min(Number.parseInt(numericSuffix, 10), 89);
|
||||||
|
} else {
|
||||||
|
lane = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const laneFloor = Number(`${dateKey}${String(lane).padStart(2, "0")}`);
|
||||||
|
return { dateKey, legacyFloor, laneFloor, lane };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canonicalSparkleBuildFromVersion(shortVersion: string): number | null {
|
||||||
|
return sparkleBuildFloorsFromShortVersion(shortVersion)?.laneFloor ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function runCli(args: string[]): number {
|
||||||
|
const [command, version] = args;
|
||||||
|
if (command !== "canonical-build" || !version) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const build = canonicalSparkleBuildFromVersion(version);
|
||||||
|
if (build === null) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(String(build));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
|
||||||
|
process.exit(runCli(process.argv.slice(2)));
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue