diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index b64cdf9a212..c77888fca35 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -178,17 +178,63 @@ jobs: # Cleanup empty directories find . -type d -empty -delete - # Check for meaningful changes, ignoring: - # - lastupdated date lines in HTML (Sphinx build-time timestamps) - # - epub/pdf binaries (they regenerate automatically alongside HTML) - meaningful_html=$(git diff HEAD -- '*.html' | grep -E '^[+-]' | grep -v '^[+-]{3}' | grep -ivE 'lastupdated|Last updated on' | wc -l) - other_changes=$(git diff --name-only HEAD | grep -cvE '\.(html|epub|pdf)$' || true) + # ---------------------------------------------------------------- + # Prune build-only noise so the PR carries exclusively real content + # changes. A rebuilt page differs every night even when its content + # is identical, because of: + # - Sphinx build-time timestamps (lastupdated / "Last updated on") + # - mermaid diagram zoom ids (random UUID regenerated each build) + # Files whose ENTIRE diff is noise are reverted to HEAD; files with a + # real change are kept untouched (noise lines ride along, harmless). + # ---------------------------------------------------------------- + NOISE='lastupdated|Last updated on|data-zoom-id' + + # Read-only diffs must not take .git/index.lock: a `git diff` that + # refreshes the index while a `git checkout` writes it races on the + # lock. GIT_OPTIONAL_LOCKS=0 suppresses the refresh write; we also + # materialise each file list fully before running any checkout, and + # batch the reverts into a single checkout call. + export GIT_OPTIONAL_LOCKS=0 + + # 1) Collect HTML files whose only changes are noise, then revert them. + : > /tmp/revert-html.txt + git diff --name-only HEAD -- '*.html' > /tmp/changed-html.txt + while IFS= read -r f; do + [ -n "$f" ] || continue + real=$(git diff HEAD -- "$f" | grep -E '^[+-]' | grep -vE '^[+-]{3}' | grep -ivE "$NOISE" | wc -l) + [ "$real" -eq 0 ] && printf '%s\n' "$f" >> /tmp/revert-html.txt + done < /tmp/changed-html.txt + if [ -s /tmp/revert-html.txt ]; then + xargs -a /tmp/revert-html.txt -r git checkout HEAD -- + fi + + # 2) PDF/ePub binaries regenerate every build with no content change. + # Keep them only for a version folder that still has a real HTML + # change after step 1; otherwise revert them too. Runs after the + # HTML revert so the per-folder check sees the pruned tree. + : > /tmp/revert-bin.txt + git diff --name-only HEAD -- '*.pdf' '*.epub' > /tmp/changed-bin.txt + while IFS= read -r f; do + [ -n "$f" ] || continue + case "$f" in + server/*) + vdir="server/$(printf '%s' "${f#server/}" | cut -d/ -f1)" + remaining=$(git diff --name-only HEAD -- "$vdir" | grep -vE '\.(epub|pdf)$' | wc -l) + [ "$remaining" -eq 0 ] && printf '%s\n' "$f" >> /tmp/revert-bin.txt + ;; + *) printf '%s\n' "$f" >> /tmp/revert-bin.txt ;; + esac + done < /tmp/changed-bin.txt + if [ -s /tmp/revert-bin.txt ]; then + xargs -a /tmp/revert-bin.txt -r git checkout HEAD -- + fi - if [ "$meaningful_html" -gt 0 ] || [ "$other_changes" -gt 0 ]; then + # Anything real left to deploy? (tracked diffs or brand-new files) + if [ -n "$(git status --porcelain)" ]; then echo "has_changes=true" >> $GITHUB_OUTPUT else echo "has_changes=false" >> $GITHUB_OUTPUT - echo "::notice::Skipping deploy PR: only lastupdated timestamps or epub/pdf binaries changed" + echo "::notice::Skipping deploy PR: only build noise (timestamps, mermaid ids, binaries) changed" fi - name: Strip noindex from stable docs