flagon-io/g1t

public

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

Commit

Builds say Replaced or Down once they are no longer live

Every successful build stayed 'Live' in a project's history, though each deploy replaces its app's Worker in place and taken-down previews are deleted. Now one build per app is Live: the one a newer build replaced is Replaced, and one whose app was taken down is Down. A migration corrects the builds already recorded.

syntaqxcommitted Parent96bd789Browse files
5 files+34−10/5 viewed
+2−0
55 queued: { label: "Queued", tone: "text-muted" },
66 building: { label: "Building", tone: "text-warn" },
77 ready: { label: "Live", tone: "text-accent" },
8+ replaced: { label: "Replaced", tone: "text-faint" },
9+ down: { label: "Down", tone: "text-faint" },
810 failed: { label: "Failed", tone: "text-danger" },
911 skipped: { label: "Skipped", tone: "text-faint" },
1012 };
+2−0
2323 queued: "Waiting for a sandbox",
2424 building: "Building",
2525 ready: "Live",
26+ replaced: "Replaced by a newer build",
27+ down: "Taken down",
2628 failed: "Failed",
2729 skipped: "Skipped",
2830 } as const;
+5−0
4646 /** Waiting for a sandbox. */
4747 | "queued"
4848 | "building"
49+ /** What its app serves now. */
4950 | "ready"
51+ /** Built and served, until a newer build of the same app replaced it. */
52+ | "replaced"
53+ /** Built and served, until its app was taken down. */
54+ | "down"
5055 | "failed"
5156 /** Not built: the workspace's plan is off, or the build was replaced. */
5257 | "skipped";
+16−0
1+-- A build stays 'ready' only while it is what its app serves. One a newer
2+-- build replaced becomes 'replaced'; one whose app was taken down becomes
3+-- 'down'. This corrects the builds already recorded.
4+
5+-- Taken down: no app holds the script any more.
6+UPDATE deployments SET status = 'down'
7+WHERE status = 'ready' AND script NOT IN (SELECT script FROM apps);
8+
9+-- Replaced: a later ready build of the same app exists.
10+UPDATE deployments SET status = 'replaced'
11+WHERE status = 'ready'
12+ AND EXISTS (
13+ SELECT 1 FROM deployments newer
14+ WHERE newer.script = deployments.script AND newer.status = 'ready'
15+ AND COALESCE(newer.finished_at, newer.created_at) > COALESCE(deployments.finished_at, deployments.created_at)
16+ );
+9−1
882882 WHERE id = ?`,
883883 )
884884 .bind(JSON.stringify(Array.isArray(body.warnings) ? body.warnings : []), String(body.log ?? ""), seconds, at, id),
885+ // The build it replaces is no longer what the app serves.
885886 this.db
887+ .prepare(`UPDATE deployments SET status = 'replaced' WHERE script = ? AND id != ? AND status = 'ready'`)
888+ .bind(row.script, id),
889+ this.db
886890 .prepare(
887891 `INSERT INTO apps (script, project_id, workspace, slug, kind, branch, number, commit_sha, deployed_at, created_at)
888892 VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?9)
10541058
10551059 private async removeApp(script: string): Promise<void> {
10561060 await this.cloudflare?.deleteScript(script);
1057− await this.db.prepare("DELETE FROM apps WHERE script = ?").bind(script).run();
1061+ await this.db.batch([
1062+ this.db.prepare("DELETE FROM apps WHERE script = ?").bind(script),
1063+ // Its build is no longer live anywhere.
1064+ this.db.prepare("UPDATE deployments SET status = 'down' WHERE script = ? AND status = 'ready'").bind(script),
1065+ ]);
10581066 }
10591067
10601068 private async takeDownWhere(projectId: string, kind: DeployKind | null, branch?: string): Promise<void> {