// 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); }