feat: centralize candidate promotion pipelines
This commit is contained in:
@@ -3,11 +3,17 @@ import test from "node:test";
|
||||
|
||||
import {
|
||||
deployExactImage,
|
||||
expandTokens,
|
||||
mergeEnvironment,
|
||||
orderApplications,
|
||||
resolveDeploymentBranch,
|
||||
selectDeployment,
|
||||
selectPipeline,
|
||||
toSavePayload,
|
||||
validateArtifact,
|
||||
validateApplication,
|
||||
validateTarget,
|
||||
validateVersion2Pipeline,
|
||||
verifyEndpoint,
|
||||
} from "./deploy.mjs";
|
||||
|
||||
@@ -65,6 +71,63 @@ test("validates OCI paths and repository-local build paths", () => {
|
||||
);
|
||||
});
|
||||
|
||||
test("version 2 reuses one artifact across ordered applications", () => {
|
||||
const config = {
|
||||
version: 2,
|
||||
artifacts: [
|
||||
{ name: "webapp", image: "InnoMieter/Webapp", requiredFiles: ["/app/server.js"] },
|
||||
{ name: "thumbnail", image: "innomieter/thumbnail", dockerfile: "Dockerfile.thumbnail" },
|
||||
],
|
||||
pipelines: [
|
||||
{
|
||||
branch: "staging",
|
||||
strategy: "candidate",
|
||||
applications: [
|
||||
{ name: "worker", artifact: "webapp", appId: "app-worker", dependsOn: ["web"] },
|
||||
{ name: "web", artifact: "webapp", appId: "app-web" },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
assert.equal(selectPipeline(config, "staging")?.strategy, "candidate");
|
||||
const pipeline = validateVersion2Pipeline(config, "staging");
|
||||
assert.deepEqual(pipeline.artifacts.map((artifact) => artifact.name), ["webapp", "thumbnail"]);
|
||||
assert.deepEqual(pipeline.applications.map((application) => application.name), ["web", "worker"]);
|
||||
assert.equal(pipeline.applications[1].artifact, "webapp");
|
||||
});
|
||||
|
||||
test("version 2 validates promotion contracts and token expansion", () => {
|
||||
const sha = "1234567890abcdef1234567890abcdef12345678";
|
||||
assert.equal(expandTokens("build-$sha12-$version", { sha, version: "v1.2.3" }), "build-1234567890ab-v1.2.3");
|
||||
assert.throws(
|
||||
() => validateVersion2Pipeline({
|
||||
version: 2,
|
||||
artifacts: [{ name: "web", image: "owner/web" }],
|
||||
pipelines: [{ branch: "prod", strategy: "promote", applications: [{ name: "web", artifact: "web", appId: "app" }] }],
|
||||
}, "prod"),
|
||||
/requires release configuration/,
|
||||
);
|
||||
assert.throws(() => validateArtifact({ name: "web", image: "owner/web", requiredFiles: ["../secret"] }), /safe absolute path/);
|
||||
assert.throws(
|
||||
() => validateApplication({ name: "web", artifact: "missing", appId: "app" }, new Set(["known"])),
|
||||
/unknown artifact/,
|
||||
);
|
||||
});
|
||||
|
||||
test("application dependencies reject missing nodes and cycles", () => {
|
||||
assert.throws(
|
||||
() => orderApplications([{ name: "web", dependsOn: ["missing"] }]),
|
||||
/unknown application/,
|
||||
);
|
||||
assert.throws(
|
||||
() => orderApplications([
|
||||
{ name: "web", dependsOn: ["worker"] },
|
||||
{ name: "worker", dependsOn: ["web"] },
|
||||
]),
|
||||
/cycle/,
|
||||
);
|
||||
});
|
||||
|
||||
test("preserves response-only fields and existing environment secrets safely", () => {
|
||||
const payload = toSavePayload(app());
|
||||
assert.equal(payload.createdAt, undefined);
|
||||
|
||||
Reference in New Issue
Block a user