fix: bootstrap new services in artifact catalogs

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
root
2026-07-16 21:14:04 +02:00
parent 66afd74c06
commit 8ea32b6d36
3 changed files with 46 additions and 6 deletions
+20 -5
View File
@@ -327,12 +327,21 @@ function assertRuntimeLaneDeployAndCatalog(deploy, catalog, laneName) {
assert.deepEqual((catalog.services ?? []).map((service) => service.serviceId), serviceIds, `catalog services must cover deploy.lanes.${laneName}.envReuseServices in order`);
}
function normalizeCatalogForLane(catalog, lane, deploy) {
if (!catalog || !isRuntimeArtifactLane(lane)) return catalog;
const allowed = new Set(serviceIdsForLane(lane, deploy));
function normalizeCatalogForLane(catalog, args, deploy, target, registryPrefix) {
if (!catalog) return catalog;
const serviceIds = isRuntimeArtifactLane(args.lane)
? serviceIdsForLane(args.lane, deploy)
: SERVICE_IDS;
const allowed = new Set(serviceIds);
const environment = artifactEnvironment(args);
const namespace = artifactNamespace(args, deploy);
const existingById = new Map((catalog.services ?? [])
.filter((service) => allowed.has(service.serviceId))
.map((service) => [service.serviceId, service]));
return {
...catalog,
services: (catalog.services ?? []).filter((service) => allowed.has(service.serviceId))
services: serviceIds.map((serviceId) => existingById.get(serviceId)
?? catalogSkeletonService({ args, serviceId, target, registryPrefix, environment, namespace }))
};
}
@@ -570,7 +579,13 @@ async function main() {
]);
let catalog = await readConfigIfPresent(args.catalogPath, null);
if (!catalog && isRuntimeArtifactLane(args.lane)) catalog = artifactCatalogSkeleton({ args, deploy, target, registryPrefix: publishReport?.artifactPublish?.registryPrefix ?? defaultRegistryPrefix });
catalog = normalizeCatalogForLane(catalog, args.lane, deploy);
catalog = normalizeCatalogForLane(
catalog,
args,
deploy,
target,
publishReport?.artifactPublish?.registryPrefix ?? defaultRegistryPrefix
);
assert.ok(catalog, `${args.catalogPath} is required for ${args.lane} catalog refresh`);
assertLaneDeployAndCatalog(args, deploy, catalog);
+24 -1
View File
@@ -333,7 +333,7 @@ test("v03 refresh accepts runtime lane config and env-reuse image tags", async (
const deployPath = path.join(tempDir, "deploy.yaml");
const catalogPath = path.join(tempDir, "artifact-catalog.v03.json");
const reportPath = path.join(tempDir, "v03-artifacts.json");
const serviceIds = V02_SERVICE_IDS;
const serviceIds = [...V02_SERVICE_IDS, "hwlab-tasktree-api", "hwlab-tasktree-worker"];
await writeStructuredFile(tempDir, deployPath, {
environment: "dev",
namespace: "hwlab-dev",
@@ -354,6 +354,29 @@ test("v03 refresh accepts runtime lane config and env-reuse image tags", async (
},
services: SERVICE_IDS.map((serviceId) => ({ serviceId }))
});
await writeFile(catalogPath, `${JSON.stringify({
catalogVersion: "v1",
kind: "hwlab-artifact-catalog",
environment: "v03",
profile: "v03",
namespace: "hwlab-v03",
endpoint: "https://hwlab-v03.74-48-78-17.nip.io",
commitId,
artifactState: "published",
publish: { ciPublished: true, registryVerified: true, provenance: "previous-run" },
allowedProfiles: ["v03"],
forbiddenProfiles: ["dev", "prod"],
services: V02_SERVICE_IDS.map((serviceId, index) => ({
serviceId,
commitId,
sourceCommitId: commitId,
image: `127.0.0.1:5000/hwlab/${serviceId}:${commitId}`,
imageTag: commitId,
digest: digestFor(index),
profile: "v03",
namespace: "hwlab-v03"
}))
}, null, 2)}\n`);
await writeFile(reportPath, `${JSON.stringify({
reportVersion: "v1",
taskId: "v03-artifact-publish",