diff --git a/.github/workflows/docs-generate-html.yml b/.github/workflows/docs-generate-html.yml index d3f2947..c77aee2 100644 --- a/.github/workflows/docs-generate-html.yml +++ b/.github/workflows/docs-generate-html.yml @@ -1,5 +1,5 @@ name: "Generate HTML" -run-name: "Generate HTML for ${{ inputs.dispatch-env }}" +run-name: "Generate HTML from ${{ inputs.build-ref }}" permissions: contents: read @@ -16,25 +16,48 @@ on: type: string required: true publish-env: - description: 'staging or prod - passed through to reusable-docs-build.yml, which uses it to resolve DOCS_PUBLISH_URL' + 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: true - dispatch-env: - description: 'dev or prod - the environment label used for the docs-publish dispatch payload' - type: string - required: true + required: false + default: '' jobs: + # 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: + 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: name: Generate HTML + needs: resolve-env uses: ./.github/workflows/reusable-docs-build.yml with: docs-dir: 'docs' package-script: 'verify:publish' build-ref: ${{ inputs.build-ref }} fetch-depth: 0 - publish-env: ${{ inputs.publish-env }} + publish-env: ${{ needs.resolve-env.outputs.publish-env }} docs-verify: name: Verify HTML @@ -42,4 +65,24 @@ jobs: uses: ./.github/workflows/reusable-docs-verify.yml with: failOnWarnings: true - \ No newline at end of file + + # Hand off to docs-publish (a separate repo) to actually publish this run's "docs" + # artifact. + publish-html: + name: Publish HTML + needs: [docs-verify, 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-html + client-payload: |- + { + "org": "${{ github.repository_owner }}", + "repo": "${{ github.event.repository.name }}", + "run_id": "${{ github.run_id }}", + "publish_env": "${{ needs.resolve-env.outputs.publish-env }}" + } diff --git a/.github/workflows/docs-publish.yml b/.github/workflows/docs-publish.yml index 812f17c..5a282c8 100644 --- a/.github/workflows/docs-publish.yml +++ b/.github/workflows/docs-publish.yml @@ -1,11 +1,32 @@ name: "Publish docs" +# This workflow's job is dispatching docs-generate-html.yml with the right build-ref(s) +# for whatever just happened - it is NOT the only valid way to wire this up, and isn't +# always the right choice. +# +# Use this (docs-publish.yml -> docs-generate-html.yml) when a single trigger might +# legitimately need to build more than one environment - e.g. a manual "rebuild +# everything" workflow_dispatch, or 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 (e.g. dev and main), you +# almost certainly do NOT want this: a commit to dev should only ever build staging, and +# a commit to main should only ever build prod - never both from one commit, since +# they're different content on different branches. For that shape, skip this file +# entirely and give docs-generate-html.yml its own direct `on: push: branches: [...]` +# trigger per environment instead (see docs-aura's docs-generate-html.yml for that +# pattern) - simpler, and structurally can't build the wrong branch's content into the +# wrong environment. + permissions: contents: read actions: write -# edit the list of branches according to your repository -# the list of branches should contain all the branches in your Antora publish playbooks +# Edit the branches list below to match your repository: it must be the union of every +# branch listed in BOTH your staging and prod Antora publish.yml playbooks (content +# sources' `branches`). prepare-ref-env's logic below assumes this - it doesn't inspect +# the playbooks itself, it just trusts that if this workflow ran at all, the branch that +# triggered it is a real content branch for at least one of the two environments. on: push: branches: @@ -21,65 +42,81 @@ env: jobs: prepare-ref-env: - name: Set build branch and environments + name: Set builds to trigger runs-on: ubuntu-latest outputs: - build-ref: ${{ steps.set-ref-env.outputs.build-ref }} - environments: ${{ steps.set-ref-env.outputs.environments }} + # JSON array of {buildRef, publishEnv} - one entry per independent + # docs-generate-html.yml run to trigger. publishEnv is left '' except in the one + # case where it's genuinely ambiguous (see below) - docs-generate-html.yml derives + # it itself from build-ref against its own vars.DOCS_PROD_BRANCH whenever + # publishEnv is blank. + builds: ${{ steps.set-ref-env.outputs.builds }} steps: - - name: Set Build Ref + - name: Set builds id: set-ref-env run: | dev_branch="${{ env.DEV_BRANCH }}" prod_branch="${{ env.PROD_BRANCH }}" + # Rules: + # - No separate prod branch configured -> staging only, always (nothing to + # double up). + # - 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 -> staging 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 [[ -z "${prod_branch}" ]]; then - build_from="${dev_branch}" - environments='["dev"]' + builds=$(jq -nc --arg dev "$dev_branch" \ + '[{buildRef:$dev,publishEnv:""}]') + elif [[ "${dev_branch}" == "${prod_branch}" ]]; then + # build-ref alone can't distinguish these two - same branch - so publishEnv + # has to be passed explicitly here, or docs-generate-html.yml's derivation + # would resolve both to the same environment. + builds=$(jq -nc --arg b "$dev_branch" \ + '[{buildRef:$b,publishEnv:"dev"},{buildRef:$b,publishEnv:"prod"}]') elif [[ "${GITHUB_REF}" == "refs/heads/${dev_branch}" ]]; then - build_from="${dev_branch}" - environments='["dev"]' + builds=$(jq -nc --arg dev "$dev_branch" \ + '[{buildRef:$dev,publishEnv:""}]') else - build_from="${prod_branch}" - environments='["prod"]' - fi - - if [[ -n "${prod_branch}" && "${dev_branch}" == "${prod_branch}" ]]; then - environments='["dev","prod"]' + builds=$(jq -nc --arg dev "$dev_branch" --arg prod "$prod_branch" \ + '[{buildRef:$dev,publishEnv:""},{buildRef:$prod,publishEnv:""}]') fi - echo "build-ref=${build_from}" >> $GITHUB_OUTPUT - echo "environments=${environments}" >> $GITHUB_OUTPUT + echo "builds=${builds}" >> $GITHUB_OUTPUT - # Trigger docs-generate-html.yml as its own separate run, once per environment that - # applies - not a workflow_call (which would keep both in this one run) - so dev and - # prod are fully independent runs: if dev's run fails, prod's run is unaffected, and - # each ends up with a plain "docs" artifact exactly like a run does today. + # Trigger docs-generate-html.yml as its own separate run, once per build - not a + # workflow_call (which would keep them all in this one run) - so each is fully + # independent: if one run fails, the others are unaffected, and each ends up with a + # plain "docs" artifact exactly like a run does today (no name collisions, since + # they're separate runs, not jobs sharing one run). trigger-generate-html: - name: Trigger per-environment builds + name: Trigger builds needs: prepare-ref-env runs-on: ubuntu-latest steps: - - name: Dispatch docs-generate-html.yml for each environment + - name: Dispatch docs-generate-html.yml for each build uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: - BUILD_REF: ${{ needs.prepare-ref-env.outputs.build-ref }} - ENVIRONMENTS: ${{ needs.prepare-ref-env.outputs.environments }} + BUILDS: ${{ needs.prepare-ref-env.outputs.builds }} DISPATCH_REF: ${{ github.ref_name }} with: script: | - const environments = JSON.parse(process.env.ENVIRONMENTS) - const publishEnvFor = { dev: 'staging', prod: 'prod' } - for (const dispatchEnv of environments) { + const builds = JSON.parse(process.env.BUILDS) + for (const build of builds) { await github.rest.actions.createWorkflowDispatch({ owner: context.repo.owner, repo: context.repo.repo, workflow_id: 'docs-generate-html.yml', ref: process.env.DISPATCH_REF, inputs: { - 'build-ref': process.env.BUILD_REF, - 'publish-env': publishEnvFor[dispatchEnv], - 'dispatch-env': dispatchEnv, + 'build-ref': build.buildRef, + 'publish-env': build.publishEnv, }, }) } diff --git a/.github/workflows/reusable-docs-build.yml b/.github/workflows/reusable-docs-build.yml index a19e05c..077a766 100644 --- a/.github/workflows/reusable-docs-build.yml +++ b/.github/workflows/reusable-docs-build.yml @@ -37,10 +37,10 @@ on: type: string default: 'verify:preview' publish-env: - description: "The publish environment to build docs for: staging or prod" + description: "The publish environment to build docs for: dev or prod" required: false type: string - default: 'staging' + default: 'dev' antora-attributes: description: 'Antora attributes to pass to the build script' required: false @@ -157,15 +157,15 @@ jobs: # sandbox right now. # # Resolved once here, not duplicated at each use: ANTORA_CLI_OPTIONS and - # DOCS_NAV_URL both need the staging-vs-prod split, but they read it via + # DOCS_NAV_URL both need the dev-vs-prod split, but they read it via # env.DOCS_PUBLISH_URL from the "Run package script" step's own env: block # below rather than from here directly - a step's env CAN reference an # already-resolved job-level env var, but two entries in this same job-level # env: block can't reference each other (this one included), so they can't be # defined here alongside it. - DOCS_PUBLISH_URL: "${{ inputs.publish-env == 'staging' && 'https://development.neo4j.dev/docs/sandbox/restructure/docs' || 'https://neo4j.com/docs' }}" + DOCS_PUBLISH_URL: "${{ inputs.publish-env == 'dev' && 'https://development.neo4j.dev/docs/sandbox/restructure/docs' || 'https://neo4j.com/docs' }}" ANTORA_UI_BUNDLE_URL: "${{ inputs.package-script == 'verify:publish' && 'https://static-content.neo4j.com/build/ui-bundle-docs-restructure.zip'|| inputs.antora-ui-bundle-url }}" - # page-no-local-manifest: staging/prod never serve local-manifest.json (that's a + # page-no-local-manifest: dev/prod never serve local-manifest.json (that's a # local-dev-only file - see the tabbed-nav extension's emitLocalManifest option and # its middleware). Stamped so the UI bundle can skip fetching it there entirely, # rather than issuing a request that's guaranteed to 404. @@ -346,7 +346,7 @@ jobs: # extra place to look, so those extensions can still find hoisted deps (e.g. vinyl) that are # only installed under docs/node_modules. NODE_PATH: ${{ github.workspace }}/${{ env.DOCS_DIR }}/node_modules - # Both derive the staging/prod split from the single env.DOCS_PUBLISH_URL set + # Both derive the dev/prod split from the single env.DOCS_PUBLISH_URL set # at job level above - defined here, not there, because that's a job-level # env: block and this one can read it; two entries in the SAME block can't # read each other. Everything else - including PR previews - derives the