diff --git a/.github/scripts/bot-comment-dismiss.js b/.github/scripts/bot-comment-dismiss.js index ea3f46d55..7875a74d1 100644 --- a/.github/scripts/bot-comment-dismiss.js +++ b/.github/scripts/bot-comment-dismiss.js @@ -113,7 +113,7 @@ async function dismissReviewComments(options = {}) { const dismissable = options.dismissable || []; const owner = options.owner; const repo = options.repo; - const withRetry = options.withRetry || ((fn) => fn()); + const withRetry = options.withRetry || ((fn) => fn(github)); const logger = options.logger || console; if (!github || !github.rest || !github.rest.pulls) { @@ -129,8 +129,8 @@ async function dismissReviewComments(options = {}) { for (const entry of dismissable) { try { - await withRetry(() => - github.rest.pulls.deleteReviewComment({ + await withRetry((client) => + client.rest.pulls.deleteReviewComment({ owner, repo, comment_id: entry.id, @@ -165,7 +165,7 @@ async function autoDismissReviewComments(options = {}) { const owner = options.owner; const repo = options.repo; const pullNumber = options.pullNumber; - const withRetry = options.withRetry || ((fn) => fn()); + const withRetry = options.withRetry || ((fn) => fn(github)); const logger = options.logger || console; if (!github || !github.rest || !github.rest.pulls) { @@ -178,8 +178,8 @@ async function autoDismissReviewComments(options = {}) { throw new Error('pullNumber is required'); } - const response = await withRetry(() => - github.rest.pulls.listReviewComments({ + const response = await withRetry((client) => + client.rest.pulls.listReviewComments({ owner, repo, pull_number: pullNumber, diff --git a/.github/workflows/health-74-template-drift.yml b/.github/workflows/health-74-template-drift.yml index d2a36cd3d..c2967b69a 100644 --- a/.github/workflows/health-74-template-drift.yml +++ b/.github/workflows/health-74-template-drift.yml @@ -21,13 +21,13 @@ jobs: id: drift run: | set -euo pipefail - + echo "🔍 Checking for drift between main workflows and templates..." echo "" - + drift_found=false drift_report="" - + # Map of main workflows to their template counterparts # Format: "main_workflow:template_name" declare -a mappings=( @@ -39,34 +39,34 @@ jobs: "agents-pr-meta.yml:agents-pr-meta.yml" "agents-verifier.yml:agents-verifier.yml" ) - + for mapping in "${mappings[@]}"; do main_file="${mapping%%:*}" template_file="${mapping##*:}" - + main_path=".github/workflows/${main_file}" template_path="templates/consumer-repo/.github/workflows/${template_file}" - + # Skip if either file doesn't exist if [[ ! -f "$main_path" ]]; then echo "⏭️ Skipping $main_file (main workflow doesn't exist)" continue fi - + if [[ ! -f "$template_path" ]]; then echo "⚠️ WARNING: $template_file template missing but main workflow exists" drift_found=true drift_report+="- **$main_file**: Template missing entirely\n" continue fi - + # Compare files (ignoring whitespace-only differences) # Count differing lines diff_lines=$(diff -u "$main_path" "$template_path" 2>/dev/null | grep -c '^[-+]' || true) - + # Threshold: warn if more than 50 lines differ (configurable) threshold=50 - + if [[ "$diff_lines" -gt "$threshold" ]]; then echo "❌ DRIFT: $main_file vs $template_file ($diff_lines lines differ)" drift_found=true @@ -77,10 +77,10 @@ jobs: echo "✅ In sync: $main_file ↔ $template_file" fi done - + echo "" echo "drift_found=${drift_found}" >> "$GITHUB_OUTPUT" - + if [[ "$drift_found" == "true" ]]; then # Warn but don't fail - drift may be intentional or pre-existing # TODO: Enable strict mode once existing drift is resolved diff --git a/templates/consumer-repo/.github/scripts/bot-comment-dismiss.js b/templates/consumer-repo/.github/scripts/bot-comment-dismiss.js index ea3f46d55..7875a74d1 100644 --- a/templates/consumer-repo/.github/scripts/bot-comment-dismiss.js +++ b/templates/consumer-repo/.github/scripts/bot-comment-dismiss.js @@ -113,7 +113,7 @@ async function dismissReviewComments(options = {}) { const dismissable = options.dismissable || []; const owner = options.owner; const repo = options.repo; - const withRetry = options.withRetry || ((fn) => fn()); + const withRetry = options.withRetry || ((fn) => fn(github)); const logger = options.logger || console; if (!github || !github.rest || !github.rest.pulls) { @@ -129,8 +129,8 @@ async function dismissReviewComments(options = {}) { for (const entry of dismissable) { try { - await withRetry(() => - github.rest.pulls.deleteReviewComment({ + await withRetry((client) => + client.rest.pulls.deleteReviewComment({ owner, repo, comment_id: entry.id, @@ -165,7 +165,7 @@ async function autoDismissReviewComments(options = {}) { const owner = options.owner; const repo = options.repo; const pullNumber = options.pullNumber; - const withRetry = options.withRetry || ((fn) => fn()); + const withRetry = options.withRetry || ((fn) => fn(github)); const logger = options.logger || console; if (!github || !github.rest || !github.rest.pulls) { @@ -178,8 +178,8 @@ async function autoDismissReviewComments(options = {}) { throw new Error('pullNumber is required'); } - const response = await withRetry(() => - github.rest.pulls.listReviewComments({ + const response = await withRetry((client) => + client.rest.pulls.listReviewComments({ owner, repo, pull_number: pullNumber, diff --git a/templates/consumer-repo/.github/workflows/agents-bot-comment-handler.yml b/templates/consumer-repo/.github/workflows/agents-bot-comment-handler.yml index 43344be68..58e41135c 100644 --- a/templates/consumer-repo/.github/workflows/agents-bot-comment-handler.yml +++ b/templates/consumer-repo/.github/workflows/agents-bot-comment-handler.yml @@ -191,6 +191,8 @@ jobs: # Dismiss ignored-path bot reviews to prevent noisy inline comments dismiss_ignored: name: Dismiss ignored bot reviews + # Dismisses the review state (not individual comments) so bot reviews + # on ignored paths don't block merge or clutter the PR timeline. needs: resolve if: vars.USE_CONSOLIDATED_WORKFLOWS != 'true' && needs.resolve.outputs.should_run == 'true' runs-on: ubuntu-latest @@ -213,7 +215,9 @@ jobs: - name: Dismiss ignored-path bot reviews uses: actions/github-script@v8 env: - BOT_AUTHORS: 'Copilot,copilot[bot],github-actions[bot],coderabbitai[bot],chatgpt-codex-connector[bot]' + BOT_AUTHORS: >- + Copilot,copilot[bot],github-actions[bot], + coderabbitai[bot],chatgpt-codex-connector[bot] IGNORED_PATHS: '.agents/,scripts/langchain/prompts/,docs/' with: script: | @@ -240,14 +244,14 @@ jobs: return; } - const [commentsResponse, reviewsResponse] = await Promise.all([ - withRetry((client) => client.rest.pulls.listReviewComments({ + const [comments, reviews] = await Promise.all([ + withRetry((client) => client.paginate(client.rest.pulls.listReviewComments, { owner: context.repo.owner, repo: context.repo.repo, pull_number: prNumber, per_page: 100, })), - withRetry((client) => client.rest.pulls.listReviews({ + withRetry((client) => client.paginate(client.rest.pulls.listReviews, { owner: context.repo.owner, repo: context.repo.repo, pull_number: prNumber, @@ -255,8 +259,6 @@ jobs: })), ]); - const comments = commentsResponse.data || []; - const reviews = reviewsResponse.data || []; const reviewsById = new Map(reviews.map((review) => [review.id, review])); const commentsByReview = new Map(); @@ -270,7 +272,6 @@ jobs: total: 0, ignored: 0, paths: [], - botLogins: new Set(), ignoredComments: [], }; @@ -280,17 +281,16 @@ jobs: if (ignoredPaths.some((prefix) => commentPath.startsWith(prefix))) { entry.ignored += 1; - const login = (comment.user?.login || '').toLowerCase(); - if (login) { - entry.botLogins.add(login); - } entry.ignoredComments.push({ id: comment.id, path: commentPath, login: comment.user?.login || 'unknown', }); + const botName = comment.user?.login; console.log( - `Auto-dismiss candidate: comment=${comment.id} bot=${comment.user?.login} path=${commentPath}` + 'Auto-dismiss candidate: ' + + `comment=${comment.id} ` + + `bot=${botName} path=${commentPath}` ); } @@ -316,7 +316,10 @@ jobs: const uniquePaths = Array.from(new Set(entry.paths)).filter(Boolean); for (const ignored of entry.ignoredComments) { console.log( - `Auto-dismissed review comment: comment=${ignored.id} bot=${ignored.login} path=${ignored.path}` + 'Auto-dismissed review comment: ' + + `comment=${ignored.id} ` + + `bot=${ignored.login} ` + + `path=${ignored.path}` ); } const message = [ @@ -334,8 +337,11 @@ jobs: })); dismissed += 1; + const paths = uniquePaths.join(', '); console.log( - `Dismissed review ${reviewId} from ${review.user?.login} for paths: ${uniquePaths.join(', ')}` + `Dismissed review ${reviewId} ` + + `from ${review.user?.login} ` + + `for paths: ${paths}` ); }