Skip to content
381 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 statement is a month at a time, a line per kind of charge1import type { User, Viewer } from "./identity";
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb972import type { RepoPath } from "./repos";
The statement is a month at a time, a line per kind of charge3import type { Result } from "./result";
4
5/**
6 * Deployments: a project's production, deployed from its default branch on
7 * every push, and a live preview of every branch with an open pull request.
8 * Apps run as Workers in a Workers for Platforms namespace, so an app no
9 * one visits costs nothing. A paid feature: the workspace turns it on with
10 * a monthly plan (see `Feature` in `./billing`), and each project then
11 * chooses for itself.
12 */
13
14/** The domain apps are served on. Never g1t.sh, so they share no cookies with it. */
15export const DEPLOYMENTS_DOMAIN = "g1t.page";
16
17/** A project, as deployments name it. */
18export type ProjectRef = { workspace: string; slug: string };
19
20/** A project's deployment settings. */
21export type DeploySettings = {
22 /** Whether this project deploys at all. Off until someone turns it on. */
23 enabled: boolean;
24 /** A preview for every branch with an open pull request. */
25 previews: boolean;
26 /** The default branch deployed to production on every push. */
27 production: boolean;
28 /** Runs instead of the project's own `build` script. */
29 buildCommand: string | null;
30 /** What to serve, for a static site; found by itself when null. */
31 outputDir: string | null;
32 /** A preview no one has visited in this many days is taken down. */
33 idleDays: number;
Merge branch 'claude/cool-newton-7nm8r9' (#36): real GitHub Actions on g1t, managed deploy workflows, g1t/deploy and the Sysbox runner 0.2.0. The merge keeps both sides' webhook events and API operations, says agent images need tar, guards the job engine's stop to Unix so the runner builds on Windows again, and keeps the moves tests' previews from going idle as the calendar passes their fixture's date.34 /**
35 * Whether it builds through the deploy workflow g1t manages for it, a
36 * workflow run on each push and pull request like any other, rather
37 * than through Deployments' own build.
38 */
39 viaWorkflow?: boolean;
The statement is a month at a time, a line per kind of charge40 /** Where production is served. */
41 productionUrl: string;
42 /**
43 * The project's own domain for production, once it is active: the first
44 * custom domain added that serves the app rather than redirecting. Null
45 * until one is.
46 */
47 primaryDomain: string | null;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look48 /**
49 * What the last finished build found the project to be: a Workers
50 * project (it has a Workers config), a static site its build wrote, or
51 * plain HTML served as it is. Null until a build has finished. Read-only.
52 */
53 detected: DetectedKind | null;
The statement is a month at a time, a line per kind of charge54};
55
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look56export type DetectedKind = "workers" | "static" | "html";
57
The statement is a month at a time, a line per kind of charge58export type DeployKind = "preview" | "production";
59
60export type DeployStatus =
61 /** Waiting for a sandbox. */
62 | "queued"
63 | "building"
64 /** What its app serves now. */
65 | "ready"
66 /** Built and served, until a newer build of the same app replaced it. */
67 | "replaced"
68 /** Built and served, until its app was taken down. */
69 | "down"
70 | "failed"
71 /** Not built: the workspace's plan is off, or the build was replaced. */
72 | "skipped";
73
74/** One build of one commit, and where it went. */
75export type Deployment = {
76 id: string;
77 kind: DeployKind;
78 /** For a preview: the branch, or `pr-<n>` for a pull request from a fork. */
79 branch: string | null;
80 /** For a preview: its pull request. */
81 number: number | null;
82 commit: string;
83 status: DeployStatus;
84 url: string;
85 /** Why it failed or was skipped. */
86 error: string | null;
87 /** What the build could not provide, such as bindings not provisioned yet. */
88 warnings: string[];
89 /** How long the build ran, in seconds; charged at the container price. */
90 buildSeconds: number | null;
91 createdBy: string;
92 /** RFC 3339. */
93 createdAt: string;
94 finishedAt: string | null;
95};
96
97/** An app that is up: production, or one branch's preview. */
98export type LiveApp = {
99 kind: DeployKind;
100 branch: string | null;
101 number: number | null;
102 url: string;
103 commit: string;
104 /** RFC 3339: when it was last deployed. */
105 deployedAt: string;
106};
107
108/** One project at a glance, for the workspace's page. */
109export type ProjectDeploys = {
110 slug: string;
111 enabled: boolean;
112 production: LiveApp | null;
113 previews: number;
114 /** The newest build, whatever its status. */
115 latest: Deployment | null;
116};
117
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas118/** What a workspace's apps used this month. Every request, CPU millisecond and build second is metered; apps are not. */
The statement is a month at a time, a line per kind of charge119export type DeployUsage = {
120 /** `YYYY-MM`. */
121 month: string;
122 requests: number;
123 cpuMs: number;
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas124 /** Apps up now (production and previews), and the most at once this month: for information, never charged. */
The statement is a month at a time, a line per kind of charge125 apps: number;
126 peakApps: number;
127 buildSeconds: number;
128 /** Charged so far this month for builds, in millionths of a dollar. */
129 buildMicros: number;
Merge branch 'worktree-agent-ab9543c492a7ed481' into spend-guardrails130 /** RFC 3339: when requests and CPU time last went up. */
The statement is a month at a time, a line per kind of charge131 countedAt: string | null;
132};
133
134/** Where custom domains point: a hostname on g1t.page that routes to the dispatcher. */
135export const CUSTOM_DOMAIN_TARGET = "domains.g1t.page";
136
137/**
138 * A custom domain's state: `pending` until its DNS points at g1t (or its
139 * ownership record is found), `verifying` while its certificate is
140 * issued, then `active`. `failed` says why in `error`; `removing` is on
141 * its way out.
142 */
143export type DomainStatus = "pending" | "verifying" | "active" | "failed" | "removing";
144
145/** A DNS record the domain's owner adds at their DNS provider. */
146export type DomainRecord = {
147 /** `ALIAS` stands for a flattened CNAME at the apex, whatever the provider calls it. */
148 type: "CNAME" | "TXT" | "ALIAS";
149 /** The record's full name. */
150 name: string;
151 value: string;
152 /** What it is for, in a few words. */
153 purpose: string;
154};
155
156/** A hostname of the project's own, serving its production. */
157export type Domain = {
158 id: string;
159 hostname: string;
160 /** What it serves: `production`. */
161 target: "production";
162 status: DomainStatus;
163 /** Cloudflare's state for its certificate, as given. */
164 sslStatus: string | null;
165 /** Whether it is a registrable domain itself (`example.com`), which needs a flattened CNAME. */
166 apex: boolean;
167 /** Every record to add: where traffic goes, then any Cloudflare asks for. */
168 records: DomainRecord[];
169 /** A hostname this one redirects to (308, path and query kept), for a www/apex pair. */
170 redirectTo: string | null;
171 /** Why it is not active yet, or failed. */
172 error: string | null;
173 createdBy: string;
174 createdAt: string;
175 verifiedAt: string | null;
176};
177
178export type ProjectDomains = {
179 domains: Domain[];
180 /** The hostname every domain points at. */
181 target: string;
182 /** False until custom domains are switched on for g1t.page; `notice` says so. */
183 available: boolean;
184 notice: string | null;
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas185 /** What one custom domain costs a month on the plan, in millionths of a dollar: g1t's cost plus 20%. */
186 monthlyMicros: number;
The statement is a month at a time, a line per kind of charge187 /** The workspace's custom domains now. */
188 used: number;
189};
190
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97191// ---- A repository's deployments, wherever they run ---------------------
192//
193// Every deployment of a repository, in one model: g1t.page builds (read
194// from the builds above, never copied), deployments g1t Actions makes for
195// a job with an `environment:`, and deployments any other system reports
196// through the API. These travel in `snake_case` between services too, as
197// the API shows them, so a deployment's `payload` reaches the API with its
198// keys as they were given.
199
200/** Where a deployment is, as its latest status says. */
201export type DeploymentState = "queued" | "in_progress" | "success" | "failure" | "error" | "inactive";
202
203export const DEPLOYMENT_STATES: readonly DeploymentState[] = ["queued", "in_progress", "success", "failure", "error", "inactive"];
204
205/**
206 * What made a deployment: `api` (reported with a token), `actions` (a g1t
207 * Actions job with an `environment:`) or `g1t_page` (a build on g1t.page).
208 */
209export type DeploymentSource = "api" | "actions" | "g1t_page";
210
211/** One deployment of one commit to one environment. */
212export type RepoDeployment = {
213 /** `dep_…` for a reported deployment, `dpl_…` for a g1t.page build. */
214 id: string;
215 /** Such as `production`, `staging` or `preview`. */
216 environment: string;
217 /** The branch, tag or commit asked for. */
218 ref: string;
219 sha: string;
220 /** What kind of deployment: `deploy` unless given, such as `deploy:migrations`. */
221 task: string;
222 description: string | null;
223 /** Whatever the reporter attached, as given. */
224 payload: Record<string, unknown>;
225 /** An environment that goes away, such as a pull request's preview. */
226 transient_environment: boolean;
227 /** An environment people use directly. */
228 production_environment: boolean;
229 /** Its latest status's state. */
230 state: DeploymentState;
231 /** Where it is served, from its latest status that gave one. */
232 environment_url: string | null;
233 /** Where its output can be read, from its latest status that gave one. */
234 log_url: string | null;
235 /** The username that created it, or `g1t`. */
236 creator: string;
237 source: DeploymentSource;
238 /** For `actions`: the workflow run, and its address on the site. */
239 run_id: string | null;
240 run_url: string | null;
241 /** For `g1t_page`: the project it built, and a preview's pull request. */
242 project: string | null;
243 number: number | null;
244 /** RFC 3339. */
245 created_at: string;
246 /** RFC 3339: its latest status. */
247 updated_at: string;
248};
249
250/** One status of a deployment: what it said, and when. */
251export type DeploymentStatus = {
252 id: string;
253 deployment_id: string;
254 state: DeploymentState;
255 description: string | null;
256 environment_url: string | null;
257 log_url: string | null;
258 creator: string;
259 /** RFC 3339. */
260 created_at: string;
261};
262
263/** A deployment with every status it has had, oldest first. */
264export type DeploymentDetail = RepoDeployment & { statuses: DeploymentStatus[] };
265
266/** An environment: a name deployments go to, made by the first. */
267export type DeploymentEnvironment = {
268 name: string;
269 /** Where its current deployment is served. */
270 url: string | null;
271 production_environment: boolean;
272 transient_environment: boolean;
273 /** How many deployments it has had. */
274 deployments_count: number;
275 /** Its newest deployment, whatever its state. */
276 latest: RepoDeployment | null;
277 /** The newest deployment that succeeded and is still active: what it serves. */
278 current: RepoDeployment | null;
279 /** RFC 3339: its newest deployment's latest status. */
280 updated_at: string;
281};
282
283/** A repository's environments, production first, and its count of deployments. */
284export type DeploymentEnvironments = {
285 /** Deployments across every environment. */
286 total_count: number;
287 environments: DeploymentEnvironment[];
288};
289
290/** Which deployments to list. Every field narrows the list. */
291export type DeploymentFilter = {
292 environment?: string | null;
293 ref?: string | null;
294 sha?: string | null;
295 task?: string | null;
296 state?: DeploymentState | null;
297 source?: DeploymentSource | null;
298 creator?: string | null;
299 /** From 1. */
300 page?: number | null;
301 /** 1 to 100; 30 unless given. */
302 per_page?: number | null;
303};
304
305/** One page of deployments, newest first. */
306export type DeploymentPage = {
307 deployments: RepoDeployment[];
308 total_count: number;
309 page: number;
310 per_page: number;
311};
312
313/** What `create_deployment` takes, as the API does. */
314export type NewDeployment = {
315 ref: string;
316 /** The commit; resolved from `ref` when left out. */
317 sha?: string | null;
318 environment?: string | null;
319 task?: string | null;
320 description?: string | null;
321 payload?: Record<string, unknown> | null;
322 transient_environment?: boolean | null;
323 production_environment?: boolean | null;
324 /** The state of its first status: `queued` unless given. */
325 state?: DeploymentState | null;
326 environment_url?: string | null;
327 log_url?: string | null;
328};
329
330/** What `create_deployment_status` takes. */
331export type NewDeploymentStatus = {
332 state: DeploymentState;
333 description?: string | null;
334 environment_url?: string | null;
335 log_url?: string | null;
336 /**
337 * On a success: the environment's older deployments that succeeded get
338 * an `inactive` status. True unless given.
339 */
340 auto_inactive?: boolean | null;
341};
342
The statement is a month at a time, a line per kind of charge343export interface DeploymentsApi {
344 /** Members of the workspace only. */
345 settings(project: ProjectRef, viewer: Viewer): Promise<Result<DeploySettings>>;
346 /** Members only. Turning deployments on needs the workspace's plan. */
347 updateSettings(actor: User, project: ProjectRef, changes: Partial<DeploySettings>): Promise<Result<DeploySettings>>;
348 /** The newest builds first, and what is up now. Members only. */
349 list(project: ProjectRef, viewer: Viewer): Promise<Result<{ deployments: Deployment[]; live: LiveApp[] }>>;
350 /** One build, with its log. Members only. */
351 get(project: ProjectRef, id: string, viewer: Viewer): Promise<Result<Deployment & { log: string | null }>>;
352 /** Builds production (`branch` null), or a branch's preview, again from its head. */
353 redeploy(actor: User, project: ProjectRef, branch: string | null): Promise<Result<Deployment>>;
354 /** Takes production (`branch` null), or a branch's preview, down now. */
355 takeDown(actor: User, project: ProjectRef, branch: string | null): Promise<Result<true>>;
356 /** Every project of a workspace at a glance. Members only. */
357 overview(workspace: string, viewer: Viewer): Promise<Result<ProjectDeploys[]>>;
358 /** What the workspace's apps used this month. Members only. */
359 usage(workspace: string, viewer: Viewer): Promise<Result<DeployUsage>>;
360 /** The project's custom domains. Members only. */
361 domains(project: ProjectRef, viewer: Viewer): Promise<Result<ProjectDomains>>;
362 /**
363 * Adds a custom domain for production. With `twin`, its www or apex twin
364 * is added too, redirecting to it. Members only; needs the Deployments plan.
365 */
366 addDomain(actor: User, project: ProjectRef, hostname: string, options?: { twin?: boolean }): Promise<Result<Domain[]>>;
367 /** Removes a custom domain, and any domain redirecting to it. Members only. */
368 removeDomain(actor: User, project: ProjectRef, id: string): Promise<Result<true>>;
369 /** Asks Cloudflare to check the domain again now. Members only. */
370 refreshDomain(actor: User, project: ProjectRef, id: string): Promise<Result<Domain>>;
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97371 /** A repository's deployments, newest first, filtered. Anyone who can read it. */
372 repoDeployments(repo: RepoPath, viewer: Viewer, filter?: DeploymentFilter): Promise<Result<DeploymentPage>>;
373 /** One deployment with its statuses, oldest first. Anyone who can read the repository. */
374 repoDeployment(repo: RepoPath, id: string, viewer: Viewer): Promise<Result<DeploymentDetail>>;
375 /** A repository's environments with their current and latest deployments. Anyone who can read it. */
376 environments(repo: RepoPath, viewer: Viewer): Promise<Result<DeploymentEnvironments>>;
377 /** Reports a deployment. Takes the Write role. */
378 createDeployment(actor: User, repo: RepoPath, input: NewDeployment): Promise<Result<DeploymentDetail>>;
379 /** Adds a status to a reported deployment. Takes the Write role. */
380 createDeploymentStatus(actor: User, repo: RepoPath, id: string, input: NewDeploymentStatus): Promise<Result<DeploymentStatus>>;
The statement is a month at a time, a line per kind of charge381}

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