Skip to content

Commit 3a2ff56

Browse files
committed
feat: add pr preview
1 parent 69f5a4f commit 3a2ff56

File tree

7 files changed

+209
-0
lines changed

7 files changed

+209
-0
lines changed

.github/act/pull_request.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"act": true,
3+
"action": "synchronize",
4+
"repository": {
5+
"name": "managing-innersource-projects",
6+
"full_name": "InnerSourceCommons/managing-innersource-projects"
7+
},
8+
"pull_request": {
9+
"number": 107,
10+
"head": {
11+
"repo": {
12+
"full_name": "InnerSourceCommons/managing-innersource-projects"
13+
}
14+
}
15+
}
16+
}

.github/act/push.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"act": true
3+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
name: Deploy mdBook PR preview
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened, closed]
6+
7+
permissions:
8+
contents: write
9+
pull-requests: write
10+
11+
concurrency:
12+
# One running preview job per PR number. If new commits arrive, cancel older runs.
13+
group: pr-preview-${{ github.event.pull_request.number }}
14+
cancel-in-progress: true
15+
16+
jobs:
17+
deploy-preview:
18+
if: github.event.action != 'closed' && github.event.pull_request.head.repo.full_name == github.repository
19+
runs-on: ubuntu-latest
20+
env:
21+
CARGO_HOME: ${{ github.workspace }}/.cargo
22+
RUSTUP_HOME: ${{ github.workspace }}/.rustup
23+
PREVIEW_DIR: pr-${{ github.event.pull_request.number }}
24+
PREVIEW_URL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/pr-${{ github.event.pull_request.number }}/
25+
steps:
26+
- uses: actions/checkout@v4
27+
28+
- name: Install mdBook
29+
run: bash scripts/install-mdbook.sh
30+
env:
31+
REPO_ROOT: ${{ github.workspace }}
32+
33+
- name: Build with mdBook
34+
run: ${{ env.CARGO_HOME }}/bin/mdbook build
35+
36+
- name: Deploy preview to gh-pages/pr-<id>
37+
# Important: we build from the PR branch, but publish static files to gh-pages.
38+
# GitHub Pages serves from a configured publishing branch (gh-pages here),
39+
# not from arbitrary PR branches.
40+
uses: peaceiris/actions-gh-pages@v4
41+
with:
42+
github_token: ${{ secrets.GITHUB_TOKEN }}
43+
publish_branch: gh-pages
44+
publish_dir: ./book
45+
# Keep each preview isolated under pr-<number>/ so multiple PR previews can coexist.
46+
destination_dir: ${{ env.PREVIEW_DIR }}
47+
keep_files: true
48+
49+
- name: Comment preview URL on PR
50+
uses: actions/github-script@v7
51+
with:
52+
# Keep workflow YAML concise: run comment logic from .github/workflows/mdbook/comment-preview-url.js.
53+
script: |
54+
const { commentPreviewUrl } = require('./.github/workflows/mdbook/comment-preview-url.js')
55+
await commentPreviewUrl({
56+
github,
57+
context,
58+
previewUrl: process.env.PREVIEW_URL,
59+
})
60+
61+
cleanup-preview:
62+
if: github.event.action == 'closed' && github.event.pull_request.head.repo.full_name == github.repository
63+
runs-on: ubuntu-latest
64+
env:
65+
PREVIEW_DIR: pr-${{ github.event.pull_request.number }}
66+
steps:
67+
- name: Checkout gh-pages
68+
# Cleanup edits the published site branch directly because previews live there.
69+
uses: actions/checkout@v4
70+
with:
71+
ref: gh-pages
72+
fetch-depth: 0
73+
74+
- name: Remove preview directory
75+
run: |
76+
# Keep workflow YAML concise: run cleanup logic from .github/workflows/mdbook/cleanup-preview.sh.
77+
bash .github/workflows/mdbook/cleanup-preview.sh "${PREVIEW_DIR}" "${{ github.event.pull_request.number }}"

.github/workflows/mdbook.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,24 @@ jobs:
3838
env:
3939
REPO_ROOT: ${{ github.workspace }}
4040
- name: Setup Pages
41+
if: ${{ !env.ACT }}
4142
id: pages
4243
uses: actions/configure-pages@v5
4344
- name: Build with mdBook
4445
run: ${{ env.CARGO_HOME }}/bin/mdbook build
4546
- name: Upload artifact
47+
if: ${{ !env.ACT }}
4648
uses: actions/upload-pages-artifact@v3
4749
with:
4850
path: ./book
51+
- name: Confirm local act build
52+
if: ${{ env.ACT }}
53+
run: |
54+
echo "Local act run: mdBook build completed; skipping Pages upload/deploy steps."
4955
5056
# Deployment job
5157
deploy:
58+
if: ${{ !github.event.act }}
5259
environment:
5360
name: github-pages
5461
url: ${{ steps.deployment.outputs.page_url }}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
PREVIEW_DIR="${1:?preview directory is required}"
5+
PR_NUMBER="${2:?pull request number is required}"
6+
7+
# Delete this PR's published preview folder from gh-pages.
8+
rm -rf "${PREVIEW_DIR}"
9+
10+
if git status --porcelain | grep -q .; then
11+
# If something changed, commit+push so GitHub Pages drops that preview URL.
12+
git config user.name "github-actions[bot]"
13+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
14+
# Stage only the working-tree changes from this cleanup step before committing.
15+
git add -A
16+
git commit -m "chore: remove preview for #${PR_NUMBER}"
17+
git push
18+
else
19+
echo "No preview directory to remove."
20+
fi
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
function buildCommentBody(marker, previewUrl) {
2+
return `${marker}\n📘 mdBook preview for this PR:\n\n${previewUrl}`
3+
}
4+
5+
async function commentPreviewUrl({ github, context, previewUrl }) {
6+
const marker = '<!-- mdbook-pr-preview -->'
7+
const body = buildCommentBody(marker, previewUrl)
8+
9+
const { owner, repo } = context.repo
10+
const issue_number = context.issue.number
11+
12+
const comments = await github.paginate(github.rest.issues.listComments, {
13+
owner,
14+
repo,
15+
issue_number,
16+
per_page: 100,
17+
})
18+
19+
const existing = comments.find(
20+
(comment) => comment.user?.type === 'Bot' && comment.body?.includes(marker),
21+
)
22+
23+
if (existing) {
24+
await github.rest.issues.updateComment({
25+
owner,
26+
repo,
27+
comment_id: existing.id,
28+
body,
29+
})
30+
return
31+
}
32+
33+
await github.rest.issues.createComment({
34+
owner,
35+
repo,
36+
issue_number,
37+
body,
38+
})
39+
}
40+
41+
module.exports = {
42+
commentPreviewUrl,
43+
}

scripts/test-mdbook-deploy.sh

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/usr/bin/env bash
2+
# Run the mdBook GitHub Actions workflows locally with act.
3+
# Usage: ./scripts/test-mdbook-deploy.sh [act args]
4+
set -euo pipefail
5+
6+
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
7+
MAIN_WORKFLOW_PATH="${REPO_ROOT}/.github/workflows/mdbook.yml"
8+
PREVIEW_WORKFLOW_PATH="${REPO_ROOT}/.github/workflows/mdbook-pr-preview.yml"
9+
PUSH_EVENT_PATH="${REPO_ROOT}/.github/act/push.json"
10+
PULL_REQUEST_EVENT_PATH="${REPO_ROOT}/.github/act/pull_request.json"
11+
12+
if ! command -v act >/dev/null 2>&1; then
13+
echo "Error: 'act' is not installed or not on PATH." >&2
14+
exit 1
15+
fi
16+
17+
if [[ ! -f "${MAIN_WORKFLOW_PATH}" ]]; then
18+
echo "Error: workflow file not found at ${MAIN_WORKFLOW_PATH}" >&2
19+
exit 1
20+
fi
21+
22+
if [[ ! -f "${PREVIEW_WORKFLOW_PATH}" ]]; then
23+
echo "Error: workflow file not found at ${PREVIEW_WORKFLOW_PATH}" >&2
24+
exit 1
25+
fi
26+
27+
if [[ ! -f "${PUSH_EVENT_PATH}" ]]; then
28+
echo "Error: event payload not found at ${PUSH_EVENT_PATH}" >&2
29+
exit 1
30+
fi
31+
32+
if [[ ! -f "${PULL_REQUEST_EVENT_PATH}" ]]; then
33+
echo "Error: event payload not found at ${PULL_REQUEST_EVENT_PATH}" >&2
34+
exit 1
35+
fi
36+
37+
cd "${REPO_ROOT}"
38+
39+
echo "Running main Pages workflow (push): ${MAIN_WORKFLOW_PATH}"
40+
act push -W "${MAIN_WORKFLOW_PATH}" -e "${PUSH_EVENT_PATH}" "$@"
41+
42+
echo "Running PR preview workflow (pull_request): ${PREVIEW_WORKFLOW_PATH}"
43+
act pull_request -W "${PREVIEW_WORKFLOW_PATH}" -e "${PULL_REQUEST_EVENT_PATH}" "$@"

0 commit comments

Comments
 (0)