feat: default G14 artifact publish to component reuse

This commit is contained in:
Codex
2026-05-26 10:51:01 +08:00
parent 986d8f5c07
commit 7a14c6bfb3
4 changed files with 243 additions and 25 deletions
+41 -13
View File
@@ -23,6 +23,8 @@ const defaultRegistryPrefix = process.env.HWLAB_DEV_REGISTRY_PREFIX || process.e
const digestPattern = /^sha256:[a-f0-9]{64}$/;
const commitPattern = /^[a-f0-9]{7,40}$/;
const publishReadyStatuses = new Set(["published", "reused"]);
function parseArgs(argv) {
const args = {
targetRef: "HEAD",
@@ -122,6 +124,19 @@ function commitMatchesTarget(value, target) {
return value === target.commitId || value === target.shortCommitId;
}
function shortCommitForRecord(record, target) {
const value = record?.commitId ?? record?.imageTag ?? null;
if (typeof value === "string" && commitPattern.test(value)) return value.slice(0, 7);
if (typeof record?.sourceCommitId === "string" && commitPattern.test(record.sourceCommitId)) return record.sourceCommitId.slice(0, 7);
return target.shortCommitId;
}
function revisionForRecord(record, target) {
if (typeof record?.sourceCommitId === "string" && commitPattern.test(record.sourceCommitId)) return record.sourceCommitId;
if (typeof record?.commitId === "string" && commitPattern.test(record.commitId)) return record.commitId;
return target.commitId;
}
function assertDevOnlyDeployAndCatalog(deploy, catalog) {
assert.equal(deploy.environment, ENVIRONMENT_DEV, "deploy environment must be dev");
assert.equal(deploy.namespace, "hwlab-dev", "deploy namespace must be hwlab-dev");
@@ -160,16 +175,15 @@ function publishRecordsFromReport(report, target) {
"publish plan must cover every frozen service"
);
assert.equal(
artifactPublish.publishedCount,
(artifactPublish.publishedCount ?? 0) + (artifactPublish.reusedCount ?? 0),
requiredServiceIds.length,
"publish report must publish every required enabled service"
"publish report must publish or reuse every required enabled service"
);
const records = new Map();
for (const service of artifactPublish.services ?? []) {
assert.ok(SERVICE_IDS.includes(service.serviceId), `unknown service ${service.serviceId} in publish report`);
const image = parseTaggedImage(service.image, service.serviceId);
assert.equal(image.tag, target.shortCommitId, `${service.serviceId} image tag must match target short commit`);
if (!requiredServiceIds.includes(service.serviceId)) {
assert.equal(service.artifactRequired, false, `${service.serviceId} disabled service must not be required`);
assert.equal(service.digest, "not_published", `${service.serviceId} disabled digest must stay not_published`);
@@ -177,11 +191,17 @@ function publishRecordsFromReport(report, target) {
continue;
}
assert.equal(service.status, "published", `${service.serviceId} status must be published`);
assert.equal(publishReadyStatuses.has(service.status), true, `${service.serviceId} status must be published or reused`);
assert.equal(service.artifactRequired, true, `${service.serviceId} required service must state artifactRequired=true`);
if (service.status === "published") {
assert.equal(image.tag, target.shortCommitId, `${service.serviceId} newly published image tag must match target short commit`);
}
assert.match(service.digest, digestPattern, `${service.serviceId} digest must be a sha256 registry digest`);
records.set(service.serviceId, {
serviceId: service.serviceId,
status: service.status,
commitId: service.commitId ?? image.tag,
sourceCommitId: service.sourceCommitId ?? null,
image: service.image,
imageTag: image.tag,
buildCreatedAt: service.buildCreatedAt ?? null,
@@ -196,7 +216,8 @@ function publishRecordsFromReport(report, target) {
buildArgsHash: service.buildArgsHash ?? null,
ciAffected: service.ciAffected ?? null,
ciReason: service.ciReason ?? [],
reuse: service.reuse ?? null
reuse: service.reuse ?? null,
reusedFrom: service.reusedFrom ?? null
});
}
@@ -206,13 +227,15 @@ function publishRecordsFromReport(report, target) {
function updateEnvObject(env, service, target, publishRecord) {
if (!env || typeof env !== "object" || Array.isArray(env)) return;
if (Object.hasOwn(env, "HWLAB_COMMIT_ID")) env.HWLAB_COMMIT_ID = target.shortCommitId;
const shortCommitId = shortCommitForRecord(publishRecord, target);
const revision = revisionForRecord(publishRecord, target);
if (Object.hasOwn(env, "HWLAB_COMMIT_ID")) env.HWLAB_COMMIT_ID = shortCommitId;
if (Object.hasOwn(env, "HWLAB_IMAGE")) env.HWLAB_IMAGE = service.image;
if (Object.hasOwn(env, "HWLAB_IMAGE_TAG")) env.HWLAB_IMAGE_TAG = service.imageTag;
if (Object.hasOwn(env, "HWLAB_REVISION")) env.HWLAB_REVISION = target.commitId;
if (Object.hasOwn(env, "HWLAB_REVISION")) env.HWLAB_REVISION = revision;
if (Object.hasOwn(env, "HWLAB_BUILD_CREATED_AT")) env.HWLAB_BUILD_CREATED_AT = publishRecord?.buildCreatedAt ?? "";
if (Object.hasOwn(env, "HWLAB_BUILD_SOURCE")) env.HWLAB_BUILD_SOURCE = publishRecord?.buildSource ?? "";
if (Object.hasOwn(env, "HWLAB_SKILLS_COMMIT_ID")) env.HWLAB_SKILLS_COMMIT_ID = target.shortCommitId;
if (Object.hasOwn(env, "HWLAB_SKILLS_COMMIT_ID")) env.HWLAB_SKILLS_COMMIT_ID = shortCommitId;
if (Object.hasOwn(env, "HWLAB_IMAGE_DIGEST")) env.HWLAB_IMAGE_DIGEST = publishRecord?.digest ?? "not_published";
}
@@ -226,14 +249,16 @@ function serviceIdForWorkload(item, container) {
function updateEnvList(envList, service, target, publishRecord) {
if (!Array.isArray(envList)) return;
const shortCommitId = shortCommitForRecord(publishRecord, target);
const revision = revisionForRecord(publishRecord, target);
for (const entry of envList) {
if (entry.name === "HWLAB_COMMIT_ID") entry.value = target.shortCommitId;
if (entry.name === "HWLAB_COMMIT_ID") entry.value = shortCommitId;
if (entry.name === "HWLAB_IMAGE") entry.value = service.image;
if (entry.name === "HWLAB_IMAGE_TAG") entry.value = service.imageTag;
if (entry.name === "HWLAB_REVISION") entry.value = target.commitId;
if (entry.name === "HWLAB_REVISION") entry.value = revision;
if (entry.name === "HWLAB_BUILD_CREATED_AT") entry.value = publishRecord?.buildCreatedAt ?? "";
if (entry.name === "HWLAB_BUILD_SOURCE") entry.value = publishRecord?.buildSource ?? "";
if (entry.name === "HWLAB_SKILLS_COMMIT_ID") entry.value = target.shortCommitId;
if (entry.name === "HWLAB_SKILLS_COMMIT_ID") entry.value = shortCommitId;
if (entry.name === "HWLAB_IMAGE_DIGEST") entry.value = publishRecord?.digest ?? "not_published";
}
}
@@ -276,11 +301,12 @@ function refreshDocuments({ deploy, catalog, workloads, target, publishRecords,
const publishRecord = records?.get(serviceId) ?? null;
const image = publishRecord?.image ?? targetImage(serviceId, target.shortCommitId, registryPrefix);
const imageTag = publishRecord?.imageTag ?? target.shortCommitId;
const serviceCommitId = shortCommitForRecord(publishRecord, target);
deployService.image = image;
updateEnvObject(deployService.env, { image, imageTag }, target, publishRecord);
catalogService.commitId = target.shortCommitId;
catalogService.commitId = serviceCommitId;
catalogService.image = image;
catalogService.imageTag = imageTag;
catalogService.buildCreatedAt = publishRecord?.buildCreatedAt ?? null;
@@ -295,7 +321,8 @@ function refreshDocuments({ deploy, catalog, workloads, target, publishRecords,
catalogService.ciAffected = publishRecord?.ciAffected ?? catalogService.ciAffected ?? null;
catalogService.ciReason = publishRecord?.ciReason ?? catalogService.ciReason ?? [];
catalogService.reuse = publishRecord?.reuse ?? catalogService.reuse ?? null;
catalogService.publishState = publishRecord ? "published" : "skeleton-only";
catalogService.reusedFrom = publishRecord?.reusedFrom ?? catalogService.reusedFrom ?? null;
catalogService.publishState = publishRecord?.status === "reused" ? "reused" : publishRecord ? "published" : "skeleton-only";
catalogService.publishEnabled = inventory?.publishEnabled ?? required;
catalogService.artifactRequired = required;
catalogService.artifactScope = required ? "required" : "disabled";
@@ -313,6 +340,7 @@ function refreshDocuments({ deploy, catalog, workloads, target, publishRecords,
dockerfileHash: catalogService.dockerfileHash,
ciAffected: catalogService.ciAffected,
ciReason: catalogService.ciReason,
reusedFrom: catalogService.reusedFrom ?? null,
publishState: catalogService.publishState,
artifactRequired: catalogService.artifactRequired,
notPublishedReason: catalogService.notPublishedReason