#!/usr/bin/env bash # Publish the updates to ATProto as standard.site records: one # site.standard.document per post, in the publication owner's own repository. # Configuration is web/sequoia.json. # # ATP_IDENTIFIER=... ATP_APP_PASSWORD=... web/scripts/publish.sh [--dry-run] # # The last step of a deploy, not part of one. A document record says "this # post is at this address", so the address has to answer first — otherwise # the network is told about a page that is not there. This refuses to publish # a post the live site is not already serving. # # ATP_APP_PASSWORD is an app password, never an account password; it is # never written or printed here. set -euo pipefail cd "$(dirname "$0")/.." dry_run="" if [ $# -gt 0 ]; then case "$1" in --dry-run | -n) dry_run=1 ;; *) echo "usage: web/scripts/publish.sh [--dry-run]" >&2 exit 2 ;; esac fi sequoia="./node_modules/.bin/sequoia" [ -x "$sequoia" ] || { echo "$sequoia is missing. Run: npm --prefix web install" >&2 exit 1 } if grep -q PLACEHOLDER sequoia.json; then echo "sequoia.json still has the placeholder publicationUri." >&2 echo "Create the publication once (sequoia login && sequoia init)," >&2 echo "then put its at:// URI there and in" >&2 echo "public/.well-known/site.standard.publication." >&2 exit 1 fi : "${ATP_APP_PASSWORD:?set it to an app password for the publishing account}" export ATP_APP_PASSWORD export ATP_IDENTIFIER="${ATP_IDENTIFIER:?set it to the publishing account handle}" # What publishing would do, and the only place the post URLs come from. A # real run may skip some of these after syncing state from the PDS, so this # is a superset of what gets written — the safe direction for a check. plan="$("$sequoia" publish --dry-run --verbose)" echo "$plan" # Read from the config rather than spelled again here: a second copy is a # second thing to get wrong. prefix="$(node -p 'const c = require("./sequoia.json"); c.siteUrl + c.pathPrefix')" urls="$(printf '%s\n' "$plan" | grep -oE "${prefix}/[^[:space:]]+" | sort -u || true)" if [ -z "$urls" ]; then echo "Nothing to publish." exit 0 fi # The canonical link is what proves the right page is being served at the # claimed address, not the status code. echo echo "Checking the live site..." not_live=0 while IFS= read -r url; do if ! body="$(curl -fsS --max-time 20 "$url")"; then echo " not serving: $url" >&2 not_live=1 elif ! printf '%s' "$body" | grep -qF "rel=\"canonical\" href=\"$url\""; then echo " wrong page at: $url" >&2 not_live=1 else echo " live: $url" fi done <<<"$urls" if [ "$not_live" -ne 0 ]; then echo >&2 echo "Refusing to publish: deploy first, then run this again." >&2 exit 1 fi if [ -n "$dry_run" ]; then echo echo "Dry run: every post is live, nothing published." exit 0 fi echo "$sequoia" publish echo echo "Published. Commit the atUri frontmatter sequoia wrote into the posts."