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

Projects live: fixes from walking them end to end

Verified on g1t.sh and g1t.page: the workspace page of project cards; a project's overview; production of automation-lab at its new address (automation-lab-syntaqx.g1t.page) with its config and its secret's Production row; a branch's preview (automation-lab-git-fix-login-syntaqx.g1t.page) with the Preview row; a preview live 42 s after its pull request opened and down 5 s after it closed. - Taking an app down now replaces it with a "not up" notice before deleting it. A deleted app kept answering for over 15 minutes where Cloudflare still had it warm; a new version reaches the edge at once. - Secrets and variables kept under a repository move to its primary project on every read, however the project is named. Deployments name the project, so the move never ran and the first build on the new address got none of its rows. - The dispatcher marks a preview noindex by its new name (-git-), and its pages speak of projects. - "New project" everywhere the site still said "New repository".

syntaqxcommitted Parentd191f93Browse files
6 files+46−190/6 viewed
+1−1
646646 const words: Record<string, string> = {
647647 settings: "Account",
648648 explore: "Explore",
649− new: "New repository",
649+ new: "New project",
650650 search: "Search",
651651 workspaces: "New workspace",
652652 };
+2−2
169169 <>
170170 <Link
171171 to="/new"
172− aria-label="New repository"
172+ aria-label="New project"
173173 className="rounded-md border border-line p-1.5 text-muted transition-colors hover:border-line-strong hover:text-fg"
174174 >
175175 <Plus size={16} />
214214 <DropdownMenuItem asChild>
215215 <Link to="/new">
216216 <Plus />
217− New repository
217+ New project
218218 </Link>
219219 </DropdownMenuItem>
220220 <DropdownMenuSeparator />
+1−1
8080 {role && (
8181 <ButtonLink to={`/new?workspace=${workspace.slug}`}>
8282 <Plus size={15} />
83− New repository
83+ New project
8484 </ButtonLink>
8585 )}
8686 </div>
+7−6
482482 /// and its running app get.
483483 pub async fn resolve_settings(&self, a: ResolveSettingsArgs) -> Result<ResolvedSettings> {
484484 let environment = a.environment.as_deref();
485− let (project_id, slug) = match (a.project_id, a.project_slug) {
486− (Some(id), Some(slug)) => (id, slug),
487− _ => match self.project_of(&a.repo_id).await? {
488− Some(project) => (project.id, project.slug),
489− None => return Ok(ResolvedSettings::default()),
490− },
485+ // Rows kept under the repository from before projects move to its
486+ // primary project first, however the project is named here.
487+ let primary = self.project_of(&a.repo_id).await?;
488+ let (project_id, slug) = match (a.project_id, a.project_slug, primary) {
489+ (Some(id), Some(slug), _) => (id, slug),
490+ (_, _, Some(project)) => (project.id, project.slug),
491+ _ => return Ok(ResolvedSettings::default()),
491492 };
492493 Ok(ResolvedSettings {
493494 secrets: self
+23−2
3333 /** Serves the site's files, for an app that brings no code of its own. */
3434 const ASSETS_ONLY = `export default { fetch(request, env) { return env.ASSETS.fetch(request); } };\n`;
3535
36−const HTML_HANDLING = ["auto-trailing-slash", "force-trailing-slash", "drop-trailing-slash", "none"];
36+/** What an app answers between being taken down and being gone. */
37+const TAKEN_DOWN = `export default {
38+ fetch() {
39+ return new Response("<!doctype html><meta charset=utf-8><meta name=robots content=noindex><title>Not up</title><body style='font:16px system-ui;background:#121214;color:#ececf1;display:grid;place-items:center;min-height:100vh;margin:0'><main><h1>This app is not up</h1><p style='color:#9a9aa6'>It was taken down. Deploying it again brings it back.</p></main>", { status: 404, headers: { "content-type": "text/html; charset=utf-8", "x-robots-tag": "noindex", "cache-control": "no-store" } });
40+ },
41+};
42+`;
43+
44+const HTML_HANDLING =["auto-trailing-slash", "force-trailing-slash", "drop-trailing-slash", "none"];
3745 const NOT_FOUND_HANDLING = ["single-page-application", "404-page", "none"];
3846
3947 export class Cloudflare {
148156 );
149157 }
150158
151− /** Takes an app down. Already gone is fine. */
159+ /**
160+ * Takes an app down. Already gone is fine.
161+ *
162+ * A deleted app can keep answering for a while where Cloudflare still has
163+ * it warm. So it is first replaced by a notice that it is down, which
164+ * reaches the edge as fast as any deploy, and deleted after.
165+ */
152166 async deleteScript(script: string): Promise<void> {
167+ const form = new FormData();
168+ form.append(
169+ "metadata",
170+ JSON.stringify({ main_module: "index.js", compatibility_date: "2026-09-26", bindings: [], tags: ["taken-down"] }),
171+ );
172+ form.append("index.js", new File([TAKEN_DOWN], "index.js", { type: "application/javascript+module" }));
173+ await this.call("PUT", this.scriptPath(script), form).catch(() => undefined);
153174 try {
154175 await this.call("DELETE", `${this.scriptPath(script)}?force=true`);
155176 } catch (error) {
+12−7
22 * The dispatcher for g1t.page: every app deployed by g1t is served here.
33 *
44 * The hostname's first label is the app's script name in the Workers for
5− * Platforms namespace (`pr-12--web--acme.g1t.page` is pull request 12's
6− * preview of acme/web), so a request needs no lookup: the app is fetched
7− * by name and runs only for as long as it answers. An app no one visits
5+ * Platforms namespace (`web-git-fix-login-acme.g1t.page` is the fix-login
6+ * branch's preview of acme's web project), so a request needs no lookup:
7+ * the app is fetched by name and runs only for as long as it answers. An app no one visits
88 * runs nothing and costs nothing.
99 *
1010 * Kept apart from g1t.sh, so apps share no cookies or origin with the site
8181 );
8282 }
8383 // Previews are for the people reviewing a change, not search engines.
84− if (label.startsWith("pr-")) {
84+ if (isPreview(label)) {
8585 response = new Response(response.body, response);
8686 response.headers.set("x-robots-tag", "noindex");
8787 }
8989 },
9090 } satisfies ExportedHandler<Env>;
9191
92+/** A branch's preview: `<project>-git-<branch>-<workspace>`. */
93+function isPreview(label: string): boolean {
94+ return label.includes("-git-");
95+}
96+
9297 function missing(label: string): Response {
93− const preview = label.startsWith("pr-");
98+ const preview = isPreview(label);
9499 return page(
95100 404,
96101 preview ? "This preview is not up" : "Nothing deployed here",
97102 preview
98− ? `<p>A preview comes down when its pull request is closed or merged, or after its repository's idle days without a visit. Pushing to the pull request, or redeploying it from the repository's Deployments page, brings it back.</p>`
99− : `<p>No app is deployed at <code>${escape(label)}.${DOMAIN}</code>. Deployments are turned on per repository, from its Deployments page on g1t.</p>`,
103+ ? `<p>A preview comes down when its pull request is closed or merged, or after its project's idle days without a visit. Pushing to the branch, or redeploying it from the project's Deployments page, brings it back.</p>`
104+ : `<p>No app is deployed at <code>${escape(label)}.${DOMAIN}</code>. Deployments are turned on per project, from its Settings on g1t.</p>`,
100105 );
101106 }