From f14667de6ac0601785cbeb73e288c708827731da Mon Sep 17 00:00:00 2001 From: David Gamero Date: Tue, 11 Aug 2026 13:47:15 -0400 Subject: [PATCH 1/4] ci(docs): publish docs via GitHub Pages Actions instead of gh-pages branch The docs deploy has been failing since 2021. The gh-pages branch has a protection rule requiring the EasyCLA status check and disallowing force pushes, but JamesIves/github-pages-deploy-action force-pushes a synthetic branch to it, so every push has been declined: remote: error: GH006: Protected branch update failed for refs/heads/gh-pages. remote: - Required status check "EasyCLA" is expected. The branch has exactly two commits, both from 2021-07-16, and the live site still serves that build. Separately, the repo's Pages publishing source is already build_type=workflow, so the branch is no longer the publishing source and no workflow was able to publish at all. Switch to actions/upload-pages-artifact + actions/deploy-pages, which publishes through the Pages API and never touches a protected branch. Also consolidate the two docs workflows. deploy-docs.yml (typedoc) and deploy-docs-v2.yml (Docusaurus) both deployed to the same Pages root with --delete and would clobber each other. The standalone typedoc build is redundant: docs/ already wires up docusaurus-plugin-typedoc, which generates the SDK reference into docs/sdk during the site build. Root typedoc.json also has out="docs", which writes typedoc HTML into the Docusaurus source dir. - fold deploy-docs-v2.yml into deploy-docs.yml, split into build + deploy jobs - drop the standalone typedoc build; the site build covers it - narrow contents: write to contents: read; scope pages/id-token to deploy - add concurrency group with cancel-in-progress: false - keep the PR trigger so link validation still runs on PRs - drop the paths filter, which was scoped to typedoc inputs and would skip deploys for docs-only content changes Verified locally: docs build emits 95 SDK reference pages plus api-reference, models and examples, and the link check reports 0 bad links and 0 bad anchors across 30225 links. --- .github/workflows/deploy-docs-v2.yml | 44 ------------------- .github/workflows/deploy-docs.yml | 63 +++++++++++++++++++++------- 2 files changed, 48 insertions(+), 59 deletions(-) delete mode 100644 .github/workflows/deploy-docs-v2.yml diff --git a/.github/workflows/deploy-docs-v2.yml b/.github/workflows/deploy-docs-v2.yml deleted file mode 100644 index ff29e1a3efd..00000000000 --- a/.github/workflows/deploy-docs-v2.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Build and Deploy Docs v2 -on: - push: - branches: - - main - pull_request: - branches: - - main -permissions: - contents: write -jobs: - build-and-deploy-docs: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Setup Node.js - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: '20' - - name: Install root dependencies - run: npm ci - - name: Install docs dependencies - run: npm ci - working-directory: docs - - name: Build docs - run: npm run build - working-directory: docs - - name: Validate links and anchors - # Docusaurus baseUrl is /javascript/, so all internal links are emitted - # as /javascript/... . hyperlink treats the given dir as server root "/", - # so the build must be staged under a matching javascript/ subdirectory - # for site-absolute links to resolve. - run: | - rm -rf _linkcheck - mkdir -p _linkcheck/javascript - cp -R docs/build/. _linkcheck/javascript/ - npx @untitaker/hyperlink _linkcheck --check-anchors - - name: Deploy to gh-pages - if: github.event_name == 'push' - uses: JamesIves/github-pages-deploy-action@d92aa235d04922e8f08b40ce78cc5442fcfbfa2f # v4.8.0 - with: - branch: gh-pages - folder: docs/build diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 6039e6d8bf5..6e73f6b188c 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -3,20 +3,23 @@ on: push: branches: - main - paths: - - 'src/**' - - 'typedoc.json' - - 'package.json' - - 'package-lock.json' - - '.github/workflows/deploy-docs.yml' + pull_request: + branches: + - main permissions: {} +# Allow one concurrent deployment; queue rather than cancel so an in-flight +# Pages deployment is never left half-applied. +concurrency: + group: pages + cancel-in-progress: false + jobs: - build-and-deploy-docs: + build: runs-on: ubuntu-latest permissions: - contents: write + contents: read steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -30,13 +33,43 @@ jobs: # and package-lock.json. Needs to run before npm install - name: Validate package.json and package-lock.json versions run: node version-check.js - - name: Install dependencies + # Root deps are required: docusaurus-plugin-typedoc reads ../src/*.ts + # and needs the root dependency types to resolve. + - name: Install root dependencies run: npm ci + - name: Install docs dependencies + run: npm ci + working-directory: docs - name: Build docs - run: npm run docs - - - name: Deploy docs - uses: JamesIves/github-pages-deploy-action@d92aa235d04922e8f08b40ce78cc5442fcfbfa2f # v4.8.0 + run: npm run build + working-directory: docs + - name: Validate links and anchors + # Docusaurus baseUrl is /javascript/, so all internal links are emitted + # as /javascript/... . hyperlink treats the given dir as server root "/", + # so the build must be staged under a matching javascript/ subdirectory + # for site-absolute links to resolve. + run: | + rm -rf _linkcheck + mkdir -p _linkcheck/javascript + cp -R docs/build/. _linkcheck/javascript/ + npx @untitaker/hyperlink _linkcheck --check-anchors + - name: Upload Pages artifact + if: github.event_name == 'push' + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 with: - branch: gh-pages # The branch the action should deploy to. - folder: docs # The folder the action should deploy. + path: docs/build + + deploy: + if: github.event_name == 'push' + needs: build + runs-on: ubuntu-latest + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0 From a200993b2e99ee8cdc12ce5a26fe373960aa72ae Mon Sep 17 00:00:00 2001 From: David Gamero Date: Tue, 11 Aug 2026 15:06:02 -0400 Subject: [PATCH 2/4] ci(docs): split docs build/test out of the deploy workflow Folding the PR build into the deploy workflow meant gating half the steps on `if: github.event_name == 'push'`, which is noisy and made the deploy path harder to read. Split them into two single-purpose workflows: - docs-build.yml runs on pull_request: build plus link/anchor validation, contents: read only, no Pages permissions, and cancel-in-progress so stale PR runs are dropped. - deploy-docs.yml runs on push to main: build, upload artifact, deploy. No event conditionals left. Also drop the duplicated version-check.js step. test.yml already runs it, and its paths filter covers package.json, package-lock.json and version-check.js itself, so the inputs that check validates always trigger it. Broken internal links still block a deploy independently of the PR job, since docusaurus.config.ts sets onBrokenLinks and onBrokenAnchors to 'throw'. Verified locally from a clean tree: build succeeds and the link check reports 0 bad links and 0 bad anchors across 30225 links in 378 files. --- .github/workflows/deploy-docs.yml | 21 +------------- .github/workflows/docs-build.yml | 47 +++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 20 deletions(-) create mode 100644 .github/workflows/docs-build.yml diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 6e73f6b188c..a18579c9dd0 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -1,11 +1,8 @@ -name: Build and Deploy Docs +name: Deploy Docs on: push: branches: - main - pull_request: - branches: - - main permissions: {} @@ -29,10 +26,6 @@ jobs: uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: '22' - # Pre-check to validate that versions match between package.json - # and package-lock.json. Needs to run before npm install - - name: Validate package.json and package-lock.json versions - run: node version-check.js # Root deps are required: docusaurus-plugin-typedoc reads ../src/*.ts # and needs the root dependency types to resolve. - name: Install root dependencies @@ -43,24 +36,12 @@ jobs: - name: Build docs run: npm run build working-directory: docs - - name: Validate links and anchors - # Docusaurus baseUrl is /javascript/, so all internal links are emitted - # as /javascript/... . hyperlink treats the given dir as server root "/", - # so the build must be staged under a matching javascript/ subdirectory - # for site-absolute links to resolve. - run: | - rm -rf _linkcheck - mkdir -p _linkcheck/javascript - cp -R docs/build/. _linkcheck/javascript/ - npx @untitaker/hyperlink _linkcheck --check-anchors - name: Upload Pages artifact - if: github.event_name == 'push' uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 with: path: docs/build deploy: - if: github.event_name == 'push' needs: build runs-on: ubuntu-latest permissions: diff --git a/.github/workflows/docs-build.yml b/.github/workflows/docs-build.yml new file mode 100644 index 00000000000..8ecf19f1d31 --- /dev/null +++ b/.github/workflows/docs-build.yml @@ -0,0 +1,47 @@ +name: Docs Build and Test +on: + pull_request: + branches: + - main + +permissions: {} + +# Stale runs for a PR are worthless once a new commit lands. +concurrency: + group: docs-build-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Setup Node.js + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: '22' + # Root deps are required: docusaurus-plugin-typedoc reads ../src/*.ts + # and needs the root dependency types to resolve. + - name: Install root dependencies + run: npm ci + - name: Install docs dependencies + run: npm ci + working-directory: docs + - name: Build docs + run: npm run build + working-directory: docs + - name: Validate links and anchors + # Docusaurus baseUrl is /javascript/, so all internal links are emitted + # as /javascript/... . hyperlink treats the given dir as server root "/", + # so the build must be staged under a matching javascript/ subdirectory + # for site-absolute links to resolve. + run: | + rm -rf _linkcheck + mkdir -p _linkcheck/javascript + cp -R docs/build/. _linkcheck/javascript/ + npx @untitaker/hyperlink _linkcheck --check-anchors From f654d3feedcc095cf313d8e7af7778f915bbd6bd Mon Sep 17 00:00:00 2001 From: David Gamero Date: Tue, 11 Aug 2026 17:16:15 -0400 Subject: [PATCH 3/4] ci(docs): allow manually triggering the docs deploy Add workflow_dispatch to the deploy workflow so docs can be re-published on demand, e.g. after a failed deploy or a Pages settings change, without having to push an empty commit to main. --- .github/workflows/deploy-docs.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index a18579c9dd0..59ee4b4f161 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -3,6 +3,9 @@ on: push: branches: - main + # Allow re-publishing on demand, e.g. after a failed deploy or a Pages + # settings change, without pushing an empty commit to main. + workflow_dispatch: permissions: {} From 6838fad3d0e82d9baf36d9137ed87eb1cc1b1138 Mon Sep 17 00:00:00 2001 From: David Gamero Date: Tue, 11 Aug 2026 17:19:01 -0400 Subject: [PATCH 4/4] ci(docs): only allow the docs deploy to run from main workflow_dispatch can be triggered from any ref, and the ref chosen is what gets built and published, so a manual run from a feature branch would publish that branch to the live docs site. Guard the build job with `github.ref == 'refs/heads/main'`. The push trigger is already main-only, so this only constrains manual runs. deploy needs build, and GitHub skips dependent jobs when a needed job is skipped, so the whole workflow no-ops on any other ref. This is defence in depth alongside restricting the github-pages environment's deployment branches to main. --- .github/workflows/deploy-docs.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 59ee4b4f161..c78a637dd12 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -17,6 +17,11 @@ concurrency: jobs: build: + # workflow_dispatch can be triggered from any ref, and the ref chosen is + # what would get published. Only ever publish main. The push trigger is + # already main-only, so this guard applies solely to manual runs. + # `deploy` needs `build`, so skipping here skips the whole workflow. + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest permissions: contents: read