mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 01:31:08 +00:00
* feat(ios): decouple app versioning from gateway * feat(ios): pin calver release versioning * refactor(ios): drop prerelease version helper fields * docs(changelog): note pinned ios release versioning (#63001) (thanks @ngutman)
149 lines
4.3 KiB
TypeScript
149 lines
4.3 KiB
TypeScript
import path from "node:path";
|
|
import {
|
|
normalizePinnedIosVersion,
|
|
resolveGatewayVersionForIosRelease,
|
|
resolveIosVersion,
|
|
syncIosVersioning,
|
|
writeIosVersionManifest,
|
|
} from "./lib/ios-version.ts";
|
|
|
|
type CliOptions = {
|
|
explicitVersion: string | null;
|
|
fromGateway: boolean;
|
|
rootDir: string;
|
|
sync: boolean;
|
|
};
|
|
|
|
export type PinIosVersionResult = {
|
|
previousVersion: string | null;
|
|
nextVersion: string;
|
|
packageVersion: string | null;
|
|
versionFilePath: string;
|
|
syncedPaths: string[];
|
|
};
|
|
|
|
function usage(): string {
|
|
return [
|
|
"Usage: node --import tsx scripts/ios-pin-version.ts (--from-gateway | --version <YYYY.M.D>) [--no-sync] [--root dir]",
|
|
"",
|
|
"Examples:",
|
|
" node --import tsx scripts/ios-pin-version.ts --from-gateway",
|
|
" node --import tsx scripts/ios-pin-version.ts --version 2026.4.10",
|
|
].join("\n");
|
|
}
|
|
|
|
export function parseArgs(argv: string[]): CliOptions {
|
|
let explicitVersion: string | null = null;
|
|
let fromGateway = false;
|
|
let rootDir = path.resolve(".");
|
|
let sync = true;
|
|
|
|
for (let index = 0; index < argv.length; index += 1) {
|
|
const arg = argv[index];
|
|
switch (arg) {
|
|
case "--from-gateway": {
|
|
fromGateway = true;
|
|
break;
|
|
}
|
|
case "--version": {
|
|
explicitVersion = argv[index + 1] ?? null;
|
|
index += 1;
|
|
break;
|
|
}
|
|
case "--no-sync": {
|
|
sync = false;
|
|
break;
|
|
}
|
|
case "--root": {
|
|
const value = argv[index + 1];
|
|
if (!value) {
|
|
throw new Error("Missing value for --root.");
|
|
}
|
|
rootDir = path.resolve(value);
|
|
index += 1;
|
|
break;
|
|
}
|
|
case "-h":
|
|
case "--help": {
|
|
console.log(`${usage()}\n`);
|
|
process.exit(0);
|
|
}
|
|
default: {
|
|
throw new Error(`Unknown argument: ${arg}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fromGateway === (explicitVersion !== null)) {
|
|
throw new Error("Choose exactly one of --from-gateway or --version <YYYY.M.D>.");
|
|
}
|
|
|
|
if (explicitVersion !== null && !explicitVersion.trim()) {
|
|
throw new Error("Missing value for --version.");
|
|
}
|
|
|
|
return { explicitVersion, fromGateway, rootDir, sync };
|
|
}
|
|
|
|
export function pinIosVersion(params: CliOptions): PinIosVersionResult {
|
|
const rootDir = path.resolve(params.rootDir);
|
|
let previousVersion: string | null = null;
|
|
try {
|
|
previousVersion = resolveIosVersion(rootDir).canonicalVersion;
|
|
} catch {
|
|
previousVersion = null;
|
|
}
|
|
|
|
const gatewayVersion = params.fromGateway ? resolveGatewayVersionForIosRelease(rootDir) : null;
|
|
const packageVersion = gatewayVersion?.packageVersion ?? null;
|
|
const nextVersion =
|
|
gatewayVersion?.pinnedIosVersion ?? normalizePinnedIosVersion(params.explicitVersion ?? "");
|
|
const versionFilePath = writeIosVersionManifest(nextVersion, rootDir);
|
|
const syncedPaths = params.sync ? syncIosVersioning({ mode: "write", rootDir }).updatedPaths : [];
|
|
|
|
return {
|
|
previousVersion,
|
|
nextVersion,
|
|
packageVersion,
|
|
versionFilePath,
|
|
syncedPaths,
|
|
};
|
|
}
|
|
|
|
export async function main(argv: string[]): Promise<number> {
|
|
try {
|
|
const options = parseArgs(argv);
|
|
const result = pinIosVersion(options);
|
|
const sourceText = result.packageVersion
|
|
? ` from gateway version ${result.packageVersion}`
|
|
: "";
|
|
process.stdout.write(`Pinned iOS version to ${result.nextVersion}${sourceText}.\n`);
|
|
if (result.previousVersion && result.previousVersion !== result.nextVersion) {
|
|
process.stdout.write(`Previous pinned iOS version: ${result.previousVersion}.\n`);
|
|
}
|
|
process.stdout.write(
|
|
`Updated version manifest: ${path.relative(process.cwd(), result.versionFilePath)}\n`,
|
|
);
|
|
if (options.sync) {
|
|
if (result.syncedPaths.length === 0) {
|
|
process.stdout.write("iOS versioning artifacts already up to date.\n");
|
|
} else {
|
|
process.stdout.write(
|
|
`Updated iOS versioning artifacts:\n- ${result.syncedPaths.map((filePath) => path.relative(process.cwd(), filePath)).join("\n- ")}\n`,
|
|
);
|
|
}
|
|
}
|
|
return 0;
|
|
} catch (error) {
|
|
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
const exitCode = await main(process.argv.slice(2));
|
|
if (exitCode !== 0) {
|
|
process.exit(exitCode);
|
|
}
|
|
}
|