#!/usr/bin/env node // Restore the node/lane artifact catalog from the GitOps branch before CI planning. import { execFileSync } from "node:child_process"; import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; import { dirname } from "node:path"; const startedAt = Date.now(); function env(name) { const value = process.env[name]; return typeof value === "string" && value.trim().length > 0 ? value.trim() : null; } function emit(payload) { process.stderr.write(JSON.stringify({ event: "artifact-catalog-restore", source: "scripts/ci/restore-artifact-catalog.mjs", at: new Date().toISOString(), durationMs: Date.now() - startedAt, catalogPath, gitopsBranch, ...payload }) + "\n"); } function catalogHasServices(filePath) { if (!existsSync(filePath)) return false; try { const parsed = JSON.parse(readFileSync(filePath, "utf8")); return Array.isArray(parsed?.services) && parsed.services.length > 0; } catch { return false; } } function git(args, options = {}) { return execFileSync("git", args, { cwd: process.cwd(), encoding: "utf8", stdio: options.capture === false ? ["ignore", "ignore", "pipe"] : ["ignore", "pipe", "pipe"], timeout: options.timeoutMs ?? 45_000 }); } const catalogPath = env("HWLAB_CATALOG_PATH"); const gitopsBranch = env("HWLAB_GITOPS_BRANCH"); const remote = env("HWLAB_GIT_READ_URL") ?? env("HWLAB_GIT_URL"); if (!catalogPath || !gitopsBranch || !remote) { emit({ status: "skipped", reason: "required-input-missing", hasCatalogPath: Boolean(catalogPath), hasGitopsBranch: Boolean(gitopsBranch), hasRemote: Boolean(remote) }); process.exit(0); } if (catalogHasServices(catalogPath)) { emit({ status: "source-present", reason: "catalog-already-present" }); process.exit(0); } try { git(["fetch", "--depth=1", remote, `refs/heads/${gitopsBranch}`], { capture: false, timeoutMs: 60_000 }); const content = git(["show", `FETCH_HEAD:${catalogPath}`], { timeoutMs: 30_000 }); const parsed = JSON.parse(content); if (!Array.isArray(parsed?.services) || parsed.services.length === 0) { emit({ status: "skipped", reason: "gitops-catalog-has-no-services" }); process.exit(0); } mkdirSync(dirname(catalogPath), { recursive: true }); writeFileSync(catalogPath, JSON.stringify(parsed, null, 2) + "\n"); emit({ status: "restored", reason: "gitops-catalog", serviceCount: parsed.services.length, bytes: Buffer.byteLength(content) }); } catch (error) { emit({ status: "skipped", reason: "gitops-catalog-unavailable", error: error instanceof Error ? error.message.slice(0, 500) : String(error).slice(0, 500) }); }