Skip to content

Commit a421386

Browse files
Add PR preview pruning and retention management
1 parent ee91dca commit a421386

1 file changed

Lines changed: 110 additions & 0 deletions

File tree

.github/workflows/build-and-preview-site.yml

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,14 @@ defaults:
2626

2727
jobs:
2828
build-and-deploy-preview:
29+
outputs:
30+
removed_prs_json: ${{ steps.prune-previews.outputs.removed_prs_json }}
31+
2932
runs-on: ubuntu-24.04
3033

34+
env:
35+
PREVIEW_RETENTION_LIMIT: 6
36+
3137
steps:
3238
- name: Checkout PR code
3339
if: github.event.action != 'closed'
@@ -74,6 +80,61 @@ jobs:
7480
action: auto
7581
comment: false
7682

83+
- name: Checkout gh-pages for preview retention
84+
if: github.event.action != 'closed'
85+
uses: actions/checkout@v6
86+
with:
87+
ref: gh-pages
88+
fetch-depth: 0
89+
persist-credentials: true
90+
filter: blob:none
91+
sparse-checkout: |
92+
pr-preview
93+
path: gh-pages-maintenance
94+
95+
96+
- name: Prune old PR previews
97+
id: prune-previews
98+
if: github.event.action != 'closed'
99+
run: |
100+
cd gh-pages-maintenance
101+
mkdir -p pr-preview
102+
removed_prs=()
103+
104+
mapfile -t previews < <(
105+
while IFS= read -r preview; do
106+
timestamp="$(git log -1 --format=%ct -- "pr-preview/$preview" 2>/dev/null || echo 0)"
107+
printf '%s %s\n' "$timestamp" "$preview"
108+
done < <(find pr-preview -mindepth 1 -maxdepth 1 -type d -name 'pr-*' -printf '%f\n') \
109+
| sort -nr \
110+
| awk '{print $2}'
111+
)
112+
113+
if (( ${#previews[@]} <= $PREVIEW_RETENTION_LIMIT )); then
114+
echo "removed_prs_json=[]" >> "$GITHUB_OUTPUT"
115+
exit 0
116+
fi
117+
118+
for preview in "${previews[@]:$PREVIEW_RETENTION_LIMIT}"; do
119+
rm -rf "pr-preview/$preview"
120+
removed_prs+=("${preview#pr-}")
121+
done
122+
123+
git add pr-preview
124+
125+
if git diff --cached --quiet; then
126+
echo "removed_prs_json=[]" >> "$GITHUB_OUTPUT"
127+
exit 0
128+
fi
129+
130+
git config user.name "github-actions[bot]"
131+
git config user.email "github-actions[bot]@users.noreply.github.com"
132+
133+
git add pr-preview
134+
git commit -m "Prune old PR previews" || true
135+
git push || true
136+
137+
echo "removed_prs_json=$(printf '%s\n' "${removed_prs[@]}" | jq -R . | jq -sc .)" >> "$GITHUB_OUTPUT"
77138
- name: Comment PR with Preview URL
78139
if: github.event.action != 'closed'
79140
uses: marocchino/sticky-pull-request-comment@v2
@@ -83,7 +144,56 @@ jobs:
83144
🚀 Preview deployment: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/pr-preview/pr-${{ github.event.pull_request.number }}/
84145
> *Note: Preview may take a moment (GitHub Pages deployment in progress). Please wait and refresh. Track deployment [here](https://github.com/${{ github.repository }}/actions/workflows/pages/pages-build-deployment)*
85146
147+
- name: Comment on pruned previews
148+
if: github.event.action != 'closed' && steps.prune-previews.outputs.removed_prs_json != '[]'
149+
uses: actions/github-script@v7
150+
env:
151+
REMOVED_PRS_JSON: ${{ steps.prune-previews.outputs.removed_prs_json }}
152+
PREVIEW_RETENTION_LIMIT: ${{ env.PREVIEW_RETENTION_LIMIT }}
153+
with:
154+
script: |
155+
const removedPrs = JSON.parse(process.env.REMOVED_PRS_JSON);
156+
const retentionLimit = process.env.PREVIEW_RETENTION_LIMIT;
157+
const header = "pr-preview";
158+
const marker = `<!-- Sticky Pull Request Comment${header} -->`;
159+
160+
for (const prNumber of removedPrs) {
161+
const body =
162+
`Preview deployment for PR #${prNumber} removed.\n\n` +
163+
`This PR preview was automatically pruned because we keep only the ${retentionLimit} most recently updated previews on GitHub Pages to stay within deployment size limits.\n\n` +
164+
`If needed, push a new commit to this PR to generate a fresh preview.\n` +
165+
`${marker}`;
166+
167+
const { data: comments } = await github.rest.issues.listComments({
168+
owner: context.repo.owner,
169+
repo: context.repo.repo,
170+
issue_number: Number(prNumber),
171+
per_page: 100,
172+
});
173+
174+
const existingComment = [...comments].reverse().find((comment) =>
175+
comment.user?.login === "github-actions[bot]" &&
176+
comment.body?.includes(marker)
177+
);
178+
179+
if (existingComment) {
180+
await github.rest.issues.updateComment({
181+
owner: context.repo.owner,
182+
repo: context.repo.repo,
183+
comment_id: existingComment.id,
184+
body,
185+
});
186+
continue;
187+
}
86188
189+
await github.rest.issues.createComment({
190+
owner: context.repo.owner,
191+
repo: context.repo.repo,
192+
issue_number: Number(prNumber),
193+
body,
194+
});
195+
}
196+
87197
- name: Cleanup PR preview on close
88198
if: github.event.action == 'closed'
89199
uses: rossjrw/pr-preview-action@v1.6.3

0 commit comments

Comments
 (0)