#!/usr/bin/env node /** * sync-sources.mjs — keep the kustomization mirror in sync with the * source-of-truth config files (TASK-0135, phase-15). * * kustomize's configMapGenerator cannot read files outside the * kustomization's directory, so infrastructure/kubernetes/observability/ * carries MIRROR copies of the files authored in * infrastructure/observability/. This script is the guard: * * node infrastructure/kubernetes/observability/scripts/sync-sources.mjs # check (CI) * node .../sync-sources.mjs --write # re-mirror after editing sources * * Exit 0 = in sync, 1 = drift (check mode) or failure. */ import { copyFileSync, existsSync, readFileSync } from "node:fs"; import { dirname, join, relative } from "node:path"; import { fileURLToPath } from "node:url"; const here = dirname(fileURLToPath(import.meta.url)); const kdir = join(here, ".."); // infrastructure/kubernetes/observability const sdir = join(here, "..", "..", "..", "observability"); // infrastructure/observability const PAIRS = [ ["prometheus/scrape.yaml", "prometheus/scrape.yaml"], ["prometheus/recording-rules.yaml", "prometheus/recording-rules.yaml"], ["prometheus/alerts.yaml", "prometheus/alerts.yaml"], ["alertmanager/alertmanager.yaml", "alertmanager/alertmanager.yaml"], ["grafana/provisioning/datasources/datasource.yaml", "grafana/provisioning/datasources/datasource.yaml"], ["grafana/provisioning/dashboards/dashboards.yaml", "grafana/provisioning/dashboards/dashboards.yaml"], ["grafana/dashboards/api-overview.json", "grafana/dashboards/api-overview.json"], ["grafana/dashboards/realtime.json", "grafana/dashboards/realtime.json"], ["grafana/dashboards/workers-queues.json", "grafana/dashboards/workers-queues.json"], ["grafana/dashboards/search.json", "grafana/dashboards/search.json"], ["grafana/dashboards/ai.json", "grafana/dashboards/ai.json"], ["grafana/dashboards/infra.json", "grafana/dashboards/infra.json"] ]; const write = process.argv.includes("--write"); let bad = 0; for (const [srcRel, mirrorRel] of PAIRS) { const src = join(sdir, srcRel); const mirror = join(kdir, mirrorRel); if (!existsSync(src)) { console.error(`MISSING SOURCE: ${srcRel}`); bad++; continue; } if (!existsSync(mirror) || readFileSync(src, "utf8") !== readFileSync(mirror, "utf8")) { if (write) { copyFileSync(src, mirror); console.log(`re-mirrored ${mirrorRel}`); } else { console.error(`DRIFT: ${mirrorRel} != ${srcRel}`); bad++; } } } if (write && bad === 0) { console.log("OK: mirror is in sync (write mode)"); } else if (bad === 0) { console.log(`OK: ${PAIRS.length} mirror files are in sync with infrastructure/observability/`); } else { console.error(`${bad} file(s) out of sync — run: node ${relative(process.cwd(), join(here, "sync-sources.mjs"))} --write`); process.exit(1); }