#!/usr/bin/env bash # Builds did.bot (via scripts/build-site.sh) and puts it online, as an # immutable release tree and a CloudFront origin flip. scripts/publish-lib.sh # holds the steps and says how a release and a rollback work. # # Roll back by applying the sha of a tree already uploaded: # # tofu -chdir=infra/site apply -var release_sha= # # The bucket, the distribution and the records are infra/site/'s -- see that # stack's own comments for the zone, the certificate and the viewer-request # function that resolves a directory index. # # Publishes. That is what the name says and what running it does; --dry-run is # the flag, for the times the plan is what is wanted. # # Usage: # scripts/publish-site.sh # build + upload + apply + invalidate # scripts/publish-site.sh --dry-run # build + upload plan + tofu plan # scripts/publish-site.sh --build-only # build, skip AWS entirely # scripts/publish-site.sh --skip-build # reuse site/dist/, publish it # # Anything else is passed straight to `tofu apply` (and to the dry run's `tofu # plan`), which is how an unattended run gets `-auto-approve`. set -euo pipefail cd "$(dirname "$0")/.." name="publish-site" build="scripts/build-site.sh" dist="site/dist" bucket="did-bot-site" stack="infra/site" url="https://did.bot/" . scripts/publish-lib.sh publish_parse_args "$@" publish_build # CloudFront answers a request outside the release tree, and a request S3 # refuses, with this page. A tree missing it leaves every miss showing # CloudFront's own error instead of the site's. if [ ! -f "${dist}/404.html" ]; then echo "${name}: ${dist}/404.html is missing; refusing to publish a tree without it" >&2 exit 1 fi publish_require_credentials publish_name_release publish_require_bucket # Astro's /_astro/ and rustdoc's api/static.files/ both carry a content hash in # the filename, so a browser may keep them forever; everything else takes the # distribution's own caching, which each publish invalidates. That is two # Cache-Control values, and `aws s3 sync` sets one per call, so this is two # calls over the same tree rather than one. # # Content types are the sync's own guess from the extension, which covers # every kind in the tree -- including the landing page's .wasm, which a # browser refuses to instantiate if it arrives as octet-stream. sync_tree() { local dryrun=("$@") aws s3 sync "${dist}" "s3://${bucket}/${prefix}" --no-progress \ --exclude "_astro/*" --exclude "api/static.files/*" ${dryrun+"${dryrun[@]}"} aws s3 sync "${dist}" "s3://${bucket}/${prefix}" --no-progress \ --exclude "*" --include "_astro/*" --include "api/static.files/*" \ --cache-control "public, max-age=31536000, immutable" ${dryrun+"${dryrun[@]}"} } publish_release