From 3225155c04a37951445f2704b9f61f3c21f28ee9 Mon Sep 17 00:00:00 2001 From: Neil Dewhurst Date: Thu, 8 Oct 2026 11:14:51 +0100 Subject: [PATCH] Add PDF generation pipeline, update trigger/generate-html to latest template format - docs-trigger-builds.yml now dispatches both docs-generate-html.yml and the new docs-generate-pdf.yml, keeping all four push-triggering branches (dev, main, 5.x, 4.4). - docs-generate-html.yml refreshed to the latest docs-template shape: per-run publish-env resolution via workflow_dispatch inputs rather than a push-time matrix job, matching every other repo already migrated. Dropped the dead "approval granted" echo step - no GitHub Environment protection rule actually gates it. - docs-generate-pdf.yml added, calling reusable-docs-pdf-build.yml@v2 and handing off to docs-publish the same way docs-generate-html.yml already does. This docset has a real version (antora.yml), so no versionless flag. --- .github/workflows/docs-generate-html.yml | 91 ++++++------ .github/workflows/docs-generate-pdf.yml | 85 +++++++++++ .github/workflows/docs-trigger-builds.yml | 169 ++++++++++++++++++++++ 3 files changed, 296 insertions(+), 49 deletions(-) create mode 100644 .github/workflows/docs-generate-pdf.yml create mode 100644 .github/workflows/docs-trigger-builds.yml diff --git a/.github/workflows/docs-generate-html.yml b/.github/workflows/docs-generate-html.yml index 546fc2e..c8960d0 100644 --- a/.github/workflows/docs-generate-html.yml +++ b/.github/workflows/docs-generate-html.yml @@ -1,59 +1,62 @@ - name: "Generate HTML" +run-name: "Generate ${{ inputs.publish-env != '' && inputs.publish-env || (inputs.build-ref == vars.DOCS_PROD_BRANCH && 'prod' || 'dev') }} HTML from ${{ inputs.build-ref }}" + +permissions: + contents: read -# edit the list of branches according to your repository -# the list of branches should contain all the branches in your Antora publish playbooks +# Builds, verifies, and publishes docs for ONE environment, as a run entirely independent +# of any other environment's run. Triggered (via the API, not a workflow_call) by +# docs-trigger-builds.yml, once per environment that applies to a given push (dev, prod, or both) - +# so if dev's run fails, prod's run is completely unaffected, and vice versa. on: - push: - branches: - - "main" - - "dev" - - "5.x" - - "4.4" workflow_dispatch: - -# change `dev` and `main` according to your repository's branch names -# `dev` is the branch you use to build and publish to staging -# `main` is the branch you use to build and publish to neo4j.com/docs -# in some cases, PROD_BRANCH and DEV_BRANCH may be the same branch -env: - DEV_BRANCH: 'dev' - PROD_BRANCH: 'main' + inputs: + build-ref: + description: 'The git ref to build from' + type: string + required: true + publish-env: + description: 'Override for dev/prod. Leave blank to derive it from build-ref against vars.DOCS_PROD_BRANCH - only needs setting explicitly when DOCS_DEV_BRANCH == DOCS_PROD_BRANCH, where build-ref alone cannot tell the two builds apart.' + type: string + required: false + default: '' jobs: - prepare-ref-env: - name: Set build branch and environments + # Resolves publish-env (dev/prod) once, so neither docs-build nor publish-html + # duplicates the override-or-derive logic. + resolve-env: + name: Resolve environment runs-on: ubuntu-latest outputs: - build-ref: ${{ steps.set-ref-env.outputs.build-ref }} - environments: ${{ steps.set-ref-env.outputs.environments }} + publish-env: ${{ steps.resolve.outputs.publish-env }} steps: - - name: Set Build Ref - id: set-ref-env + - name: Resolve publish-env + id: resolve + env: + PUBLISH_ENV_OVERRIDE: ${{ inputs.publish-env }} + BUILD_REF: ${{ inputs.build-ref }} + PROD_BRANCH: ${{ vars.DOCS_PROD_BRANCH }} run: | - if [[ "${GITHUB_REF}" == "refs/heads/${{ env.DEV_BRANCH }}" ]]; then - build_from=${{ env.DEV_BRANCH }} - environments='["dev"]' + if [[ -n "${PUBLISH_ENV_OVERRIDE}" ]]; then + publish_env="${PUBLISH_ENV_OVERRIDE}" + elif [[ "${BUILD_REF}" == "${PROD_BRANCH}" ]]; then + publish_env="prod" else - build_from=${{ env.PROD_BRANCH }} - environments='["prod"]' + publish_env="dev" fi - # if dev branch = prod branch publish to both - if [[ "${{ env.DEV_BRANCH }}" == "${{ env.PROD_BRANCH }}" ]]; then - environments='["dev","prod"]' - fi - echo "build-ref=${build_from}" >> $GITHUB_OUTPUT - echo "environments=${environments[@]}" >> $GITHUB_OUTPUT + + echo "publish-env=${publish_env}" >> $GITHUB_OUTPUT docs-build: name: Generate HTML - needs: prepare-ref-env + needs: resolve-env uses: neo4j/docs-tools/.github/workflows/reusable-docs-build.yml@v2 with: package-script: 'verify:publish' - build-ref: ${{needs.prepare-ref-env.outputs.build-ref}} + build-ref: ${{ inputs.build-ref }} fetch-depth: 0 + publish-env: ${{ needs.resolve-env.outputs.publish-env }} docs-verify: name: Verify HTML @@ -64,15 +67,10 @@ jobs: publish-html: name: Publish HTML - needs: [docs-verify, prepare-ref-env] + needs: [docs-verify, resolve-env] runs-on: ubuntu-latest - - strategy: - matrix: - environments: ${{ fromJson(needs.prepare-ref-env.outputs.environments) }} - steps: - - name: Publish to ${{ matrix.environments }} + - name: Publish to ${{ needs.resolve-env.outputs.publish-env }} uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 #v4 with: token: ${{ secrets.DOCS_DISPATCH_TOKEN }} @@ -83,10 +81,5 @@ jobs: "org": "${{ github.repository_owner }}", "repo": "${{ github.event.repository.name }}", "run_id": "${{ github.run_id }}", - "publish_env": "${{ matrix.environments }}" + "publish_env": "${{ needs.resolve-env.outputs.publish-env }}" } - - - name: Echo - if: ${{ matrix.environments == 'prod' }} - run: | - echo "If this step runs then approval has been granted" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/docs-generate-pdf.yml b/.github/workflows/docs-generate-pdf.yml new file mode 100644 index 0000000..8b167bb --- /dev/null +++ b/.github/workflows/docs-generate-pdf.yml @@ -0,0 +1,85 @@ +name: "Generate PDF" +run-name: "Generate ${{ inputs.publish-env != '' && inputs.publish-env || (inputs.build-ref == vars.DOCS_PROD_BRANCH && 'prod' || 'dev') }} PDF from ${{ inputs.build-ref }}" + +permissions: + contents: read + +# Mirrors docs-generate-html.yml's shape (workflow_dispatch with build-ref and +# publish-env inputs, resolve-env -> build -> publish) and its own reusable-workflow +# reference convention (a pinned neo4j/docs-tools/...@v2 tag, not a relative path - +# this repo doesn't contain reusable-docs-pdf-build.yml itself). Still simpler than +# docs-generate-html.yml in one way: there's no docs-verify step (no equivalent check +# exists yet for a PDF), and build/publish are two plain jobs rather than a +# reusable-workflow call plus a verify call. +on: + workflow_dispatch: + inputs: + build-ref: + description: 'The git ref to build from' + type: string + required: true + publish-env: + description: 'Override for dev/prod. Leave blank to derive it from build-ref against vars.DOCS_PROD_BRANCH - only needs setting explicitly when DOCS_DEV_BRANCH == DOCS_PROD_BRANCH, where build-ref alone cannot tell the two builds apart.' + type: string + required: false + default: '' + +jobs: + + # Resolves publish-env (dev/prod) once, so publish-pdf doesn't duplicate the + # override-or-derive logic - same job as docs-generate-html.yml's own resolve-env. + resolve-env: + name: Resolve environment + runs-on: ubuntu-latest + outputs: + publish-env: ${{ steps.resolve.outputs.publish-env }} + steps: + - name: Resolve publish-env + id: resolve + env: + PUBLISH_ENV_OVERRIDE: ${{ inputs.publish-env }} + BUILD_REF: ${{ inputs.build-ref }} + PROD_BRANCH: ${{ vars.DOCS_PROD_BRANCH }} + run: | + if [[ -n "${PUBLISH_ENV_OVERRIDE}" ]]; then + publish_env="${PUBLISH_ENV_OVERRIDE}" + elif [[ "${BUILD_REF}" == "${PROD_BRANCH}" ]]; then + publish_env="prod" + else + publish_env="dev" + fi + + echo "publish-env=${publish_env}" >> $GITHUB_OUTPUT + + docs-build-pdf: + name: Generate PDF + uses: neo4j/docs-tools/.github/workflows/reusable-docs-pdf-build.yml@v2 + with: + build-ref: ${{ inputs.build-ref }} + fetch-depth: 0 + + # Hand off to docs-publish (a separate repo) to actually publish this run's "pdf" + # artifact - same mechanism docs-generate-html.yml already uses for its "docs" + # artifact. docset/version come from docs-build-pdf itself (read back out of the + # PDF's own build path - see reusable-docs-pdf-build.yml), since there's no HTML + # directory tree here for docs-publish to infer them from the way it does for HTML. + publish-pdf: + name: Publish PDF + needs: [docs-build-pdf, resolve-env] + runs-on: ubuntu-latest + steps: + - name: Publish to ${{ needs.resolve-env.outputs.publish-env }} + uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 #v4 + with: + token: ${{ secrets.DOCS_DISPATCH_TOKEN }} + repository: neo4j/docs-publish + event-type: publish-pdf + client-payload: |- + { + "org": "${{ github.repository_owner }}", + "repo": "${{ github.event.repository.name }}", + "run_id": "${{ github.run_id }}", + "publish_env": "${{ needs.resolve-env.outputs.publish-env }}", + "docset": "${{ needs.docs-build-pdf.outputs.docset }}", + "version": "${{ needs.docs-build-pdf.outputs.version }}" + } diff --git a/.github/workflows/docs-trigger-builds.yml b/.github/workflows/docs-trigger-builds.yml new file mode 100644 index 0000000..049f6ce --- /dev/null +++ b/.github/workflows/docs-trigger-builds.yml @@ -0,0 +1,169 @@ +name: "Trigger docs builds" + +# This workflow's job is dispatching docs-generate-html.yml and docs-generate-pdf.yml +# with the right build-ref(s) for whatever just happened - it is NOT the only valid way +# to wire this up. It doesn't publish anything itself - the dispatched workflows hand +# off to the (separate) docs-publish repo for that. +# +# Use this (docs-trigger-builds.yml -> docs-generate-*.yml) when a single trigger might +# legitimately need to build more than one environment - e.g. a repo where +# DOCS_DEV_BRANCH == DOCS_PROD_BRANCH (one branch serving both, so every push to it +# always means both). +# +# If your repo instead has clean, separate dev/prod branches, you may not need this at +# all: docs-generate-html.yml can be given its own direct `on: push: branches: [...]` +# trigger per environment instead - simpler, and structurally can't build the wrong +# branch's content into the wrong environment. This template still works fine for that +# shape too (it will just always resolve to a single build), so which to use is a +# judgment call, not a hard requirement. + +permissions: + contents: read + actions: write + +# edit the list of branches according to your repository - every branch that should +# trigger a rebuild, including older versioned content branches (a push there still +# needs to refresh dev/prod's current HTML and this push's own PDF). +on: + push: + branches: + - 'dev' + - 'main' + - '5.x' + - '4.4' + workflow_dispatch: + +jobs: + + prepare-builds: + name: Set builds to trigger + runs-on: ubuntu-latest + outputs: + # JSON array of {workflow, buildRef, publishEnv} - one entry per independent + # dispatch to make. publishEnv is left '' for docs-generate-html.yml except in + # the one case where it's genuinely ambiguous (see below) - that workflow + # derives it itself from build-ref against its own vars.DOCS_PROD_BRANCH + # whenever publishEnv is blank. docs-generate-pdf.yml's publishEnv is always + # resolved explicitly here instead, using the same conservative default as the + # HTML rules below: the dev branch is the only case treated as dev, every other + # branch defaults to prod. + builds: ${{ steps.set-builds.outputs.builds }} + steps: + # DOCS_DEV_BRANCH and DOCS_PROD_BRANCH are required repository variables + # (Settings -> Secrets and variables -> Actions -> Variables), not values to edit + # here. docs-generate-html.yml, docs-generate-pdf.yml, and docs-publish (a + # separate repo) all independently read the same variables, so they can't be set + # by editing this file on a branch/PR. + # `dev` is the branch you use to build and publish to staging. + # `main` is the branch you use to build and publish to neo4j.com/docs. + # If your repo has no separate prod environment, set DOCS_PROD_BRANCH equal to + # DOCS_DEV_BRANCH - every push will then resolve to both (see the rules below). + - name: Set builds + id: set-builds + env: + DEV_BRANCH: ${{ vars.DOCS_DEV_BRANCH }} + PROD_BRANCH: ${{ vars.DOCS_PROD_BRANCH }} + run: | + dev_branch="${DEV_BRANCH}" + prod_branch="${PROD_BRANCH}" + + if [[ -z "${dev_branch}" ]]; then + echo "::error::vars.DOCS_DEV_BRANCH is not set for this repository. Set it in Settings -> Secrets and variables -> Actions -> Variables." + exit 1 + fi + if [[ -z "${prod_branch}" ]]; then + echo "::error::vars.DOCS_PROD_BRANCH is not set for this repository. Set it in Settings -> Secrets and variables -> Actions -> Variables." + exit 1 + fi + + # HTML rules: + # - DEV_BRANCH == PROD_BRANCH -> both, always (one branch serves both, so + # there's no "the other one didn't change" case to worry about). + # - The triggering branch IS the dev branch -> dev only (a change on dev has + # no bearing on prod's already-published content). + # - Anything else (including a push to the prod branch, or any other branch) + # -> both. We deliberately don't try to be clever about only rebuilding the + # one that "actually changed" - e.g. a branch that's fallen out of the dev + # set but is still in the prod set would be misdetected either way, so we + # just always rebuild everything except the one case (dev branch) we know + # for certain doesn't affect prod. + if [[ "${dev_branch}" == "${prod_branch}" ]]; then + html_builds=$(jq -nc --arg b "$dev_branch" \ + '[{workflow:"docs-generate-html.yml",buildRef:$b,publishEnv:"dev"},{workflow:"docs-generate-html.yml",buildRef:$b,publishEnv:"prod"}]') + elif [[ "${GITHUB_REF}" == "refs/heads/${dev_branch}" ]]; then + html_builds=$(jq -nc --arg dev "$dev_branch" \ + '[{workflow:"docs-generate-html.yml",buildRef:$dev,publishEnv:""}]') + else + html_builds=$(jq -nc --arg dev "$dev_branch" --arg prod "$prod_branch" \ + '[{workflow:"docs-generate-html.yml",buildRef:$dev,publishEnv:""},{workflow:"docs-generate-html.yml",buildRef:$prod,publishEnv:""}]') + fi + + # PDF always builds from the branch that triggered this run - no dev/prod + # pairing to work out the way HTML has to (there's only ever one PDF build + # per trigger). Its publish-env is still dev or prod, though, resolved with + # the same conservative default the HTML rules above use: the dev branch is + # the one case known for certain not to affect prod, so it's the only one + # that resolves to dev - every other branch (the real prod branch, a third + # long-lived branch, a typo, ...) resolves to prod. + if [[ "${GITHUB_REF}" == "refs/heads/${dev_branch}" ]]; then + pdf_publish_env="dev" + else + pdf_publish_env="prod" + fi + pdf_build=$(jq -nc --arg ref "${GITHUB_REF_NAME}" --arg env "$pdf_publish_env" \ + '[{workflow:"docs-generate-pdf.yml",buildRef:$ref,publishEnv:$env}]') + + builds=$(jq -nc --argjson html "$html_builds" --argjson pdf "$pdf_build" '$html + $pdf') + echo "builds=${builds}" >> $GITHUB_OUTPUT + + # One matrix job instance per build prepare-builds resolved, each dispatching its + # target workflow as its own separate run - not a workflow_call (which would keep + # them all in this one run), so each is fully independent: fail-fast: false means + # one matrix instance failing to dispatch doesn't cancel the others, and each + # dispatched run ends up with its own normally-named artifacts (no collisions, since + # they're separate runs, not jobs sharing one run). + trigger-builds: + name: Trigger ${{ matrix.build.workflow }} (${{ matrix.build.buildRef }}) + needs: prepare-builds + strategy: + fail-fast: false + matrix: + build: ${{ fromJson(needs.prepare-builds.outputs.builds) }} + runs-on: ubuntu-latest + steps: + - name: Dispatch + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + BUILD: ${{ toJson(matrix.build) }} + PROD_BRANCH: ${{ vars.DOCS_PROD_BRANCH }} + with: + script: | + const build = JSON.parse(process.env.BUILD) + const prodBranch = process.env.PROD_BRANCH + // Both docs-generate-html.yml and docs-generate-pdf.yml accept publish-env. + const inputs = { 'build-ref': build.buildRef, 'publish-env': build.publishEnv } + await github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: build.workflow, + // Dispatch from build.buildRef itself, NOT the branch that triggered + // this workflow - a dispatched run's ref becomes its real head_branch, + // which is exactly what docs-publish's check-build-branch inspects. + // Using a single fixed ref for every build here would make every + // dispatched run's head_branch equal whatever branch triggered THIS + // workflow, regardless of which environment it's actually building for + // - so a trigger from any branch other than build.buildRef (e.g. a + // versioned content branch, or the "other" HTML build when both are + // triggered) would always fail that check downstream, even for an + // otherwise-legitimate build. + ref: build.buildRef, + inputs, + }) + // Mirrors docs-generate-html.yml's own publish-env derivation for + // display purposes only - the real derivation happens inside the + // dispatched run, this is just to show what it will resolve to when no + // explicit override was passed (the empty-string case, only possible for + // an HTML build - see prepare-builds above). + const env = build.publishEnv || (build.buildRef === prodBranch ? 'prod' : 'dev') + core.summary.addRaw(`Triggered \`${build.workflow}\` on branch \`${build.buildRef}\` for \`${env}\``, true) + await core.summary.write()