feat: add HWLAB runtime lane control CLI

This commit is contained in:
Codex
2026-06-08 06:48:50 +00:00
parent 8e189385f2
commit fb8c1aaebf
3 changed files with 745 additions and 118 deletions
+36 -3
View File
@@ -1,4 +1,5 @@
import { activeV02PipelineRuns, g14ObservabilityQueryAssertion, gitMirrorFlushJobManifest, gitMirrorStatusSummary, gitMirrorSyncJobManifest, gitMirrorV02SyncRequirement, hwlabG14Help, hwlabG14MonitorStateFileName, parseGitMirrorStatusRefs, parseK8sCpuMillicores, parseK8sMemoryMiB, parsePipelineTaskRunMetrics, parseV02TriggerSnapshot, rolloutRecordBody, semanticChangelogBullets, summarizeV02CdStatus, v02CloseoutVerdict, v02CommitAlignment, v02ControlPlaneRefreshScriptHash, v02ControlPlaneRenderScript, v02ExistingPipelineRunReuseDecision, v02FalseGreenGuard, v02GitMirrorPreSyncWaitMs, v02LatestOnlyTargetValidation, v02PipelineServiceIds, v02PrAutomationCommentBody, v02ReusableGitMirrorPreSyncMarker, v02ReusableRefreshMarker, v02StatusHistoryPolicy, v02TaskRunPerformanceSummary } from "./src/hwlab-g14";
import { hwlabRuntimeLaneIds, hwlabRuntimeLaneSpec } from "./src/hwlab-g14-lanes";
import { runCommand } from "./src/command";
function assertCondition(condition: unknown, message: string, detail: unknown = {}): void {
@@ -44,6 +45,29 @@ assertCondition(
"v0.2 control-plane help must expose targeted PipelineRun/source-commit status, closeout inspection, and cleanup",
hwlabHelpUsage,
);
assertCondition(
hwlabHelpUsage.some((line) => line.includes("control-plane status --lane v03"))
&& hwlabHelpUsage.some((line) => line.includes("control-plane apply --lane v03 --dry-run"))
&& hwlabHelpUsage.some((line) => line.includes("control-plane trigger-current --lane v03 --dry-run"))
&& JSON.stringify(hwlabG14Help()).includes("runtime lane v02/v03"),
"v0.3 control-plane help must expose the runtime lane bootstrap status/apply/trigger entrypoints",
hwlabHelpUsage,
);
const v03LaneSpec = hwlabRuntimeLaneSpec("v03");
assertCondition(
JSON.stringify(hwlabRuntimeLaneIds()) === JSON.stringify(["v02", "v03"])
&& v03LaneSpec.sourceBranch === "v0.3"
&& v03LaneSpec.gitopsBranch === "v0.3-gitops"
&& v03LaneSpec.workspace === "/root/hwlab-v03"
&& v03LaneSpec.cicdRepo === "/root/hwlab-v03-cicd.git"
&& v03LaneSpec.runtimeNamespace === "hwlab-v03"
&& v03LaneSpec.runtimeRenderDir === "runtime-v03"
&& v03LaneSpec.pipeline === "hwlab-v03-ci-image-publish"
&& v03LaneSpec.publicWebUrl.endsWith(":19766")
&& v03LaneSpec.publicApiUrl.endsWith(":19767"),
"runtime lane spec must make v0.3 expansion a config-driven lane instead of scattered literals",
v03LaneSpec,
);
assertCondition(
hwlabHelpUsage.some((line) => line.includes("monitor-prs --lane v02"))
&& hwlabHelpUsage.some((line) => line.includes("monitor-prs --lane v02 --status"))
@@ -52,6 +76,12 @@ assertCondition(
"v0.2 PR monitor help must expose the auto CI/CD lane, status query, latest-only CD, and dedupe comment state",
hwlabG14Help(),
);
assertCondition(
hwlabHelpUsage.some((line) => line.includes("git-mirror apply --lane v02 --confirm"))
&& hwlabHelpUsage.some((line) => line.includes("git-mirror apply --lane v03 --confirm")),
"git mirror help must expose lane-selected apply so v0.3 mirror config is not rendered through v0.2",
hwlabHelpUsage,
);
assertCondition(
hwlabHelpUsage.some((line) => line.includes("secret status --lane v02 --name hwlab-v02-openfga"))
&& hwlabHelpUsage.some((line) => line.includes("secret ensure --lane v02 --name hwlab-v02-openfga --confirm"))
@@ -268,8 +298,10 @@ assertCondition(
&& renderScript.includes("git -C \"$worktree_dir\" checkout --detach \"$source_commit\"")
&& renderScript.includes("npm ci --ignore-scripts --no-audit --prefer-offline")
&& renderScript.includes("bun install --frozen-lockfile --ignore-scripts")
&& renderScript.includes("scripts/run-bun.mjs")
&& renderScript.includes("--lane \"$render_lane\"")
&& renderScript.includes("/tmp/hwlab-v02-control-plane-source-aaaaaaaaaaaa-"),
"v0.2 control-plane render must use an isolated temp clone with lockfile-based dependencies so same-commit concurrent triggers do not share worktree metadata",
"v0.2 control-plane render must use an isolated temp clone with lockfile-based dependencies and the modular Bun renderer fallback",
renderScript,
);
assertCondition(
@@ -308,10 +340,11 @@ assertCondition(
);
assertCondition(
sourceText.includes("function runG14K3sRemoteAsync")
&& sourceText.includes("label: \"v02-control-plane-apply\"")
&& sourceText.includes("function applyRuntimeLaneControlPlaneFiles")
&& sourceText.includes("label: `${spec.lane}-control-plane-apply`")
&& sourceText.includes("remote async command timed out after")
&& sourceText.includes("return runG14K3sRemoteAsync({"),
"v0.2 control-plane apply must use short start/poll remote-async semantics instead of one long G14:k3s apply call",
"runtime lane control-plane apply must use short start/poll remote-async semantics instead of one long G14:k3s apply call",
);
const existingPipelineRunReuse = v02ExistingPipelineRunReuseDecision({
sourceCommit: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+104
View File
@@ -0,0 +1,104 @@
export type HwlabRuntimeLane = "v02" | "v03";
export interface HwlabRuntimeLaneConfig {
readonly lane: HwlabRuntimeLane;
readonly minor: number;
}
export interface HwlabRuntimeLaneSpec {
readonly lane: HwlabRuntimeLane;
readonly minor: number;
readonly version: string;
readonly sourceBranch: string;
readonly workspace: string;
readonly cicdRepo: string;
readonly cicdRepoLock: string;
readonly app: string;
readonly pipeline: string;
readonly pipelineRunPrefix: string;
readonly serviceAccountName: string;
readonly controlPlaneFieldManager: string;
readonly gitUrl: string;
readonly gitReadUrl: string;
readonly gitWriteUrl: string;
readonly gitopsBranch: string;
readonly catalogPath: string;
readonly runtimePath: string;
readonly runtimeNamespace: string;
readonly runtimeRenderDir: string;
readonly tektonDir: string;
readonly argoApplicationFile: string;
readonly registryPrefix: string;
readonly baseImage: string;
readonly serviceIds: readonly string[];
readonly publicWebUrl: string;
readonly publicApiUrl: string;
}
export const HWLAB_RUNTIME_LANE_CONFIGS = [
{ lane: "v02", minor: 2 },
{ lane: "v03", minor: 3 },
] as const satisfies readonly HwlabRuntimeLaneConfig[];
const HWLAB_GIT_URL = "git@github.com:pikasTech/HWLAB.git";
const HWLAB_GIT_READ_URL = "http://git-mirror-http.devops-infra.svc.cluster.local/pikasTech/HWLAB.git";
const HWLAB_GIT_WRITE_URL = "http://git-mirror-write.devops-infra.svc.cluster.local/pikasTech/HWLAB.git";
const HWLAB_REGISTRY_PREFIX = "127.0.0.1:5000/hwlab";
const HWLAB_BASE_IMAGE = "127.0.0.1:5000/hwlab/hwlab-node20-base:20-bookworm-slim";
const HWLAB_SERVICE_IDS = [
"hwlab-cloud-api",
"hwlab-cloud-web",
"hwlab-gateway",
"hwlab-edge-proxy",
"hwlab-agent-skills",
] as const;
function buildRuntimeLaneSpec(config: HwlabRuntimeLaneConfig): HwlabRuntimeLaneSpec {
const version = `v0.${config.minor}`;
const lane = config.lane;
return {
lane,
minor: config.minor,
version,
sourceBranch: version,
workspace: `/root/hwlab-${lane}`,
cicdRepo: `/root/hwlab-${lane}-cicd.git`,
cicdRepoLock: `/tmp/hwlab-${lane}-cicd-repo.lock`,
app: `hwlab-g14-${lane}`,
pipeline: `hwlab-${lane}-ci-image-publish`,
pipelineRunPrefix: `hwlab-${lane}-ci-poll`,
serviceAccountName: `hwlab-${lane}-tekton-runner`,
controlPlaneFieldManager: `unidesk-hwlab-${lane}-control-plane`,
gitUrl: HWLAB_GIT_URL,
gitReadUrl: HWLAB_GIT_READ_URL,
gitWriteUrl: HWLAB_GIT_WRITE_URL,
gitopsBranch: `${version}-gitops`,
catalogPath: `deploy/artifact-catalog.${lane}.json`,
runtimePath: `deploy/gitops/g14/runtime-${lane}`,
runtimeNamespace: `hwlab-${lane}`,
runtimeRenderDir: `runtime-${lane}`,
tektonDir: `tekton-${lane}`,
argoApplicationFile: `application-${lane}.yaml`,
registryPrefix: HWLAB_REGISTRY_PREFIX,
baseImage: HWLAB_BASE_IMAGE,
serviceIds: HWLAB_SERVICE_IDS,
publicWebUrl: `http://74.48.78.17:${19466 + config.minor * 100}`,
publicApiUrl: `http://74.48.78.17:${19467 + config.minor * 100}`,
};
}
const RUNTIME_LANE_SPECS = Object.fromEntries(
HWLAB_RUNTIME_LANE_CONFIGS.map((config) => [config.lane, buildRuntimeLaneSpec(config)]),
) as Record<HwlabRuntimeLane, HwlabRuntimeLaneSpec>;
export function isHwlabRuntimeLane(value: string): value is HwlabRuntimeLane {
return Object.prototype.hasOwnProperty.call(RUNTIME_LANE_SPECS, value);
}
export function hwlabRuntimeLaneSpec(lane: HwlabRuntimeLane): HwlabRuntimeLaneSpec {
return RUNTIME_LANE_SPECS[lane];
}
export function hwlabRuntimeLaneIds(): HwlabRuntimeLane[] {
return HWLAB_RUNTIME_LANE_CONFIGS.map((config) => config.lane);
}
+605 -115
View File
File diff suppressed because it is too large Load Diff