From c8bf85de3716f175ea93503bcfc6efd2253030cf Mon Sep 17 00:00:00 2001 From: Drewry Pope Date: Fri, 30 Oct 2026 06:54:24 -0500 Subject: [PATCH 1/3] ci(mcpx): build docs in CI and deploy to GitHub Pages (#1941) --- .github/workflows/mcpx-docs.yml | 123 ++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 .github/workflows/mcpx-docs.yml diff --git a/.github/workflows/mcpx-docs.yml b/.github/workflows/mcpx-docs.yml new file mode 100644 index 000000000..031b9efdb --- /dev/null +++ b/.github/workflows/mcpx-docs.yml @@ -0,0 +1,123 @@ +name: mcpx docs + +# CI tier policy: see .github/ci-policy.md + +# Build the mcpx book (#1941, Approach C) and publish it to GitHub Pages. +# +# Pull requests build .#mcpx-docs and upload the rendered site as an +# ordinary build artifact — no deploy, no PR previews (reviewers download +# the artifact). Pushes to main and manual dispatches deploy the same +# build to Pages via the Actions artifact flow: Pages source for this +# repository is "GitHub Actions" (build_type=workflow), no generated +# HTML is ever committed, and no extra repository or secret is needed. +# +# The build is the flake output .#mcpx-docs (pkgs/mcpx/docs.nix, from +# #1939 / PR #2629): the same `nix build` locally and in CI. The output +# does not yet accept a base-URL / site-url argument, so local and CI +# builds are identical rather than differing only in that value; the +# plumbing note is filed back on #1939. + +on: + pull_request: + paths: + - "pkgs/mcpx/**" + - "flake.nix" + - "flake.lock" + - ".github/workflows/mcpx-docs.yml" + push: + branches: [main] + paths: + - "pkgs/mcpx/**" + - "flake.nix" + - "flake.lock" + - ".github/workflows/mcpx-docs.yml" + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + name: "build: nix build .#mcpx-docs" + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v7 + + - uses: DeterminateSystems/nix-installer-action@3138316df39ed29be04236d7ffc686fa525866aa # v23 + + - uses: DeterminateSystems/magic-nix-cache-action@84c0677f58dcedf3b91f8223ce36a9ea5b3c84b7 # v15 + with: + # Same cache posture as mcpx-nixbuild.yml (#2120): no + # FlakeHub, the GitHub Actions cache is the cache. + use-flakehub: false + use-gha-cache: true + + - name: Nix build + run: nix build .#mcpx-docs --print-build-logs + + # The nix result is a symlink into the store; copy it dereferenced + # so the artifact is a plain static site tree. + - name: Stage site + run: | + rm -rf site + cp -rL result site + test -f site/index.html + + - name: Upload site artifact (PR builds only) + if: github.event_name == 'pull_request' + uses: actions/upload-artifact@v7 + with: + name: mcpx-docs-site + path: site + if-no-files-found: error + + deploy: + name: "deploy: GitHub Pages" + # Deploys only from main: pushes to main and manual dispatches + # (a dispatch on a non-main ref is refused here rather than + # publishing a branch build). + if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') + needs: build + runs-on: ubuntu-latest + timeout-minutes: 30 + # Serialise deploys: two deploys must never interleave, and a queued + # deploy is never cancelled by a later one (#1941). + concurrency: + group: pages + cancel-in-progress: false + permissions: + contents: read + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - uses: actions/checkout@v7 + + - uses: DeterminateSystems/nix-installer-action@3138316df39ed29be04236d7ffc686fa525866aa # v23 + + - uses: DeterminateSystems/magic-nix-cache-action@84c0677f58dcedf3b91f8223ce36a9ea5b3c84b7 # v15 + with: + use-flakehub: false + use-gha-cache: true + + - name: Nix build + run: nix build .#mcpx-docs --print-build-logs + + - name: Stage site + run: | + rm -rf site + cp -rL result site + test -f site/index.html + + - uses: actions/configure-pages@v5 + + - uses: actions/upload-pages-artifact@v3 + with: + path: site + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 From 1adeebaa36194ed29434b09112ddb712b2c9fc5a Mon Sep 17 00:00:00 2001 From: Drewry Pope Date: Fri, 30 Oct 2026 14:48:42 -0500 Subject: [PATCH 2/3] ci(mcpx): bake base URL as the mcpx-docs derivation argument (siteUrl, #1941) --- .github/workflows/mcpx-docs.yml | 9 +++++---- pkgs/mcpx/docs.nix | 10 ++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.github/workflows/mcpx-docs.yml b/.github/workflows/mcpx-docs.yml index 031b9efdb..df122d648 100644 --- a/.github/workflows/mcpx-docs.yml +++ b/.github/workflows/mcpx-docs.yml @@ -12,10 +12,11 @@ name: mcpx docs # HTML is ever committed, and no extra repository or secret is needed. # # The build is the flake output .#mcpx-docs (pkgs/mcpx/docs.nix, from -# #1939 / PR #2629): the same `nix build` locally and in CI. The output -# does not yet accept a base-URL / site-url argument, so local and CI -# builds are identical rather than differing only in that value; the -# plumbing note is filed back on #1939. +# #1939 / PR #2629): the same `nix build` locally and in CI. The +# derivation takes the base URL as its `siteUrl` argument (default "/", +# the Pages Actions deploy root), baked in as mdBook's site-url — so +# local, CI, and any future custom-domain build differ only in that +# one value (#1941). on: pull_request: diff --git a/pkgs/mcpx/docs.nix b/pkgs/mcpx/docs.nix index 4e5224b4a..70adbb7ad 100644 --- a/pkgs/mcpx/docs.nix +++ b/pkgs/mcpx/docs.nix @@ -3,10 +3,18 @@ # nixpkgs and no network access. Exposed as the .#mcpx-docs flake # output, so CI builds it through the ordinary flake-check path like # every other output. +# +# The base URL is a derivation argument (#1941): `siteUrl` is baked +# into the rendered book as mdBook's output.html.site-url, so a local +# build, the CI build, and a future custom-domain build differ only in +# that one value. The flake output uses the default "/" (the GitHub +# Pages Actions deploy root); other deployments override the argument, +# e.g. `mcpxDocs.override { siteUrl = "/code/"; }`. { lib, runCommand, mdbook, + siteUrl ? "/", }: let # Only the book inputs enter the store: book.toml plus the docs tree. @@ -47,5 +55,7 @@ runCommand "mcpx-docs" "s|](\.\./|](''${repoURL}|g" {} + find docs -mindepth 2 -maxdepth 2 -name '*.md' -exec sed -i \ "s|](\.\./\.\./|](''${repoURL}|g" {} + + # Bake the base URL into the book (see the siteUrl argument above). + export MDBOOK_OUTPUT__HTML__SITE_URL="${siteUrl}" mdbook build --dest-dir $out '' From a45cc7c617ffed3bfe31ca357c65816aab530b45 Mon Sep 17 00:00:00 2001 From: Drewry Pope Date: Fri, 30 Oct 2026 14:55:28 -0500 Subject: [PATCH 3/3] =?UTF-8?q?ci(mcpx):=20deploy=20the=20book=20with=20si?= =?UTF-8?q?teUrl=20/code/=20=E2=80=94=20the=20project=20Pages=20path=20(40?= =?UTF-8?q?4=20page=20assets,=20#1941)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/mcpx-docs.yml | 20 ++++++++++++++------ pkgs/mcpx/docs.nix | 9 +++++---- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/.github/workflows/mcpx-docs.yml b/.github/workflows/mcpx-docs.yml index df122d648..54e0aa3df 100644 --- a/.github/workflows/mcpx-docs.yml +++ b/.github/workflows/mcpx-docs.yml @@ -13,10 +13,10 @@ name: mcpx docs # # The build is the flake output .#mcpx-docs (pkgs/mcpx/docs.nix, from # #1939 / PR #2629): the same `nix build` locally and in CI. The -# derivation takes the base URL as its `siteUrl` argument (default "/", -# the Pages Actions deploy root), baked in as mdBook's site-url — so -# local, CI, and any future custom-domain build differ only in that -# one value (#1941). +# derivation takes the base URL as its `siteUrl` argument, baked in as +# mdBook's site-url: PR/local builds use the default "/", the Pages +# deploy overrides it with "/code/" (the project site's path) — builds +# differ only in that one value (#1941). on: pull_request: @@ -104,8 +104,16 @@ jobs: use-flakehub: false use-gha-cache: true - - name: Nix build - run: nix build .#mcpx-docs --print-build-logs + # The deployed book is served from the project Pages path + # (https://developing-today.github.io/code/), and mdBook needs + # that path as its site-url: with "/" the generated 404 page + # points its CSS/JS and navigation at the domain root and breaks. + # Same derivation as the PR build, differing only in the siteUrl + # argument (#1941). + - name: Nix build (deploy variant, siteUrl /code/) + run: | + nix build --impure --print-build-logs --expr \ + '(builtins.getFlake (toString ./.)).packages.${builtins.currentSystem}.mcpx-docs.override { siteUrl = "/code/"; }' - name: Stage site run: | diff --git a/pkgs/mcpx/docs.nix b/pkgs/mcpx/docs.nix index 70adbb7ad..78925839d 100644 --- a/pkgs/mcpx/docs.nix +++ b/pkgs/mcpx/docs.nix @@ -6,10 +6,11 @@ # # The base URL is a derivation argument (#1941): `siteUrl` is baked # into the rendered book as mdBook's output.html.site-url, so a local -# build, the CI build, and a future custom-domain build differ only in -# that one value. The flake output uses the default "/" (the GitHub -# Pages Actions deploy root); other deployments override the argument, -# e.g. `mcpxDocs.override { siteUrl = "/code/"; }`. +# build, the CI build, and a deployed build differ only in that one +# value. The flake output uses the default "/"; the GitHub Pages +# deploy overrides it with "/code/" (the project site's path — mdBook +# needs the real hosting path or its generated 404 page points assets +# at the domain root), e.g. `mcpxDocs.override { siteUrl = "/code/"; }`. { lib, runCommand,