mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-22 10:08:15 +00:00
201 lines
6.1 KiB
TypeScript
201 lines
6.1 KiB
TypeScript
// Android Pin Version script supports OpenClaw repository automation.
|
|
import path from "node:path";
|
|
import {
|
|
canonicalAndroidVersionCode,
|
|
normalizeAndroidVersionCode,
|
|
normalizePinnedAndroidVersion,
|
|
resolveAndroidVersion,
|
|
resolveGatewayVersionForAndroidRelease,
|
|
syncAndroidVersioning,
|
|
writeAndroidVersionManifest,
|
|
} from "./lib/android-version.ts";
|
|
|
|
type CliOptions = {
|
|
explicitVersion: string | null;
|
|
explicitVersionCode: number | null;
|
|
fromGateway: boolean;
|
|
rootDir: string;
|
|
sync: boolean;
|
|
};
|
|
|
|
export type PinAndroidVersionResult = {
|
|
previousVersion: string | null;
|
|
previousVersionCode: number | null;
|
|
nextVersion: string;
|
|
nextVersionCode: number;
|
|
packageVersion: string | null;
|
|
versionFilePath: string;
|
|
syncedPaths: string[];
|
|
};
|
|
|
|
function usage(): string {
|
|
return [
|
|
"Usage: node --import tsx scripts/android-pin-version.ts (--from-gateway | --version <YYYY.M.PATCH>) [--version-code <int>] [--no-sync] [--root dir]",
|
|
"",
|
|
"Examples:",
|
|
" node --import tsx scripts/android-pin-version.ts --from-gateway",
|
|
" node --import tsx scripts/android-pin-version.ts --version 2026.6.5",
|
|
" node --import tsx scripts/android-pin-version.ts --version 2026.6.5 --version-code 2026060502",
|
|
].join("\n");
|
|
}
|
|
|
|
function parseExplicitVersionCode(raw: string): number {
|
|
const text = raw.trim();
|
|
if (!/^[1-9]\d*$/u.test(text)) {
|
|
throw new Error(`Invalid value for --version-code: ${raw}. Expected a positive integer.`);
|
|
}
|
|
const value = Number(text);
|
|
if (!Number.isSafeInteger(value)) {
|
|
throw new Error(`Invalid value for --version-code: ${raw}. Expected a safe integer.`);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
export function parseArgs(argv: string[]): CliOptions {
|
|
let explicitVersion: string | null = null;
|
|
let explicitVersionCode: number | 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 "--version-code": {
|
|
const value = argv[index + 1];
|
|
if (!value) {
|
|
throw new Error("Missing value for --version-code.");
|
|
}
|
|
explicitVersionCode = parseExplicitVersionCode(value);
|
|
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.PATCH>.");
|
|
}
|
|
|
|
if (explicitVersion !== null && !explicitVersion.trim()) {
|
|
throw new Error("Missing value for --version.");
|
|
}
|
|
|
|
return { explicitVersion, explicitVersionCode, fromGateway, rootDir, sync };
|
|
}
|
|
|
|
export function pinAndroidVersion(params: CliOptions): PinAndroidVersionResult {
|
|
const rootDir = path.resolve(params.rootDir);
|
|
let previousVersion: string | null;
|
|
let previousVersionCode: number | null;
|
|
try {
|
|
const currentVersion = resolveAndroidVersion(rootDir);
|
|
previousVersion = currentVersion.canonicalVersion;
|
|
previousVersionCode = currentVersion.versionCode;
|
|
} catch {
|
|
previousVersion = null;
|
|
previousVersionCode = null;
|
|
}
|
|
|
|
const gatewayVersion = params.fromGateway
|
|
? resolveGatewayVersionForAndroidRelease(rootDir)
|
|
: null;
|
|
const packageVersion = gatewayVersion?.packageVersion ?? null;
|
|
const nextVersion =
|
|
gatewayVersion?.pinnedAndroidVersion ??
|
|
normalizePinnedAndroidVersion(params.explicitVersion ?? "");
|
|
const nextVersionCode =
|
|
params.explicitVersionCode === null
|
|
? (gatewayVersion?.versionCode ?? canonicalAndroidVersionCode(nextVersion))
|
|
: normalizeAndroidVersionCode(params.explicitVersionCode, nextVersion);
|
|
const versionFilePath = writeAndroidVersionManifest(nextVersion, nextVersionCode, rootDir);
|
|
const syncedPaths = params.sync
|
|
? syncAndroidVersioning({ mode: "write", rootDir }).updatedPaths
|
|
: [];
|
|
|
|
return {
|
|
previousVersion,
|
|
previousVersionCode,
|
|
nextVersion,
|
|
nextVersionCode,
|
|
packageVersion,
|
|
versionFilePath,
|
|
syncedPaths,
|
|
};
|
|
}
|
|
|
|
export async function main(argv: string[]): Promise<number> {
|
|
try {
|
|
const options = parseArgs(argv);
|
|
const result = pinAndroidVersion(options);
|
|
const sourceText = result.packageVersion
|
|
? ` from gateway version ${result.packageVersion}`
|
|
: "";
|
|
process.stdout.write(
|
|
`Pinned Android version to ${result.nextVersion} (${result.nextVersionCode})${sourceText}.\n`,
|
|
);
|
|
if (
|
|
result.previousVersion &&
|
|
(result.previousVersion !== result.nextVersion ||
|
|
result.previousVersionCode !== result.nextVersionCode)
|
|
) {
|
|
process.stdout.write(
|
|
`Previous pinned Android version: ${result.previousVersion} (${result.previousVersionCode}).\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("Android versioning artifacts already up to date.\n");
|
|
} else {
|
|
process.stdout.write(
|
|
`Updated Android 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);
|
|
}
|
|
}
|