clone

a personal forge on plain git: static pages, stacked-diff reviews, signed local ci, repo sites and releases

Deploy a commit, not the working tree, and only with a CI pass

cat committed 4383583
deploy.sh rsynced the checkout as it was, so uncommitted edits went to
slate with it; with two sessions in one checkout that nearly shipped
another's unfinished work. It now exports a commit with git archive,
HEAD by default, and wants a verified passing CI attestation for it, as
main on the forge does with forge.requireci; --force ships one without.
The commit deployed is written to /srv/forge/src/DEPLOYED.
commit
4383583dc93eae0004733fd59207510c2553c8a5
parent
6f5e766c14b0996f54a268d452da1ffe91bc977d
author
cat <admin@dev.site>
ci
✓ passed in 67s, signed by cat
kind
fix risk score 2.1 of 3, Jev's estimate
review
#2 Deploy a commit, not the working tree
ci attestation
forge-attestation 1
type ci
commit 4383583dc93eae0004733fd59207510c2553c8a5
tree dd0cad6a3a04f96b563a799f09b430d0fb6cbd34
script .forge/ci 05d612a331a46d602928c28846e036e53299df48
result pass
exit 0
started 2026-10-18T22:06:48Z
duration 67s
runner (not shown here; refs/notes/ci has it)
system Darwin 25.5.0 arm64
env host
log sha256:04b7c894c00e88db285420c2124fe34f85a96d8f65d1f2a6444332e03528bd93 234 lines
|remote: review #4: /dami/greet/reviews/4/
|pushed wip/i18n
|b8eac5d running .forge/ci: greet.sh: say what it is
|  | sh: /bin/sh
|  | ok   greet
|b8eac5d pass in 0s, signed
|pushed main
|remote: review #4: /dami/greet/reviews/4/
|pushed wip/i18n
|587d54d running .forge/ci: wave at the world
|  | sh: /bin/sh
|  | FAIL greet : got 'hello, world o/', want 'hello, world'
|587d54d fail in 1s, signed
|forge: 1 commit(s) did not pass
|remote: review #6: /dami/greet/reviews/6/
|pushed ana/wave
|942ce01 running .forge/ci: update the test for the wave
|  | sh: /bin/sh
|  | ok   greet
|942ce01 pass in 0s, signed
|remote: review #6: /dami/greet/reviews/6/
|pushed ana/wave
|warning: You appear to have cloned an empty repository.
|site home: deployed 132dac6 -> /sites/ana/dotfiles/home/
|created ana/notes
|remote: review #1: /ana/notes/reviews/1/
|pushed ana/todo
|landing #1 A todo list: ana/todo -> main
|f3676c7 running .forge/ci: web, server and Python versions of greet
|  | sh: /bin/sh
|  | ok   greet
|f3676c7 pass in 0s, signed
|pushed main
|bb4f3e1 running .forge/ci: messages: notes for the later regions
|  | sh: /bin/sh
|  | ok   greet
|bb4f3e1 pass in 0s, signed
|remote: review #7: /dami/greet/reviews/7/
|pushed dami/regions
|created dami/forge
|warning: You appear to have cloned an empty repository.
|site guide: deployed 06503cc -> /sites/dami/forge/guide/
|(node:59876) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time
|(Use `node --trace-warnings ...` to show where the warning was created)
|built ana/dotfiles in 0s -> /Users/dami/Library/Caches/forge/ci/35f7a65d0235/demo/root/.forge/www
|(node:60000) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time
|(Use `node --trace-warnings ...` to show where the warning was created)
|built ana/notes in 1s -> /Users/dami/Library/Caches/forge/ci/35f7a65d0235/demo/root/.forge/www
|(node:60136) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time
|(Use `node --trace-warnings ...` to show where the warning was created)
|built dami/forge in 0s -> /Users/dami/Library/Caches/forge/ci/35f7a65d0235/demo/root/.forge/www
|(node:60266) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time
|(Use `node --trace-warnings ...` to show where the warning was created)
|built dami/greet in 2s -> /Users/dami/Library/Caches/forge/ci/35f7a65d0235/demo/root/.forge/www
|(node:60930) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time
|(Use `node --trace-warnings ...` to show where the warning was created)
|built - in 0s -> /Users/dami/Library/Caches/forge/ci/35f7a65d0235/demo/root/.forge/www
|226 of 226 pages render the same without 11ty
|guide: 4 files, links ok
|ok

Signature: good, cat

2 files changed, +33 -3
MREADME.md8+++++++-
Mdeploy/slate/deploy.sh28++++++++++++++++++++++++++--
M README.md +7 -1
M deploy/slate/deploy.sh +26 -2
@@ -1,9 +1,33 @@
11 #!/bin/sh2-# Ship this checkout to slate and rebuild the forge container there.2+# Ship a commit of this repo to slate and rebuild the forge container there.33 # Data in /srv/forge/data is untouched.4+#5+# deploy/slate/deploy.sh [--force] [<commit>] HEAD by default6+#7+# What ships is the commit, exported with git archive, never the working8+# tree: uncommitted edits, whoever made them, stay here. It needs a9+# verified passing CI attestation (forge verify), as main on the forge10+# does; --force ships it anyway. The commit deployed is written to11+# /srv/forge/src/DEPLOYED.412 set -eu513 here=$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)614 host=${FORGE_HOST:-slate}15+force=016+[ "${1:-}" = --force ] && { force=1; shift; }17+rev=$(git -C "$here" rev-parse --verify "${1:-HEAD}^{commit}")18+short=$(git -C "$here" rev-parse --short "$rev")19+if ! git -C "$here" diff --quiet HEAD 2>/dev/null; then20+ echo "deploy: the working tree has uncommitted changes; they stay here, $short ships" >&221+fi22+if ! "$here/bin/forge" verify "$rev" >/dev/null 2>&1; then23+ [ "$force" = 1 ] || { echo "deploy: $short has no verified passing CI attestation (forge attest $short), or pass --force" >&2; exit 1; }24+ echo "deploy: shipping $short without a verified CI pass (--force)" >&225+fi26+tmp=$(mktemp -d "${TMPDIR:-/tmp}/forge-deploy.XXXXXX")27+trap 'rm -rf "$tmp"' EXIT28+git -C "$here" archive "$rev" | tar -x -C "$tmp"29+printf '%s\n' "$rev" >"$tmp/DEPLOYED"730 rsync -a --delete --exclude node_modules --exclude demo/root --exclude demo/work \8- --exclude .git --exclude .env --exclude _site --exclude .cache "$here/" "$host:/srv/forge/src/"31+ --exclude .env --exclude _site --exclude .cache "$tmp/" "$host:/srv/forge/src/"932 ssh "$host" 'cd /srv/forge/src/deploy/slate && docker compose up -d --build'33+echo "deploy: $short is on $host"