Skip to content

g1t/services/deployments/src/environments.test.ts

146 lines6,218 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Merge branch 'main' into worktree-agent-a69aeabc4b0deeb971import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import {
5 actionsTransition,
6 address,
7 buildState,
8 commitState,
9 compareEnvironments,
10 environmentName,
11 payloadOf,
12 runOutcome,
13 shortRef,
14 statusContext,
15} from "./environments.ts";
16import { buildStatuses, fromBuild, type BuildRow } from "./environments.ts";
17
18const appUrl = (script: string) => `https://${script}.g1t.page`;
19
20test("an environment is named as given, production when not", () => {
21 assert.equal(environmentName(undefined), "production");
22 assert.equal(environmentName(" "), "production");
23 assert.equal(environmentName(" staging "), "staging");
24 assert.equal(environmentName("review/feature-x"), "review/feature-x");
25 assert.deepEqual(environmentName("a\nb"), { error: "`environment` cannot hold control characters." });
26 assert.ok(typeof environmentName("x".repeat(256)) === "object");
27 assert.ok(typeof environmentName(3) === "object");
28});
29
30test("addresses are http(s), and a payload is an object", () => {
31 assert.equal(address("https://g1t.sh", "environment_url"), "https://g1t.sh");
32 assert.equal(address(null, "log_url"), null);
33 assert.ok(typeof address("ftp://example.com", "log_url") === "object");
34 assert.ok(typeof address("not a url", "log_url") === "object");
35 assert.deepEqual(payloadOf(undefined), { value: {} });
36 assert.deepEqual(payloadOf({ error: "kept" }), { value: { error: "kept" } });
37 assert.deepEqual(payloadOf('{"units":["api"]}'), { value: { units: ["api"] } });
38 assert.ok("error" in payloadOf("[1]"));
39 assert.ok("error" in payloadOf("{"));
40});
41
42test("refs read as their branch or tag", () => {
43 assert.equal(shortRef("refs/heads/main"), "main");
44 assert.equal(shortRef("refs/tags/v1.2.0"), "v1.2.0");
45 assert.equal(shortRef("main"), "main");
46});
47
48test("each state says something on the commit, but inactive", () => {
49 assert.equal(statusContext("production"), "deploy / production");
50 assert.equal(commitState("queued"), "pending");
51 assert.equal(commitState("in_progress"), "pending");
52 assert.equal(commitState("success"), "success");
53 assert.equal(commitState("failure"), "failure");
54 assert.equal(commitState("error"), "error");
55 assert.equal(commitState("inactive"), null);
56});
57
58test("a g1t.page build's status reads as a deployment state", () => {
59 assert.equal(buildState("queued"), "queued");
60 assert.equal(buildState("building"), "in_progress");
61 assert.equal(buildState("ready"), "success");
62 assert.equal(buildState("failed"), "failure");
63 assert.equal(buildState("skipped"), "error");
64 assert.equal(buildState("replaced"), "inactive");
65 assert.equal(buildState("down"), "inactive");
66});
67
68test("a run's deployment moves on, and a failure sticks until the run ends", () => {
69 assert.equal(actionsTransition(null, "in_progress", false), "in_progress");
70 assert.equal(actionsTransition("in_progress", "in_progress", false), null);
71 assert.equal(actionsTransition("in_progress", "failure", false), "failure");
72 assert.equal(actionsTransition("failure", "in_progress", false), null, "a later job does not undo a failure");
73 assert.equal(actionsTransition("failure", "success", true), "success", "the run's outcome is the last word");
74 assert.equal(actionsTransition("success", "in_progress", false), null);
75 assert.equal(actionsTransition("in_progress", "success", true), "success");
76});
77
78test("a run's outcome for an environment comes from the jobs that ran", () => {
79 assert.equal(runOutcome(["success", "skipped"]), "success");
80 assert.equal(runOutcome(["success", "failure"]), "failure");
81 assert.equal(runOutcome(["success", "cancelled"]), "error");
82 assert.equal(runOutcome(["skipped", "skipped"]), null);
83 assert.equal(runOutcome([]), null);
84});
85
86test("production comes first, then the newest", () => {
87 const env = (name: string, production: boolean, at: string) => ({ name, production_environment: production, updated_at: at });
88 const sorted = [env("preview", false, "2026-10-07"), env("staging", false, "2026-10-06"), env("Production", true, "2026-10-01"), env("eu", true, "2026-10-05")].sort(
89 compareEnvironments,
90 );
91 assert.deepEqual(
92 sorted.map((e) => e.name),
93 ["Production", "eu", "preview", "staging"],
94 );
95});
96
97const build = (over: Partial<BuildRow>): BuildRow => ({
98 id: "dpl_1",
99 workspace: "acme",
100 slug: "web",
101 repo_id: "rep_1",
102 kind: "production",
103 branch: null,
104 number: null,
105 commit_sha: "a".repeat(40),
106 script: "web-acme",
107 status: "ready",
108 error: null,
109 created_by: "usr_1",
110 created_at: "2026-10-07T10:00:00.000Z",
111 started_at: "2026-10-07T10:00:05.000Z",
112 finished_at: "2026-10-07T10:01:00.000Z",
113 ...over,
114});
115
116test("a g1t.page build is a deployment in the same model", () => {
117 const live = fromBuild(build({}), "main", "https://g1t.sh", appUrl, { usr_1: "ada" });
118 assert.equal(live.environment, "production");
119 assert.equal(live.ref, "main");
120 assert.equal(live.state, "success");
121 assert.equal(live.source, "g1t_page");
122 assert.equal(live.creator, "ada");
123 assert.equal(live.environment_url, "https://web-acme.g1t.page");
124 assert.equal(live.log_url, "https://g1t.sh/acme/web/deployments/dpl_1");
125 assert.equal(live.production_environment, true);
126 const preview = fromBuild(build({ kind: "preview", branch: "fix", number: 7, status: "failed", error: "The build failed.", finished_at: null }), "main", "https://g1t.sh", appUrl);
127 assert.equal(preview.ref, "fix");
128 assert.equal(preview.number, 7);
129 assert.equal(preview.transient_environment, true);
130 assert.equal(preview.environment_url, null, "a failed build is not served");
131 assert.equal(preview.creator, "g1t", "an id no one could name is g1t");
132});
133
134test("a build's statuses come from its own timestamps", () => {
135 const row = build({ status: "replaced" });
136 const statuses = buildStatuses(row, fromBuild(row, "main", "https://g1t.sh", appUrl));
137 assert.deepEqual(
138 statuses.map((s) => s.state),
139 ["queued", "in_progress", "success", "inactive"],
140 );
141 const queued = build({ status: "queued", started_at: null, finished_at: null });
142 assert.deepEqual(
143 buildStatuses(queued, fromBuild(queued, "main", "https://g1t.sh", appUrl)).map((s) => s.state),
144 ["queued"],
145 );
146});

This file's history is long; its oldest lines are credited to the oldest commit read.