Vendor OpenClaw source as Adolf fork baseline
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11), free to diverge. Tree copied sans upstream .git; upstream remote added for future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19. Preserves docs/ARCHITECTURE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
This commit is contained in:
376
scripts/mobile-release-ref.ts
Normal file
376
scripts/mobile-release-ref.ts
Normal file
@@ -0,0 +1,376 @@
|
||||
// Tracks uploaded mobile store builds with non-tag Git refs.
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { existsSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
|
||||
export type MobileReleasePlatform = "ios" | "android";
|
||||
export type MobileReleaseCommand = "preflight" | "record" | "resolve";
|
||||
|
||||
type GitDeps = {
|
||||
execFileSync?: typeof execFileSync;
|
||||
};
|
||||
|
||||
type MobileReleaseOptions = {
|
||||
build: string | null;
|
||||
command: MobileReleaseCommand;
|
||||
platform: MobileReleasePlatform;
|
||||
remote: string;
|
||||
rootDir: string;
|
||||
sha: string;
|
||||
version: string;
|
||||
versionCode: string | null;
|
||||
};
|
||||
|
||||
type RemoteRefState = {
|
||||
ref: string;
|
||||
sha: string;
|
||||
} | null;
|
||||
|
||||
const REF_PREFIX = "refs/openclaw/mobile-releases";
|
||||
const VERSION_RE = /^20\d{2}\.(?:[1-9]\d?)\.(?:[1-9]\d*)$/u;
|
||||
const POSITIVE_INTEGER_RE = /^[1-9]\d*$/u;
|
||||
|
||||
function git(args: string[], rootDir: string, deps: GitDeps = {}): string {
|
||||
const exec = deps.execFileSync ?? execFileSync;
|
||||
return exec("git", args, {
|
||||
cwd: rootDir,
|
||||
encoding: "utf8",
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
maxBuffer: 16 * 1024 * 1024,
|
||||
});
|
||||
}
|
||||
|
||||
function errorOutput(value: unknown): string {
|
||||
if (Buffer.isBuffer(value)) {
|
||||
return value.toString("utf8");
|
||||
}
|
||||
if (typeof value === "string") {
|
||||
return value;
|
||||
}
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
return JSON.stringify(value) ?? Object.prototype.toString.call(value);
|
||||
}
|
||||
|
||||
function gitAllowFailure(
|
||||
args: string[],
|
||||
rootDir: string,
|
||||
deps: GitDeps = {},
|
||||
): { ok: boolean; stdout: string; stderr: string } {
|
||||
try {
|
||||
return { ok: true, stdout: git(args, rootDir, deps), stderr: "" };
|
||||
} catch (error) {
|
||||
const e = error as { stdout?: unknown; stderr?: unknown };
|
||||
const stdout = errorOutput(e.stdout);
|
||||
const stderr = errorOutput(e.stderr);
|
||||
return { ok: false, stdout, stderr };
|
||||
}
|
||||
}
|
||||
|
||||
function readOptionValue(argv: string[], index: number, flag: string): string {
|
||||
const value = argv[index + 1];
|
||||
if (!value || value.startsWith("-")) {
|
||||
throw new Error(`Missing value for ${flag}.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function parsePlatform(raw: string | null): MobileReleasePlatform {
|
||||
if (raw === "ios" || raw === "android") {
|
||||
return raw;
|
||||
}
|
||||
throw new Error("Missing or invalid --platform. Expected ios or android.");
|
||||
}
|
||||
|
||||
function parseCommand(raw: string | undefined): MobileReleaseCommand {
|
||||
if (raw === "-h" || raw === "--help") {
|
||||
throw new Error(usage());
|
||||
}
|
||||
if (raw === "preflight" || raw === "record" || raw === "resolve") {
|
||||
return raw;
|
||||
}
|
||||
throw new Error(`Unknown command '${raw ?? ""}'. Expected preflight, record, or resolve.`);
|
||||
}
|
||||
|
||||
export function parseArgs(argv: string[]): MobileReleaseOptions {
|
||||
const command = parseCommand(argv[0]);
|
||||
let build: string | null = null;
|
||||
let platform: string | null = null;
|
||||
let remote = "origin";
|
||||
let rootDir = path.resolve(".");
|
||||
let sha = "HEAD";
|
||||
let version = "";
|
||||
let versionCode: string | null = null;
|
||||
|
||||
for (let index = 1; index < argv.length; index += 1) {
|
||||
const arg = argv[index];
|
||||
switch (arg) {
|
||||
case "--":
|
||||
break;
|
||||
case "--platform":
|
||||
platform = readOptionValue(argv, index, arg);
|
||||
index += 1;
|
||||
break;
|
||||
case "--version":
|
||||
version = readOptionValue(argv, index, arg);
|
||||
index += 1;
|
||||
break;
|
||||
case "--build":
|
||||
build = readOptionValue(argv, index, arg);
|
||||
index += 1;
|
||||
break;
|
||||
case "--version-code":
|
||||
versionCode = readOptionValue(argv, index, arg);
|
||||
index += 1;
|
||||
break;
|
||||
case "--sha":
|
||||
sha = readOptionValue(argv, index, arg);
|
||||
index += 1;
|
||||
break;
|
||||
case "--remote":
|
||||
remote = readOptionValue(argv, index, arg);
|
||||
index += 1;
|
||||
break;
|
||||
case "--root":
|
||||
rootDir = path.resolve(readOptionValue(argv, index, arg));
|
||||
index += 1;
|
||||
break;
|
||||
case "-h":
|
||||
case "--help":
|
||||
throw new Error(usage());
|
||||
default:
|
||||
throw new Error(`Unknown argument: ${arg}`);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
build,
|
||||
command,
|
||||
platform: parsePlatform(platform),
|
||||
remote,
|
||||
rootDir,
|
||||
sha,
|
||||
version,
|
||||
versionCode,
|
||||
};
|
||||
}
|
||||
|
||||
function validateVersion(version: string): string {
|
||||
const trimmed = version.trim();
|
||||
if (!VERSION_RE.test(trimmed)) {
|
||||
throw new Error(`Invalid mobile release version '${version}'. Expected YYYY.M.D.`);
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
function validatePositiveInteger(label: string, value: string | null): string {
|
||||
const trimmed = value?.trim() ?? "";
|
||||
if (!POSITIVE_INTEGER_RE.test(trimmed)) {
|
||||
throw new Error(`Invalid ${label} '${value ?? ""}'. Expected a positive integer.`);
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
function androidVersionCodePrefix(version: string): string {
|
||||
const [year, rawMonth, rawPatch] = version.split(".");
|
||||
return `${year}${rawMonth?.padStart(2, "0")}${rawPatch?.padStart(2, "0")}`;
|
||||
}
|
||||
|
||||
function validateAndroidVersionCode(version: string, versionCode: string | null): string {
|
||||
const code = validatePositiveInteger("Android versionCode", versionCode);
|
||||
const prefix = androidVersionCodePrefix(version);
|
||||
const suffix = Number.parseInt(code.slice(prefix.length), 10);
|
||||
if (
|
||||
!code.startsWith(prefix) ||
|
||||
code.length !== prefix.length + 2 ||
|
||||
!Number.isInteger(suffix) ||
|
||||
suffix < 1 ||
|
||||
suffix > 99
|
||||
) {
|
||||
throw new Error(
|
||||
`Invalid Android versionCode '${code}'. Expected ${prefix}01 through ${prefix}99 for version ${version}.`,
|
||||
);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
export function mobileReleaseRefFor(options: {
|
||||
build?: string | null;
|
||||
platform: MobileReleasePlatform;
|
||||
version: string;
|
||||
versionCode?: string | null;
|
||||
}): string {
|
||||
const version = validateVersion(options.version);
|
||||
if (options.platform === "ios") {
|
||||
const build = validatePositiveInteger("iOS build", options.build ?? null);
|
||||
return `${REF_PREFIX}/ios/${version}-${build}`;
|
||||
}
|
||||
|
||||
const versionCode = validateAndroidVersionCode(version, options.versionCode ?? null);
|
||||
return `${REF_PREFIX}/android/${version}-${versionCode}`;
|
||||
}
|
||||
|
||||
function assertRootDir(rootDir: string): void {
|
||||
if (!existsSync(path.join(rootDir, ".git"))) {
|
||||
throw new Error(`Not a Git checkout root: ${rootDir}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveCommitSha(sha: string, rootDir: string, deps: GitDeps = {}): string {
|
||||
return git(["rev-parse", "--verify", `${sha}^{commit}`], rootDir, deps).trim();
|
||||
}
|
||||
|
||||
export function readRemoteRef(
|
||||
remote: string,
|
||||
ref: string,
|
||||
rootDir: string,
|
||||
deps: GitDeps = {},
|
||||
): RemoteRefState {
|
||||
const result = gitAllowFailure(["ls-remote", "--refs", remote, ref], rootDir, deps);
|
||||
if (!result.ok) {
|
||||
const detail = (result.stderr || result.stdout).trim();
|
||||
throw new Error(`Failed to inspect remote release ref ${ref}: ${detail}`);
|
||||
}
|
||||
|
||||
const line = result.stdout.trim();
|
||||
if (!line) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [sha, remoteRef] = line.split(/\s+/u);
|
||||
if (!sha || remoteRef !== ref) {
|
||||
throw new Error(`Unexpected remote ref lookup output for ${ref}: ${line}`);
|
||||
}
|
||||
return { ref: remoteRef, sha };
|
||||
}
|
||||
|
||||
function shortSha(sha: string): string {
|
||||
return sha.slice(0, 12);
|
||||
}
|
||||
|
||||
function recoveryCommand(options: { ref: string; remote: string; sha: string }): string {
|
||||
return `git push --force-with-lease=${options.ref}: ${options.remote} ${options.sha}:${options.ref}`;
|
||||
}
|
||||
|
||||
export function preflightMobileReleaseRef(
|
||||
options: MobileReleaseOptions,
|
||||
deps: GitDeps = {},
|
||||
): { ref: string; sha: string; status: "available" | "already-recorded" } {
|
||||
assertRootDir(options.rootDir);
|
||||
const ref = mobileReleaseRefFor(options);
|
||||
const sha = resolveCommitSha(options.sha, options.rootDir, deps);
|
||||
const existing = readRemoteRef(options.remote, ref, options.rootDir, deps);
|
||||
|
||||
if (!existing) {
|
||||
return { ref, sha, status: "available" };
|
||||
}
|
||||
if (existing.sha === sha) {
|
||||
return { ref, sha, status: "already-recorded" };
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Mobile release ref ${ref} already points at ${existing.sha}; refusing to record ${sha}.`,
|
||||
);
|
||||
}
|
||||
|
||||
export function recordMobileReleaseRef(
|
||||
options: MobileReleaseOptions,
|
||||
deps: GitDeps = {},
|
||||
): { ref: string; sha: string; status: "created" | "already-recorded" } {
|
||||
const preflight = preflightMobileReleaseRef(options, deps);
|
||||
if (preflight.status === "already-recorded") {
|
||||
return { ...preflight, status: "already-recorded" };
|
||||
}
|
||||
|
||||
const pushArgs = [
|
||||
"push",
|
||||
`--force-with-lease=${preflight.ref}:`,
|
||||
options.remote,
|
||||
`${preflight.sha}:${preflight.ref}`,
|
||||
];
|
||||
const result = gitAllowFailure(pushArgs, options.rootDir, deps);
|
||||
if (!result.ok) {
|
||||
const detail = (result.stderr || result.stdout).trim();
|
||||
throw new Error(
|
||||
`Failed to create mobile release ref ${preflight.ref}. Recovery command:\n${recoveryCommand({
|
||||
ref: preflight.ref,
|
||||
remote: options.remote,
|
||||
sha: preflight.sha,
|
||||
})}\n${detail}`,
|
||||
);
|
||||
}
|
||||
|
||||
const recorded = readRemoteRef(options.remote, preflight.ref, options.rootDir, deps);
|
||||
if (recorded?.sha !== preflight.sha) {
|
||||
throw new Error(
|
||||
`Mobile release ref ${preflight.ref} was not recorded at ${preflight.sha}; remote has ${recorded?.sha ?? "no ref"}.`,
|
||||
);
|
||||
}
|
||||
|
||||
return { ref: preflight.ref, sha: preflight.sha, status: "created" };
|
||||
}
|
||||
|
||||
export function resolveMobileReleaseRef(
|
||||
options: MobileReleaseOptions,
|
||||
deps: GitDeps = {},
|
||||
): { ref: string; sha: string } {
|
||||
assertRootDir(options.rootDir);
|
||||
const ref = mobileReleaseRefFor(options);
|
||||
const existing = readRemoteRef(options.remote, ref, options.rootDir, deps);
|
||||
if (!existing) {
|
||||
throw new Error(`Mobile release ref ${ref} does not exist on ${options.remote}.`);
|
||||
}
|
||||
return { ref, sha: existing.sha };
|
||||
}
|
||||
|
||||
function usage(): string {
|
||||
return [
|
||||
"Usage:",
|
||||
" node --import tsx scripts/mobile-release-ref.ts preflight --platform ios --version YYYY.M.D --build N [--sha HEAD] [--remote origin]",
|
||||
" node --import tsx scripts/mobile-release-ref.ts record --platform android --version YYYY.M.D --version-code YYYYMMDDNN [--sha HEAD] [--remote origin]",
|
||||
" node --import tsx scripts/mobile-release-ref.ts resolve --platform ios --version YYYY.M.D --build N [--remote origin]",
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
async function main(argv: string[]): Promise<number> {
|
||||
try {
|
||||
const options = parseArgs(argv);
|
||||
if (options.command === "preflight") {
|
||||
const result = preflightMobileReleaseRef(options);
|
||||
const suffix =
|
||||
result.status === "already-recorded"
|
||||
? `already records ${shortSha(result.sha)}`
|
||||
: `available for ${shortSha(result.sha)}`;
|
||||
process.stdout.write(`Mobile release ref ${result.ref} is ${suffix}.\n`);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (options.command === "record") {
|
||||
const result = recordMobileReleaseRef(options);
|
||||
const verb = result.status === "already-recorded" ? "already records" : "recorded";
|
||||
process.stdout.write(`Mobile release ref ${result.ref} ${verb} ${result.sha}.\n`);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const result = resolveMobileReleaseRef(options);
|
||||
process.stdout.write(`${result.sha}\t${result.ref}\n`);
|
||||
return 0;
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
if (message.startsWith("Usage:")) {
|
||||
process.stdout.write(`${message}\n`);
|
||||
return 0;
|
||||
}
|
||||
process.stderr.write(`${message}\n`);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (import.meta.url === pathToFileURL(path.resolve(process.argv[1] ?? "")).href) {
|
||||
const exitCode = await main(process.argv.slice(2));
|
||||
if (exitCode !== 0) {
|
||||
process.exit(exitCode);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user