Skip to content

[jsweep] Clean update_pull_request_branches.cjs#36057

Merged
pelikhan merged 3 commits into
mainfrom
signed/jsweep/update-pull-request-branches-966533ce3e64f585
May 31, 2026
Merged

[jsweep] Clean update_pull_request_branches.cjs#36057
pelikhan merged 3 commits into
mainfrom
signed/jsweep/update-pull-request-branches-966533ce3e64f585

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot commented May 31, 2026

Summary

Refactors update_pull_request_branches.cjs for correctness and readability, and significantly expands its test coverage with fake timers and new edge-case scenarios. Also removes a minor outdated recommendation from the agentic-workflows agent guide.


Changes by file

actions/setup/js/update_pull_request_branches.cjs (modified — medium impact)

  • Skip-reason logic rewritten from continue-based control flow to if/else branches, improving readability and making early-exit paths explicit.
  • Sleep delay moved from the end of each iteration to the start (after the first iteration), ensuring the delay is applied before work rather than after — fixing a subtle timing issue where the last iteration would sleep unnecessarily.

actions/setup/js/update_pull_request_branches.test.cjs (modified — medium impact)

  • Introduced fake timer support across existing tests to eliminate real async waits and make the suite deterministic.
  • Added new test cases covering:
    • Early-return paths — verifying the function exits cleanly under boundary conditions.
    • Fatal vs non-fatal error counting — asserting the distinction between errors that abort the loop and those that are tolerated.
    • isNonFatalUpdateBranchError classification — unit tests for the error-classification helper directly.
    • Non-integer PR number filtering — ensuring malformed PR numbers are correctly excluded before processing.

.github/agents/agentic-workflows.md (modified — low impact)

  • Removed the recommendation to set an emoji: frontmatter value when creating workflows. No functional change.

Motivation

The sleep-at-end pattern meant the final loop iteration always incurred a pointless delay, and the continue-based skip logic obscured which conditions caused early exits. The refactor aligns the code with its intended semantics. The expanded test suite locks in this behaviour and adds coverage for previously untested classification and filtering logic.


Risk

Low. The JS refactor is a logic-preserving restructure with no interface changes. New tests are additive. The agent-guide edit is documentation-only.

Generated by PR Description Updater for issue #36057 · sonnet46 1.1M ·

- Remove redundant continue after pushing to mergeable list
- Fix else-block indentation for clarity
- Simplify loop to sleep before each iteration (except first) instead of after
- Add 8 new tests covering: early return on empty PRs, fatal vs non-fatal error counting, isNonFatalUpdateBranchError directly, non-integer PR number filtering

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@pelikhan pelikhan marked this pull request as ready for review May 31, 2026 11:12
Copilot AI review requested due to automatic review settings May 31, 2026 11:12
@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions Bot commented May 31, 2026

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #36057 does not have the 'implementation' label (has_implementation_label=false) and has 0 new lines of code in business logic directories (default_business_additions=0, well under the 100 threshold). The changes consist of modifications to skill query scripts and an MCP server file, none of which require an Architecture Decision Record.

@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions Bot commented May 31, 2026

🧪 Test Quality Sentinel completed test quality analysis.

@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions Bot commented May 31, 2026

PR Code Quality Reviewer completed the code quality review.

@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions Bot commented May 31, 2026

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Cleans up the update_pull_request_branches.cjs GitHub Script used in actions/setup to update mergeable PR branches, and expands its Vitest coverage for early-exit and error-classification behavior.

Changes:

  • Refactors filterMergeablePullRequests to remove a redundant continue and tighten skip-reason logging structure.
  • Moves the per-PR delay to the start of each loop iteration (except the first) for clearer control flow.
  • Adds additional unit tests covering early returns, fatal vs non-fatal error accounting, and PR-number filtering.
Show a summary per file
File Description
actions/setup/js/update_pull_request_branches.cjs Small control-flow cleanups in mergeable filtering and update-loop sleep placement.
actions/setup/js/update_pull_request_branches.test.cjs Adds coverage for early exits, error classification/accounting, and input filtering.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 2

Comment on lines +164 to +177
it("counts fatal errors separately from non-fatal errors", async () => {
mockGithub.paginate.mockResolvedValue([{ number: 10 }, { number: 11 }]);
mockGithub.rest.pulls.get.mockResolvedValue({
data: { state: "open", mergeable: true, draft: false, head: { repo: { full_name: "owner/repo" } } },
});
const fatalErr = new Error("Something unexpected");
const nonFatalErr = Object.assign(new Error("update branch failed"), { status: 422 });
mockGithub.rest.pulls.updateBranch.mockRejectedValueOnce(fatalErr).mockRejectedValueOnce(nonFatalErr);

await expect(moduleUnderTest.main()).resolves.not.toThrow();
expect(mockCore.error).toHaveBeenCalledWith(expect.stringContaining("Failed to update branch for PR #10"));
expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("Skipping PR #11"));
expect(mockCore.notice).toHaveBeenCalledWith(expect.stringContaining("updated=0, skipped=1, failed=1"));
});
Comment on lines +196 to +208
it("filters out non-integer pull request numbers", async () => {
mockGithub.paginate.mockResolvedValue([{ number: 1 }, { number: "bad" }, { number: null }, { number: 2 }]);
mockGithub.rest.pulls.get.mockResolvedValue({
data: { state: "open", mergeable: true, draft: false, head: { repo: { full_name: "owner/repo" } } },
});
mockGithub.rest.pulls.updateBranch.mockResolvedValue({ data: {} });

await moduleUnderTest.main();

expect(mockGithub.rest.pulls.updateBranch).toHaveBeenCalledTimes(2);
expect(mockGithub.rest.pulls.updateBranch).toHaveBeenCalledWith(expect.objectContaining({ pull_number: 1 }));
expect(mockGithub.rest.pulls.updateBranch).toHaveBeenCalledWith(expect.objectContaining({ pull_number: 2 }));
});
@github-actions github-actions Bot mentioned this pull request May 31, 2026
Copy link
Copy Markdown
Contributor Author

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes are correct and behavior-equivalent. No blocking issues found.

Review notes
  • Sleep refactor (i > 0 guard before vs i < length - 1 guard after): semantically identical for all normal and exceptional loop exits — no behavior change.
  • continueif/else: purely structural; logic is identical.
  • New tests: the 8 added tests cover previously untested paths. The "counts fatal vs non-fatal errors" test uses substring matching on the notice output, but the adjacent mockCore.error / mockCore.warning assertions already verify the correct error-type-to-log-level mapping, making the counter assertion sufficient.

🔎 Code quality review by PR Code Quality Reviewer · sonnet46 1.1M

@github-actions
Copy link
Copy Markdown
Contributor Author

🧪 Test Quality Sentinel Report

Test Quality Score: 80/100 — Excellent

Analyzed 13 test(s): 13 design, 0 implementation, 0 guideline violation(s). Test inflation flag applied (66 test lines vs 9 production lines added).

📊 Metrics & Test Classification (13 tests analyzed)
Metric Value
New/modified tests analyzed 13
✅ Design tests (behavioral contracts) 13 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 13 (100%)
Duplicate test clusters 0
Test inflation detected Yes (66 test lines / 9 production lines ≈ 7.3:1)
🚨 Coding-guideline violations 0

Test Classification Details

Test File Classification Issues Detected
updates only mergeable pull requests update_pull_request_branches.test.cjs:55 ✅ Design Verifies updateBranch called for correct PRs and comments posted
continues on non-fatal updateBranch failures update_pull_request_branches.test.cjs:80 ✅ Design Error path — 422 failures don't propagate
ignores draft pull requests when filtering mergeable pull requests update_pull_request_branches.test.cjs:99 ✅ Design Behavioral filter contract
ignores fork pull requests that cannot be updated by repository token update_pull_request_branches.test.cjs:114 ✅ Design Fork-exclusion contract
logs explicit reason when head repository is unavailable update_pull_request_branches.test.cjs:127 ✅ Design Edge case — null head.repo
returns early when there are no open pull requests update_pull_request_branches.test.cjs:137 ✅ Design Early-exit edge case
returns early when no pull requests are mergeable update_pull_request_branches.test.cjs:145 ✅ Design Early-exit edge case
counts fatal errors separately from non-fatal errors update_pull_request_branches.test.cjs:154 ✅ Design Error classification contract
identifies non-fatal error by status 422 update_pull_request_branches.test.cjs:169 ✅ Design Unit test for helper output
identifies non-fatal error by message 'update branch failed' update_pull_request_branches.test.cjs:174 ✅ Design Unit test for helper output
identifies non-fatal error by message 'head branch is not behind' update_pull_request_branches.test.cjs:178 ✅ Design Unit test for helper output
does not treat other errors as non-fatal update_pull_request_branches.test.cjs:182 ✅ Design Negative case for helper
filters out non-integer pull request numbers update_pull_request_branches.test.cjs:186 ✅ Design Input validation edge case

Language Support

Tests analyzed:

  • 🐹 Go (*_test.go): 0 tests
  • 🟨 JavaScript (*.test.cjs): 13 tests (vitest)

Verdict

Check passed. 0% of new tests are implementation tests (threshold: 30%). All 13 tests verify observable behavioral contracts. Test inflation (7.3:1 ratio) is expected here — the change deliberately expanded coverage from 5 → 13 tests while only lightly refactoring production code.

📖 Understanding Test Classifications

Design Tests (High Value) verify what the system does:

  • Assert on observable outputs, return values, or state changes
  • Cover error paths and boundary conditions
  • Would catch a behavioral regression if deleted
  • Remain valid even after internal refactoring

Implementation Tests (Low Value) verify how the system does it:

  • Assert on internal function calls (mocking internals)
  • Only test the happy path with typical inputs
  • Break during legitimate refactoring even when behavior is correct
  • Give false assurance: they pass even when the system is wrong

Goal: Shift toward tests that describe the system's behavioral contract — the promises it makes to its users and collaborators.

References:

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 1.2M ·

Copy link
Copy Markdown
Contributor Author

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 80/100. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%). All 13 tests verify observable behavioral contracts.

Copy link
Copy Markdown
Contributor Author

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /tdd and /zoom-out — approving with one minor observation on test timer hygiene.

📋 Key Themes & Highlights

Key Themes

  • Sleep refactor is correct: The i < length-1 after-sleep to i > 0 before-sleep inversion is semantically equivalent in all cases including a single-element list. ✅
  • continueif/else is clean: The restructuring improves readability without changing behaviour. ✅
  • Test expansion is thorough: +8 tests covering early exits, fatal vs non-fatal error discrimination, isNonFatalUpdateBranchError unit tests, and non-integer PR filtering are all well-scoped.

Minor Observation

  • Tests that exercise 2 PRs (counts fatal errors separately, filters out non-integer pull request numbers) will trigger one real sleep(UPDATE_DELAY_MS) call. If the delay is non-trivial, consider Jest fake timers to keep the suite fast. (Non-blocking.)

Positive Highlights

  • ✅ Semantic equivalence of the sleep refactor is easy to verify
  • isNonFatalUpdateBranchError unit tests are clearly named and cover all branches
  • ✅ Formatting/lint/typecheck validation confirmed in PR description

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 1.2M


await expect(moduleUnderTest.main()).resolves.not.toThrow();
expect(mockCore.error).toHaveBeenCalledWith(expect.stringContaining("Failed to update branch for PR #10"));
expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("Skipping PR #11"));
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The counts fatal errors separately and filters out non-integer pull request numbers tests each iterate over 2 PRs, triggering one real sleep(UPDATE_DELAY_MS) call between iterations. If UPDATE_DELAY_MS is non-trivial, these tests will be slow.

💡 Suggestion: mock the sleep delay

Consider using Jest fake timers to keep tests fast and deterministic:

beforeEach(() => { jest.useFakeTimers(); });
afterEach(() => { jest.useRealTimers(); });

This ensures that if UPDATE_DELAY_MS is ever tuned upward, the test suite does not silently slow down.

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot review all comments an reviews from copilot and GitHub-actions actor

Copilot AI and others added 2 commits May 31, 2026 11:35
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented May 31, 2026

@copilot review all comments an reviews from copilot and GitHub-actions actor

Done. I addressed the actionable review feedback about test delays by switching the affected main() tests to Vitest fake timers so they no longer wait on real sleep calls. Included in commit 8f333b1.

Copilot AI requested a review from pelikhan May 31, 2026 11:38
@pelikhan pelikhan merged commit 45a0784 into main May 31, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants