From 0df1b98b078d15bcb686aae30853dad94a3f298c Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Sun, 27 Sep 2026 01:40:45 +0000 Subject: [PATCH] ci(docs): keep only the current and previous production docs on gh-pages (#7396) --- .github/workflows/docs-release.yml | 7 ++-- .github/workflows/post-release-cleanup.yml | 40 +++++++++++++++++----- RELEASE_PROCESS.md | 2 +- docs/README.md | 9 +++-- docs/_includes/version_switcher.html | 2 +- scripts/docs/regenerate-versions.py | 5 +-- 6 files changed, 46 insertions(+), 19 deletions(-) diff --git a/.github/workflows/docs-release.yml b/.github/workflows/docs-release.yml index 5f6682e515..3e979e30a2 100644 --- a/.github/workflows/docs-release.yml +++ b/.github/workflows/docs-release.yml @@ -7,8 +7,8 @@ name: Docs Release # trigger covers a tag pushed by hand, and a manual run against a tag ref # (re)publishes that version without cutting a new tag. # -# Production tags (vX.Y.Z) own the site root and get a permanent /vX.Y.Z/ copy, -# plus a refreshed Dokka reference at /api/. +# Production tags (vX.Y.Z) own the site root and get a /vX.Y.Z/ copy, plus a +# refreshed Dokka reference at /api/. # # Open- and closed-testing tags (vX.Y.Z-open.N / vX.Y.Z-closed.N) publish a # per-tag snapshot at /vX.Y.Z-open.N/ only. They deliberately do NOT touch the @@ -16,7 +16,8 @@ name: Docs Release # unversioned channel that docs-deploy.yml rebuilds from main every day. # # These per-tag prerelease directories accumulate during a version cycle and are -# reaped by post-release-cleanup.yml, which a production publish dispatches. +# reaped by post-release-cleanup.yml, which a production publish dispatches. That +# cleanup also removes every production copy older than the newest one below /vX.Y.Z/. # # The /main/ snapshot is owned by docs-deploy.yml and is left untouched here. diff --git a/.github/workflows/post-release-cleanup.yml b/.github/workflows/post-release-cleanup.yml index 2f8335010b..d5773b0223 100644 --- a/.github/workflows/post-release-cleanup.yml +++ b/.github/workflows/post-release-cleanup.yml @@ -102,8 +102,9 @@ jobs: # The docs site keeps a per-tag snapshot for every open/closed testing tag # in a version cycle (see docs-release.yml). Once vX.Y.Z ships, /vX.Y.Z/ - # supersedes them all, so reap them to stop gh-pages growing without bound. - - name: Cleanup pre-release docs snapshots on gh-pages + # supersedes them all, so reap them. Production copies older than the + # release before vX.Y.Z go too, to keep gh-pages under the Pages size limit. + - name: Cleanup superseded docs on gh-pages run: | set -euo pipefail DRY_RUN=true @@ -145,20 +146,41 @@ jobs: | awk -v base="$BASE_VERSION" "$AT_OR_BELOW" | sort ) - if [ ${#stale[@]} -eq 0 ]; then - echo "No pre-release docs snapshots found." + # Production copies strictly below base_version, oldest first. The newest of them + # stays beside base_version; nothing above base_version is listed, so a backfill + # dispatch for an old version never deletes newer docs. + mapfile -t older < <( + find "$work" -maxdepth 1 -mindepth 1 -type d \ + -regextype posix-extended \ + -regex ".*/v[0-9]+\.[0-9]+\.[0-9]+" -printf '%f\n' \ + | awk -v base="$BASE_VERSION" "$AT_OR_BELOW" \ + | grep -vxF "v${BASE_VERSION}" | sort -V || true + ) + culled=() + if [ ${#older[@]} -gt 1 ]; then + culled=("${older[@]:0:${#older[@]}-1}") + fi + + if [ ${#stale[@]} -eq 0 ] && [ ${#culled[@]} -eq 0 ]; then + echo "No superseded docs found." exit 0 fi - printf 'Pre-release docs snapshots to reap:\n' - printf ' %s\n' "${stale[@]}" + if [ ${#stale[@]} -gt 0 ]; then + printf 'Pre-release docs snapshots to reap:\n' + printf ' %s\n' "${stale[@]}" + fi + if [ ${#culled[@]} -gt 0 ]; then + printf 'Production docs older than %s to remove:\n' "${older[-1]}" + printf ' %s\n' "${culled[@]}" + fi if [ "$DRY_RUN" = true ]; then echo "DRY RUN: the directories above would be removed from gh-pages." exit 0 fi - for d in "${stale[@]}"; do + for d in "${stale[@]}" "${culled[@]}"; do rm -rf "${work:?}/$d" done @@ -174,9 +196,9 @@ jobs: fi git -c user.name='github-actions[bot]' \ -c user.email='41898282+github-actions[bot]@users.noreply.github.com' \ - commit -q -m "docs: reap pre-release snapshots for ${BASE_VERSION}" + commit -q -m "docs: reap superseded docs for ${BASE_VERSION}" git push --quiet origin HEAD:gh-pages - echo "Removed ${#stale[@]} pre-release docs snapshot(s) from gh-pages." + echo "Removed ${#stale[@]} pre-release and ${#culled[@]} production docs directories from gh-pages." - name: Cleanup dangling pre-release tags env: diff --git a/RELEASE_PROCESS.md b/RELEASE_PROCESS.md index ce0eeaa2ef..eae0aa437c 100644 --- a/RELEASE_PROCESS.md +++ b/RELEASE_PROCESS.md @@ -79,7 +79,7 @@ remains by hand. Each store workflow warns in its summary when its secrets are not set and it submitted nothing, and the promotion checklist already says so. 4. **Flathub** *(production only)*: merge the `update-flathub` PR in `flathub/org.meshtastic.MeshtasticDesktop` once Flathub's test build passes, or bump it by hand when `FLATHUB_TOKEN` is unset (see Flatpak below). -5. **Post-Release Cleanup** *(production only)*: `Docs Release` dispatches `post-release-cleanup.yml` with `confirm_deletion: true` once it has published `/vX.Y.Z/`, deleting the pre-releases, tags and docs snapshots at or below `X.Y.Z`. Check that run; a manual dispatch is the retry and defaults to a dry run. +5. **Post-Release Cleanup** *(production only)*: `Docs Release` dispatches `post-release-cleanup.yml` with `confirm_deletion: true` once it has published `/vX.Y.Z/`, deleting the pre-releases, tags and docs snapshots at or below `X.Y.Z` and every production docs copy older than the newest one below `X.Y.Z`. Check that run; a manual dispatch is the retry and defaults to a dry run. 6. **Next version line** *(production only)*: the `version-bump.yml` PR bumps `VERSION_NAME_BASE` and merges itself. Replace its placeholder `` before the next internal cut. 7. **Merge:** If a `release/*` branch was used for stabilization (CI runs the same PR checks against PRs targeting `release/**` as it does for `main`), merge it back into `main` now diff --git a/docs/README.md b/docs/README.md index 415de88026..7342a5068d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -58,7 +58,7 @@ channels (GitHub Pages must be configured to serve from that branch): | Path | Content | Published by | |------|---------|--------------| | `/` | Latest production release (default landing) | `docs-release.yml` on `vX.Y.Z` tags, dispatched by `promote.yml` | -| `/vX.Y.Z/` | Permanent per-release copy | `docs-release.yml` on `vX.Y.Z` tags, dispatched by `promote.yml` | +| `/vX.Y.Z/` | Copy of the current and the previous production release | `docs-release.yml` on `vX.Y.Z` tags, dispatched by `promote.yml` | | `/vX.Y.Z-open.N/` | Per-tag open-testing snapshot | `docs-release.yml` on `vX.Y.Z-open.N` tags, dispatched by `promote.yml` | | `/vX.Y.Z-closed.N/` | Per-tag closed-testing snapshot | `docs-release.yml` on `vX.Y.Z-closed.N` tags, dispatched by `promote.yml` | | `/main/` | Snapshot of the `main` branch | `docs-deploy.yml` on pushes to `main` that touch the site | @@ -76,7 +76,10 @@ Prerelease snapshots accumulate during a version cycle so testers can read the docs for the exact build they are running. Once the production `vX.Y.Z` tag ships, `/vX.Y.Z/` supersedes them, and once it is published Docs Release dispatches **Post-Release Cleanup**, which reaps every open and closed directory -and prerelease tag at or below `X.Y.Z`. A manual dispatch defaults to a dry run. +and prerelease tag at or below `X.Y.Z`. It also keeps two production copies, +`/vX.Y.Z/` and the newest one below it, and removes every older one. Copies above +`X.Y.Z` are left alone, so a backfill never removes newer docs. A manual dispatch +defaults to a dry run. Only production releases own `/` and rebuild `/api/`. Prerelease tags publish their own directory only, since `/api/` is unversioned and `docs-deploy.yml` @@ -86,7 +89,7 @@ upgrades automatically as better channels appear. Real release content at the root is never overwritten by that fallback. Each deploy overlays only its own channels via `scripts/docs/publish-to-gh-pages.sh`, -so release history accumulates instead of being wiped by the next deploy. The header +so every other channel survives the next deploy. The header version dropdown (`_includes/version_switcher.html`) reads `/versions.json` at runtime; a separate header link points to the upstream docs at meshtastic.org. To backfill a release (e.g. after first enabling this), run the "Docs Release" workflow manually diff --git a/docs/_includes/version_switcher.html b/docs/_includes/version_switcher.html index acb09f814c..c102d1912e 100644 --- a/docs/_includes/version_switcher.html +++ b/docs/_includes/version_switcher.html @@ -4,7 +4,7 @@ The site is deployed as parallel channels on gh-pages: / -> latest published release (default) /main/ -> snapshot of the main branch - /vX.Y.Z/ -> each published release + /vX.Y.Z/ -> the current and previous production release Which channel this build belongs to is inferred from site.baseurl (e.g. "/Meshtastic-Android", "/Meshtastic-Android/main", diff --git a/scripts/docs/regenerate-versions.py b/scripts/docs/regenerate-versions.py index 4c69637e20..59b01b0133 100755 --- a/scripts/docs/regenerate-versions.py +++ b/scripts/docs/regenerate-versions.py @@ -7,14 +7,15 @@ never disagree with what is published. Channel layout on gh-pages: / production release docs (owns the root) - /vX.Y.Z/ permanent per-release snapshot + /vX.Y.Z/ per-release snapshot (current and previous release) /vX.Y.Z-open.N/ per-tag open-testing snapshot /vX.Y.Z-closed.N/ per-tag closed-testing snapshot /main/ snapshot of the main branch /api/ Dokka reference (unversioned) Prerelease snapshots accumulate during a version cycle and are reaped by -post-release-cleanup.yml once the production vX.Y.Z tag ships. +post-release-cleanup.yml once the production vX.Y.Z tag ships. The same +cleanup removes every production snapshot older than the one before vX.Y.Z. Usage: regenerate-versions.py """