diff --git a/.github/workflows/03.1.agentic_v2_metadata.yml b/.github/workflows/03.1.agentic_v2_metadata.yml index c57a3c96..03e04e5f 100644 --- a/.github/workflows/03.1.agentic_v2_metadata.yml +++ b/.github/workflows/03.1.agentic_v2_metadata.yml @@ -66,8 +66,12 @@ jobs: echo "No changes in inventory to commit." else git commit -m "chore: update inventory stars and licenses [skip ci]" - git pull origin develop --rebase - git push origin develop + # Retry rebase+push to survive concurrent bot pushes to develop. + for i in {1..5}; do + git pull origin develop --rebase && git push origin develop && exit 0 + echo "Push attempt $i/5 rejected — retrying..."; sleep $((i * 3)) + done + echo "::error::Inventory metadata push failed after 5 attempts."; exit 1 fi - name: Persist Incremental Inventory to Cache diff --git a/.github/workflows/03.2.agentic_v2_ai.yml b/.github/workflows/03.2.agentic_v2_ai.yml index 368cb70c..6e65b1ce 100644 --- a/.github/workflows/03.2.agentic_v2_ai.yml +++ b/.github/workflows/03.2.agentic_v2_ai.yml @@ -80,8 +80,12 @@ jobs: echo "No changes in AI analysis to commit." else git commit -m "chore: update inventory AI analysis" - git pull origin develop --rebase - git push origin develop + # Retry rebase+push to survive concurrent bot pushes to develop. + for i in {1..5}; do + git pull origin develop --rebase && git push origin develop && exit 0 + echo "Push attempt $i/5 rejected — retrying..."; sleep $((i * 3)) + done + echo "::error::Inventory AI-analysis push failed after 5 attempts."; exit 1 fi - name: Persist Incremental Inventory to Cache diff --git a/.github/workflows/03.3.agentic_v2_videos.yml b/.github/workflows/03.3.agentic_v2_videos.yml index 7b71d24a..e0dfcb7e 100644 --- a/.github/workflows/03.3.agentic_v2_videos.yml +++ b/.github/workflows/03.3.agentic_v2_videos.yml @@ -90,8 +90,12 @@ jobs: echo "No automated changes to commit." else git commit -m "docs: update Video Hub with high-fidelity metadata" - git pull origin develop --rebase - git push origin develop + # Retry rebase+push to survive concurrent bot pushes to develop. + for i in {1..5}; do + git pull origin develop --rebase && git push origin develop && exit 0 + echo "Push attempt $i/5 rejected — retrying..."; sleep $((i * 3)) + done + echo "::error::Video Hub push failed after 5 attempts."; exit 1 fi - name: Persist Incremental Inventory Cache diff --git a/.github/workflows/05.1.readme_sync.yml b/.github/workflows/05.1.readme_sync.yml index a648888f..dd5b3cc1 100644 --- a/.github/workflows/05.1.readme_sync.yml +++ b/.github/workflows/05.1.readme_sync.yml @@ -59,38 +59,33 @@ jobs: git config --global user.name "Nubenetes Bot" git config --global user.email "bot@nubenetes.com" export PYTHONPATH=$PYTHONPATH:. - # Pull latest before committing to shrink the conflict window - git pull --no-rebase origin develop - # Re-run updater so metrics reflect the latest remote state - python src/readme_updater.py - python src/safety_readme.py - git add README.md - if git diff --staged --quiet; then - echo "No changes in README.md to commit." - exit 0 - fi - git commit -m "docs: automated README metric synchronization [skip ci]" - # Push-first loop: try push, then merge-pull on rejection (not rebase) - # Using merge avoids --ours/--theirs confusion that plagued the rebase approach + # README.md is a *pure function* of the inventory, so we never need to + # preserve a local README state: each attempt hard-resets to the freshest + # remote tip, regenerates, commits and pushes. This eliminates the two + # failure classes that previously broke this job: + # 1. Dirty-tree abort — the earlier steps modify README.md, then + # `git pull` aborted with "local changes would be overwritten by merge". + # 2. Merge/rebase --ours/--theirs confusion under concurrent bot pushes. + # A push can now only be rejected if the remote advanced between reset and + # push; we simply retry from the new tip. No conflict resolution required. for i in {1..5}; do - echo "Push attempt $i/5..." + echo "README sync attempt $i/5..." + git fetch origin develop + git reset --hard origin/develop + python src/readme_updater.py + python src/safety_readme.py + git add README.md + if git diff --staged --quiet; then + echo "README already in sync with inventory. Nothing to commit." + exit 0 + fi + git commit -m "docs: automated README metric synchronization [skip ci]" if git push origin develop; then echo "Push succeeded on attempt $i." exit 0 fi - echo "Attempt $i rejected — integrating remote changes via merge..." - git fetch origin develop - if ! git merge --no-edit -X ours origin/develop; then - # Merge could not auto-resolve; keep bot's README and continue - git checkout --ours README.md - git add README.md - GIT_EDITOR=true git merge --continue - fi - # Re-compute metrics on the merged state (idempotent) - python src/readme_updater.py - python src/safety_readme.py - git add README.md - git diff --staged --quiet || git commit --amend --no-edit + echo "Attempt $i rejected — remote advanced, retrying from fresh tip..." sleep $((i * 3)) done - git push origin develop + echo "::error::README sync failed after 5 attempts (persistent write contention on develop)." + exit 1 diff --git a/.github/workflows/07.1.pr_guardian.yml b/.github/workflows/07.1.pr_guardian.yml index bdad0bd7..f1f1f5bf 100644 --- a/.github/workflows/07.1.pr_guardian.yml +++ b/.github/workflows/07.1.pr_guardian.yml @@ -10,6 +10,11 @@ on: required: false type: string +# Cancel superseded Guardian runs when a PR is updated (saves CI minutes + Gemini calls). +concurrency: + group: pr-guardian-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: agentic-presubmit: runs-on: ubuntu-latest @@ -35,6 +40,11 @@ jobs: pip install --no-cache-dir pydantic PyGithub httpx fake-useragent pytz python-dotenv pyyaml tenacity - name: Run PR Guardian Analysis + # Advisory gate: the Guardian is an AI heuristic that can misattribute + # pre-existing lines or mischaracterize a PR. It always posts its findings + # as a PR comment, but a non-zero exit must NOT show the PR as a blocking + # red ❌. continue-on-error keeps the check green while preserving the comment. + continue-on-error: true env: GEMINI_API_KEY_1: ${{ secrets.GEMINI_API_KEY_1 }} GEMINI_API_KEY_2: ${{ secrets.GEMINI_API_KEY_2 }} diff --git a/.github/workflows/07.2.markdown_linter.yml b/.github/workflows/07.2.markdown_linter.yml index 2015caa2..92078c8c 100644 --- a/.github/workflows/07.2.markdown_linter.yml +++ b/.github/workflows/07.2.markdown_linter.yml @@ -10,6 +10,11 @@ on: paths: - '**/*.md' +# Supersede in-flight lint runs for the same PR/branch on new commits. +concurrency: + group: md-linter-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: lint: runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c7474ed..c4ea8273 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [[2.9.13]](https://github.com/nubenetes/awesome-kubernetes/releases/tag/v2.9.13) - 2026-06-19 + +### Fixed +- **README Sync Dirty-Tree / Race Failure (root cause)**: `05.1.readme_sync.yml` modified `README.md` in earlier steps and then ran `git pull`, which aborted with *"Your local changes to README.md would be overwritten by merge"* — guaranteed to fail whenever a concurrent bot commit (e.g. the V2 Publisher's `[skip ci]` sync) advanced `develop` first. Rewrote the commit step as a `fetch → reset --hard origin/develop → regenerate → commit → push` retry loop. Since `README.md` is a *pure function* of the inventory, hard-resetting to the freshest remote tip is always safe and removes the merge-conflict and `--ours/--theirs` confusion classes entirely. A push is now only rejected if the remote advances mid-attempt, in which case it retries from the new tip. + +### Changed +- **Inventory Push Retries (03.1 / 03.2 / 03.3)**: The metadata, AI-analysis and Video-Hub workflows did a single `git pull --rebase && git push` with no retry, so any rejection from a concurrent push failed the run. Wrapped each in a 5-attempt rebase+push loop (matching the proven `09.weekly_digest.yml` idiom). +- **PR Guardian is now advisory (07.1)**: The AI presubmit is a heuristic that can misattribute pre-existing lines or mischaracterize a PR (it flagged an untouched `about.md` line on PR #392). It still posts its findings as a PR comment, but `continue-on-error: true` stops a non-zero exit from showing the PR as a blocking red ❌. Added PR-scoped `concurrency` so superseded runs are cancelled (saving CI minutes and Gemini calls). +- **Markdown Linter concurrency (07.2)**: Added PR/branch-scoped `concurrency` with `cancel-in-progress` so new commits supersede in-flight lint runs. + ## [[2.9.12]](https://github.com/nubenetes/awesome-kubernetes/releases/tag/v2.9.12) - 2026-06-19 ### Fixed