#!/usr/bin/env bash # Publish the blog to ATProto as standard.site records: one # site.standard.document per post, in lance.blue's own repository. # Configuration is web/sequoia.json. # # 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. # # Order: web/scripts/push.sh, point infra's site_origin_path at the new # prefix, apply, invalidate, then run this. 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 ci" >&2 exit 1 } if grep -q PLACEHOLDER sequoia.json; then echo "sequoia.json still has the placeholder publicationUri." >&2 echo "Create the publication once, then put its at:// URI there." >&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:-lance.blue}" # 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 # A page that is not being served comes back as the app's own index.html with # a 200 - see the comment in push.sh - so the status proves nothing on its # own. The canonical link does: only the right page carries the right one. 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."