fix(v02): remove stale endpoint contract freeze
This commit is contained in:
@@ -584,14 +584,25 @@ function laneDeployConfig(deployManifest, lane) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function isHttpEndpoint(value) {
|
||||
if (typeof value !== "string" || value.trim().length === 0) return false;
|
||||
try {
|
||||
const url = new URL(value);
|
||||
return url.protocol === "http:" || url.protocol === "https:";
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function assertV02Contracts(catalog, deployManifest) {
|
||||
const lane = laneDeployConfig(deployManifest, "v02");
|
||||
assert.ok(lane && typeof lane === "object", "deploy.lanes.v02 must exist for v02 artifact publish");
|
||||
assert.equal(lane.namespace, "hwlab-v02", "deploy.lanes.v02.namespace must be hwlab-v02");
|
||||
assert.equal(lane.endpoint, "http://74.48.78.17:19667", "deploy.lanes.v02.endpoint must be the v02 API endpoint");
|
||||
assert.ok(isHttpEndpoint(lane.endpoint), "deploy.lanes.v02.endpoint must be a non-empty http(s) URL");
|
||||
assert.equal(catalog.environment, "v02", "catalog.environment must be v02");
|
||||
assert.equal(catalog.profile, "v02", "catalog.profile must be v02");
|
||||
assert.equal(catalog.namespace, "hwlab-v02", "catalog.namespace must be hwlab-v02");
|
||||
if (catalog.endpoint != null) assert.ok(isHttpEndpoint(catalog.endpoint), "catalog.endpoint must be a non-empty http(s) URL");
|
||||
assert.deepEqual(catalog.allowedProfiles, ["v02"], "catalog.allowedProfiles must only allow v02");
|
||||
assert.deepEqual(catalog.forbiddenProfiles, ["dev", "prod"], "catalog.forbiddenProfiles must forbid dev/prod");
|
||||
const catalogIds = (catalog.services ?? []).map((service) => service.serviceId);
|
||||
@@ -618,13 +629,15 @@ function artifactEnvironment(args) {
|
||||
|
||||
function artifactCatalogSkeleton({ args, deployManifest, commitId }) {
|
||||
const tag = imageTagForCommit(args, commitId);
|
||||
const laneEndpoint = args.lane === "v02" ? deployManifest?.lanes?.v02?.endpoint : "http://74.48.78.17:16667";
|
||||
assert.ok(isHttpEndpoint(laneEndpoint), "deploy lane endpoint must be a non-empty http(s) URL");
|
||||
return {
|
||||
catalogVersion: "v1",
|
||||
kind: "hwlab-artifact-catalog",
|
||||
environment: artifactEnvironment(args),
|
||||
profile: artifactEnvironment(args),
|
||||
namespace: args.lane === "v02" ? "hwlab-v02" : "hwlab-dev",
|
||||
endpoint: args.lane === "v02" ? "http://74.48.78.17:19667" : "http://74.48.78.17:16667",
|
||||
endpoint: laneEndpoint,
|
||||
commitId: tag,
|
||||
artifactState: "contract-skeleton",
|
||||
publish: {
|
||||
|
||||
@@ -172,11 +172,24 @@ function artifactNamespace(args) {
|
||||
return args.lane === "v02" ? "hwlab-v02" : "hwlab-dev";
|
||||
}
|
||||
|
||||
function artifactEndpoint(args) {
|
||||
return args.lane === "v02" ? "http://74.48.78.17:19667" : DEV_ENDPOINT;
|
||||
function isHttpEndpoint(value) {
|
||||
if (typeof value !== "string" || value.trim().length === 0) return false;
|
||||
try {
|
||||
const url = new URL(value);
|
||||
return url.protocol === "http:" || url.protocol === "https:";
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function artifactCatalogSkeleton({ args, target, registryPrefix = defaultRegistryPrefix }) {
|
||||
function artifactEndpoint(args, deploy) {
|
||||
if (args.lane !== "v02") return DEV_ENDPOINT;
|
||||
const endpoint = deploy?.lanes?.v02?.endpoint;
|
||||
assert.ok(isHttpEndpoint(endpoint), "deploy.lanes.v02.endpoint must be a non-empty http(s) URL");
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
function artifactCatalogSkeleton({ args, deploy, target, registryPrefix = defaultRegistryPrefix }) {
|
||||
const environment = artifactEnvironment(args);
|
||||
const namespace = artifactNamespace(args);
|
||||
return {
|
||||
@@ -185,7 +198,7 @@ function artifactCatalogSkeleton({ args, target, registryPrefix = defaultRegistr
|
||||
environment,
|
||||
profile: environment,
|
||||
namespace,
|
||||
endpoint: artifactEndpoint(args),
|
||||
endpoint: artifactEndpoint(args, deploy),
|
||||
commitId: target.imageTag,
|
||||
artifactState: "contract-skeleton",
|
||||
publish: {
|
||||
@@ -303,13 +316,13 @@ function assertV02DeployAndCatalog(deploy, catalog) {
|
||||
const lane = deploy?.lanes?.v02;
|
||||
assert.ok(lane && typeof lane === "object", "deploy.lanes.v02 must exist for v02 catalog refresh");
|
||||
assert.equal(lane.namespace, "hwlab-v02", "deploy.lanes.v02.namespace must be hwlab-v02");
|
||||
assert.equal(lane.endpoint, "http://74.48.78.17:19667", "deploy.lanes.v02.endpoint must be the v02 API endpoint");
|
||||
assert.ok(isHttpEndpoint(lane.endpoint), "deploy.lanes.v02.endpoint must be a non-empty http(s) URL");
|
||||
assert.deepEqual((deploy.services ?? []).map((service) => service.serviceId), SERVICE_IDS, "deploy services must cover frozen service IDs in order");
|
||||
|
||||
assert.equal(catalog.environment, "v02", "catalog environment must be v02");
|
||||
assert.equal(catalog.profile, "v02", "catalog profile must be v02");
|
||||
assert.equal(catalog.namespace, "hwlab-v02", "catalog namespace must be hwlab-v02");
|
||||
assert.equal(catalog.endpoint, "http://74.48.78.17:19667", "catalog endpoint must be the v02 API endpoint");
|
||||
if (catalog.endpoint != null) assert.ok(isHttpEndpoint(catalog.endpoint), "catalog endpoint must be a non-empty http(s) URL");
|
||||
assert.deepEqual(catalog.allowedProfiles, ["v02"], "catalog allowedProfiles must only allow v02");
|
||||
assert.deepEqual(catalog.forbiddenProfiles, ["dev", "prod"], "catalog forbiddenProfiles must forbid dev/prod");
|
||||
assert.deepEqual((catalog.services ?? []).map((service) => service.serviceId), serviceIdsForLane("v02"), "catalog services must cover retained v0.2 service IDs in order");
|
||||
@@ -425,6 +438,7 @@ function refreshDocuments({ deploy, catalog, target, publishRecords, serviceInve
|
||||
const nextCatalogServices = [];
|
||||
|
||||
catalog.commitId = target.imageTag;
|
||||
if (catalog.profile === "v02") catalog.endpoint = artifactEndpoint({ lane: "v02" }, deploy);
|
||||
catalog.artifactState = published ? "published" : "contract-skeleton";
|
||||
catalog.serviceInventory = serviceInventory;
|
||||
catalog.publish = {
|
||||
@@ -545,7 +559,7 @@ async function main() {
|
||||
args.publishReportPath ? readJson(args.publishReportPath) : Promise.resolve(null)
|
||||
]);
|
||||
let catalog = await readJsonIfPresent(args.catalogPath, null);
|
||||
if (!catalog && args.lane === "v02") catalog = artifactCatalogSkeleton({ args, target, registryPrefix: publishReport?.artifactPublish?.registryPrefix ?? defaultRegistryPrefix });
|
||||
if (!catalog && args.lane === "v02") catalog = artifactCatalogSkeleton({ args, deploy, target, registryPrefix: publishReport?.artifactPublish?.registryPrefix ?? defaultRegistryPrefix });
|
||||
catalog = normalizeCatalogForLane(catalog, args.lane);
|
||||
assert.ok(catalog, `${args.catalogPath} is required for ${args.lane} catalog refresh`);
|
||||
assertLaneDeployAndCatalog(args, deploy, catalog);
|
||||
@@ -581,6 +595,7 @@ async function main() {
|
||||
artifactCommitId: target.imageTag,
|
||||
lane: args.lane,
|
||||
catalogPath: args.catalogPath,
|
||||
endpoint: catalog.endpoint ?? null,
|
||||
imageTagMode: args.imageTagMode,
|
||||
wrote: args.write ? [args.catalogPath] : [],
|
||||
deployTruthPolicy: "deploy.json is human-authored runtime config; artifact promotion must not rewrite it",
|
||||
|
||||
@@ -353,6 +353,72 @@ test("v02 refresh accepts env-reuse device-pod image tag from environment hash",
|
||||
assert.equal(devicePod.bootSh, "deploy/runtime/boot/hwlab-device-pod.sh");
|
||||
});
|
||||
|
||||
test("v02 refresh follows the current deploy endpoint instead of the retired 19667 freeze", async () => {
|
||||
const commitId = await git(["rev-parse", "HEAD"]);
|
||||
const tempDir = await mkdtemp(path.join(os.tmpdir(), "hwlab-refresh-v02-https-endpoint-"));
|
||||
const deployPath = path.join(tempDir, "deploy.json");
|
||||
const catalogPath = path.join(tempDir, "artifact-catalog.v02.json");
|
||||
await writeFile(deployPath, `${JSON.stringify({
|
||||
environment: "dev",
|
||||
namespace: "hwlab-dev",
|
||||
endpoint: "http://74.48.78.17:16667",
|
||||
profiles: { dev: { enabled: true }, prod: { enabled: false } },
|
||||
lanes: {
|
||||
v02: {
|
||||
namespace: "hwlab-v02",
|
||||
endpoint: "https://hwlab.74-48-78-17.nip.io"
|
||||
}
|
||||
},
|
||||
services: SERVICE_IDS.map((serviceId) => ({ serviceId }))
|
||||
}, null, 2)}\n`);
|
||||
await writeFile(catalogPath, `${JSON.stringify({
|
||||
catalogVersion: "v1",
|
||||
kind: "hwlab-artifact-catalog",
|
||||
environment: "v02",
|
||||
profile: "v02",
|
||||
namespace: "hwlab-v02",
|
||||
endpoint: "http://74.48.78.17:19667",
|
||||
commitId,
|
||||
artifactState: "contract-skeleton",
|
||||
publish: { registryPrefix: "127.0.0.1:5000/hwlab" },
|
||||
allowedProfiles: ["v02"],
|
||||
forbiddenProfiles: ["dev", "prod"],
|
||||
services: V02_SERVICE_IDS.map((serviceId) => ({
|
||||
serviceId,
|
||||
profile: "v02",
|
||||
namespace: "hwlab-v02",
|
||||
commitId,
|
||||
sourceCommitId: commitId,
|
||||
image: `127.0.0.1:5000/hwlab/${serviceId}:${commitId}`,
|
||||
imageTag: commitId,
|
||||
digest: "not_published"
|
||||
}))
|
||||
}, null, 2)}\n`);
|
||||
|
||||
const result = await execFileAsync(process.execPath, [
|
||||
"scripts/refresh-artifact-catalog.mjs",
|
||||
"--lane",
|
||||
"v02",
|
||||
"--image-tag-mode",
|
||||
"full",
|
||||
"--target-ref",
|
||||
"HEAD",
|
||||
"--deploy-json",
|
||||
deployPath,
|
||||
"--catalog-path",
|
||||
catalogPath,
|
||||
"--blocked",
|
||||
"--no-write"
|
||||
], {
|
||||
cwd: repoRoot,
|
||||
timeout: 15000,
|
||||
maxBuffer: 10 * 1024 * 1024
|
||||
});
|
||||
const payload = JSON.parse(result.stdout);
|
||||
assert.equal(payload.status, "blocked");
|
||||
assert.equal(payload.endpoint, "https://hwlab.74-48-78-17.nip.io");
|
||||
});
|
||||
|
||||
test("v02 refresh reports code-only env-reuse records as reused", async () => {
|
||||
const commitId = await git(["rev-parse", "HEAD"]);
|
||||
const previousCommitId = "1234567890abcdef1234567890abcdef12345678";
|
||||
|
||||
Reference in New Issue
Block a user