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.

g1t.sh
77 linesCodeBlameRaw

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.

The workspace cost alert compares only days that carry their value, not the days before it was kept1// Tells status.g1t.sh a deploy started or finished, so the restarts it
2// causes are counted but not drafted as incidents (apps/status detect.ts:
3// during the deploy and 3 minutes after; trouble that outlasts that is
4// drafted with its true start).
5//
6// node scripts/deploy/status-window.mjs started [id]
7// node scripts/deploy/status-window.mjs finished [id]
8//
9// Needs STATUS_DEPLOY_TOKEN (the status Worker's secret of the same name);
10// STATUS_URL defaults to https://status.g1t.sh. Never fails a deploy:
11// without the token it does nothing, and any error is a warning.
12//
Merge status detection: first-byte speed probe, deploy windows, 4 of 5 with a re-check, check history, reminders13// scripts/deploy.mjs `deploy()` wraps its stages in `withDeployWindow`
14// once there is something to ship (never in a dry run), so every deploy,
15// by hand or in g1t Actions (.g1t/workflows/deploy.yml passes the
16// STATUS_DEPLOY_TOKEN secret), says so. Jobs that run at once (a stage's
17// matrix) each say started and finished; the status Worker counts them and
18// the window closes when the last one finishes.
The workspace cost alert compares only days that carry their value, not the days before it was kept19
20import { pathToFileURL } from "node:url";
21
22/**
Merge status detection: first-byte speed probe, deploy windows, 4 of 5 with a re-check, check history, reminders23 * Runs `work` inside a deploy window: "started" before, "finished" after,
24 * whether it succeeded or threw. Neither announcement can fail the deploy.
25 *
26 * @template T
27 * @param {() => Promise<T>} work
28 * @param {{ id?: string | null, dryRun?: boolean, announce?: typeof announceDeploy, env?: Record<string, string | undefined>, log?: (line: string) => void }} [options]
29 * @returns {Promise<T>}
30 */
31export async function withDeployWindow(work, { id = null, dryRun = false, announce = announceDeploy, env = process.env, log } = {}) {
32 if (dryRun) return work();
33 const options = { id, env, ...(log ? { log } : {}) };
34 await announce("started", options);
35 try {
36 return await work();
37 } finally {
38 await announce("finished", options);
39 }
40}
41
42/**
The workspace cost alert compares only days that carry their value, not the days before it was kept43 * @param {"started" | "finished"} phase
44 * @param {{ id?: string | null, env?: Record<string, string | undefined>, fetchImpl?: typeof fetch, log?: (line: string) => void }} [options]
45 * @returns {Promise<boolean>} whether status.g1t.sh took it
46 */
47export async function announceDeploy(phase, { id = null, env = process.env, fetchImpl = fetch, log = (line) => console.warn(line) } = {}) {
48 const token = (env.STATUS_DEPLOY_TOKEN ?? "").trim();
49 if (!token) return false;
50 const base = (env.STATUS_URL || "https://status.g1t.sh").replace(/\/+$/, "");
51 try {
52 const response = await fetchImpl(`${base}/deploys`, {
53 method: "POST",
54 headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
55 body: JSON.stringify({ phase, ...(id ? { id: String(id).slice(0, 100) } : {}) }),
56 signal: AbortSignal.timeout(5000),
57 });
58 if (!response.ok) {
59 log(`status: the deploy ${phase} was not recorded (${response.status}); detection may draft restarts.`);
60 return false;
61 }
62 return true;
63 } catch (error) {
64 log(`status: the deploy ${phase} was not recorded (${error instanceof Error ? error.message : String(error)}).`);
65 return false;
66 }
67}
68
69if (import.meta.url === `file://${process.argv[1]?.replace(/\\/g, "/").replace(/^(?=[A-Za-z]:)/, "/")}`) {
70 const [phase, id] = process.argv.slice(2);
71 if (phase !== "started" && phase !== "finished") {
72 console.error("usage: node scripts/deploy/status-window.mjs started|finished [id]");
73 process.exit(2);
74 }
75 const ok = await announceDeploy(phase, { id: id ?? null });
76 console.log(ok ? `status: deploy ${phase}` : "status: not recorded (no STATUS_DEPLOY_TOKEN, or status did not answer)");
77}

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