From 319f3661f238e5d1e295ecbab52151e1e4c84d2c Mon Sep 17 00:00:00 2001 From: "@permadeath.com" Date: Tue, 18 Aug 2026 11:03:51 -0400 Subject: [PATCH] feat(deploy): inject the standard.site link tags before upload A post's document link tag comes from the atUri in its frontmatter, and publish.sh writes that back only after the deploy that put the page online. Between publishing and the next commit, a built page has no tag. The deploy now runs `sequoia inject` after the build and before the upload, so the tag is restored from sequoia's own state. Inject leaves alone a tag the build already emitted and touches no page that is not a published post, so the frontmatter stays the committed source and this is only the second chance at it. The state file is gitignored: a checkout that never published finds nothing to do. --- scripts/deploy-site.sh | 10 ++++++++++ scripts/deploy-site.test.mjs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 scripts/deploy-site.test.mjs diff --git a/scripts/deploy-site.sh b/scripts/deploy-site.sh index 45bad61..0b9d9c5 100755 --- a/scripts/deploy-site.sh +++ b/scripts/deploy-site.sh @@ -36,6 +36,16 @@ npm --prefix "${repo_root}/web" ci # below already reports. node "${repo_root}/scripts/sync-shots.mjs" npm --prefix "${repo_root}/web" run build +# A post page renders its document link tag from the atUri in its own +# frontmatter, and publish.sh writes that back only after the deploy that put +# the page online — so between publishing and the next commit the built page +# has no tag. Inject re-reads sequoia's state and puts it back before anything +# is uploaded: it leaves alone a tag the build already emitted, and touches no +# page that is not a published post. The state file is gitignored, so a +# checkout that never published finds nothing to do; the frontmatter is still +# the committed source of the tag, and this is the second chance at it. +(cd "${repo_root}/web" && ./node_modules/.bin/sequoia inject) +# Verify what is about to be uploaded, injected tags included. npm --prefix "${repo_root}/web" run verify:dist release="$(git -C "${repo_root}" rev-parse --short=12 HEAD)" diff --git a/scripts/deploy-site.test.mjs b/scripts/deploy-site.test.mjs new file mode 100644 index 0000000..57351c1 --- /dev/null +++ b/scripts/deploy-site.test.mjs @@ -0,0 +1,33 @@ +import { readFileSync } from 'node:fs' +import { join } from 'node:path' + +import { describe, expect, it } from 'vitest' + +const source = readFileSync(join(import.meta.dirname, 'deploy-site.sh'), 'utf8') + +// The deploy cannot be run here (it needs AWS credentials and rewrites a live +// distribution), so the ordering that matters is asserted against the source. +describe('deploy-site.sh', () => { + const at = (needle) => { + const index = source.indexOf(needle) + expect(index, `deploy-site.sh no longer contains ${needle}`).toBeGreaterThan(-1) + return index + } + + // Injection rewrites built HTML, so it has to happen after the build that + // emits it and before the upload that freezes it into a release tree — the + // tree is immutable and CloudFront serves it whole. Verification sits + // between the two on purpose: what it checks is what ships. + it('injects the standard.site link tags between the build and the upload', () => { + const inject = at('sequoia inject') + expect(inject).toBeGreaterThan(at('run build')) + expect(inject).toBeLessThan(at('run verify:dist')) + expect(inject).toBeLessThan(at('aws s3 cp')) + }) + + // A partial release tree must never be the one CloudFront is pointed at. + it('applies only after every upload', () => { + // The first `tofu -chdir=` in the file is inside the no-bucket message. + expect(at('apply "$@"')).toBeGreaterThan(at('aws s3 cp')) + }) +}) -- 2.51.2