122 lines
6.1 KiB
TypeScript
122 lines
6.1 KiB
TypeScript
// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. source module for scripts/src/hwlab-g14.ts.
|
|
|
|
// Moved mechanically from scripts/src/hwlab-g14.ts:1205-1308 for #903.
|
|
|
|
import { chmodSync, existsSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
import { dirname, join } from "node:path";
|
|
import { createHash, randomBytes } from "node:crypto";
|
|
import { repoRoot, rootPath, type Config } from "../config";
|
|
import { runCommand } from "../command";
|
|
import { cancelJob, listJobs, readJob, startJob } from "../jobs";
|
|
import { hwlabRequiredNoProxyEntries, hwlabRuntimeLaneConfigPath, hwlabRuntimeLaneIds, hwlabRuntimeLaneSpec, isHwlabRuntimeLane, type HwlabRuntimeLane, type HwlabRuntimeLaneSpec } from "../hwlab-node-lanes";
|
|
|
|
import type { CommandJsonResult } from "./types";
|
|
import { g14HostScript } from "./images";
|
|
import { statusText } from "./pr-monitor";
|
|
import { commandJson, isCommandSuccess, nested, shellQuote, shortSha } from "./remote";
|
|
import { V02_GIT_URL, V02_LANE_SPEC } from "./types";
|
|
|
|
export function runtimeLaneCicdRepoEnsureScript(spec: HwlabRuntimeLaneSpec): string {
|
|
return [
|
|
`cicd_repo=${shellQuote(spec.cicdRepo)}`,
|
|
`cicd_url=${shellQuote(spec.gitUrl)}`,
|
|
`cicd_branch=${shellQuote(spec.sourceBranch)}`,
|
|
`cicd_repo_lock=${shellQuote(spec.cicdRepoLock)}`,
|
|
"cicd_repo_ensure_fetch() {",
|
|
" mkdir -p \"$(dirname \"$cicd_repo\")\" || return $?",
|
|
" if [ -d \"$cicd_repo/objects\" ] && [ -f \"$cicd_repo/HEAD\" ]; then",
|
|
" :",
|
|
" elif [ -e \"$cicd_repo\" ]; then",
|
|
` echo "${spec.version} CI/CD repo path exists but is not a bare git repo: $cicd_repo" >&2`,
|
|
" return 41",
|
|
" else",
|
|
" git clone --bare \"$cicd_url\" \"$cicd_repo\" || return $?",
|
|
" fi",
|
|
" git --git-dir=\"$cicd_repo\" remote set-url origin \"$cicd_url\" 2>/dev/null || git --git-dir=\"$cicd_repo\" remote add origin \"$cicd_url\" || return $?",
|
|
" git --git-dir=\"$cicd_repo\" config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*' || return $?",
|
|
" git --git-dir=\"$cicd_repo\" fetch origin \"+refs/heads/$cicd_branch:refs/remotes/origin/$cicd_branch\" --prune || return $?",
|
|
"}",
|
|
"cicd_repo_lock_mode=none",
|
|
"if command -v flock >/dev/null 2>&1; then",
|
|
" exec 9>\"$cicd_repo_lock\"",
|
|
` flock -w 120 9 || { echo "timed out waiting for ${spec.version} CI/CD repo lock: $cicd_repo_lock" >&2; exit 42; }`,
|
|
" cicd_repo_lock_mode=flock",
|
|
"else",
|
|
" cicd_repo_lock_dir=\"$cicd_repo_lock.d\"",
|
|
" cicd_repo_lock_attempt=0",
|
|
" while ! mkdir \"$cicd_repo_lock_dir\" 2>/dev/null; do",
|
|
" cicd_repo_lock_attempt=$((cicd_repo_lock_attempt + 1))",
|
|
` if [ "$cicd_repo_lock_attempt" -ge 120 ]; then echo "timed out waiting for ${spec.version} CI/CD repo lock: $cicd_repo_lock_dir" >&2; exit 42; fi`,
|
|
" sleep 1",
|
|
" done",
|
|
" cicd_repo_lock_mode=dir",
|
|
"fi",
|
|
"cicd_repo_status=0",
|
|
"cicd_repo_ensure_fetch || cicd_repo_status=$?",
|
|
"if [ \"$cicd_repo_lock_mode\" = flock ]; then flock -u 9 >/dev/null 2>&1 || true; fi",
|
|
"if [ \"$cicd_repo_lock_mode\" = dir ]; then rmdir \"$cicd_repo_lock_dir\" >/dev/null 2>&1 || true; fi",
|
|
`if [ "$cicd_repo_status" -ne 0 ]; then echo "${spec.version} CI/CD repo refresh failed status=$cicd_repo_status repo=$cicd_repo" >&2; exit "$cicd_repo_status"; fi`,
|
|
].join("\n");
|
|
}
|
|
|
|
export function v02CicdRepoEnsureScript(): string {
|
|
return runtimeLaneCicdRepoEnsureScript(V02_LANE_SPEC);
|
|
}
|
|
|
|
export function resolveV02Head(): { sourceCommit: string | null; result: CommandJsonResult } {
|
|
const result = g14HostScript([
|
|
"set -eu",
|
|
v02CicdRepoEnsureScript(),
|
|
"git --git-dir=\"$cicd_repo\" rev-parse refs/remotes/origin/v0.2",
|
|
].join("\n"), 180_000);
|
|
if (!isCommandSuccess(result)) return { sourceCommit: null, result };
|
|
const output = String(nested(result.parsed, ["data", "stdout"]) ?? result.stdout).trim();
|
|
const match = /[0-9a-f]{40}/iu.exec(output);
|
|
return { sourceCommit: match?.[0] ?? null, result };
|
|
}
|
|
|
|
export function getV02Head(): string | null {
|
|
return resolveV02Head().sourceCommit;
|
|
}
|
|
|
|
export function resolveV02LatestRemoteHead(): { sourceCommit: string | null; result: CommandJsonResult } {
|
|
const result = commandJson(["git", "ls-remote", V02_GIT_URL, "refs/heads/v0.2"], 30_000);
|
|
if (!isCommandSuccess(result)) return { sourceCommit: null, result };
|
|
const output = statusText(result);
|
|
const match = /^[0-9a-f]{40}/imu.exec(output);
|
|
return { sourceCommit: match?.[0] ?? null, result };
|
|
}
|
|
|
|
export function resolveRuntimeLaneHead(spec: HwlabRuntimeLaneSpec): { sourceCommit: string | null; result: CommandJsonResult } {
|
|
const result = g14HostScript([
|
|
"set -eu",
|
|
runtimeLaneCicdRepoEnsureScript(spec),
|
|
`git --git-dir="$cicd_repo" rev-parse refs/remotes/origin/${spec.sourceBranch}`,
|
|
].join("\n"), 180_000);
|
|
if (!isCommandSuccess(result)) return { sourceCommit: null, result };
|
|
const output = String(nested(result.parsed, ["data", "stdout"]) ?? result.stdout).trim();
|
|
const match = /[0-9a-f]{40}/iu.exec(output);
|
|
return { sourceCommit: match?.[0] ?? null, result };
|
|
}
|
|
|
|
export function resolveRuntimeLaneLatestRemoteHead(spec: HwlabRuntimeLaneSpec): { sourceCommit: string | null; result: CommandJsonResult } {
|
|
const result = commandJson(["git", "ls-remote", spec.gitUrl, `refs/heads/${spec.sourceBranch}`], 30_000);
|
|
if (!isCommandSuccess(result)) return { sourceCommit: null, result };
|
|
const output = statusText(result);
|
|
const match = /^[0-9a-f]{40}/imu.exec(output);
|
|
return { sourceCommit: match?.[0] ?? null, result };
|
|
}
|
|
|
|
export function runtimeLanePipelineRunName(spec: HwlabRuntimeLaneSpec, sourceCommit: string): string {
|
|
return `${spec.pipelineRunPrefix}-${shortSha(sourceCommit)}`;
|
|
}
|
|
|
|
export function runtimeLaneRerunPipelineRunName(spec: HwlabRuntimeLaneSpec, sourceCommit: string, now = new Date()): string {
|
|
const stamp = now.toISOString().replace(/\D/gu, "").slice(0, 14);
|
|
return `${runtimeLanePipelineRunName(spec, sourceCommit)}-r${stamp}`;
|
|
}
|
|
|
|
export function v02PipelineRunName(sourceCommit: string): string {
|
|
return runtimeLanePipelineRunName(V02_LANE_SPEC, sourceCommit);
|
|
}
|