Repository navigation
ci: publish docs previews for fork PRs #1700
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| name: Publish docs preview on PR | ||
|
|
||
| # Publish what pr-docs-preview.yml built, and remove it when the PR closes. | ||
| # This workflow has a write token, so it never runs code from the PR: | ||
| # it only copies files and treats the artifact as untrusted data. | ||
| # The author of a fork PR controls the artifact, including any HTML and | ||
| # JavaScript. So publish only for PR authors with write or member access. | ||
|
|
||
| on: | ||
| workflow_run: | ||
| workflows: ["Create docs preview on PR"] | ||
| types: [completed] | ||
|
|
||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
| actions: read | ||
|
|
||
| # One group per PR branch: a newer run replaces a pending older run. | ||
| concurrency: | ||
| group: docs-preview-${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Keep the latest build from being canceled by an older build. Builds can finish out of commit order. If a publisher is running, the latest build can become pending, then an older build can finish and cancel it. The older build subsequently fails the SHA check, leaving the preview stale. Queue pending publishers instead of replacing them. GitHub supports
|
||
| cancel-in-progress: false | ||
|
coderabbitai[bot] marked this conversation as resolved.
Resolved
|
||
|
|
||
| jobs: | ||
| publish: | ||
| if: github.event.workflow_run.conclusion == 'success' | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Download preview | ||
| uses: actions/download-artifact@v8 | ||
| with: | ||
| name: docs-preview | ||
| path: preview | ||
| run-id: ${{ github.event.workflow_run.id }} | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| # Accept only a PR whose head is the commit that was built. | ||
| # Remove the preview when the PR is not open. | ||
| - name: Check preview metadata | ||
| id: meta | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| HEAD_SHA: ${{ github.event.workflow_run.head_sha }} | ||
| run: | | ||
| set -euo pipefail | ||
| PR=$(head -c 16 preview/pr | tr -d '\n') | ||
| ACTION=$(head -c 16 preview/action | tr -d '\n') | ||
| [[ "${PR}" =~ ^[0-9]+$ ]] || { echo "::error::Invalid PR number"; exit 1; } | ||
| [[ "${ACTION}" =~ ^(publish|remove)$ ]] || { echo "::error::Invalid action"; exit 1; } | ||
| read -r PR_SHA PR_STATE PR_ASSOC < <(gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR}" \ | ||
| --jq '"\(.head.sha) \(.state) \(.author_association)"') | ||
| if [[ "${PR_SHA}" != "${HEAD_SHA}" ]]; then | ||
| # A newer push or a wrong PR number. A newer run publishes instead. | ||
| echo "::notice::PR #${PR} head is not ${HEAD_SHA}. Skip." | ||
| ACTION=skip | ||
| elif [[ "${PR_STATE}" != "open" ]]; then | ||
| ACTION=remove | ||
|
Comment on lines
+57
to
+58
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Skip removal artifacts when the PR is open. If a PR is closed and then reopened without a new commit, a delayed close artifact can still have Set
|
||
| elif [[ "${ACTION}" == "publish" && ! "${PR_ASSOC}" =~ ^(OWNER|MEMBER|COLLABORATOR)$ ]]; then | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check who controls the PR branch, not only its author. A maintainer can open a PR from another user’s fork. The fork owner can then update the branch and control the build artifact, while Require approval for fork builds or verify that the head branch is controlled by trusted users.
|
||
| echo "::notice::PR #${PR} author is ${PR_ASSOC}. No preview." | ||
| ACTION=skip | ||
| fi | ||
| echo "pr=${PR}" >> "$GITHUB_OUTPUT" | ||
| echo "action=${ACTION}" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Checkout `www` branch | ||
| if: steps.meta.outputs.action != 'skip' | ||
| uses: actions/checkout@v7 | ||
| with: | ||
| ref: www | ||
| path: www | ||
|
|
||
| # Remove previews of closed PRs, so www stays below the 1 GB Pages limit. | ||
| - name: Update `www` branch | ||
| if: steps.meta.outputs.action != 'skip' | ||
| working-directory: www | ||
| env: | ||
| PR: ${{ steps.meta.outputs.pr }} | ||
| ACTION: ${{ steps.meta.outputs.action }} | ||
| run: | | ||
| set -euo pipefail | ||
| git config user.name github-actions | ||
| git config user.email github-actions@github.com | ||
| if [[ "${ACTION}" == "publish" ]]; then | ||
| mkdir -p "${PR}" | ||
| rsync -a --delete --no-links --exclude='.git*' ../preview/site/ "${PR}/" | ||
| git add -A "${PR}" | ||
| git commit -q -m "Update docs preview for PR #${PR}" || { echo "No changes."; exit 0; } | ||
| else | ||
| [[ -d "${PR}" ]] || { echo "No preview for PR #${PR}."; exit 0; } | ||
| git rm -r -q "${PR}" | ||
| git commit -q -m "www: remove docs preview for closed PR #${PR}" | ||
| fi | ||
| for attempt in 1 2 3; do | ||
| git push origin www && exit 0 | ||
| echo "Push failed (attempt ${attempt}). Rebase on the latest www." >&2 | ||
| git pull -q --rebase origin www | ||
| done | ||
| echo "::error::Push to www failed after 3 attempts" | ||
| exit 1 | ||
|
|
||
| # One comment per PR. Later runs leave it as it is. | ||
| - name: Comment on PR with preview link | ||
| if: steps.meta.outputs.action == 'publish' | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| PR: ${{ steps.meta.outputs.pr }} | ||
| run: | | ||
| set -euo pipefail | ||
| MARKER="<!-- docs-preview -->" | ||
| COMMENTS=$(gh api "repos/${GITHUB_REPOSITORY}/issues/${PR}/comments" --paginate --jq '.[].body') | ||
| if grep -qF "${MARKER}" <<< "${COMMENTS}"; then | ||
| exit 0 | ||
| fi | ||
| gh pr comment "${PR}" -R "${GITHUB_REPOSITORY}" --body "${MARKER} | ||
| Documentation preview, available a few minutes after each push: | ||
|
|
||
| <a href=\"https://armbian.github.io/documentation/${PR}\"><kbd><br> Open WWW preview <br></kbd></a>" | ||
Uh oh!
There was an error while loading. Please reload this page.