diff --git a/.github/workflows/build-and-preview-site.yml b/.github/workflows/build-and-preview-site.yml
index d2afd102..6f135d87 100644
--- a/.github/workflows/build-and-preview-site.yml
+++ b/.github/workflows/build-and-preview-site.yml
@@ -26,8 +26,14 @@ defaults:
jobs:
build-and-deploy-preview:
+ outputs:
+ removed_prs_json: ${{ steps.prune-previews.outputs.removed_prs_json }}
+
runs-on: ubuntu-24.04
+ env:
+ PREVIEW_RETENTION_LIMIT: 6
+
steps:
- name: Checkout PR code
if: github.event.action != 'closed'
@@ -74,6 +80,61 @@ jobs:
action: auto
comment: false
+ - name: Checkout gh-pages for preview retention
+ if: github.event.action != 'closed'
+ uses: actions/checkout@v6
+ with:
+ ref: gh-pages
+ fetch-depth: 0
+ persist-credentials: true
+ filter: blob:none
+ sparse-checkout: |
+ pr-preview
+ path: gh-pages-maintenance
+
+
+ - name: Prune old PR previews
+ id: prune-previews
+ if: github.event.action != 'closed'
+ run: |
+ cd gh-pages-maintenance
+ mkdir -p pr-preview
+ removed_prs=()
+
+ mapfile -t previews < <(
+ while IFS= read -r preview; do
+ timestamp="$(git log -1 --format=%ct -- "pr-preview/$preview" 2>/dev/null || echo 0)"
+ printf '%s %s\n' "$timestamp" "$preview"
+ done < <(find pr-preview -mindepth 1 -maxdepth 1 -type d -name 'pr-*' -printf '%f\n') \
+ | sort -nr \
+ | awk '{print $2}'
+ )
+
+ if (( ${#previews[@]} <= $PREVIEW_RETENTION_LIMIT )); then
+ echo "removed_prs_json=[]" >> "$GITHUB_OUTPUT"
+ exit 0
+ fi
+
+ for preview in "${previews[@]:$PREVIEW_RETENTION_LIMIT}"; do
+ rm -rf "pr-preview/$preview"
+ removed_prs+=("${preview#pr-}")
+ done
+
+ git add pr-preview
+
+ if git diff --cached --quiet; then
+ echo "removed_prs_json=[]" >> "$GITHUB_OUTPUT"
+ exit 0
+ fi
+
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+
+ git add pr-preview
+ git commit -m "Prune old PR previews" || true
+ git push || true
+
+ echo "removed_prs_json=$(printf '%s\n' "${removed_prs[@]}" | jq -R . | jq -sc .)" >> "$GITHUB_OUTPUT"
- name: Comment PR with Preview URL
if: github.event.action != 'closed'
uses: marocchino/sticky-pull-request-comment@v2
@@ -83,7 +144,56 @@ jobs:
🚀 Preview deployment: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/pr-preview/pr-${{ github.event.pull_request.number }}/
> *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)*
+ - name: Comment on pruned previews
+ if: github.event.action != 'closed' && steps.prune-previews.outputs.removed_prs_json != '[]'
+ uses: actions/github-script@v7
+ env:
+ REMOVED_PRS_JSON: ${{ steps.prune-previews.outputs.removed_prs_json }}
+ PREVIEW_RETENTION_LIMIT: ${{ env.PREVIEW_RETENTION_LIMIT }}
+ with:
+ script: |
+ const removedPrs = JSON.parse(process.env.REMOVED_PRS_JSON);
+ const retentionLimit = process.env.PREVIEW_RETENTION_LIMIT;
+ const header = "pr-preview";
+ const marker = ``;
+
+ for (const prNumber of removedPrs) {
+ const body =
+ `Preview deployment for PR #${prNumber} removed.\n\n` +
+ `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` +
+ `If needed, push a new commit to this PR to generate a fresh preview.\n` +
+ `${marker}`;
+
+ const { data: comments } = await github.rest.issues.listComments({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: Number(prNumber),
+ per_page: 100,
+ });
+
+ const existingComment = [...comments].reverse().find((comment) =>
+ comment.user?.login === "github-actions[bot]" &&
+ comment.body?.includes(marker)
+ );
+
+ if (existingComment) {
+ await github.rest.issues.updateComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ comment_id: existingComment.id,
+ body,
+ });
+ continue;
+ }
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: Number(prNumber),
+ body,
+ });
+ }
+
- name: Cleanup PR preview on close
if: github.event.action == 'closed'
uses: rossjrw/pr-preview-action@v1.6.3
diff --git a/docs/_data/discuss/nighthawk.json b/docs/_data/discuss/nighthawk.json
index 54b64695..8b0bf5ef 100644
--- a/docs/_data/discuss/nighthawk.json
+++ b/docs/_data/discuss/nighthawk.json
@@ -1,7 +1,2 @@
-
-
301 Moved Permanently
-
-301 Moved Permanently
-
cloudflare
-
-
+{"users":[{"id":3,"username":"Lee","name":"Lee Calcote","avatar_template":"/user_avatar/discuss.layer5.io/lee/{size}/7_2.png","flair_name":"Team","flair_url":"/uploads/default/original/2X/2/217d51a6a52fec6ed215c48ec60f366eb09c02da.png","flair_bg_color":"7FFFFFF","flair_group_id":42,"admin":true,"moderator":true,"trust_level":2},{"id":129,"username":"Yash_Kamboj","name":"Yash Kamboj","avatar_template":"/letter_avatar_proxy/v4/letter/y/ed8c4c/{size}.png","trust_level":0},{"id":17,"username":"navendu","name":"Navendu Pottekkat","avatar_template":"/user_avatar/discuss.layer5.io/navendu/{size}/247_2.png","trust_level":2},{"id":1651,"username":"Parth.Malaviya","name":"Parth Malaviya","avatar_template":"/letter_avatar_proxy/v4/letter/p/ecd19e/{size}.png","trust_level":1},{"id":1701,"username":"Akhilender_Bongirwar","name":"Akhilender Bongirwar","avatar_template":"/user_avatar/discuss.layer5.io/akhilender_bongirwar/{size}/1642_2.png","trust_level":2},{"id":736,"username":"gopi.vaibhav","name":"Gopi Vaibhav","avatar_template":"/user_avatar/discuss.layer5.io/gopi.vaibhav/{size}/1671_2.png","trust_level":1},{"id":132,"username":"asubedy","name":"Aaditya Narayan Subedy","avatar_template":"/user_avatar/discuss.layer5.io/asubedy/{size}/248_2.png","trust_level":2},{"id":621,"username":"Yash_Sharma","name":"Yash Sharma","avatar_template":"/user_avatar/discuss.layer5.io/yash_sharma/{size}/2715_2.png","trust_level":2}],"primary_groups":[],"flair_groups":[{"id":42,"name":"Team","flair_url":"/uploads/default/original/2X/2/217d51a6a52fec6ed215c48ec60f366eb09c02da.png","flair_bg_color":"7FFFFFF","flair_color":""}],"topic_list":{"can_create_topic":false,"per_page":30,"top_tags":[{"id":78,"name":"meshery","slug":"meshery"},{"id":28,"name":"community","slug":"community"},{"id":29,"name":"meetings","slug":"meetings"},{"id":46,"name":"layer5","slug":"layer5"},{"id":47,"name":"doubt","slug":"doubt"},{"id":81,"name":"websites","slug":"websites"},{"id":2,"name":"meshmate","slug":"meshmate"},{"id":71,"name":"mesheryctl","slug":"mesheryctl"},{"id":65,"name":"meshery-ui","slug":"meshery-ui"},{"id":141,"name":"kanvas","slug":"kanvas"},{"id":72,"name":"ux","slug":"ux"},{"id":57,"name":"weekly-summary","slug":"weekly-summary"},{"id":105,"name":"docs","slug":"docs"},{"id":62,"name":"newcomers","slug":"newcomers"},{"id":58,"name":"error","slug":"error"},{"id":53,"name":"meshery-adapter","slug":"meshery-adapter"},{"id":80,"name":"setup-issue","slug":"setup-issue"},{"id":118,"name":"sistent","slug":"sistent"},{"id":109,"name":"discussion","slug":"discussion"},{"id":151,"name":"certification","slug":"certification"},{"id":11,"name":"kubernetes","slug":"kubernetes"},{"id":84,"name":"announcements","slug":"announcements"},{"id":88,"name":"devops","slug":"devops"},{"id":126,"name":"hacktoberfest","slug":"hacktoberfest"},{"id":130,"name":"cicd","slug":"cicd"},{"id":67,"name":"docker-desktop","slug":"docker-desktop"},{"id":142,"name":"kubecon","slug":"kubecon"},{"id":86,"name":"maintainer","slug":"maintainer"},{"id":98,"name":"meshmodel","slug":"meshmodel"},{"id":125,"name":"models","slug":"models"},{"id":33,"name":"reactjs","slug":"reactjs"}],"tags":[{"id":82,"name":"nighthawk","slug":"nighthawk","topic_count":3,"staff":false,"description":null}],"topics":[{"fancy_title":"New Meshery Nighthawk adapter makes its first appearance in Meshery UI","id":4732,"title":"New Meshery Nighthawk adapter makes its first appearance in Meshery UI","slug":"new-meshery-nighthawk-adapter-makes-its-first-appearance-in-meshery-ui","posts_count":2,"reply_count":0,"highest_post_number":2,"image_url":"https://discuss.layer5.io/uploads/default/original/2X/c/cb554efad9e8eafaec7fac6333cb0353949bf92c.png","created_at":"2024-02-28T05:25:20.925Z","last_posted_at":"2024-03-27T19:44:19.707Z","bumped":true,"bumped_at":"2024-03-27T19:44:19.707Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":[{"max_width":null,"max_height":null,"width":406,"height":150,"url":"https://discuss.layer5.io/uploads/default/original/2X/c/cb554efad9e8eafaec7fac6333cb0353949bf92c.png"},{"max_width":400,"max_height":400,"width":400,"height":147,"url":"https://discuss.layer5.io/uploads/default/optimized/2X/c/cb554efad9e8eafaec7fac6333cb0353949bf92c_2_400x147.png"},{"max_width":300,"max_height":300,"width":300,"height":110,"url":"https://discuss.layer5.io/uploads/default/optimized/2X/c/cb554efad9e8eafaec7fac6333cb0353949bf92c_2_300x110.png"},{"max_width":200,"max_height":200,"width":200,"height":73,"url":"https://discuss.layer5.io/uploads/default/optimized/2X/c/cb554efad9e8eafaec7fac6333cb0353949bf92c_2_200x73.png"}],"tags":[{"id":53,"name":"meshery-adapter","slug":"meshery-adapter"},{"id":82,"name":"nighthawk","slug":"nighthawk"}],"tags_descriptions":{},"views":171,"like_count":3,"has_summary":false,"last_poster_username":"Lee","category_id":6,"op_like_count":2,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":3,"primary_group_id":null,"flair_group_id":42}]},{"fancy_title":"How to setup getnighthawk.dev website development server?","id":278,"title":"How to setup getnighthawk.dev website development server?","slug":"how-to-setup-getnighthawk-dev-website-development-server","posts_count":6,"reply_count":3,"highest_post_number":6,"image_url":null,"created_at":"2021-12-13T17:36:09.632Z","last_posted_at":"2023-08-30T07:31:34.545Z","bumped":true,"bumped_at":"2023-08-30T07:31:34.545Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[{"id":82,"name":"nighthawk","slug":"nighthawk"}],"tags_descriptions":{},"views":778,"like_count":6,"has_summary":false,"last_poster_username":"Akhilender_Bongirwar","category_id":8,"op_like_count":2,"pinned_globally":false,"featured_link":null,"has_accepted_answer":true,"posters":[{"extras":null,"description":"Original Poster","user_id":129,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster, Accepted Answer","user_id":3,"primary_group_id":null,"flair_group_id":42},{"extras":null,"description":"Frequent Poster","user_id":17,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster","user_id":1651,"primary_group_id":null,"flair_group_id":null},{"extras":"latest","description":"Most Recent Poster","user_id":1701,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"While Setting up development server using make site command returning some error","id":3356,"title":"While Setting up development server using make site command returning some error","slug":"while-setting-up-development-server-using-make-site-command-returning-some-error","posts_count":18,"reply_count":7,"highest_post_number":18,"image_url":"https://discuss.layer5.io/uploads/default/optimized/2X/5/5288c2d5ba8544e7f3371fbba645ffa4ed40a0f1_2_1024x134.png","created_at":"2023-08-11T20:43:47.361Z","last_posted_at":"2023-08-30T06:30:00.616Z","bumped":true,"bumped_at":"2023-08-30T06:30:00.616Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":[{"max_width":null,"max_height":null,"width":1143,"height":150,"url":"https://discuss.layer5.io/uploads/default/original/2X/5/5288c2d5ba8544e7f3371fbba645ffa4ed40a0f1.png"},{"max_width":1024,"max_height":1024,"width":1024,"height":134,"url":"https://discuss.layer5.io/uploads/default/optimized/2X/5/5288c2d5ba8544e7f3371fbba645ffa4ed40a0f1_2_1024x134.png"},{"max_width":800,"max_height":800,"width":800,"height":104,"url":"https://discuss.layer5.io/uploads/default/optimized/2X/5/5288c2d5ba8544e7f3371fbba645ffa4ed40a0f1_2_800x104.png"},{"max_width":600,"max_height":600,"width":600,"height":78,"url":"https://discuss.layer5.io/uploads/default/optimized/2X/5/5288c2d5ba8544e7f3371fbba645ffa4ed40a0f1_2_600x78.png"},{"max_width":400,"max_height":400,"width":400,"height":52,"url":"https://discuss.layer5.io/uploads/default/optimized/2X/5/5288c2d5ba8544e7f3371fbba645ffa4ed40a0f1_2_400x52.png"},{"max_width":300,"max_height":300,"width":300,"height":39,"url":"https://discuss.layer5.io/uploads/default/optimized/2X/5/5288c2d5ba8544e7f3371fbba645ffa4ed40a0f1_2_300x39.png"},{"max_width":200,"max_height":200,"width":200,"height":26,"url":"https://discuss.layer5.io/uploads/default/optimized/2X/5/5288c2d5ba8544e7f3371fbba645ffa4ed40a0f1_2_200x26.png"}],"tags":[{"id":28,"name":"community","slug":"community"},{"id":47,"name":"doubt","slug":"doubt"},{"id":82,"name":"nighthawk","slug":"nighthawk"}],"tags_descriptions":{},"views":1152,"like_count":3,"has_summary":false,"last_poster_username":"Parth.Malaviya","category_id":8,"op_like_count":0,"pinned_globally":false,"featured_link":null,"has_accepted_answer":true,"posters":[{"extras":"latest","description":"Original Poster, Most Recent Poster","user_id":1651,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster, Accepted Answer","user_id":736,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster","user_id":132,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster","user_id":621,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster","user_id":1701,"primary_group_id":null,"flair_group_id":null}]}]}}
+