summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgithub/.gitignore1
-rw-r--r--cgithub/CLAUDE.md2
-rw-r--r--cgithub/package.json4
-rw-r--r--cgithub/scripts/build.ts52
-rw-r--r--cgithub/scripts/compile-views.ts29
-rw-r--r--cgithub/src/app.ts3
-rw-r--r--cgithub/src/worker.ts2
-rw-r--r--cgithub/views/layout.eta2
8 files changed, 60 insertions, 35 deletions
diff --git a/cgithub/.gitignore b/cgithub/.gitignore
index 5a5e404..b8fc600 100644
--- a/cgithub/.gitignore
+++ b/cgithub/.gitignore
@@ -1,3 +1,4 @@
/node_modules/
/.wrangler/
+/src/commit.generated.ts
/src/views.generated.ts
diff --git a/cgithub/CLAUDE.md b/cgithub/CLAUDE.md
index 37774cc..0ef4b47 100644
--- a/cgithub/CLAUDE.md
+++ b/cgithub/CLAUDE.md
@@ -24,7 +24,7 @@ pnpm test
- `src/worker.ts` - Cloudflare Workers entry (config in `wrangler.jsonc`)
- `src/scraper.ts` - GitHub HTML fetching and JSON extraction logic
-**Templates:** `views/*.eta` - Eta templates with layout inheritance (`layout.eta` as base). On Workers, runtime code generation is disallowed, so `scripts/compile-views.ts` precompiles templates to `src/views.generated.ts` (gitignored, regenerated by the `dev`/`deploy` scripts).
+**Templates:** `views/*.eta` - Eta templates with layout inheritance (`layout.eta` as base). On Workers, runtime code generation is disallowed, so `scripts/build.ts` precompiles templates to `src/views.generated.ts`. The same script records the build's `git describe` output in `src/commit.generated.ts` for the page footer. Both are gitignored and regenerated by the `dev`/`deploy` scripts.
**Static files:** `public/static/*`, served by Workers Static Assets.
diff --git a/cgithub/package.json b/cgithub/package.json
index 337fabc..7673612 100644
--- a/cgithub/package.json
+++ b/cgithub/package.json
@@ -5,8 +5,8 @@
"license": "MIT",
"type": "module",
"scripts": {
- "dev": "node scripts/compile-views.ts && wrangler dev",
- "deploy": "node scripts/compile-views.ts && wrangler deploy",
+ "dev": "node scripts/build.ts && wrangler dev",
+ "deploy": "node scripts/build.ts && wrangler deploy",
"test": "node --test --test-concurrency=4 src/scraper.test.ts"
},
"dependencies": {
diff --git a/cgithub/scripts/build.ts b/cgithub/scripts/build.ts
new file mode 100644
index 0000000..766e5e8
--- /dev/null
+++ b/cgithub/scripts/build.ts
@@ -0,0 +1,52 @@
+// Generates the sources that can't exist at runtime on Workers:
+//
+// src/views.generated.ts - views/*.eta precompiled into plain functions.
+// Workers disallow runtime code generation (`new Function`), so Eta cannot
+// compile templates there at request time.
+// src/commit.generated.ts - the commit this build was made from, for the
+// page footer. Workers can't shell out to git at request time either.
+import { execFileSync } from "node:child_process";
+import { Eta } from "eta";
+import fs from "node:fs";
+import path from "node:path";
+
+const root = path.join(import.meta.dirname, "..");
+const viewsDir = path.join(root, "views");
+const eta = new Eta({ views: viewsDir });
+
+const names = fs
+ .readdirSync(viewsDir)
+ .filter((name) => name.endsWith(".eta"))
+ .sort();
+
+let out = `// @ts-nocheck
+// Generated by scripts/build.ts -- do not edit.
+export const views = {
+`;
+for (const name of names) {
+ const source = fs.readFileSync(path.join(viewsDir, name), "utf8");
+ const body = eta.compileToString(source);
+ out += ` ${JSON.stringify(name)}: function (it, options) {\n${body}\n },\n`;
+}
+out += "};\n";
+
+fs.writeFileSync(path.join(root, "src", "views.generated.ts"), out);
+console.log(`Compiled ${names.length} templates to src/views.generated.ts`);
+
+// Untagged repositories describe as a bare short hash; --dirty marks a build
+// made from an unclean working copy.
+let commit = "unknown";
+try {
+ commit = execFileSync("git", ["describe", "--tags", "--always", "--dirty"], {
+ cwd: root,
+ encoding: "utf8",
+ }).trim();
+} catch {
+ // Building from a source copy without git history.
+}
+
+fs.writeFileSync(
+ path.join(root, "src", "commit.generated.ts"),
+ `// Generated by scripts/build.ts -- do not edit.\nexport const commit = ${JSON.stringify(commit)};\n`,
+);
+console.log(`Wrote commit ${commit} to src/commit.generated.ts`);
diff --git a/cgithub/scripts/compile-views.ts b/cgithub/scripts/compile-views.ts
deleted file mode 100644
index 785efc1..0000000
--- a/cgithub/scripts/compile-views.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-// Precompiles views/*.eta into plain functions for the Cloudflare Workers
-// build (src/views.generated.ts). Workers disallow runtime code generation
-// (`new Function`), so Eta cannot compile templates there at request time.
-import { Eta } from "eta";
-import fs from "node:fs";
-import path from "node:path";
-
-const root = path.join(import.meta.dirname, "..");
-const viewsDir = path.join(root, "views");
-const eta = new Eta({ views: viewsDir });
-
-const names = fs
- .readdirSync(viewsDir)
- .filter((name) => name.endsWith(".eta"))
- .sort();
-
-let out = `// @ts-nocheck
-// Generated by scripts/compile-views.ts -- do not edit.
-export const views = {
-`;
-for (const name of names) {
- const source = fs.readFileSync(path.join(viewsDir, name), "utf8");
- const body = eta.compileToString(source);
- out += ` ${JSON.stringify(name)}: function (it, options) {\n${body}\n },\n`;
-}
-out += "};\n";
-
-fs.writeFileSync(path.join(root, "src", "views.generated.ts"), out);
-console.log(`Compiled ${names.length} templates to src/views.generated.ts`);
diff --git a/cgithub/src/app.ts b/cgithub/src/app.ts
index 5bed45d..0218918 100644
--- a/cgithub/src/app.ts
+++ b/cgithub/src/app.ts
@@ -1,6 +1,7 @@
import type { Eta } from "eta";
import { type Context, Hono } from "hono";
import type { StatusCode } from "hono/utils/http-status";
+import { commit } from "./commit.generated.ts";
import {
getGitHubBlob,
getGitHubCommits,
@@ -47,7 +48,7 @@ export function createApp(eta: Eta) {
// Our URLs mirror GitHub's, so the page we scraped is the same path there.
const { pathname, search } = new URL(c.req.url);
const githubUrl = `https://github.com${pathname}${search}`;
- return c.html(eta.render(template, { ...data, githubUrl }));
+ return c.html(eta.render(template, { ...data, githubUrl, commit }));
}
// For fragments fetched asynchronously by client-side JS (see public/static/refs.js):
diff --git a/cgithub/src/worker.ts b/cgithub/src/worker.ts
index 024b01a..7bf9100 100644
--- a/cgithub/src/worker.ts
+++ b/cgithub/src/worker.ts
@@ -5,7 +5,7 @@ import { createApp } from "./app.ts";
import { views } from "./views.generated.ts";
// Workers disallow runtime code generation, so templates are precompiled by
-// scripts/compile-views.ts and preloaded into Eta's cache here. With
+// scripts/build.ts and preloaded into Eta's cache here. With
// cache: true, Eta serves them from the cache and never compiles.
const eta = new Eta({ cache: true });
diff --git a/cgithub/views/layout.eta b/cgithub/views/layout.eta
index f803caf..ca6fff2 100644
--- a/cgithub/views/layout.eta
+++ b/cgithub/views/layout.eta
@@ -34,7 +34,7 @@ git clone git@github.com:<%= it.repo.owner %>/<%= it.repo.name %>.git</code></pr
<%~ it.body %>
- <footer>Generated by cgithub · <a href="<%= it.githubUrl %>" rel="noreferrer">View original</a></footer>
+ <footer>Generated by cgithub commit <code><%= it.commit %></code> · <a href="<%= it.githubUrl %>" rel="noreferrer">View original</a></footer>
<script>
document.addEventListener("keydown", function(e) {