Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 92 additions & 14 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,32 +77,110 @@ jobs:
name: iso-word-document
path: build/${{ env.DOC }}.docx

# The site is served from the gh-pages branch (Pages source: "Deploy from a
# branch"): main's Editor's Copy lives at the root, and per-PR previews live
# under PREVIEW-DO-NOT-USE/pr-<N>/ (removed again by preview-cleanup.yml).
# Same model as the openid/publication repo.
publish-to-pages:
name: Publish Editor's Copy to GitHub Pages
if: github.ref == 'refs/heads/main'
needs: build
runs-on: ubuntu-latest
# Serialise Pages deployments so two quick merges to main can't race (one
# failing with "a deployment is already in progress", or publishing stale).
# Serialise gh-pages pushes so two quick merges to main can't race.
concurrency:
group: "pages"
cancel-in-progress: false
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
contents: write
steps:
- uses: actions/checkout@v4
- name: Download site artifact
uses: actions/download-artifact@v4
with:
name: site
path: _site
- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v3
path: ${{ runner.temp }}/site
- name: Publish to gh-pages branch
# Run a copy from outside the work tree: the script switches the
# checkout to gh-pages, which has no tools/.
run: |
cp tools/publish-gh-pages.sh "$RUNNER_TEMP/"
bash "$RUNNER_TEMP/publish-gh-pages.sh" root "$RUNNER_TEMP/site" \
"Publish Editor's Copy for ${GITHUB_SHA}"

# HTML preview of the PR's Editor's Copy, linked from a sticky PR comment.
# Fork PRs get a read-only GITHUB_TOKEN, so previews only run for branches in
# this repo.
deploy-preview:
name: Deploy PR preview to GitHub Pages
if: >
github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository
needs: build
runs-on: ubuntu-latest
concurrency:
group: preview-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: Download site artifact
uses: actions/download-artifact@v4
with:
path: _site
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
name: site
path: ${{ runner.temp }}/site
- name: Deploy preview to gh-pages branch
run: |
cp tools/publish-gh-pages.sh "$RUNNER_TEMP/"
bash "$RUNNER_TEMP/publish-gh-pages.sh" subdir \
"PREVIEW-DO-NOT-USE/pr-${{ github.event.pull_request.number }}" \
"$RUNNER_TEMP/site" \
"Preview for PR #${{ github.event.pull_request.number }}"
- name: Comment with preview link
uses: actions/github-script@v7
with:
script: |
const prNum = context.issue.number;
const sha = context.payload.pull_request.head.sha;
// Assumes the default <owner>.github.io/<repo> Pages host (no CNAME).
const url = `https://${context.repo.owner}.github.io/${context.repo.repo}/PREVIEW-DO-NOT-USE/pr-${prNum}/${process.env.DOC}-editors-copy.html`;

// Invisible marker identifying our comment, so the visible heading
// can be reworded without breaking the update-in-place matching.
const marker = '<!-- dchp-preview-comment -->';
const body = [
'📄 **Editor\'s Copy preview**',
'',
url,
'',
`_Preview of ${sha}; updated on every push. For review only — ` +
'the official specifications are published at https://openid.net/specs/_',
marker,
].join('\n');

// Update the existing preview comment rather than adding a new one.
let existing = null;
for await (const response of github.paginate.iterator(
github.rest.issues.listComments,
{ owner: context.repo.owner, repo: context.repo.repo, issue_number: prNum, per_page: 100 }
)) {
const found = response.data.find(c => c.body.includes(marker));
if (found) { existing = found; break; }
}

if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNum,
body,
});
}
34 changes: 34 additions & 0 deletions .github/workflows/preview-cleanup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Clean up PR preview

# Removes the PR's HTML preview (deployed to the gh-pages branch by the
# deploy-preview job in build.yml) once the PR is closed or merged.
on:
pull_request:
types: [closed]

permissions:
contents: write

jobs:
cleanup-preview:
name: Remove PR preview from GitHub Pages
# Fork PRs never get a preview (see deploy-preview in build.yml).
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
# Same group as deploy-preview, so a still-running deployment for this PR
# finishes before we delete its output.
concurrency:
group: preview-${{ github.event.pull_request.number }}
cancel-in-progress: false
steps:
# Check out the default branch for tools/: the PR's merge ref can be
# gone by the time a closed PR's workflow runs.
- uses: actions/checkout@v4
with:
ref: ${{ github.event.repository.default_branch }}
- name: Remove preview
run: |
cp tools/publish-gh-pages.sh "$RUNNER_TEMP/"
bash "$RUNNER_TEMP/publish-gh-pages.sh" delete \
"PREVIEW-DO-NOT-USE/pr-${{ github.event.pull_request.number }}" \
"Remove preview for PR #${{ github.event.pull_request.number }}"
84 changes: 84 additions & 0 deletions tools/publish-gh-pages.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/bin/bash
# Publish content to the gh-pages branch (the GitHub Pages source). Shared by
# the publish-to-pages and deploy-preview jobs in .github/workflows/build.yml
# and by .github/workflows/preview-cleanup.yml.
#
# publish-gh-pages.sh root <source-dir> <commit-message>
# Replace the site root with <source-dir>'s contents, keeping the
# PREVIEW-DO-NOT-USE/ PR previews.
# publish-gh-pages.sh subdir <subdir> <source-dir> <commit-message>
# Replace <subdir> with <source-dir>'s contents.
# publish-gh-pages.sh delete <subdir> <commit-message>
# Remove <subdir>; a no-op if it (or the branch) doesn't exist.
#
# Switches the current checkout to gh-pages, so the workflows run a copy from
# outside the work tree ($RUNNER_TEMP) rather than the checked-out file.

set -euo pipefail

mode=$1

git config user.name "OIDF GitHub Automation"
git config user.email "github@oidf.org"

# The fetch doubles as the does-the-branch-exist probe. --depth=1 because the
# branch accumulates a full site snapshot per publish and nothing here needs
# its history. The explicit refspec creates the local branch directly:
# actions/checkout configures origin to fetch only the triggering ref, so a
# bare `git fetch origin gh-pages` wouldn't give `git checkout` anything to
# resolve `gh-pages` against.
if git fetch --depth=1 origin gh-pages:gh-pages; then
git checkout gh-pages
elif [ "$mode" = delete ]; then
echo "No gh-pages branch; nothing to clean up."
exit 0
else
# Very first publish: start the branch empty.
git checkout --orphan gh-pages
git rm -rf --quiet .
fi

case $mode in
root)
src=$2 msg=$3
find . -mindepth 1 -maxdepth 1 \
! -name .git ! -name PREVIEW-DO-NOT-USE -exec rm -rf {} +
cp "$src"/* .
;;
subdir)
dir=$2 src=$3 msg=$4
rm -rf "$dir"
mkdir -p "$dir"
cp "$src"/* "$dir/"
;;
delete)
dir=$2 msg=$3
if [ ! -d "$dir" ]; then
echo "No $dir; nothing to clean up."
exit 0
fi
rm -rf "$dir"
;;
*)
echo "usage: $0 root <source-dir> <msg> | subdir <dir> <source-dir> <msg> | delete <dir> <msg>" >&2
exit 2
;;
esac

# Serve files as-is (skip Pages' default Jekyll processing).
touch .nojekyll

git add -A
if git diff --cached --quiet; then
echo "gh-pages unchanged; nothing to push."
exit 0
fi
git commit -m "$msg"
# Retry around pushes racing another job's gh-pages push (main publish vs. PR
# previews run in different concurrency groups); concurrent commits touch
# disjoint paths, so the rebase is conflict-free.
for _ in 1 2 3; do
git push origin gh-pages && exit 0
git pull --rebase origin gh-pages
done
exit 1
Loading