Files
pikasTech-HWLAB/internal/build-metadata.mjs
T
2026-05-30 14:05:28 +08:00

110 lines
4.5 KiB
JavaScript

const unknownValue = "unknown";
export function normalizeIsoTimestamp(value) {
const source = String(value ?? "").trim();
if (!source) return null;
if (/^\d+$/u.test(source)) {
const seconds = Number.parseInt(source, 10);
if (Number.isSafeInteger(seconds)) {
const date = new Date(seconds * 1000);
if (Number.isFinite(date.getTime())) return date.toISOString();
}
}
const date = new Date(source);
return Number.isFinite(date.getTime()) ? date.toISOString() : null;
}
export function imageTagFromReference(imageReference) {
const source = String(imageReference ?? "").trim();
const slashIndex = source.lastIndexOf("/");
const colonIndex = source.lastIndexOf(":");
if (colonIndex <= slashIndex) return null;
return source.slice(colonIndex + 1) || null;
}
export function shortRevision(value) {
const source = String(value ?? "").trim();
return source.length >= 7 ? source.slice(0, 7) : source || unknownValue;
}
export function buildMetadataFromEnv(env = process.env, { serviceId = "hwlab-unknown", fallbackImageRepository = null } = {}) {
const commitId = firstNonEmpty(env.HWLAB_COMMIT_ID, env.HWLAB_GIT_SHA, env.GIT_COMMIT) ?? unknownValue;
const revision = firstNonEmpty(env.HWLAB_REVISION, commitId) ?? unknownValue;
const fallbackRepository = fallbackImageRepository ?? `ghcr.io/pikastech/${serviceId}`;
const imageReference = firstNonEmpty(env.HWLAB_IMAGE, `${fallbackRepository}:${shortRevision(commitId)}`) ?? unknownValue;
const imageTag = firstNonEmpty(env.HWLAB_IMAGE_TAG, imageTagFromReference(imageReference), shortRevision(commitId)) ?? unknownValue;
const buildCreatedAt = normalizeIsoTimestamp(
firstNonEmpty(env.HWLAB_BUILD_CREATED_AT, env.HWLAB_IMAGE_CREATED_AT, env.SOURCE_DATE_EPOCH, env.BUILD_DATE)
);
const buildSource = firstNonEmpty(env.HWLAB_BUILD_SOURCE, "runtime-env") ?? "runtime-env";
return {
revision,
commit: {
id: commitId,
source: buildSource
},
image: {
reference: imageReference,
tag: imageTag,
digest: firstNonEmpty(env.HWLAB_IMAGE_DIGEST, unknownValue) ?? unknownValue
},
build: {
createdAt: buildCreatedAt,
source: buildSource,
provenance: firstNonEmpty(env.HWLAB_BUILD_PROVENANCE, null),
metadataSource: buildCreatedAt ? "runtime-env:HWLAB_BUILD_CREATED_AT" : "unavailable",
unavailableReason: buildCreatedAt ? null : "HWLAB_BUILD_CREATED_AT missing from runtime environment"
},
runtime: runtimeIdentityFromEnv(env)
};
}
export function runtimeIdentityFromEnv(env = process.env) {
const runtimeMode = firstNonEmpty(env.HWLAB_RUNTIME_MODE, null);
const bootRepo = firstNonEmpty(env.HWLAB_BOOT_REPO, null);
const bootCommit = firstNonEmpty(env.HWLAB_BOOT_COMMIT, null);
const bootSh = firstNonEmpty(env.HWLAB_BOOT_SH, null);
const environmentImage = firstNonEmpty(env.HWLAB_ENVIRONMENT_IMAGE, null);
const environmentDigest = firstNonEmpty(env.HWLAB_ENVIRONMENT_DIGEST, env.HWLAB_IMAGE_DIGEST, null);
const environmentInputHash = firstNonEmpty(env.HWLAB_ENVIRONMENT_INPUT_HASH, null);
const codeInputHash = firstNonEmpty(env.HWLAB_CODE_INPUT_HASH, null);
const pod = runtimePodIdentityFromEnv(env);
if (!runtimeMode && !bootRepo && !bootCommit && !bootSh && !environmentDigest && !pod) return null;
return pruneUndefined({
mode: runtimeMode,
environmentImage,
environmentDigest,
environmentInputHash,
codeInputHash,
pod,
boot: pruneUndefined({
repo: bootRepo,
commit: bootCommit,
sh: bootSh
})
});
}
function runtimePodIdentityFromEnv(env = process.env) {
const name = firstNonEmpty(env.HWLAB_RUNTIME_POD_NAME, env.POD_NAME, env.HOSTNAME, null);
const namespace = firstNonEmpty(env.HWLAB_RUNTIME_NAMESPACE, env.POD_NAMESPACE, env.KUBERNETES_NAMESPACE, env.HWLAB_NAMESPACE, null);
const container = firstNonEmpty(env.HWLAB_RUNTIME_CONTAINER, env.HWLAB_CONTAINER_NAME, null);
const nodeName = firstNonEmpty(env.HWLAB_RUNTIME_NODE_NAME, env.NODE_NAME, null);
if (!name && !namespace && !container && !nodeName) return null;
return pruneUndefined({ name, namespace, container, nodeName });
}
function firstNonEmpty(...values) {
for (const value of values) {
if (value === null || value === undefined) continue;
const text = String(value).trim();
if (text) return text;
}
return null;
}
function pruneUndefined(value) {
return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined && item !== null && item !== ""));
}