Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
e325438
feat: add the repo file source with GitHub and fixture adapters
hunterbecton Oct 29, 2026
9452b14
test: record the shaders#264 snapshot for the fixture source
hunterbecton Oct 29, 2026
8315d0d
feat: render a guide as a two-pane page
hunterbecton Oct 29, 2026
02fa788
docs: add the guide format reference at /guides/format/
hunterbecton Oct 29, 2026
dd5b62c
ci: deploy the site to Pages and run the specs on pull requests
hunterbecton Oct 29, 2026
0abcdbc
docs: describe setup, env vars, tests, and deploys in the README
hunterbecton Oct 29, 2026
3018297
feat: link to a step with its #step-<n> anchor
hunterbecton Oct 29, 2026
6b451f6
feat: move between steps with the j and k keys
hunterbecton Oct 29, 2026
d8ef760
feat: highlight an inline pointer's lines on hover, focus, and click
hunterbecton Oct 29, 2026
ba8f2dd
feat: fail the build when an inline pointer names lines its step does…
hunterbecton Oct 29, 2026
35e9fc7
docs: document inline pointers in the format reference
hunterbecton Oct 29, 2026
88974c0
test: add fixture guides for shaders#241 and bones#23
hunterbecton Oct 29, 2026
690af71
feat: list guides per repo, newest first, with a scope filter
hunterbecton Oct 29, 2026
ecbefbe
feat: search the prose of every guide with Pagefind
hunterbecton Oct 29, 2026
6835cf1
docs: describe search and the scope filter
hunterbecton Oct 29, 2026
0110414
Merge branch 't3/guides-sha-280-287' into sha-286
hunterbecton Oct 29, 2026
7dd3d9e
feat: list the changed files no step shows under "Also changed"
hunterbecton Oct 29, 2026
5e146eb
test: record the shaders#235 and #243 snapshots for image fixtures
hunterbecton Oct 29, 2026
382701f
feat: stack the panes on narrow screens
hunterbecton Oct 29, 2026
0996406
docs: document the #step-<n> anchor in the format reference
hunterbecton Oct 29, 2026
8312425
feat: show an image pointer as the image before and after the change
hunterbecton Oct 29, 2026
46331c5
docs: document image pointers and the "Also changed" section
hunterbecton Oct 29, 2026
b7db983
Merge branch 't3/guides-sha-280-287' into sha-284
hunterbecton Oct 29, 2026
63f6b93
feat: mark files as reviewed, and clear a mark when the file changes
hunterbecton Oct 29, 2026
7dc3b84
feat: warn when the pull request has moved past the guide's commit
hunterbecton Oct 29, 2026
c0fb241
Merge branch 't3/guides-sha-280-287' into sha-285
hunterbecton Oct 29, 2026
6f91b39
test: record the shaders#169, #193, and #232 snapshots
hunterbecton Oct 29, 2026
4f9e8bc
test: expect the step anchor after an inline pointer opens its step
hunterbecton Oct 29, 2026
0f88efc
fix: ignore only the root content checkout
hunterbecton Oct 29, 2026
ba33d4f
feat: hide the rest of each file behind expandable separators
hunterbecton Oct 29, 2026
79302fe
feat: render pointers into new, deleted, and renamed files
hunterbecton Oct 29, 2026
745552d
feat: cache the files a build reads, by commit SHA
hunterbecton Oct 29, 2026
7c92a5a
ci: keep the repo file cache between deploys
hunterbecton Oct 29, 2026
30b0390
docs: describe separators and new, deleted, and renamed files
hunterbecton Oct 29, 2026
f894fe6
Merge branch 't3/guides-sha-280-287' into sha-283
hunterbecton Oct 29, 2026
4c1782d
Merge branch 't3/guides-sha-280-287' into sha-283
hunterbecton Oct 29, 2026
d7889fc
Merge branch 't3/guides-sha-280-287' into sha-281
hunterbecton Oct 29, 2026
5a41f46
Merge branch 'sha-284' into t3/guides-sha-280-287
hunterbecton Oct 29, 2026
1a68ed5
test: expect the step anchor to reopen step 2 after a reload
hunterbecton Oct 29, 2026
6b77460
feat: give image files in a step a Reviewed checkbox
hunterbecton Oct 29, 2026
cd7a0e7
Merge branch 'sha-281' into t3/guides-sha-280-287
hunterbecton Oct 29, 2026
9ec567a
Merge branch 't3/guides-sha-280-287' into sha-283
hunterbecton Oct 29, 2026
c7d9019
test: expect a third step in the #264 fixture guide
hunterbecton Oct 29, 2026
e6c30f5
fix: check a file's Reviewed box in every step that shows it
hunterbecton Oct 29, 2026
5f93a64
fix: let j and k move between steps after a click on a checkbox
hunterbecton Oct 29, 2026
990ee9f
feat: mark an inline pointer's highlighted lines with <mark>
hunterbecton Oct 29, 2026
d6e705d
refactor: work out a changed file's base and head versions in one place
hunterbecton Oct 29, 2026
fb60b7f
fix: read removed lines and Before images at the merge base
hunterbecton Oct 29, 2026
d1b61f3
fix: let an inline pointer name lines of a deleted file
hunterbecton Oct 29, 2026
57f5e09
feat: check that the title is a Conventional Commit and scope matches it
hunterbecton Oct 29, 2026
6b437e4
feat: link guide and repo pages back to the home page
hunterbecton Oct 29, 2026
1382bfa
fix: show "Binary" instead of +0 -0 for binary files in Also changed
hunterbecton Oct 29, 2026
752a8ee
fix: give the guide header the panes' side padding on phones
hunterbecton Oct 29, 2026
51b39c1
fix: keep inline code whole when it wraps in prose
hunterbecton Oct 29, 2026
f2bf903
ci: key the repo file cache on the guides and drop checkout credentials
hunterbecton Oct 29, 2026
a24436e
docs: give each thing in the format reference one name
hunterbecton Oct 29, 2026
14816dd
refactor: share the file header, line counts, and hidden-heading style
hunterbecton Oct 29, 2026
990c50f
refactor: share the base path, guide URL, aria-controls, and snapshot…
hunterbecton Oct 29, 2026
c077bca
refactor: resolve a step's images and Also changed on PullRequestFiles
hunterbecton Oct 29, 2026
fed6d2c
refactor: name repositories, pull requests, and short SHAs one way
hunterbecton Oct 29, 2026
e29b4fc
refactor: call the hidden rows and their separators by one name
hunterbecton Oct 29, 2026
0549f35
refactor: name a file's path and its path at the merge base once
hunterbecton Oct 29, 2026
bc8988d
refactor: drop parameters and exports that nothing uses
hunterbecton Oct 29, 2026
44c0b45
fix: let the build read Pages, keep SVGs off the site, decode pointer…
hunterbecton Oct 29, 2026
cf6803f
fix: never publish the SVG side of a rename, and resolve reference-st…
hunterbecton Oct 29, 2026
84e96e6
fix: read a symlink's own blob, not its target
hunterbecton Oct 29, 2026
a6229d7
fix: keep the Scope filter hidden until its script runs
hunterbecton Oct 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Type-checks the renderer and runs the Playwright specs against the fixture guides.
# The specs build the site from the recorded snapshot in tests/fixtures, so they need no network.
name: CI

on:
pull_request:
branches: [main]

permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
name: Typecheck and Playwright
runs-on: ubuntu-latest
env:
ASTRO_TELEMETRY_DISABLED: '1'
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version-file: .node-version
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm check
- run: pnpm exec playwright install --with-deps chromium
- run: pnpm test
- if: failure()
uses: actions/upload-artifact@v7
with:
name: playwright-results
path: test-results
retention-days: 7
74 changes: 74 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Builds main's renderer with the guides on the content branch and deploys the site to GitHub Pages.
# A push to content runs that branch's trigger-deploy.yml, which dispatches this workflow on main.
name: Deploy

on:
push:
branches: [main]
workflow_dispatch:

# Each job grants only the permissions it needs.
permissions: {}

# One deploy at a time. A newer run waits for the current one instead of canceling it.
concurrency:
group: pages
cancel-in-progress: false

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
# configure-pages reads the Pages site through the API.
pages: read
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- name: Check out the guides from the content branch
uses: actions/checkout@v7
with:
ref: content
path: content
persist-credentials: false
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version-file: .node-version
cache: pnpm
- run: pnpm install --frozen-lockfile
# A file at a commit never changes, so cached files never go stale and the cache only grows.
# The key is a hash of the guides. A run with the same guides reuses the cache and saves nothing,
# and a run with changed guides restores the newest cache and saves it under a new key.
- name: Restore the repo file cache
uses: actions/cache@v6
with:
path: .cache/repo-files
key: repo-files-${{ hashFiles('content/*/*.md') }}
restore-keys: repo-files-
- name: Build the site
run: pnpm build
env:
GUIDES_DIR: content
REPO_FILE_SOURCE: github
REPO_FILE_CACHE: .cache/repo-files
GITHUB_TOKEN: ${{ github.token }}
ASTRO_TELEMETRY_DISABLED: '1'
- uses: actions/configure-pages@v6
- uses: actions/upload-pages-artifact@v5
with:
path: dist

deploy:
needs: build
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@v5
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
node_modules/
dist/
.astro/
test-results/
playwright-report/
# The deploy workflow checks out the content branch here.
/content/
# REPO_FILE_CACHE, when a local build sets it to .cache/repo-files.
.cache/
1 change: 1 addition & 0 deletions .node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24
84 changes: 83 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,84 @@
# guides
Step-by-step guides to campdotdev pull requests, written by the agent that wrote each one.

Step-by-step guides to campdotdev pull requests, written by the agent that wrote each one. The site is https://campdotdev.github.io/guides/.

The repository has two branches with different jobs:

- `main` holds the renderer, an Astro site. Changes reach it through pull requests.
- `content` holds the guide files, one per pull request at `<repo>/<pr>.md`. Agents push to it directly.

[Guide file format](docs/guide-format.md) documents the guide file. The site serves the same page at `/guides/format/`.

## Run the site locally

You need Node 24 and pnpm 11.

```sh
pnpm install
pnpm exec playwright install chromium # once, for pnpm test
pnpm dev # serves the fixture guides at http://localhost:4321/guides/
pnpm build # writes the static site and its Pagefind search index to dist/
pnpm check # type-checks the project
pnpm test # builds the site from the fixtures, serves it, and runs the Playwright specs
```

Search on the home page reads the index that `pnpm build` writes, so `pnpm dev` has no search results. To try search, run `pnpm build && pnpm preview`.

If another server already holds port 4321, pick another port for the tests, such as `PLAYWRIGHT_PORT=4400 pnpm test`.

To build the published guides, check out `content` into `content/` and read the pull requests' files from GitHub:

```sh
git worktree add content content
GUIDES_DIR=content REPO_FILE_SOURCE=github REPO_FILE_CACHE=.cache/repo-files GITHUB_TOKEN=$(gh auth token) pnpm build
```

## Environment variables

| Variable | Default | Effect |
| --- | --- | --- |
| `GUIDES_DIR` | `tests/fixtures/guides` | The directory the build reads guides from. |
| `REPO_FILE_SOURCE` | `fixture` | Where the build reads the pull requests' files. `github` reads the GitHub API, and `fixture` reads a recorded snapshot. |
| `GITHUB_TOKEN` | None | The token the `github` source sends. `REPO_FILE_SOURCE=github` requires it. |
| `REPO_FILE_FIXTURES` | `tests/fixtures/repo-files` | The snapshot the `fixture` source reads. |
| `REPO_FILE_CACHE` | None | A directory where the build caches the files it reads from the source, by commit SHA. A later build reads them from there instead of fetching them again. The build logs each file it fetches. |
| `PLAYWRIGHT_PORT` | `4321` | The port that `pnpm test` serves the build on. |

## Tests

The specs in `tests/e2e` drive the built site in Chromium and assert through roles and accessible names. They read the fixture guides in `tests/fixtures/guides`, which the test suite owns, so the sample guide on `content` can change without breaking them. The search specs query the real Pagefind index that the build writes. Each guide in `tests/fixtures/malformed` must fail the build with an error that names the bad field.

`tests/fixtures/guides/shaders/241.md` names a `baseSha` newer than the merge base, so `merge-base.spec.ts` checks that removed lines come from the merge base.

`tests/fixtures/previous-head` holds the #264 fixture guide pinned to the pull request's previous head, `f09b489`. `reviewed-files.spec.ts` serves a build of it, marks files as reviewed, and then reloads into the main build, the way a guide refresh replaces the page.

The `fixture` source serves each fixture guide's files from `tests/fixtures/repo-files`. The snapshot holds GitHub's comparison of the guide's `baseSha` and `headSha`, which names their merge base, and every changed file at the merge base and the head commit. The tests never touch the network. To record the snapshot for a new fixture guide, run:

```sh
GITHUB_TOKEN=$(gh auth token) pnpm record-fixture tests/fixtures/guides/<repo>/<pr>.md
```

The script reads the files through the production `github` source and checks each one against the blob SHA that GitHub lists.

## Deploys

`.github/workflows/deploy.yml` builds `main`'s renderer with the guides on `content` and deploys the site to GitHub Pages. It runs on every push to `main`. Only `main` may deploy to the `github-pages` environment, so a push to `content` runs that branch's `trigger-deploy.yml`, which dispatches `deploy.yml` on `main`.

The workflow keeps `.cache/repo-files` between runs with `actions/cache`, so a deploy fetches only the files that no earlier deploy fetched. The cache key is a hash of the guides on `content`, so the workflow saves a new cache only when a guide changes.

A malformed guide on `content` fails the deploy build, and the site keeps its last good deployment.

`.github/workflows/ci.yml` type-checks the project and runs the Playwright specs on every pull request to `main`.

## Code layout

| Path | Holds |
| --- | --- |
| `src/content.config.ts` | The `guides` collection, read from `GUIDES_DIR`. |
| `src/guide/` | The guide model. It parses and validates a guide file and resolves its pointers to diff hunks. Components never parse Markdown. |
| `src/repo-files/` | The repo file source: its interface, the `github` and `fixture` sources, the cache, and the switch between them. |
| `src/components/` | The page components. |
| `src/client/` | Browser behavior, one module per feature. |
| `src/highlight.ts` | Syntax highlighting with Shiki, one token list per line. |
| `docs/guide-format.md` | The guide format reference. |
| `scripts/record-fixture.ts` | The script that records a fixture snapshot. |
12 changes: 12 additions & 0 deletions astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// @ts-check
import { defineConfig } from 'astro/config';

export default defineConfig({
site: 'https://campdotdev.github.io',
base: '/guides',
output: 'static',
devToolbar: { enabled: false },
markdown: {
shikiConfig: { themes: { light: 'github-light', dark: 'github-dark' } },
},
});
Loading
Loading