ymal: compose repeated node lane templates
This commit is contained in:
@@ -9,6 +9,7 @@ import type { RenderedCliResult } from "./output";
|
||||
import { shQuote } from "./platform-infra-public-service";
|
||||
import { fingerprintSecretValues, readEnvSourceFile, requiredEnvValue } from "./secrets";
|
||||
import { transHostProxyEnvSummary } from "./trans-host-proxy";
|
||||
import { materializeYamlComposition } from "./yaml-composition";
|
||||
|
||||
const configPath = "config/platform-infra/host-proxy.yaml";
|
||||
|
||||
@@ -161,7 +162,7 @@ function parseOptions(args: string[]): HostProxyOptions {
|
||||
}
|
||||
|
||||
function readHostProxyConfig(): HostProxyConfig {
|
||||
const root = record(Bun.YAML.parse(readFileSync(rootPath(configPath), "utf8")), configPath);
|
||||
const root = record(materializeYamlComposition(Bun.YAML.parse(readFileSync(rootPath(configPath), "utf8")) as unknown, { label: configPath }).value, configPath);
|
||||
if (root.kind !== "platform-infra-host-proxy") throw new Error(`${configPath}.kind must be platform-infra-host-proxy`);
|
||||
const defaultsRaw = record(root.defaults, `${configPath}.defaults`);
|
||||
const server = parseServer(record(root.server, `${configPath}.server`), `${configPath}.server`);
|
||||
@@ -172,7 +173,7 @@ function readHostProxyConfig(): HostProxyConfig {
|
||||
}));
|
||||
const targets: Record<string, HostProxyTarget> = {};
|
||||
for (const [id, value] of Object.entries(record(root.targets, `${configPath}.targets`))) {
|
||||
targets[id] = parseTarget(id, record(value, `${configPath}.targets.${id}`), sources);
|
||||
targets[id] = parseTarget(id, record(value, `${configPath}.targets.${id}`), sources, root);
|
||||
}
|
||||
return {
|
||||
defaults: { targetId: stringField(defaultsRaw, "targetId", `${configPath}.defaults`) },
|
||||
@@ -315,7 +316,7 @@ function podAccessSpec(raw: Record<string, unknown>, label: string): HostProxyPo
|
||||
return { enabled, listenHost, listenPort, proxyUrl };
|
||||
}
|
||||
|
||||
function parseTarget(id: string, raw: Record<string, unknown>, sources: Record<string, HostProxySource>): HostProxyTarget {
|
||||
function parseTarget(id: string, raw: Record<string, unknown>, sources: Record<string, HostProxySource>, root: Record<string, unknown>): HostProxyTarget {
|
||||
const sourceRef = stringField(raw, "sourceRef", `${configPath}.targets.${id}`);
|
||||
if (!sourceRef.startsWith("sources.")) throw new Error(`${configPath}.targets.${id}.sourceRef must use sources.<id>`);
|
||||
const sourceId = sourceRef.slice("sources.".length);
|
||||
@@ -324,7 +325,9 @@ function parseTarget(id: string, raw: Record<string, unknown>, sources: Record<s
|
||||
const envRaw = record(raw.env, `${configPath}.targets.${id}.env`);
|
||||
const filesRaw = record(raw.files, `${configPath}.targets.${id}.files`);
|
||||
const applyRaw = record(raw.apply, `${configPath}.targets.${id}.apply`);
|
||||
const noProxy = stringArrayField(envRaw, "noProxy", `${configPath}.targets.${id}.env`);
|
||||
const noProxy = envRaw.noProxy === undefined
|
||||
? noProxyFromRefs(envRaw, root, `${configPath}.targets.${id}.env`)
|
||||
: stringArrayField(envRaw, "noProxy", `${configPath}.targets.${id}.env`);
|
||||
if (!noProxy.includes("hyueapi.com") || !noProxy.includes(".hyueapi.com")) {
|
||||
throw new Error(`${configPath}.targets.${id}.env.noProxy must preserve hyueapi.com and .hyueapi.com`);
|
||||
}
|
||||
@@ -359,6 +362,30 @@ function parseTarget(id: string, raw: Record<string, unknown>, sources: Record<s
|
||||
return target;
|
||||
}
|
||||
|
||||
function noProxyFromRefs(envRaw: Record<string, unknown>, root: Record<string, unknown>, label: string): string[] {
|
||||
const refs = record(envRaw.noProxyRefs, `${label}.noProxyRefs`);
|
||||
const values: string[] = [];
|
||||
for (const key of ["common", "extras"] as const) {
|
||||
const ref = stringField(refs, key, `${label}.noProxyRefs`);
|
||||
values.push(...stringArrayAtPath(root, ref, `${label}.noProxyRefs.${key}`));
|
||||
}
|
||||
return [...new Set(values)];
|
||||
}
|
||||
|
||||
function stringArrayAtPath(root: unknown, ref: string, label: string): string[] {
|
||||
let current: unknown = root;
|
||||
for (const segment of ref.split(".")) {
|
||||
if (!/^[A-Za-z0-9_-]+$/u.test(segment) || typeof current !== "object" || current === null || Array.isArray(current)) {
|
||||
throw new Error(`${label} references invalid path ${ref}`);
|
||||
}
|
||||
current = (current as Record<string, unknown>)[segment];
|
||||
}
|
||||
if (!Array.isArray(current) || !current.every((item) => typeof item === "string" && item.length > 0)) {
|
||||
throw new Error(`${label} must reference a string array`);
|
||||
}
|
||||
return [...current];
|
||||
}
|
||||
|
||||
function resolveTarget(config: HostProxyConfig, targetId: string): HostProxyTarget {
|
||||
const target = config.targets[targetId];
|
||||
if (target === undefined) throw new Error(`${configPath}.targets.${targetId} is not defined`);
|
||||
|
||||
Reference in New Issue
Block a user