Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

224 linesCodeBlameRaw
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import {
5 PER_PAGE,
6 SOURCE_LABEL,
7 STATE_WORD,
8 buildError,
9 choices,
10 environmentLabel,
11 environmentUrl,
12 groupBuilds,
13 hasPayload,
14 isFiltered,
15 isNewestStatus,
16 isPageBuild,
17 orderEnvironments,
18 pageRange,
19 parseFilter,
20 productionEnvironment,
21 nativeProduction,
22 shortSha,
23 withFilter,
24} from "./deployments.ts";
25
26const GIT =
27 "the commit could not be checked out: git -c failed: fatal: reference is not a tree: d2ca224ba0fea430dcc9933cda14d8aa9fa94b4b";
28
29type Build = Parameters<typeof groupBuilds>[0][number] & { id: string };
30
31let hour = 0;
32const build = (over: Partial<Build>): Build => ({
33 id: `dep_${hour}`,
34 kind: "preview",
35 branch: "v2",
36 number: 1,
37 status: "failed",
38 error: GIT,
39 createdAt: new Date(Date.parse("2026-10-07T12:00:00Z") - hour++ * 3_600_000).toISOString(),
40 ...over,
41});
42
43test("a commit that is gone is said plainly, naming the pull request", () => {
44 assert.equal(
45 buildError({ kind: "preview", number: 1, error: GIT }),
46 "This pull request's commit no longer exists. Push again, or close pull request #1.",
47 );
48 assert.match(buildError({ kind: "production", number: null, error: GIT })!, /default branch/);
49 assert.equal(buildError({ kind: "preview", number: 1, error: "npm run build exited 1." }), "npm run build exited 1.");
50 assert.equal(buildError({ kind: "preview", number: 1, error: null }), null);
51});
52
53test("a run of the same failure of one app is one row, counted, linking to the newest", () => {
54 hour = 0;
55 const builds = [build({}), build({}), build({}), build({ status: "ready", error: null }), build({})];
56 const groups = groupBuilds(builds);
57 assert.deepEqual(
58 groups.map((g) => [g.build.id, g.count]),
59 [
60 ["dep_0", 3],
61 ["dep_3", 1],
62 ["dep_4", 1],
63 ],
64 );
65 assert.equal(groups[0]!.firstAt, builds[2]!.createdAt);
66});
67
68test("other apps' builds in between do not break a run; a different error does", () => {
69 hour = 0;
70 const groups = groupBuilds([
71 build({}),
72 build({ kind: "production", branch: null, number: null, status: "ready", error: null }),
73 build({}),
74 build({ branch: "add-ci", number: 2, error: "fatal: reference is not a tree: 213e9095" }),
75 build({}),
76 build({ error: "npm run build exited 1." }),
77 build({ error: "npm run build exited 1." }),
78 ]);
79 assert.deepEqual(
80 groups.map((g) => [g.build.id, g.count]),
81 [
82 ["dep_0", 3],
83 ["dep_1", 1],
84 ["dep_3", 1],
85 ["dep_5", 2],
86 ],
87 );
88});
89
90test("builds that did not fail are never folded", () => {
91 hour = 0;
92 const ready = groupBuilds([build({ status: "ready", error: null }), build({ status: "ready", error: null })]);
93 assert.deepEqual(ready.map((g) => g.count), [1, 1]);
94 assert.deepEqual(groupBuilds([]), []);
95});
96
97// --- A repository's deployments ------------------------------------------------
98
99type Env = Parameters<typeof productionEnvironment>[0][number];
100const env = (name: string, over: Partial<Env> = {}): Env => ({
101 name,
102 production_environment: false,
103 transient_environment: false,
104 updated_at: "2026-10-07T12:00:00Z",
105 latest: null,
106 ...over,
107});
108const deployed = { id: "dep_1" } as unknown as Env["latest"];
109
110test("environments list production first, then lasting ones, then previews, newest first in each", () => {
111 const ordered = orderEnvironments([
112 env("preview", { transient_environment: true, updated_at: "2026-10-07T11:00:00Z" }),
113 env("staging", { updated_at: "2026-10-01T00:00:00Z" }),
114 env("qa", { updated_at: "2026-10-06T00:00:00Z" }),
115 env("production-eu", { production_environment: true, updated_at: "2026-10-07T11:59:00Z" }),
116 env("production", { production_environment: true, updated_at: "2026-10-01T00:00:00Z" }),
117 ]);
118 assert.deepEqual(
119 ordered.map((e) => e.name),
120 ["production", "production-eu", "qa", "staging", "preview"],
121 );
122});
123
124test("production is the production environment that has had a deployment, named production first", () => {
125 assert.equal(productionEnvironment([env("staging", { latest: deployed })]), null);
126 assert.equal(productionEnvironment([env("production", { production_environment: true })]), null);
127 assert.equal(
128 productionEnvironment([
129 env("live", { production_environment: true, latest: deployed }),
130 env("production", { production_environment: true, latest: deployed }),
131 ])?.name,
132 "production",
133 );
134 assert.equal(
135 productionEnvironment([env("production", { production_environment: true }), env("live", { production_environment: true, latest: deployed })])
136 ?.name,
137 "live",
138 );
139});
140
141test("an environment is served at its own address, else its current deployment's", () => {
142 const at = (environment_url: string | null, state = "success") => ({ environment_url, state }) as never;
143 assert.equal(environmentUrl({ url: "https://g1t.sh", current: null, latest: null }), "https://g1t.sh");
144 assert.equal(
145 environmentUrl({ url: null, current: at("https://a.g1t.page"), latest: at("https://b.g1t.page", "failure") }),
146 "https://a.g1t.page",
147 );
148 assert.equal(environmentUrl({ url: null, current: null, latest: at("https://b.g1t.page", "failure") }), null);
149});
150
151test("the list's filter is read from the address, ignoring what it cannot be", () => {
152 const filter = parseFilter(new URLSearchParams("environment=production&state=failure&source=actions&creator=syntaqx&ref=main&page=3"));
153 assert.deepEqual(filter, {
154 environment: "production",
155 state: "failure",
156 source: "actions",
157 creator: "syntaqx",
158 ref: "main",
159 page: 3,
160 per_page: PER_PAGE,
161 });
162 const junk = parseFilter(new URLSearchParams("state=exploded&source=ftp&page=-2&per_page=1000&environment=%20"));
163 assert.equal(junk.state, null);
164 assert.equal(junk.source, null);
165 assert.equal(junk.environment, null);
166 assert.equal(junk.page, 1);
167 assert.equal(junk.per_page, 100);
168 assert.equal(isFiltered(junk), false);
169 assert.equal(isFiltered(filter), true);
170});
171
172test("changing a filter keeps the others and starts again from the first page", () => {
173 const filter = parseFilter(new URLSearchParams("environment=production&state=failure&page=2"));
174 assert.equal(withFilter("/a/b/deployments", filter, "state", "success"), "/a/b/deployments?environment=production&state=success#history");
175 assert.equal(withFilter("/a/b/deployments", filter, "environment", null), "/a/b/deployments?state=failure#history");
176 assert.equal(withFilter("/a/b/deployments", filter, "page", 3), "/a/b/deployments?environment=production&state=failure&page=3#history");
177 assert.equal(withFilter("/a/b/deployments", parseFilter(new URLSearchParams()), "page", 1), "/a/b/deployments#history");
178});
179
180test("a filter's choices are each value once, sorted, keeping the chosen one", () => {
181 const list = [{ creator: "g1t", ref: "main" }, { creator: "syntaqx", ref: "main" }, null, { creator: "g1t", ref: "v2" }];
182 assert.deepEqual(choices(list, "creator"), ["g1t", "syntaqx"]);
183 assert.deepEqual(choices(list, "ref", "release"), ["main", "release", "v2"]);
184});
185
186test("words for states, sources, environments and pages", () => {
187 assert.equal(STATE_WORD.in_progress, "Deploying");
188 assert.equal(SOURCE_LABEL.g1t_page, "g1t.page");
189 assert.equal(environmentLabel("production"), "Production");
190 assert.equal(shortSha("d2ca224ba0fea430"), "d2ca224");
191 assert.equal(isPageBuild("dpl_123"), true);
192 assert.equal(isPageBuild("dep_123"), false);
193 assert.equal(pageRange(2, 30, 304), "31–60 of 304");
194 assert.equal(pageRange(11, 30, 304), "301–304 of 304");
195 assert.equal(pageRange(1, 30, 0), "0 of 0");
196 assert.equal(hasPayload({}), false);
197 assert.equal(hasPayload({ region: "wnam" }), true);
198 assert.equal(hasPayload(null), false);
199});
200
201test("only a deployment's newest status can still be under way", () => {
202 const statuses = [
203 { created_at: "2026-10-08T10:00:00.000Z" }, // Deploying, building
204 { created_at: "2026-10-08T10:02:00.000Z" }, // Deployed
205 ];
206 assert.equal(isNewestStatus(statuses, 0), false);
207 assert.equal(isNewestStatus(statuses, 1), true);
208 // Listed out of order: the newest is still the latest written.
209 assert.equal(isNewestStatus([...statuses].reverse(), 0), true);
210 // Written in the same moment: the last listed is the newest.
211 const tied = [{ created_at: "2026-10-08T10:00:00.000Z" }, { created_at: "2026-10-08T10:00:00.000Z" }];
212 assert.equal(isNewestStatus(tied, 0), false);
213 assert.equal(isNewestStatus(tied, 1), true);
214 assert.equal(isNewestStatus([], 0), false);
215});
216
217test("native screenshots use the serving app, not a newer attempt or custom domain", () => {
218 const current = { source: "g1t_page", state: "success", environment_url: "https://app-acme.g1t.page", sha: "abcdef1", updated_at: "2026-10-15T01:00:00Z" };
219 const production = { ...env("production", { production_environment: true, latest: deployed }), current, url: "https://custom.example" };
220 assert.deepEqual(nativeProduction([production as never]), { url: current.environment_url, commit: current.sha, deployedAt: current.updated_at });
221 assert.equal(nativeProduction([{ ...production, current: null } as never]), null);
222 assert.equal(nativeProduction([{ ...production, current: { ...current, state: "inactive" } } as never]), null);
223 assert.equal(nativeProduction([{ ...production, current: { ...current, source: "actions" } } as never]), null);
224});