fix: patch runtime GitOps YAML workloads

This commit is contained in:
Codex
2026-07-14 00:29:19 +02:00
parent 700b5eec89
commit 8b518b0fb2
2 changed files with 157 additions and 17 deletions
@@ -2,8 +2,12 @@
// SPEC: PJ2026-01060703 CI/CD branch follower runtime GitOps postprocess.
// Responsibility: mutate rendered runtime GitOps files after HWLAB source render, before publish.
import { existsSync, readdirSync, readFileSync, statSync, unlinkSync, writeFileSync } from "node:fs";
import { createRequire } from "node:module";
import path from "node:path";
const requireFromScript = createRequire(import.meta.url);
const requireFromCwd = createRequire(path.join(process.cwd(), "package.json"));
const YAML = requireYaml();
const repoDir = process.cwd();
const overlay = readOverlay();
const runtimePath = requiredOverlayString("runtimePath");
@@ -45,28 +49,29 @@ function patchCodeAgentRuntimeWorkloads() {
const kafka = runtime.kafkaEventBridge;
let changed = false;
for (const file of listYamlFiles(runtimeDir)) {
const parsed = parseJsonDocument(readFileSync(file, "utf8"));
if (parsed === null) continue;
const items = isKubernetesList(parsed) ? parsed.items : [parsed];
const documents = parseStructuredDocuments(readFileSync(file, "utf8"), file);
let fileChanged = false;
for (const item of items) {
const workloadName = String(item?.metadata?.labels?.["app.kubernetes.io/name"] ?? item?.metadata?.name ?? "");
const containers = item?.spec?.template?.spec?.containers;
if (!Array.isArray(containers)) continue;
for (const container of containers) {
if (!Array.isArray(container?.env)) continue;
if (workloadName === "hwlab-cloud-api" && container.name === "hwlab-cloud-api") {
fileChanged = patchCloudApiKafkaEnv(container, kafka) || fileChanged;
}
if (workloadName === "hwlab-cloud-web" && container.name === "hwlab-cloud-web") {
fileChanged = setEnvValue(container, "HWLAB_WORKBENCH_LIVE_KAFKA_SSE_ENABLED", String(kafka.enabled && kafka.features.liveKafkaSse)) || fileChanged;
fileChanged = setEnvValue(container, "HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_ENABLED", String(kafka.enabled && kafka.features.kafkaRefreshReplay)) || fileChanged;
fileChanged = setEnvValue(container, "HWLAB_WORKBENCH_PROJECTION_REALTIME_ENABLED", String(kafka.enabled && kafka.features.projectionRealtime)) || fileChanged;
for (const document of documents.values) {
const items = isKubernetesList(document) ? document.items : [document];
for (const item of items) {
const workloadName = String(item?.metadata?.labels?.["app.kubernetes.io/name"] ?? item?.metadata?.name ?? "");
const containers = item?.spec?.template?.spec?.containers;
if (!Array.isArray(containers)) continue;
for (const container of containers) {
if (!Array.isArray(container?.env)) continue;
if (workloadName === "hwlab-cloud-api" && container.name === "hwlab-cloud-api") {
fileChanged = patchCloudApiKafkaEnv(container, kafka) || fileChanged;
}
if (workloadName === "hwlab-cloud-web" && container.name === "hwlab-cloud-web") {
fileChanged = setEnvValue(container, "HWLAB_WORKBENCH_LIVE_KAFKA_SSE_ENABLED", String(kafka.enabled && kafka.features.liveKafkaSse)) || fileChanged;
fileChanged = setEnvValue(container, "HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_ENABLED", String(kafka.enabled && kafka.features.kafkaRefreshReplay)) || fileChanged;
fileChanged = setEnvValue(container, "HWLAB_WORKBENCH_PROJECTION_REALTIME_ENABLED", String(kafka.enabled && kafka.features.projectionRealtime)) || fileChanged;
}
}
}
}
if (fileChanged) {
writeFileSync(file, `${JSON.stringify(parsed, null, 2)}\n`, "utf8");
writeFileSync(file, serializeStructuredDocuments(documents), "utf8");
changed = true;
}
}
@@ -237,6 +242,20 @@ function parseJsonDocument(text) {
}
}
function parseStructuredDocuments(text, file) {
const json = parseJsonDocument(text);
if (json !== null) return { format: "json", values: [json] };
const documents = YAML.parseAllDocuments(text);
const errors = documents.flatMap((document) => document.errors);
if (errors.length > 0) throw new Error(`invalid YAML in ${file}: ${errors.map((error) => error.message).join("; ")}`);
return { format: "yaml", values: documents.map((document) => document.toJS()).filter((document) => document !== null) };
}
function serializeStructuredDocuments(documents) {
if (documents.format === "json") return `${JSON.stringify(documents.values[0], null, 2)}\n`;
return `${documents.values.map((document) => YAML.stringify(document).trimEnd()).join("\n---\n")}\n`;
}
function leadingSpaces(value) {
const match = value.match(/^ */u);
return match ? match[0].length : 0;
@@ -264,6 +283,14 @@ function readOverlay() {
return JSON.parse(Buffer.from(encoded, "base64").toString("utf8"));
}
function requireYaml() {
try {
return requireFromScript("yaml");
} catch {
return requireFromCwd("yaml");
}
}
function requiredOverlayString(name) {
const value = overlay[name];
if (typeof value !== "string" || value.length === 0) throw new Error(`overlay.${name} is required`);