Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
use flake
25 changes: 12 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,18 @@ Each page also has the papercuts widget. A papercut keeps the page, the branch,

"Approve round <n>" in the bar publishes the newest round of the branch. It writes a request to `.review/approve/`. On the host, `scripts/review/approve-host.sh` checks the head and the worktree and runs `scripts/check.py`. Then it pushes the branch, opens the PR, runs `scripts/ship.sh <pr> <sha>`, and removes the worktree and the branch. The bar shows each step from `.review/approve-status/`. An agent can do the same with `python3 scripts/review/approve.py <branch>`, also from its worktree. An agent starts Approve only when Tim tells it to, in that conversation or in a papercut.

To run it in a container behind a login proxy:

1. Install the host side of the Approve button once: `scripts/review/approve-install.sh`. It needs `gh` on PATH. It makes `.review/approve/`, `.review/approve-status/` and a systemd user unit that starts `approve-host.sh` for each request. To keep the button working after a reboot, run `loginctl enable-linger developer` once.
2. Make the store folder and the worktrees folder: `mkdir -p .papercuts ~/code/worktrees/t7d`.

Run steps 1 and 2 before step 4. If the folders do not exist, Docker makes them as root.
3. Write the settings into `.env`:
- `REVIEW_HOST`: the host name of the review site.
- `REVIEW_PAPERCUTS_HOST`: the host name of the relay.
- `REVIEW_MAIN`: the host path of this clone.
- `REVIEW_WORKTREES`: the host path of the folder with the site worktrees (`~/code/worktrees/t7d`, as a full path).
- `PAPERCUTS_SRC`: the folder of the relay source with its Dockerfile.
4. Start the stack: `docker-compose -p t7d-review -f docker-compose.dev.yml up -d --build`.
Run it in the dev VM:

1. `direnv allow` (or `nix develop`) gives Python with Playwright and markdown, Node 22, gh and uv from `flake.nix`.
2. Install the host side of the Approve button once, in the main checkout: `scripts/review/approve-install.sh`. The dev VM keeps user units running after a reboot.
3. Start the preview of a checkout or worktree with `wt up`. It is defined in `compose.preview.yml`:
- `https://<branch>--t7d.review.t7d.dev`: the review site of that worktree.
- `https://pc-<branch>--t7d.review.t7d.dev`: its papercuts relay (store: `.papercuts/` of the main checkout).
- `https://t7d.review.t7d.dev`: the current worktree. `wt switch <branch>` moves it.
- `https://review.t7d.dev`: every running preview.
4. A new change: `wt new <branch>`, then `wt up` in the new worktree. `wt ls` lists them all.

`docker-compose.dev.yml` and its `.env` are the older way and will be removed later.

Tests: `python3 -m unittest discover -s scripts/review -p 'test_*.py'` and `node --test 'scripts/review/test_*.mjs'`.

Expand Down
66 changes: 66 additions & 0 deletions compose.preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Preview of this worktree: `wt up` -> https://<branch>--t7d.review.t7d.dev
# (https://t7d.review.t7d.dev for the current one, see `wt switch`).
# Two services: the review site (live reload, rounds, Approve) and the papercuts relay at
# https://pc-<branch>--t7d.review.t7d.dev. wt sets PREVIEW_HOST, WT_MAIN and WT_GIT_COMMON.
# Approve: the request goes to .review/approve/ of the main checkout; the host side
# (scripts/review/approve-install.sh, run once in the dev VM) publishes it.
x-preview:
name: t7d
port: 8000
service: preview

services:
preview:
build:
context: scripts/review
dockerfile: Dockerfile
image: t7d-review:local
restart: unless-stopped
command: [python3, /repo/scripts/review/devserver.py, --root, /repo,
--approve, /approve, --approve-status, /approve-status,
--host, 0.0.0.0, --port, "8000"]
environment:
PYTHONDONTWRITEBYTECODE: "1"
PAPERCUTS_URL: https://pc-${PREVIEW_HOST}
read_only: true
cap_drop: [ALL]
security_opt: [no-new-privileges:true]
mem_limit: 96m
tmpfs:
- /tmp:size=8m,mode=1777
volumes:
- .:/repo:ro
- ${WT_GIT_COMMON}:${WT_GIT_COMMON}:ro
- ${WT_MAIN}/.review/approve:/approve:rw
- ${WT_MAIN}/.review/approve-status:/approve-status:ro

papercuts:
build: ${HOME}/code/papercuts
restart: unless-stopped
environment:
PAPERCUTS_STORE: local
PAPERCUTS_DB: /data/papercuts.db
PAPERCUTS_HOST: 0.0.0.0
PAPERCUTS_ORIGINS: https://${PREVIEW_HOST}
PAPERCUTS_REPOS: Tim-Conrad/Tim-Conrad.github.io
PAPERCUTS_PUBLIC_URL: https://pc-${PREVIEW_HOST}
read_only: true
cap_drop: [ALL]
security_opt: [no-new-privileges:true]
mem_limit: 128m
tmpfs:
- /tmp
volumes:
- ${WT_MAIN}/.papercuts:/data:rw
networks: [default, proxy]
labels:
traefik.enable: "true"
traefik.docker.network: "proxy"
traefik.http.routers.${COMPOSE_PROJECT_NAME}-pc.rule: "Host(`pc-${PREVIEW_HOST}`)"
traefik.http.routers.${COMPOSE_PROJECT_NAME}-pc.entrypoints: "websecure"
traefik.http.routers.${COMPOSE_PROJECT_NAME}-pc.tls: "true"
traefik.http.services.${COMPOSE_PROJECT_NAME}-pc.loadbalancer.server.port: "8000"

networks:
proxy:
external: true
27 changes: 27 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
description = "t7d.dev (Tim-Conrad.github.io): dev shell";

inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";

outputs =
{ nixpkgs, ... }:
let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
python = pkgs.python3.withPackages (ps: [
ps.playwright # scripts/review checks
ps.markdown # scripts/gen-tools.py
]);
in
{
# `direnv allow` (or `nix develop`). Preview: `wt up` (compose.preview.yml).
devShells.${system}.default = pkgs.mkShell {
packages = [
python
pkgs.nodejs_22 # node --test, scripts/reels
pkgs.git
pkgs.gh # scripts/ship.sh, approve-host.sh
pkgs.uv
];
PLAYWRIGHT_BROWSERS_PATH = "${pkgs.playwright-driver.browsers}";
PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS = "true";
PYTHONDONTWRITEBYTECODE = "1";
};
};
}
Loading