@@ -13,9 +13,17 @@ concurrency:
1313 group : preview-${{ github.event.pull_request.number || github.run_id }}
1414 cancel-in-progress : true
1515
16+ defaults :
17+ run :
18+ shell : bash
19+
1620jobs :
1721 preview :
1822 runs-on : ubuntu-latest
23+ outputs :
24+ removed_prs_json : ${{ steps.prune-previews.outputs.removed_prs_json }}
25+ env :
26+ PREVIEW_RETENTION_LIMIT : 6
1927
2028 steps :
2129
@@ -67,15 +75,116 @@ jobs:
6775 action : auto
6876 comment : false
6977
78+ - name : Checkout gh-pages for preview retention
79+ if : github.event.action != 'closed'
80+ uses : actions/checkout@v4
81+ with :
82+ ref : gh-pages
83+ fetch-depth : 0
84+ path : gh-pages-maintenance
85+
86+ - name : Prune old PR previews
87+ id : prune-previews
88+ if : github.event.action != 'closed'
89+ run : |
90+ cd gh-pages-maintenance
91+ mkdir -p pr-preview
92+ removed_prs=()
93+
94+ mapfile -t previews < <(
95+ while IFS= read -r preview; do
96+ timestamp="$(git log -1 --format=%ct -- "pr-preview/$preview" 2>/dev/null || echo 0)"
97+ printf '%s %s\n' "$timestamp" "$preview"
98+ done < <(find pr-preview -mindepth 1 -maxdepth 1 -type d -name 'pr-*' -printf '%f\n') \
99+ | sort -nr \
100+ | awk '{print $2}'
101+ )
102+
103+ if (( ${#previews[@]} <= PREVIEW_RETENTION_LIMIT )); then
104+ echo "removed_prs_json=[]" >> "$GITHUB_OUTPUT"
105+ exit 0
106+ fi
107+
108+ for preview in "${previews[@]:PREVIEW_RETENTION_LIMIT}"; do
109+ rm -rf "pr-preview/$preview"
110+ removed_prs+=("${preview#pr-}")
111+ done
112+
113+ if git diff --quiet -- pr-preview; then
114+ echo "removed_prs=" >> "$GITHUB_OUTPUT"
115+ echo "removed_prs_json=[]" >> "$GITHUB_OUTPUT"
116+ exit 0
117+ fi
118+
119+ git config user.name "github-actions[bot]"
120+ git config user.email "github-actions[bot]@users.noreply.github.com"
121+ git add pr-preview
122+ git commit -m "Prune old PR previews"
123+ git push
124+
125+ echo "removed_prs=$(IFS=,; echo "${removed_prs[*]}")" >> "$GITHUB_OUTPUT"
126+ echo "removed_prs_json=$(printf '%s\n' "${removed_prs[@]}" | jq -R . | jq -sc .)" >> "$GITHUB_OUTPUT"
127+
70128 - name : Comment PR with Preview URL
71129 if : github.event.action != 'closed'
72130 uses : marocchino/sticky-pull-request-comment@v2
73131 with :
74132 header : pr-preview
75133 message : |
76134 🚀 Preview deployment: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/pr-preview/pr-${{ github.event.pull_request.number }}/
135+ > *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)*
136+
137+ - name : Comment on pruned previews
138+ if : github.event.action != 'closed' && steps.prune-previews.outputs.removed_prs_json != '[]'
139+ uses : actions/github-script@v7
140+ env :
141+ REMOVED_PRS_JSON : ${{ steps.prune-previews.outputs.removed_prs_json }}
142+ PREVIEW_RETENTION_LIMIT : ${{ env.PREVIEW_RETENTION_LIMIT }}
143+ with :
144+ script : |
145+ const removedPrs = JSON.parse(process.env.REMOVED_PRS_JSON);
146+ const retentionLimit = process.env.PREVIEW_RETENTION_LIMIT;
147+ const header = "pr-preview";
148+ const marker = `<!-- Sticky Pull Request Comment${header} -->`;
149+
150+ for (const prNumber of removedPrs) {
151+ const body =
152+ `Preview deployment for PR #${prNumber} removed.\n\n` +
153+ `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` +
154+ `If needed, push a new commit to this PR to generate a fresh preview.\n` +
155+ `${marker}`;
156+
157+ const { data: comments } = await github.rest.issues.listComments({
158+ owner: context.repo.owner,
159+ repo: context.repo.repo,
160+ issue_number: Number(prNumber),
161+ per_page: 100,
162+ });
163+
164+ const existingComment = [...comments].reverse().find((comment) =>
165+ comment.user?.login === "github-actions[bot]" &&
166+ comment.body?.includes(marker)
167+ );
168+
169+ if (existingComment) {
170+ await github.rest.issues.updateComment({
171+ owner: context.repo.owner,
172+ repo: context.repo.repo,
173+ comment_id: existingComment.id,
174+ body,
175+ });
176+ continue;
177+ }
178+
179+ await github.rest.issues.createComment({
180+ owner: context.repo.owner,
181+ repo: context.repo.repo,
182+ issue_number: Number(prNumber),
183+ body,
184+ });
185+ }
77186
78- - name : Cleanup PR preview
187+ - name : Cleanup PR preview on close
79188 if : github.event.action == 'closed'
80189 uses : rossjrw/pr-preview-action@v1.6.3
81190 with :
0 commit comments