From 6de1abd82019243165a549929164d2d18209e18d Mon Sep 17 00:00:00 2001 From: Emily Date: Sun, 10 Nov 2024 14:53:35 +0100 Subject: [PATCH] infra: publish PR previews for docs --- .github/workflows/docs-preview-build.yml | 49 ++++++++++++ .github/workflows/docs-preview-cleanup.yml | 32 ++++++++ .github/workflows/docs-preview-deploy.yml | 93 ++++++++++++++++++++++ 3 files changed, 174 insertions(+) create mode 100644 .github/workflows/docs-preview-build.yml create mode 100644 .github/workflows/docs-preview-cleanup.yml create mode 100644 .github/workflows/docs-preview-deploy.yml diff --git a/.github/workflows/docs-preview-build.yml b/.github/workflows/docs-preview-build.yml new file mode 100644 index 0000000000..8fb7c304ee --- /dev/null +++ b/.github/workflows/docs-preview-build.yml @@ -0,0 +1,49 @@ + +# This workflow builds the docs for each PR (including from forks), and uploads +# the rendered docs as an artifact. +# +# The artifact will be picked up by docs-preview-deploy.yml and uploaded to +# https://jj-preview.github.io/docs/. +# +# The split into "build" and "deploy" follows GitHub's guide at +# https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/. +# The build workflow has no access to the repo secrets. The deploy workflow runs +# in the context of the main repo rather than the PR branch. + +name: docs-preview-build + +on: + pull_request: + paths: + - 'docs/**' + - 'mkdocs.yml' + - 'pyproject.toml' + - 'uv.lock' + - '.github/workflows/docs-preview-build.yml' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + + - name: Install uv + uses: astral-sh/setup-uv@2e657c127d5b1635d5a8e3fa40e0ac50a5bf6992 + + - name: Build the docs + # Intentionally without --strict, to have previews even if the docs are + # mildly broken + run: uv run mkdocs build + + - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 + with: + name: rendered-docs + path: rendered-docs + + - run: | + echo ${{ github.event.pull_request.number }} > pr_number + + - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 + with: + name: pr_number + path: pr_number diff --git a/.github/workflows/docs-preview-cleanup.yml b/.github/workflows/docs-preview-cleanup.yml new file mode 100644 index 0000000000..9c4f313401 --- /dev/null +++ b/.github/workflows/docs-preview-cleanup.yml @@ -0,0 +1,32 @@ +name: docs-preview-cleanup + +permissions: + contents: write + +on: + # This always uses the workflow file from the base branch, and only runs if + # base == main + pull_request_target: + types: [closed] + +jobs: + cleanup: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + + - run: mkdir -p empty-dir + + - name: Deploy + uses: JamesIves/github-pages-deploy-action@62fec3add6773ec5dbbf18d2ee4260911aa35cf4 + with: + folder: empty-dir + repository-name: jj-preview/docs + branch: 'main' + clean: true + target-folder: 'pr-${{ github.event.pull_request.number }}' + ssh-key: ${{ secrets.DOCS_DEPLOY_KEY }} + git-config-name: 'jj-docs[bot]' + git-config-email: 'jj-docs[bot]@users.noreply.github.io' + commit-message: "Remove preview for PR ${{ github.event.pull_request.number }}" + single-commit: true diff --git a/.github/workflows/docs-preview-deploy.yml b/.github/workflows/docs-preview-deploy.yml new file mode 100644 index 0000000000..91f7d58278 --- /dev/null +++ b/.github/workflows/docs-preview-deploy.yml @@ -0,0 +1,93 @@ +# This workflow pushes docs rendered by docs-preview-build.yml to +# https://github.com/jj-preview/docs. +# +# There, GitHub's own "deploy pages" action will run to publish the static files +# to https://jj-preview.github.io/docs/. This adds a 30s delay before the docs +# are actually published/updated. +# +# jj-preview/docs has a top-level .nojekyll file. Otherwise GitHub will try +# rendering with Jekyll, and the delay will be longer. +# +# We use a separate repo for two reasons: +# 1. No chance to accidentally mess up the main GH Pages +# 2. Avoid the impression that the published content is "official" + +# TODO: PRs touching workflows should be approved by a maintainer +# TODO: enable docs-preview-build for PRs from forks + +name: docs-preview-deploy + +permissions: + contents: write + pull-requests: write + +on: + # NB: 'workflow_run' only triggers if this workflow is on the default branch, + # which is needed for security but makes it a bit annoying to test + workflow_run: + workflows: [docs-preview-build] + types: [completed] + +# Limit to one concurrent deployment. +# +# If we ever need parallel deployments, we'll need single-commit=false and +# force=false in the deploy step. +concurrency: + group: preview_deploy + +jobs: + deploy: + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + + - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 + with: + name: rendered-docs + path: rendered-docs + github-token: ${{ secrets.GITHUB_TOKEN }} + run-id: ${{ github.event.workflow_run.id }} + + - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 + with: + name: pr_number + github-token: ${{ secrets.GITHUB_TOKEN }} + run-id: ${{ github.event.workflow_run.id }} + + # Security note: The PR number is uploaded by the build workflow, and can + # be manipulated. The only thing an attacker can do, though, is overwrite + # someone else's docs preview. See + # https://github.com/orgs/community/discussions/25220 + - run: | + echo "PR_NUMBER=$(grep -o '[0-9]\+' pr_number)" >> $GITHUB_ENV + + - name: Deploy + uses: JamesIves/github-pages-deploy-action@62fec3add6773ec5dbbf18d2ee4260911aa35cf4 + with: + folder: rendered-docs + repository-name: jj-preview/docs + branch: main + clean: true + target-folder: 'pr-${{ env.PR_NUMBER }}' + # This key allows pushing to jj-preview/docs. How to set it up: + # + # 1. ssh-keygen -t ed25519 -C "" -N "" -f + # 2. Add the public key to https://github.com/jj-preview/docs/settings/keys/new + # 3. Add the private key to https://github.com/martinvonz/jj/settings/secrets/actions/new + ssh-key: ${{ secrets.DOCS_DEPLOY_KEY }} + git-config-name: 'jj-docs[bot]' + git-config-email: 'jj-docs[bot]@users.noreply.github.io' + commit-message: "Update preview for PR ${{ env.PR_NUMBER }}" + single-commit: true + + - name: Post a link to the docs in the PR + uses: thollander/actions-comment-pull-request@65f9e5c9a1f2cd378bd74b2e057c9736982a8e74 + with: + message: | + **📖 Documentation preview is published to https://jj-preview.github.io/docs/pr-${{ env.PR_NUMBER }}.** + Thanks for working on the docs! + + Note: it will take about 30 seconds before the preview is available. + pr-number: ${{ env.PR_NUMBER }} + comment-tag: docs-preview