chadtmiller.com/knotless
git that lives in your Atmosphere account
1
10
Deploys start the keeper, once its login is on the host
.knotless/workflows/deploy.yml+4−0
| @@ -103,6 +103,10 @@ env: | ||
KNOTLESS_REVIEW_REPOS: --owner chadtmiller.com --owner grain.social chadtmiller.com/group-host | ||
# Five rounds, where a merge of the base into a pull spends none. | ||
KNOTLESS_REVIEW_ARGS: --all --rounds 5 | ||
# Brings the pulls the merge queue turned away for a conflict up to | ||
# date and queues them again, once /etc/knotless/keep.env holds its | ||
# account's login (deploy/deploy.sh). | ||
KNOTLESS_KEEP_REPOS: chadtmiller.com/knotless | ||
steps: | ||
- name: tools | ||
run: | | ||
deploy/deploy.sh+24−0
| @@ -77,6 +77,13 @@ | ||
# review private repositories it reads them with an OAuth session, which | ||
# it gets by logging in at /oauth/bot: put its DID in KNOTLESS_BOT_DIDS. | ||
# | ||
# knotless-agent's keeper too, if KNOTLESS_KEEP_REPOS names repositories | ||
# whose turned-away pulls it keeps moving (or `--owner <handle>`), once | ||
# /etc/knotless/keep.env is on the host: a deploy with | ||
# KNOTLESS_KEEP_IDENTIFIER and KNOTLESS_KEEP_PASSWORD (an app password) | ||
# writes it, and one without it leaves the keeper out rather than failing. | ||
# KNOTLESS_KEEP_ARGS adds to its command line: `--attempts 2`, say. | ||
# | ||
# serve and pages are moved with no downtime by deploy/rollout.sh: a new | ||
# container beside the old, the old stopped once the new is healthy; a | ||
# serve whose new build would rebuild the index is stopped and started. | ||
| @@ -104,6 +111,7 @@ RUN_REPOS="${KNOTLESS_RUN_REPOS:-}" | ||
RUN_DATA="${KNOTLESS_RUN_DATA:-/var/lib/knotless-run}" | ||
TRIAGE_REPOS="${KNOTLESS_TRIAGE_REPOS:-}" | ||
REVIEW_REPOS="${KNOTLESS_REVIEW_REPOS:-}" | ||
KEEP_REPOS="${KNOTLESS_KEEP_REPOS:-}" | ||
SSH="ssh -o StrictHostKeyChecking=accept-new $DEST" | ||
COMMIT="${KNOTLESS_RUN_SHA:-$(git rev-parse HEAD 2>/dev/null || echo local)}" | ||
CANDIDATE="knotless:build-${COMMIT:0:12}" | ||
| @@ -233,6 +241,18 @@ if [ -n "$REVIEW_REPOS" ]; then | ||
say "not starting the reviewer: it needs KNOTLESS_REVIEW_IDENTIFIER, KNOTLESS_REVIEW_PASSWORD and CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_API_KEY once" | ||
fi | ||
fi | ||
if [ -n "$KEEP_REPOS" ]; then | ||
if [ -n "${KNOTLESS_KEEP_IDENTIFIER:-}" ] && [ -n "${KNOTLESS_KEEP_PASSWORD:-}" ]; then | ||
printf 'KNOTLESS_IDENTIFIER=%s\nKNOTLESS_PASSWORD=%s\n' \ | ||
"$KNOTLESS_KEEP_IDENTIFIER" "$KNOTLESS_KEEP_PASSWORD" | | ||
$SSH 'umask 077; cat > /etc/knotless/keep.env' | ||
fi | ||
if $SSH '[ -f /etc/knotless/keep.env ]'; then | ||
PROFILES="${PROFILES:+$PROFILES,}keep" | ||
else | ||
say "not starting the keeper: it needs KNOTLESS_KEEP_IDENTIFIER and KNOTLESS_KEEP_PASSWORD once" | ||
fi | ||
fi | ||
# Apple's push key, once it is on the host: without it, no notification is | ||
# sent, rather than the server refusing to start for a file not there. | ||
APNS_KEY="" | ||
| @@ -275,6 +295,10 @@ fi | ||
echo "KNOTLESS_REVIEW_REPOS=$REVIEW_REPOS" | ||
[ -z "${KNOTLESS_REVIEW_ARGS:-}" ] || echo "KNOTLESS_REVIEW_ARGS=$KNOTLESS_REVIEW_ARGS" | ||
fi | ||
if [ -n "$KEEP_REPOS" ]; then | ||
echo "KNOTLESS_KEEP_REPOS=$KEEP_REPOS" | ||
[ -z "${KNOTLESS_KEEP_ARGS:-}" ] || echo "KNOTLESS_KEEP_ARGS=$KNOTLESS_KEEP_ARGS" | ||
fi | ||
if [ -n "$RUN_REPOS" ]; then | ||
echo "KNOTLESS_RUN_REPOS=$RUN_REPOS" | ||
echo "KNOTLESS_RUN_DATA=$RUN_DATA" | ||
deploy/README.md+19−0
| @@ -428,6 +428,7 @@ docker pull knotless.dev/chadtmiller.com/knotless/knotless-server | ||
| `run` | `knotless-run --secrets … --state … --work … --caches …` | | ||
| `triage` | `knotless-triage --decide <url> --jetstream <url> <repos>` | | ||
| `review` | `knotless-agent review --command knotless-claude-review --jetstream <url> <repos>`, where the repositories may be `--owner <handle>` | | ||
| `keep` | `knotless-agent keep --jetstream <url> <repos>`, where the repositories may be `--owner <handle>` | | ||
| ||
knotless.dev hands those out, with `--releases | ||
knotless://chadtmiller.com/knotless` in docker-compose.yml: each file is | ||
| @@ -674,6 +675,24 @@ nothing until the owner names its account a triager of some scopes, with | ||
eval <handle>` says first how often they agree with people's. It logs each | ||
issue it judged, or failed to, as `judged` or `judging failed`. | ||
| ||
## The keeper | ||
| ||
`knotless-agent keep` brings the pulls the merge queue turned away for a | ||
conflict up to date and queues them again | ||
([the merge queue](../docs/design/merge-queue.md#keeping-turned-away-pulls-moving)). | ||
Set `KNOTLESS_KEEP_REPOS` to the repositories it keeps, or `--owner | ||
<handle>` for all of an account's, and `KNOTLESS_KEEP_ARGS` to the rest | ||
of its command line (`--attempts 2`, say). It starts once | ||
`/etc/knotless/keep.env` is on the host, which a deploy from one's own | ||
checkout writes, once, from `KNOTLESS_KEEP_IDENTIFIER` and | ||
`KNOTLESS_KEEP_PASSWORD` in `deploy/local.env`: its account, and an app | ||
password for it. The account is its own, not the owner's, and each | ||
repository it keeps names it a collaborator (`knotless repo share <url> | ||
<handle> --write`), as it pushes to their pulls' branches and queues | ||
them. Until then a deploy | ||
leaves it out and says so. It logs each pull it kept, or failed to, as | ||
`kept` or `keeping failed`. | ||
| ||
## Monitoring | ||
| ||
`/healthz` says only that serve answers, and Docker restarts it when it | ||