From 7dbb50a57b476ab529e007e4aaef1f2d80c4b5c6 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Mon, 16 Feb 2026 21:18:24 -0800 Subject: [PATCH] Eliminate double towncrier run in release workflow Add build_quartz Dagger function that builds the Quartz site without running towncrier, and reorder the workflow so towncrier runs once on the runner before passing the updated source tree to Dagger. Co-Authored-By: Claude Opus 4.6 --- .dagger/src/blumeops_ci/main.py | 7 +++- .forgejo/workflows/build-blumeops.yaml | 35 +++++++++---------- .../eliminate-double-towncrier.infra.md | 1 + 3 files changed, 23 insertions(+), 20 deletions(-) create mode 100644 docs/changelog.d/eliminate-double-towncrier.infra.md diff --git a/.dagger/src/blumeops_ci/main.py b/.dagger/src/blumeops_ci/main.py index 8f2373f..b98af9e 100644 --- a/.dagger/src/blumeops_ci/main.py +++ b/.dagger/src/blumeops_ci/main.py @@ -47,12 +47,17 @@ class BlumeopsCi: async def build_docs(self, src: dagger.Directory, version: str) -> dagger.File: """Build changelog then Quartz site. Returns docs tarball.""" updated_src = await self.build_changelog(src, version) + return await self.build_quartz(updated_src, version) + + @function + async def build_quartz(self, src: dagger.Directory, version: str) -> dagger.File: + """Build Quartz docs site from pre-processed source. Returns docs tarball.""" return await ( dag.container() .from_("node:22-slim") .with_exec(["apt-get", "update", "-qq"]) .with_exec(["apt-get", "install", "-y", "-qq", "git"]) - .with_directory("/workspace", updated_src) + .with_directory("/workspace", src) .with_workdir("/workspace") .with_exec( [ diff --git a/.forgejo/workflows/build-blumeops.yaml b/.forgejo/workflows/build-blumeops.yaml index dca745a..e6930bd 100644 --- a/.forgejo/workflows/build-blumeops.yaml +++ b/.forgejo/workflows/build-blumeops.yaml @@ -108,30 +108,14 @@ jobs: with: fetch-depth: 0 - - name: Build docs - run: | - VERSION="${{ steps.version.outputs.version }}" - TARBALL="docs-${VERSION}.tar.gz" - echo "Building docs via Dagger..." - # build-docs calls build_changelog internally (towncrier runs inside - # the Dagger container). The host working tree is not modified — only - # the tarball is exported. Towncrier runs a second time on the runner - # in the next step so that CHANGELOG.md and fragment deletion are - # captured in the git commit. - dagger call build-docs --src=. --version="$VERSION" \ - export --path="./$TARBALL" - echo "Build complete!" - ls -lh "$TARBALL" - - name: Build changelog id: changelog run: | VERSION="${{ steps.version.outputs.version }}" - # Run towncrier on the runner (not in Dagger) so that CHANGELOG.md - # updates and fragment deletions appear in the working tree for the - # git commit step. This is intentionally a second towncrier run — - # the first happened inside the Dagger build-docs container above. + # Run towncrier on the runner so that CHANGELOG.md updates and + # fragment deletions appear in the working tree for both the Quartz + # build (next step) and the git commit step. # Check if there are any changelog fragments FRAGMENTS=$(find docs/changelog.d -name "*.md" -not -name ".gitkeep" 2>/dev/null | wc -l) @@ -157,6 +141,19 @@ jobs: echo "" > /tmp/release_notes.md fi + - name: Build docs + run: | + VERSION="${{ steps.version.outputs.version }}" + TARBALL="docs-${VERSION}.tar.gz" + echo "Building docs via Dagger..." + # Towncrier already ran on the runner above, so the working tree + # has an up-to-date CHANGELOG.md. build-quartz skips towncrier + # and only runs the Quartz static site build. + dagger call build-quartz --src=. --version="$VERSION" \ + export --path="./$TARBALL" + echo "Build complete!" + ls -lh "$TARBALL" + - name: Create release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/docs/changelog.d/eliminate-double-towncrier.infra.md b/docs/changelog.d/eliminate-double-towncrier.infra.md new file mode 100644 index 0000000..3c6524d --- /dev/null +++ b/docs/changelog.d/eliminate-double-towncrier.infra.md @@ -0,0 +1 @@ +Eliminate double towncrier run in release workflow — changelog is now built once on the runner, then the pre-processed source tree is passed to a new `build_quartz` Dagger function for the Quartz site build only.