Skip to content

Commit 2ebaea7

Browse files
committed
Implement previews for GitHub pull requests
When a contributor submits a PR, we always perform a build. This takes it a step further and uploads that a custom surge.sh domain. It adds a sticky comment to link to that preview while also generating some diffs. This means reviews easier. In the implementation an additional preview step is added. This first builds the base (target of the PR) as the current. Then it downloads the generated preview that was added as an artifact in the original build step. Creating a reasonably sized diff was tricky, because there's a long Javascript line that includes the mtime, making it indeterministic. That line isn't relevant anyway, so it's removed. The diff command also ignores the search index. All of that is placed in the preview, making it readable. A sticky comment is added with a summary, making it easy to use. The sticky comment is updated for every push, rather than added a comment for every push. This keeps the PR conversation usable.
1 parent 439dda4 commit 2ebaea7

File tree

3 files changed

+158
-0
lines changed

3 files changed

+158
-0
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module.exports = async ({github, context, core, fs, artifact_name}) => {
2+
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
3+
owner: context.repo.owner,
4+
repo: context.repo.repo,
5+
run_id: context.payload.workflow_run.id,
6+
});
7+
let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
8+
return artifact.name == artifact_name
9+
})[0];
10+
let download = await github.rest.actions.downloadArtifact({
11+
owner: context.repo.owner,
12+
repo: context.repo.repo,
13+
artifact_id: matchArtifact.id,
14+
archive_format: 'zip',
15+
});
16+
fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/${artifact_name}.zip`, Buffer.from(download.data));
17+
};

.github/workflows/preview.yml

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
name: Preview
2+
3+
on:
4+
workflow_run:
5+
workflows:
6+
- Build
7+
types:
8+
- completed
9+
10+
jobs:
11+
preview-failed:
12+
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion != 'success'
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Download metadata artifact
16+
uses: actions/github-script@v7
17+
with:
18+
script: |
19+
const script = require('./.github/download_workflow_run_artifact.js');
20+
let fs = require('fs');
21+
await script({github, context, core, fs, artifact_name: 'pr'});
22+
23+
- name: Unzip artifact
24+
run: unzip pr.zip
25+
26+
- name: Read PR data
27+
run: echo "PR_NUMBER=$(cat ./pr)" >> $GITHUB_ENV
28+
29+
- name: Comment on PR
30+
uses: marocchino/sticky-pull-request-comment@v2
31+
with:
32+
number: ${{ env.PR_NUMBER }}
33+
message: "The PR preview for ${{ github.event.workflow_run.head_sha }} could not be generated"
34+
35+
preview:
36+
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
37+
runs-on: ubuntu-latest
38+
steps:
39+
# TODO: can this download from the existing pages or a cache?
40+
- name: Checkout
41+
uses: actions/checkout@v4
42+
with:
43+
persist-credentials: false
44+
45+
- name: Build current pages
46+
run: |
47+
npm install
48+
npx honkit build
49+
mv _book current
50+
51+
- name: Download metadata artifact
52+
uses: actions/github-script@v7
53+
with:
54+
script: |
55+
const script = require('./.github/download_workflow_run_artifact.js');
56+
let fs = require('fs');
57+
await script({github, context, core, fs, artifact_name: 'github-pages'});
58+
59+
- name: Unpack preview
60+
run: unzip github-pages.zip -d preview
61+
62+
- name: Remove indeterminism
63+
run: |
64+
find current/ preview/ -type f -exec sed -i '/gitbook.page.hasChanged/d' {} +
65+
66+
- name: Create diff to current
67+
run: |
68+
diff -Nrwu --exclude search_index.json current/ preview/ > preview/diff.patch || true
69+
if [[ -s preview/diff.patch ]] ; then
70+
sudo apt-get update
71+
sudo apt-get install -y diffstat python3-pygments
72+
73+
pygmentize -o preview/diff.html -l diff -f html -O full preview/diff.patch
74+
diffstat -l -p2 preview/diff.patch > diff.txt
75+
fi
76+
77+
- name: Download metadata artifact
78+
uses: actions/github-script@v7
79+
with:
80+
script: |
81+
const script = require('./.github/download_workflow_run_artifact.js');
82+
let fs = require('fs');
83+
await script({github, context, core, fs, artifact_name: 'pr'});
84+
85+
- name: Unzip artifact
86+
run: unzip pr.zip
87+
88+
- name: Read PR data
89+
run: echo "PR_NUMBER=$(cat ./pr)" >> $GITHUB_ENV
90+
91+
- name: Set preview domain
92+
run: echo "PREVIEW_DOMAIN=$(echo ${{ github.repository }} | tr / - )-${{ github.job }}-pr-${{ env.PR_NUMBER }}.surge.sh" >> $GITHUB_ENV
93+
94+
- name: Install surge
95+
run: npm install surge
96+
97+
- name: Deploy to surge.sh
98+
run: npx surge ./preview $PREVIEW_DOMAIN --token ${{ secrets.SURGE_TOKEN }}
99+
100+
- name: Generate summary
101+
run: |
102+
echo "The PR preview for ${{ github.event.workflow_run.head_sha }} is available at [${{ env.PREVIEW_DOMAIN }}](https://${{ env.PREVIEW_DOMAIN }})" >> pr.md
103+
echo "" >> pr.md
104+
105+
if [[ -f preview/diff.txt ]] ; then
106+
echo "The following output files are affected by this PR:" >> pr.md
107+
sed -E "s#(.*)#- [\1](https://${{ env.PREVIEW_DOMAIN }}/\1)#" preview/diff.txt >> pr.md
108+
else
109+
echo "No diff compared to the current website" >> pr.md
110+
fi
111+
112+
if [[ -s preview/diff.patch ]] ; then
113+
echo "" >> pr.md
114+
echo "[show diff](https://${{ env.PREVIEW_DOMAIN }}/diff.patch)" >> pr.md
115+
fi
116+
117+
if [[ -f preview/diff.html ]] ; then
118+
echo "" >> pr.md
119+
echo "[show diff as HTML](https://${{ env.PREVIEW_DOMAIN }}/diff.html)" >> pr.md
120+
fi
121+
122+
- name: Comment on PR
123+
uses: marocchino/sticky-pull-request-comment@v2
124+
with:
125+
number: ${{ env.PR_NUMBER }}
126+
path: pr.md

.github/workflows/test.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,18 @@ jobs:
1515
run: |
1616
npm install
1717
npx honkit build
18+
19+
- name: Upload artifact
20+
uses: actions/upload-artifact@v4
21+
with:
22+
name: github-pages
23+
path: _book/**
24+
25+
- name: Save PR metadata
26+
run: |
27+
echo ${{ github.event.number }} > ./pr
28+
29+
- uses: actions/upload-artifact@v4
30+
with:
31+
name: pr
32+
path: ./pr

0 commit comments

Comments
 (0)