fix: use k8s git mirror source snapshots
This commit is contained in:
@@ -323,6 +323,20 @@ export interface HwlabRuntimeImageBuildSpec {
|
||||
readonly dockerNetworkMode: "default" | "host";
|
||||
}
|
||||
|
||||
export interface HwlabRuntimeSourceAuthoritySpec {
|
||||
readonly mode: "gitMirrorSnapshot";
|
||||
readonly resolver: "k8s-git-mirror";
|
||||
readonly allowHostGit: false;
|
||||
readonly allowHostWorkspace: false;
|
||||
readonly allowGithubDirectInPipeline: false;
|
||||
}
|
||||
|
||||
export interface HwlabRuntimeSourceSnapshotSpec {
|
||||
readonly stageRefPrefix: string;
|
||||
readonly missingObjectPolicy: "fail-fast";
|
||||
readonly refreshPolicy: "sync-before-snapshot";
|
||||
}
|
||||
|
||||
export interface HwlabRuntimePublicExposureFrpcProxySpec {
|
||||
readonly name: string;
|
||||
readonly localIP: string;
|
||||
@@ -450,6 +464,8 @@ export interface HwlabRuntimeLaneSpec {
|
||||
readonly minor: number;
|
||||
readonly version: string;
|
||||
readonly sourceBranch: string;
|
||||
readonly sourceAuthority?: HwlabRuntimeSourceAuthoritySpec;
|
||||
readonly sourceSnapshot?: HwlabRuntimeSourceSnapshotSpec;
|
||||
readonly workspace: string;
|
||||
readonly cicdRepo: string;
|
||||
readonly cicdRepoLock: string;
|
||||
@@ -498,6 +514,16 @@ export function hwlabRuntimeActiveExternalPostgres(spec: HwlabRuntimeLaneSpec):
|
||||
return spec.runtimeStore?.postgres?.mode === "platform-service" ? spec.externalPostgres : undefined;
|
||||
}
|
||||
|
||||
export function hwlabRuntimeSourceSnapshotStageRefPrefix(spec: HwlabRuntimeLaneSpec): string {
|
||||
if (spec.sourceSnapshot === undefined) throw new Error(`${HWLAB_NODE_LANE_CONFIG_PATH} lanes.${spec.lane}.sourceSnapshot is required for k8s git-mirror snapshot source authority`);
|
||||
return spec.sourceSnapshot.stageRefPrefix.replaceAll("{branch}", spec.sourceBranch);
|
||||
}
|
||||
|
||||
export function hwlabRuntimeSourceSnapshotRef(spec: HwlabRuntimeLaneSpec, sourceCommit: string): string {
|
||||
if (!/^[0-9a-f]{40}$/iu.test(sourceCommit)) throw new Error(`sourceCommit must be a 40-hex git SHA for source snapshot ref: ${sourceCommit}`);
|
||||
return `${hwlabRuntimeSourceSnapshotStageRefPrefix(spec).replace(/\/+$/u, "")}/${sourceCommit.toLowerCase()}`;
|
||||
}
|
||||
|
||||
export const HWLAB_NODE_LANE_CONFIG_PATH = "config/hwlab-node-lanes.yaml";
|
||||
|
||||
interface HwlabLaneConfig {
|
||||
@@ -507,6 +533,8 @@ interface HwlabLaneConfig {
|
||||
readonly minor: number;
|
||||
readonly version: string;
|
||||
readonly sourceBranch: string;
|
||||
readonly sourceAuthority?: HwlabRuntimeSourceAuthoritySpec;
|
||||
readonly sourceSnapshot?: HwlabRuntimeSourceSnapshotSpec;
|
||||
readonly workspace: string;
|
||||
readonly cicdRepo: string;
|
||||
readonly cicdRepoLock: string;
|
||||
@@ -735,6 +763,8 @@ function laneConfig(id: HwlabRuntimeLane, raw: Record<string, unknown>): HwlabLa
|
||||
const minor = numberField(raw, "minor", `lanes.${id}`);
|
||||
const version = stringField(raw, "version", `lanes.${id}`);
|
||||
if (version !== `v0.${minor}`) throw new Error(`lanes.${id}.version must equal v0.${minor}`);
|
||||
if (minor >= 3 && raw.sourceAuthority === undefined) throw new Error(`lanes.${id}.sourceAuthority is required for HWLAB runtime v0.3+`);
|
||||
if (minor >= 3 && raw.sourceSnapshot === undefined) throw new Error(`lanes.${id}.sourceSnapshot is required for HWLAB runtime v0.3+`);
|
||||
return {
|
||||
id,
|
||||
node: stringField(raw, "node", `lanes.${id}`),
|
||||
@@ -742,6 +772,8 @@ function laneConfig(id: HwlabRuntimeLane, raw: Record<string, unknown>): HwlabLa
|
||||
minor,
|
||||
version,
|
||||
sourceBranch: stringField(raw, "sourceBranch", `lanes.${id}`),
|
||||
sourceAuthority: sourceAuthorityConfig(raw.sourceAuthority, `lanes.${id}.sourceAuthority`),
|
||||
sourceSnapshot: sourceSnapshotConfig(raw.sourceSnapshot, `lanes.${id}.sourceSnapshot`),
|
||||
workspace: stringField(raw, "workspace", `lanes.${id}`),
|
||||
cicdRepo: stringField(raw, "cicdRepo", `lanes.${id}`),
|
||||
cicdRepoLock: stringField(raw, "cicdRepoLock", `lanes.${id}`),
|
||||
@@ -805,6 +837,8 @@ function laneTargetConfig(id: HwlabRuntimeLane, nodeId: string, baseRaw: Record<
|
||||
bootstrapAdmin: mergeOptionalRecord(baseRaw.bootstrapAdmin, targetRaw.bootstrapAdmin),
|
||||
codeAgentProvider: mergeOptionalRecord(baseRaw.codeAgentProvider, targetRaw.codeAgentProvider),
|
||||
codeAgentRuntime: mergeOptionalRecord(baseRaw.codeAgentRuntime, targetRaw.codeAgentRuntime),
|
||||
sourceAuthority: mergeOptionalRecord(baseRaw.sourceAuthority, targetRaw.sourceAuthority),
|
||||
sourceSnapshot: mergeOptionalRecord(baseRaw.sourceSnapshot, targetRaw.sourceSnapshot),
|
||||
sourceWorkspace: mergeOptionalRecord(baseRaw.sourceWorkspace, targetRaw.sourceWorkspace),
|
||||
externalPostgres: mergeOptionalRecord(baseRaw.externalPostgres, targetRaw.externalPostgres),
|
||||
runtimeStore: mergeOptionalRecord(baseRaw.runtimeStore, targetRaw.runtimeStore),
|
||||
@@ -817,6 +851,38 @@ function laneTargetConfig(id: HwlabRuntimeLane, nodeId: string, baseRaw: Record<
|
||||
return laneConfig(id, merged);
|
||||
}
|
||||
|
||||
function sourceAuthorityConfig(value: unknown, path: string): HwlabRuntimeSourceAuthoritySpec | undefined {
|
||||
if (value === undefined) return undefined;
|
||||
const raw = asRecord(value, path);
|
||||
return {
|
||||
mode: enumStringField(raw, "mode", path, ["gitMirrorSnapshot"]),
|
||||
resolver: enumStringField(raw, "resolver", path, ["k8s-git-mirror"]),
|
||||
allowHostGit: falseBooleanField(raw, "allowHostGit", path),
|
||||
allowHostWorkspace: falseBooleanField(raw, "allowHostWorkspace", path),
|
||||
allowGithubDirectInPipeline: falseBooleanField(raw, "allowGithubDirectInPipeline", path),
|
||||
};
|
||||
}
|
||||
|
||||
function sourceSnapshotConfig(value: unknown, path: string): HwlabRuntimeSourceSnapshotSpec | undefined {
|
||||
if (value === undefined) return undefined;
|
||||
const raw = asRecord(value, path);
|
||||
const stageRefPrefix = stringField(raw, "stageRefPrefix", path);
|
||||
if (!stageRefPrefix.startsWith("refs/")) throw new Error(`${path}.stageRefPrefix must start with refs/`);
|
||||
if (stageRefPrefix.includes("..") || /\s/u.test(stageRefPrefix)) throw new Error(`${path}.stageRefPrefix must not contain whitespace or ..`);
|
||||
if (!stageRefPrefix.includes("{branch}")) throw new Error(`${path}.stageRefPrefix must include {branch}`);
|
||||
return {
|
||||
stageRefPrefix,
|
||||
missingObjectPolicy: enumStringField(raw, "missingObjectPolicy", path, ["fail-fast"]),
|
||||
refreshPolicy: enumStringField(raw, "refreshPolicy", path, ["sync-before-snapshot"]),
|
||||
};
|
||||
}
|
||||
|
||||
function falseBooleanField(obj: Record<string, unknown>, key: string, path: string): false {
|
||||
const value = booleanField(obj, key, path);
|
||||
if (value !== false) throw new Error(`${path}.${key} must be false`);
|
||||
return false;
|
||||
}
|
||||
|
||||
function buildkitConfig(value: unknown, path: string): HwlabRuntimeBuildkitSpec | undefined {
|
||||
if (value === undefined) return undefined;
|
||||
const raw = asRecord(value, path);
|
||||
@@ -1682,6 +1748,8 @@ function buildRuntimeLaneSpec(config: HwlabLaneConfig): HwlabRuntimeLaneSpec {
|
||||
minor: config.minor,
|
||||
version: config.version,
|
||||
sourceBranch: config.sourceBranch,
|
||||
...(config.sourceAuthority === undefined ? {} : { sourceAuthority: config.sourceAuthority }),
|
||||
...(config.sourceSnapshot === undefined ? {} : { sourceSnapshot: config.sourceSnapshot }),
|
||||
workspace: config.workspace,
|
||||
cicdRepo: config.cicdRepo,
|
||||
cicdRepoLock: config.cicdRepoLock,
|
||||
|
||||
Reference in New Issue
Block a user