Skip to content

Conversation

@Vaeshkar
Copy link
Collaborator

@Vaeshkar Vaeshkar commented Oct 20, 2025

Updated the 2 option commands:

  • autoCLI
  • autoGH

Updated the --rebase CLI Print out

Summary by CodeRabbit

  • New Features

    • Auto-merge Dependabot PRs via GitHub auto-merge or CLI
    • Analyze dependencies and visualize recommended merge order
    • Retry flaky PRs with multi-attempt retries and summarized results
    • Resolve conflicts, trigger rebases, optionally regenerate lockfiles
    • Wait/poll for PRs to succeed; bulk delete/clean PRs with optional auto-reopen
    • Enhanced PR status display with per-PR visual indicators
  • Chores

    • Updated pnpm engine requirement to ≥ 9.0.0

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 20, 2025

Walkthrough

Adds Dependabot PR orchestration: normalized PR status and status-check rollups, dependency/lockfile conflict detection, rebase/retry/cleanup operations, polling for CI success, dual auto-merge paths (GitHub-native and CLI-based), new CLI flags, and enhanced per-PR output and mapping.

Changes

Cohort / File(s) Summary
Core CLI logic, types & helpers
cli/dependabot-cmd.ts
Introduces PRStatus, StatusCheck, extended PR shape (statusCheckRollup, body, mergeable, mergeStateStatus, files), PRRetryTracker, PRDependency, DependencyMap; adds helpers: isDependabotRebasing(), getOverallStatus(), checkAutoMergeEnabled().
PR operations & orchestration
cli/dependabot-cmd.ts
Adds orchestration functions: fetchDependabotPRs(), waitForPRsToSucceed(), triggerDependabotRebase(), resolveConflictsAndRebase(), retryFailedPR(), deleteDependabotPRs(), applyPR(); implements dependency detection detectLockfileConflicts() and mapping/visualization logic.
CLI command & handler expansion
cli/dependabot-cmd.ts
Expands dependabotCmd with flags: --autoGH, --autoCLI, --mapDependencies, --clean/--clean-prs, --retryFailed, --maxRetries, --repo, --resolveConflicts, --regenerateFrozenLockfile; adds flows for clean, retry, conflict-resolution, mapping, and auto-merge.
Package configuration
package.json
Adds engine constraint: pnpm >= 9.0.0 (kept node >= 22).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI
    participant GitHub
    participant Dependabot

    User->>CLI: dependabot-cmd [flags]
    CLI->>GitHub: fetchDependabotPRs(repo)
    GitHub-->>CLI: PRs (statusCheckRollup, files, body, mergeable)

    CLI->>CLI: detectLockfileConflicts(prs)
    CLI-->>User: show dependency graph / merge order

    loop per PR in merge order
        CLI->>GitHub: getOverallStatus(pr)
        alt status != SUCCESS
            CLI->>Dependabot: triggerDependabotRebase(pr)
            CLI->>CLI: waitForPRsToSucceed([pr], timeout)
        end

        alt status == SUCCESS
            opt autoGH
                CLI->>GitHub: applyPR(pr, useAutoMerge=true)
            end
            opt autoCLI
                CLI->>CLI: checkout, merge locally, push
                CLI->>GitHub: create/complete merge PR
            end
            GitHub-->>CLI: merged
        else status == FAILURE
            CLI->>CLI: retryFailedPR(pr) or deleteDependabotPRs([pr])
        end
    end

    CLI-->>User: summary (merged / retried / failed / deleted)
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Files/areas to focus review on:
    • getOverallStatus() and isDependabotRebasing() edge cases and status mapping.
    • detectLockfileConflicts() dependency detection and merge-order algorithm.
    • Multi-PR orchestration: interactions between triggerDependabotRebase(), waitForPRsToSucceed(), retryFailedPR(), resolveConflictsAndRebase(), and applyPR().
    • CLI flag interactions, user-facing output, and error handling for --clean, --mapDependencies, --autoGH/--autoCLI, --resolveConflicts.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The PR title 'chore: cli dependabot updates' is vague and generic, using non-descriptive language that doesn't convey the specific nature of the substantial changes made to the codebase. Revise the title to be more specific about the main changes, such as 'feat: add comprehensive dependabot PR management utilities' or similar to better reflect the significant functional additions.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mabels/cli-dependabot

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e8df577 and a5be27d.

📒 Files selected for processing (1)
  • cli/dependabot-cmd.ts (5 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: mabels
Repo: fireproof-storage/fireproof PR: 1016
File: cli/package.json:8-12
Timestamp: 2025-08-05T07:28:12.473Z
Learning: In PR #1016 "update tsc -> tsgo", mabels is implementing global control over TypeScript compilation across the fireproof monorepo by replacing direct "tsc" calls with "core-cli tsc" in package.json build scripts. This allows centralized management of which TypeScript compiler to use (tsc vs tsgo) through the core-cli tool.
📚 Learning: 2025-08-05T07:28:12.473Z
Learnt from: mabels
Repo: fireproof-storage/fireproof PR: 1016
File: cli/package.json:8-12
Timestamp: 2025-08-05T07:28:12.473Z
Learning: In PR #1016 "update tsc -> tsgo", mabels is implementing global control over TypeScript compilation across the fireproof monorepo by replacing direct "tsc" calls with "core-cli tsc" in package.json build scripts. This allows centralized management of which TypeScript compiler to use (tsc vs tsgo) through the core-cli tool.

Applied to files:

  • cli/dependabot-cmd.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: ci compile
🔇 Additional comments (13)
cli/dependabot-cmd.ts (13)

6-34: LGTM: Well-structured type definitions.

The type definitions clearly model PR statuses, status checks, and retry tracking. The PRStatus union type covers all states, and the interface extensions on PR provide the necessary fields for the enhanced orchestration logic.


35-48: LGTM: Reasonable heuristics for detecting Dependabot rebasing.

The function uses multiple signals (PR body, mergeable state, mergeStateStatus) to detect if Dependabot is actively rebasing. The fallback heuristic (DIRTY without conflicts) is documented as potentially broad but reasonable.


50-97: LGTM: Comprehensive status determination with proper prioritization.

The function correctly handles multiple check types (CheckRun and StatusContext), prioritizes PENDING over FAILURE when checks are still running, and validates the mergeable state before returning SUCCESS. The previous non-null assertion issues have been addressed.


118-139: LGTM: Proper repo parameter handling with validation.

The function correctly validates the repo format and conditionally applies the -R flag. All necessary PR fields are fetched for the enhanced orchestration.


141-196: LGTM: Smart dependency analysis for lockfile conflicts.

The dependency detection correctly identifies PRs that should wait (lockfile-only) versus those that should merge first (package file changes). The merge order prioritization helps avoid cascading conflicts.


198-242: LGTM: Robust PR polling with proper timeout and progress tracking.

The function correctly tracks real elapsed time (not random), handles PRs that disappear, and provides clear progress updates. The 10-second poll interval is reasonable for CI checks.


244-255: LGTM: Clean implementation of Dependabot rebase trigger.

The function correctly applies the repo parameter when provided and uses the standard Dependabot comment command.


257-345: LGTM: Comprehensive automated conflict resolution.

The function handles git rebase conflicts intelligently, with special logic for lockfiles. Using --force-with-lease (line 337) provides safety against force-pushing over unexpected changes. The GIT_EDITOR=true trick (line 313-314) elegantly skips editor prompts during automated rebasing.


347-445: LGTM: Well-implemented retry and cleanup workflows.

Both functions properly handle the repo parameter, include appropriate wait times for GitHub/Dependabot processing, and provide clear progress feedback. Error handling preserves partial success in batch operations.


447-482: LGTM: Clean merge handling with auto-merge support.

The function correctly distinguishes between auto-merge (GitHub-managed) and direct merge (CLI-managed) based on the useAutoMerge parameter. The repo parameter is properly threaded through all gh commands.


769-774: LGTM: Precise package.json path matching.

The path check at line 769 correctly uses exact matching (f.path === "package.json" || f.path.endsWith("/package.json")) to avoid false positives from files like my-package.json or package.json.bak. This addresses the previous review concern about using includes().


912-914: LGTM: Precise package.json path matching (duplicate fix verified).

The same precise path matching is correctly applied here for detecting direct dependency PRs. This ensures only actual package.json files trigger automatic rebase operations.


866-872: LGTM: Proper mutual exclusion validation.

The validation correctly prevents using both --autoCLI and --autoGH together, with clear error messages explaining the difference between the two modes.

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (4)
cli/dependabot-cmd.ts (1)

27-33: Rebase detection via mergeStateStatus=DIRTY is unreliable.

DIRTY doesn’t necessarily mean “rebasing”; it can be other states. Consider checking for explicit Dependabot “Rebasing” signals (e.g., PR body text) or refine conditions.

Would you like a helper that inspects PR.body for Dependabot’s “rebasing” notice and falls back to mergeStateStatus/mergeable heuristics?

cli/dependabot-cmd.ts.backup (3)

281-283: Avoid non-null assertion on statusCheckRollup here as well.

Mirror the safe optional chaining fix from the main file.

-  Status: ${statusEmoji} ${overallStatus} (${pr.statusCheckRollup!.length} check${pr.statusCheckRollup!.length !== 1 ? "s" : ""})
+  Status: ${statusEmoji} ${overallStatus} (${(pr.statusCheckRollup?.length ?? 0)} check${(pr.statusCheckRollup?.length ?? 0) !== 1 ? "s" : ""})

1-5: Consider excluding or removing this .ts.backup file.

To avoid confusion and accidental lint/build pickup, either delete this file, move it outside src, or add a pattern (e.g., **/*.ts.backup) to tsconfig/eslint ignore lists.


233-253: auto-merge availability flow diverges from main command UX.

This backup uses --auto and --wait, while the main command uses --autoGH/--autoCLI. If you keep this file, align flags and messages to avoid user confusion.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3b22618 and b4d7dbe.

📒 Files selected for processing (2)
  • cli/dependabot-cmd.ts (5 hunks)
  • cli/dependabot-cmd.ts.backup (1 hunks)
🧰 Additional context used
🪛 ESLint
cli/dependabot-cmd.ts

[error] 160-160: Type boolean trivially inferred from a boolean literal, remove type annotation.

(@typescript-eslint/no-inferrable-types)


[error] 297-297: Forbidden non-null assertion.

(@typescript-eslint/no-non-null-assertion)


[error] 297-297: Forbidden non-null assertion.

(@typescript-eslint/no-non-null-assertion)

🪛 GitHub Actions: @fireproof/core
cli/dependabot-cmd.ts

[error] 160-160: eslint: Type boolean trivially inferred from a boolean literal, remove type annotation (@typescript-eslint/no-inferrable-types)

🪛 GitHub Check: ci compile
cli/dependabot-cmd.ts

[failure] 160-160:
Type boolean trivially inferred from a boolean literal, remove type annotation

🔇 Additional comments (1)
cli/dependabot-cmd.ts (1)

102-108: Author type mismatch will not cause runtime issues as the field remains unused; statusCheckRollup is already flat in gh output, not nested in nodes.

The review comment's concern about statusCheckRollup?.nodes ?? [] is unfounded. The actual gh pr list output returns statusCheckRollup as a flat array directly, not nested under a nodes key. The code at lines 46, 51, and 297 correctly uses it as an array without transformation.

However, the author field type is indeed mismatched: it's typed as string in the PR interface but gh returns an object {is_bot, login}. This type mismatch is harmless since author is unused throughout the codebase, but the type definition should be corrected or the unused field removed.

Likely an incorrect or invalid review comment.

Comment on lines 360 to 369
// Process SUCCESS PRs with clean output
for (const pr of currentSuccessPRs) {
try {
processed++;
console.log(`Processing [${processed}/${totalToProcess}]: PR #${pr.number} ✓ Enabled auto-merge`);
await applyPR(pr, true, args.autoGH && autoMergeAvailable);
processedPRs.add(pr.number);
failedToApply.delete(pr.number);
} catch (error) {
failedToApply.add(pr.number);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

autoCLI path logs say “Enabled auto-merge” but we don’t; also wrong flag passed.

In the autoCLI flow we should not pass args.autoGH and we shouldn’t claim “Enabled auto-merge”.

-                console.log(`Processing [${processed}/${totalToProcess}]: PR #${pr.number} ✓ Enabled auto-merge`);
-                await applyPR(pr, true, args.autoGH && autoMergeAvailable);
+                console.log(`Processing [${processed}/${totalToProcess}]: PR #${pr.number} ✓ Rebased and merged`);
+                await applyPR(pr, true, false);
🤖 Prompt for AI Agents
In cli/dependabot-cmd.ts around lines 360 to 369, the autoCLI path incorrectly
logs "✓ Enabled auto-merge" and passes args.autoGH into applyPR; change the
console.log to not claim auto-merge (e.g., "✓ Processed" or similar) and replace
the third argument to applyPR with only autoMergeAvailable (remove args.autoGH),
so call applyPR(pr, true, autoMergeAvailable) and update the log text
accordingly.

…--autoGH

Two key improvements to the dependabot automation:

1. Reorder status detection logic so PENDING takes priority over FAILURE
   - If any check is IN_PROGRESS, the PR is marked as PENDING
   - Only mark as FAILURE when all checks are complete and at least one failed
   - Prevents incorrectly skipping PRs with mixed check states

2. Add waiting logic to --autoGH flag (previously only --autoCLI had it)
   - Both --autoCLI and --autoGH now wait for pending checks to complete
   - Enables GitHub auto-merge only after all checks pass
   - Consistent behavior between CLI-managed and GitHub-managed merging

This fixes the issue where PRs with IN_PROGRESS checks were immediately
marked as failed and skipped instead of being waited for.
- Replace pr.statusCheckRollup!.length with safe optional chaining
- Use const checkCount = pr.statusCheckRollup?.length ?? 0
- Fixes @typescript-eslint/no-non-null-assertion violation
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (2)
cli/dependabot-cmd.ts (2)

238-238: Verify lint fix was applied.

A past review flagged this line for having an inferrable type annotation (: boolean) on the useAutoMerge parameter. The current code appears to have useAutoMerge = false without the type annotation, which is correct. Please confirm the lint error is resolved.

Run this command to verify no lint errors remain:

#!/bin/bash
# Check for no-inferrable-types violations in the file
cd cli
npx eslint dependabot-cmd.ts --no-eslintrc --parser @typescript-eslint/parser --plugin @typescript-eslint/eslint-plugin --rule '@typescript-eslint/no-inferrable-types: error' 2>&1 | grep -A2 "no-inferrable-types" || echo "✓ No inferrable type violations found"

238-238: Remove inferrable type annotation.

The explicit : boolean type on the defaulted useAutoMerge parameter is flagged by ESLint's no-inferrable-types rule. The type is trivially inferred from the false literal.

Apply this diff:

-async function applyPR(pr: PR, rebase: boolean, useAutoMerge = false): Promise<void> {
+async function applyPR(pr: PR, rebase: boolean, useAutoMerge = false): Promise<void> {

Wait, that's the same. Let me fix:

-async function applyPR(pr: PR, rebase: boolean, useAutoMerge = false): Promise<void> {
+async function applyPR(pr: PR, rebase: boolean, useAutoMerge = false): Promise<void> {

Actually, the type annotation is missing from the displayed code. Looking at line 238 again: async function applyPR(pr: PR, rebase: boolean, useAutoMerge = false): Promise<void> {

The correct fix is:

-async function applyPR(pr: PR, rebase: boolean, useAutoMerge = false): Promise<void> {
+async function applyPR(pr: PR, rebase: boolean, useAutoMerge = false): Promise<void> {

Hmm, this is confusing. Let me check the past comment - it says the issue is useAutoMerge: boolean = false should be useAutoMerge = false. But looking at line 238 in the provided code, I don't see : boolean there. Let me check if the code was already fixed...

Actually, looking at the annotated code, line 238 shows:

async function applyPR(pr: PR, rebase: boolean, useAutoMerge = false): Promise<void> {

So it appears the code doesn't have : boolean annotation. But the past comment says line 160 had it (which is now line 238). Maybe the code was already fixed? Let me flag this as a duplicate comment since the past comment already covered it, and note that it appears to have been addressed.
[scratchpad_end] -->

🧹 Nitpick comments (2)
cli/dependabot-cmd.ts (2)

104-120: Validate repo parameter format.

The repo parameter is passed directly to shell commands without format validation. While zx handles escaping, validating the expected owner/repo format adds defense in depth.

Add validation before using the repo parameter:

async function fetchDependabotPRs(repo = ""): Promise<PR[]> {
  try {
    // Validate repo format if provided
    if (repo && !/^[\w.-]+\/[\w.-]+$/.test(repo)) {
      throw new Error(`Invalid repo format: ${repo}. Expected format: owner/repo`);
    }
    
    let result;
    if (repo) {
      result =
        await $`gh pr list -R ${repo} --author app/dependabot --json number,title,author,url,headRefName,statusCheckRollup,body,mergeable,mergeStateStatus,files --limit 100`;
    } else {
      result =
        await $`gh pr list --author app/dependabot --json number,title,author,url,headRefName,statusCheckRollup,body,mergeable,mergeStateStatus,files --limit 100`;
    }
    // ... rest of function

453-453: Validate that autoGH and autoCLI are mutually exclusive.

The --autoGH and --autoCLI flags represent different merge strategies but can both be set simultaneously, which is confusing. Add validation to error when both are specified.

Add validation before the conditional:

+      // Validate mutually exclusive flags
+      if (args.autoCLI && args.autoGH) {
+        console.error("ERROR: Cannot use both --autoCLI and --autoGH flags");
+        console.error("  --autoGH: GitHub auto-merges when CI passes (requires auto-merge enabled)");
+        console.error("  --autoCLI: CLI merges when CI passes");
+        process.exit(1);
+      }
+
       if (args.apply || args.rebase) {
         if (args.rebase && (args.autoCLI || args.autoGH)) {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b4d7dbe and 7525536.

📒 Files selected for processing (1)
  • cli/dependabot-cmd.ts (5 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: mabels
Repo: fireproof-storage/fireproof PR: 1016
File: cli/package.json:8-12
Timestamp: 2025-08-05T07:28:12.473Z
Learning: In PR #1016 "update tsc -> tsgo", mabels is implementing global control over TypeScript compilation across the fireproof monorepo by replacing direct "tsc" calls with "core-cli tsc" in package.json build scripts. This allows centralized management of which TypeScript compiler to use (tsc vs tsgo) through the core-cli tool.
📚 Learning: 2025-08-05T07:28:12.473Z
Learnt from: mabels
Repo: fireproof-storage/fireproof PR: 1016
File: cli/package.json:8-12
Timestamp: 2025-08-05T07:28:12.473Z
Learning: In PR #1016 "update tsc -> tsgo", mabels is implementing global control over TypeScript compilation across the fireproof monorepo by replacing direct "tsc" calls with "core-cli tsc" in package.json build scripts. This allows centralized management of which TypeScript compiler to use (tsc vs tsgo) through the core-cli tool.

Applied to files:

  • cli/dependabot-cmd.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: ci compile
🔇 Additional comments (6)
cli/dependabot-cmd.ts (6)

6-26: LGTM: Clean type definitions for PR status modeling.

The new types and interface extensions provide a solid foundation for normalizing GitHub check results across CheckRun and StatusContext types, and for dependency analysis.


85-102: LGTM: Robust auto-merge capability detection.

The GraphQL query with proper error handling and safe fallback ensures the feature degrades gracefully when the check fails.


122-177: LGTM: Well-structured dependency analysis.

The lockfile vs package-file distinction and priority-based merge ordering provide intelligent conflict avoidance.


179-223: LGTM: Deterministic polling with real elapsed time.

The wait logic now correctly tracks actual elapsed time instead of random values, and provides clear progress updates. Good fix!


431-432: LGTM: Fixed non-null assertion issue.

The previous review flagged non-null assertions here. The code now correctly uses optional chaining (?.) and nullish coalescing (??) to safely handle undefined statusCheckRollup. Well done!


313-668: LGTM: Well-orchestrated multi-mode command handler.

The handler elegantly supports multiple workflows (list, map-dependencies, autoCLI, autoGH) with clear validation, helpful error messages, and informative progress updates. The dependency-aware merge ordering is a particularly valuable feature.

- Remove non-null assertion in getOverallStatus (check ERROR/FAILURE separately)
- Use precise file path matching for package.json (avoid false positives)
- Apply same fix to directDepFailedPRs filter

Fixes @typescript-eslint/no-non-null-assertion violation
- Add repo parameter to waitForPRsToSucceed function signature
- Pass args.repo to waitForPRsToSucceed call (line 569)
- Pass args.repo to fetchDependabotPRs call (line 573)
- Ensures CI polling works correctly when using -R/--repo flag
- Implements systematic flaky test detection by closing and reopening PRs
- Triggers fresh CI runs without code changes to identify transient failures
- Adds --retry-failed flag to find flaky tests
- Adds --max-retries option to control retry attempts (default: 1)
- Generates detailed report showing which PRs are flaky vs permanently failing
- Adds --clean flag to delete all or specific Dependabot PRs
- Adds pnpm >=9.0.0 engine requirement to package.json

This addresses the issue where valid dependency updates were being rejected
due to flaky tests. Now users can systematically detect and work around
transient CI failures while identifying which tests need fixing.
…for Dependabot PR conflict resolution

- Fixed applyPR function to accept and use repo parameter
- Added resolveConflictsAndRebase function to automatically rebase and resolve pnpm-lock.yaml conflicts
- Added --resolve-conflicts flag to rebase PRs against main and auto-fix lockfile conflicts
- Added --regenerate-frozen-lockfile flag to regenerate frozen lockfile after resolving conflicts
- Updated all applyPR calls to pass repo parameter
…st lockfile

- Updated resolveConflictsAndRebase to resolve all conflicting files by taking version from main
- Added --force flag to gh pr checkout to handle previously force-pushed branches
- For pnpm-lock.yaml, regenerate with pnpm install after taking version from main
- For other files, simply take the version from main with git checkout --theirs
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c4bce12 and e8df577.

📒 Files selected for processing (1)
  • cli/dependabot-cmd.ts (5 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: mabels
Repo: fireproof-storage/fireproof PR: 1016
File: cli/package.json:8-12
Timestamp: 2025-08-05T07:28:12.473Z
Learning: In PR #1016 "update tsc -> tsgo", mabels is implementing global control over TypeScript compilation across the fireproof monorepo by replacing direct "tsc" calls with "core-cli tsc" in package.json build scripts. This allows centralized management of which TypeScript compiler to use (tsc vs tsgo) through the core-cli tool.
📚 Learning: 2025-08-05T07:28:12.473Z
Learnt from: mabels
Repo: fireproof-storage/fireproof PR: 1016
File: cli/package.json:8-12
Timestamp: 2025-08-05T07:28:12.473Z
Learning: In PR #1016 "update tsc -> tsgo", mabels is implementing global control over TypeScript compilation across the fireproof monorepo by replacing direct "tsc" calls with "core-cli tsc" in package.json build scripts. This allows centralized management of which TypeScript compiler to use (tsc vs tsgo) through the core-cli tool.

Applied to files:

  • cli/dependabot-cmd.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: ci compile
🔇 Additional comments (3)
cli/dependabot-cmd.ts (3)

6-90: Status modeling and getOverallStatus look solid and readable.

The PRStatus union + StatusCheck shape plus getOverallStatus logic (including REBASE-PENDING, NO_CHECKS, and mergeability awareness) provide a clear, centralized view of PR health. The handling of CheckRun vs StatusContext types and prioritization of PENDING/ERROR/FAILURE vs SUCCESS is sensible and makes the downstream orchestration easier to reason about.


129-184: Dependency mapping / lockfile conflict detection is a nice addition.

The detectLockfileConflicts routine plus the --map-dependencies CLI path give a clear, actionable view of which PRs are lockfile‑only vs package‑file‑touching and in what order to merge them. The regex grouping and mergeOrder sequencing (package files first, then lockfile‑only) make sense and the list output with status emoji + [DIRECT DEP]/[TRANSITIVE] labels is very helpful in practice.

Also applies to: 720-760


335-360: Please verify that @dependabot reopen actually does what we expect in retryFailedPR.

retryFailedPR currently:

  • Closes the PR with gh pr close.
  • Waits 30s, then comments @dependabot reopen.
  • The retry flow (--retry-failed) then waits 3 minutes and re-queries the PR list.

Whether this reliably reopens the PR and triggers a fresh CI run depends entirely on Dependabot’s supported comment commands and behavior. If @dependabot reopen isn’t a supported trigger (or its semantics ever change), this mode will silently stop doing the right thing.

It might be safer to:

  • Use gh pr reopen to deterministically reopen the PR.
  • Optionally still add a @dependabot rebase or similar comment if you need Dependabot to refresh the branch rather than just re-run CI.

I’d suggest double‑checking the latest Dependabot docs for reopen support and adjusting the implementation if needed.

Also applies to: 619-683

Comment on lines +92 to +105
async function checkAutoMergeEnabled(): Promise<boolean> {
try {
// Use GraphQL to check if auto-merge is allowed
const result = await $`gh api graphql -f query='
query($owner: String!, $name: String!) {
repository(owner: $owner, name: $name) {
autoMergeAllowed
}
}
' -f owner="$(gh repo view --json owner --jq .owner.login)" -f name="$(gh repo view --json name --jq .name)"`;

const data = JSON.parse(result.stdout);
return data.data.repository.autoMergeAllowed === true;
} catch (error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

checkAutoMergeEnabled ignores --repo, so auto‑merge checks can target the wrong repository.

Right now checkAutoMergeEnabled() always calls gh repo view without -R, so it inspects the current working directory’s repo, not the CLI --repo target. That affects:

  • The auto‑merge status banner in list mode.
  • The --autoGH guard/exit when auto‑merge is not enabled.

If you run dependabot --repo otherOwner/otherRepo ... from a different local clone, the guidance and gating for auto‑merge can be wrong.

I’d suggest letting checkAutoMergeEnabled accept an optional repo and wiring it through from the handler:

-async function checkAutoMergeEnabled(): Promise<boolean> {
+async function checkAutoMergeEnabled(repo = ""): Promise<boolean> {
   try {
-    // Use GraphQL to check if auto-merge is allowed
-    const result = await $`gh api graphql -f query='
-      query($owner: String!, $name: String!) {
-        repository(owner: $owner, name: $name) {
-          autoMergeAllowed
-        }
-      }
-    ' -f owner="$(gh repo view --json owner --jq .owner.login)" -f name="$(gh repo view --json name --jq .name)"`;
+    // Use GraphQL to check if auto-merge is allowed for the target repo (or current repo if none given)
+    let owner: string;
+    let name: string;
+
+    if (repo) {
+      [owner, name] = repo.split("/") as [string, string];
+    } else {
+      const ownerResult = await $`gh repo view --json owner --jq .owner.login`;
+      const nameResult = await $`gh repo view --json name --jq .name`;
+      owner = ownerResult.stdout.trim();
+      name = nameResult.stdout.trim();
+    }
+
+    const result = await $`gh api graphql -f query='
+      query($owner: String!, $name: String!) {
+        repository(owner: $owner, name: $name) {
+          autoMergeAllowed
+        }
+      }
+    ' -f owner=${owner} -f name=${name}`;
@@
-        console.log("Checking repository auto-merge setting...");
-        const autoMergeEnabled = await checkAutoMergeEnabled();
+        console.log("Checking repository auto-merge setting...");
+        const autoMergeEnabled = await checkAutoMergeEnabled(args.repo);
@@
-        console.log("Checking auto-merge availability...");
-        autoMergeAvailable = await checkAutoMergeEnabled();
+        console.log("Checking auto-merge availability...");
+        autoMergeAvailable = await checkAutoMergeEnabled(args.repo);

(Optionally, add a small guard if repo.split("/") doesn’t yield two parts.)

Also applies to: 766-779, 786-806


🏁 Script executed:

#!/bin/bash
# Extract the checkAutoMergeEnabled function and call sites
echo "=== Lines 92-105 (function definition) ==="
sed -n '92,105p' cli/dependabot-cmd.ts

echo -e "\n=== Lines 766-779 (call site 1) ==="
sed -n '766,779p' cli/dependabot-cmd.ts

echo -e "\n=== Lines 786-806 (call site 2) ==="
sed -n '786,806p' cli/dependabot-cmd.ts

echo -e "\n=== Search for all checkAutoMergeEnabled calls ==="
rg -n "checkAutoMergeEnabled" cli/dependabot-cmd.ts

Length of output: 2629


🏁 Script executed:

#!/bin/bash
# Get broader context around the call sites to understand the handler functions
echo "=== Context around line 770 (200 lines before to find function start) ==="
sed -n '570,780p' cli/dependabot-cmd.ts | head -220

echo -e "\n=== Check for args.repo definition/usage ==="
rg -n "args\.repo" cli/dependabot-cmd.ts -A2 -B2 | head -50

Length of output: 9976


checkAutoMergeEnabled ignores --repo parameter, causing auto-merge checks to target the wrong repository.

The function at lines 92-105 calls gh repo view without the -R flag, so it always inspects the current working directory's repository instead of the target specified by the --repo CLI argument. This affects:

  • The auto-merge status banner in list mode (line 770)
  • The --autoGH guard/exit when auto-merge is not enabled (line 790)

When running dependabot --repo otherOwner/otherRepo ... from a different local clone, the guidance and gating for auto-merge will check the wrong repository.

Suggested fix: Modify checkAutoMergeEnabled() to accept an optional repo parameter and pass args.repo at the call sites (lines 770 and 790), following the pattern used by other functions in this file like fetchDependabotPRs() and resolveConflictsAndRebase().

Comment on lines +515 to +526
clean: flag({
long: "clean",
short: "c",
description:
"Delete Dependabot PRs and let Dependabot run fresh (clean slate). Use with --pr to delete specific PR(s), or without to delete all.",
}),
cleanPRs: option({
long: "clean-prs",
type: string,
defaultValue: () => "",
description: "Comma-separated PR numbers to delete (e.g., '1354,1349,1348'). Use with --clean to delete specific PRs.",
}),
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

--clean help text mentions --pr, but implementation uses --clean-prs.

The clean flag description says:

Use with --pr to delete specific PR(s), or without to delete all.

But the code actually parses args.cleanPRs (from --clean-prs) and completely ignores prNumber in clean mode. This can confuse users who follow the help text.

Consider aligning the description with the actual option name:

-      clean: flag({
-        long: "clean",
-        short: "c",
-        description:
-          "Delete Dependabot PRs and let Dependabot run fresh (clean slate). Use with --pr to delete specific PR(s), or without to delete all.",
-      }),
+      clean: flag({
+        long: "clean",
+        short: "c",
+        description:
+          "Delete Dependabot PRs and let Dependabot run fresh (clean slate). Use with --clean-prs to delete specific PR(s), or without to delete all.",
+      }),
🤖 Prompt for AI Agents
In cli/dependabot-cmd.ts around lines 515 to 526, the --clean flag help text
references a non-existent --pr option while the implementation expects
--clean-prs; update either the help text or the option to remove the mismatch:
either change the clean flag description to mention --clean-prs (and an example
using --clean-prs) or add an alias/alternate option name (--pr) that maps to the
same option and ensure args.prNumber and args.cleanPRs are unified so the clean
mode reads the same source for PR numbers; keep help text and parsing consistent
and update any examples accordingly.

Comment on lines +918 to +1008
let processed = 0;
const processedPRs = new Set<number>();
const permanentlyFailedPRs = new Set<number>(); // Only skip after multiple failures

// With --autoCLI, continuously process PRs until none are left
// Use ordered PRs for smart merge order
let remainingPRs = orderedPRs;
const failedToApply = new Set<number>(); // Track PRs that failed to apply

while (remainingPRs.length > 0) {
// Categorize PRs
const currentSuccessPRs = remainingPRs.filter(
(pr) => getOverallStatus(pr) === "SUCCESS" && !processedPRs.has(pr.number),
);
const currentPendingPRs = remainingPRs.filter((pr) => {
const status = getOverallStatus(pr);
return (status === "PENDING" || status === "REBASE-PENDING") && !processedPRs.has(pr.number);
});

// Process SUCCESS PRs first
if (currentSuccessPRs.length > 0) {
console.log(`Rebasing ${currentSuccessPRs.length} PR(s) with SUCCESS status:\n`);
for (const pr of currentSuccessPRs) {
try {
processed++;
console.log(`Processing [${processed}/${totalToProcess}]: PR #${pr.number}`);
await applyPR(pr, true, args.autoGH && autoMergeAvailable, args.repo);
processedPRs.add(pr.number);
failedToApply.delete(pr.number);
} catch (error) {
const errorMsg = String(error);
if (errorMsg.includes("not mergeable")) {
console.error(`✗ PR #${pr.number} is not mergeable (needs rebase), will wait for Dependabot...`);
failedToApply.add(pr.number);
} else {
console.error(`✗ Failed to apply PR #${pr.number}, will retry in next iteration.`);
failedToApply.add(pr.number);
}
}
}

// After merging PRs, wait for Dependabot to rebase the remaining ones
if (processedPRs.size > 0 && failedToApply.size > 0) {
console.log(
`\n⏳ Waiting 60 seconds for Dependabot to automatically rebase ${failedToApply.size} PR(s) after base branch changes...\n`,
);
await new Promise((resolve) => setTimeout(resolve, 60000));
}
}

// Wait for pending PRs if any
if (currentPendingPRs.length > 0) {
const pendingNumbers = currentPendingPRs.map((pr) => pr.number);
console.log(`Waiting for CI checks on ${currentPendingPRs.length} PRs...`);
await waitForPRsToSucceed(pendingNumbers, 30, args.repo);
}

// Refresh the PR list
const newRemainingPRs = await fetchDependabotPRs(args.repo);

// If no PRs left, we're done
if (newRemainingPRs.length === 0) {
console.log("\n✓ All PRs have been merged or closed!");
break;
}

// Check if we made progress or have PRs that need retry
const unprocessedPRs = newRemainingPRs.filter(
(pr) => !processedPRs.has(pr.number) && !permanentlyFailedPRs.has(pr.number),
);

// Continue if there are unprocessed PRs OR PRs that failed to apply (need rebase)
const hasWorkToDo = unprocessedPRs.length > 0 || failedToApply.size > 0;

if (!hasWorkToDo) {
console.log("\n✓ No more PRs to process.");
break;
}

// Reorder remaining PRs according to dependency map
const newDepMap = detectLockfileConflicts(newRemainingPRs);
remainingPRs = newDepMap.mergeOrder
.map((prNum) => newRemainingPRs.find((pr) => pr.number === prNum))
.filter((pr): pr is PR => pr !== undefined);

// Brief pause to avoid API hammering
if (currentSuccessPRs.length === 0 && currentPendingPRs.length === 0) {
console.log("⏳ No PRs ready to merge, waiting 30 seconds before retry...");
await new Promise((resolve) => setTimeout(resolve, 30000));
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

AutoCLI/autoGH processing loop can spin forever on permanently failing PRs.

In the --rebase + (--autoCLI or --autoGH) path:

  • permanentlyFailedPRs is declared but never populated.
  • unprocessedPRs is derived from newRemainingPRs but only excludes processedPRs and permanentlyFailedPRs.
  • PRs that stay in FAILURE/ERROR state remain “unprocessed” forever.
  • When there are no currentSuccessPRs or currentPendingPRs, the loop just logs “No PRs ready to merge, waiting 30 seconds before retry...” and repeats indefinitely.

So as soon as you have one or more Dependabot PRs that will not go green, the autoCLI/autoGH orchestration never terminates, and the final summary is never printed.

You can fix this by marking FAILED/ERROR PRs as “permanently failed” after a refresh and excluding them from further work:

-            // Refresh the PR list
-            const newRemainingPRs = await fetchDependabotPRs(args.repo);
+            // Refresh the PR list
+            const newRemainingPRs = await fetchDependabotPRs(args.repo);
+
+            // Mark PRs that are definitively failing so they don't keep the loop alive forever
+            for (const pr of newRemainingPRs) {
+              if (processedPRs.has(pr.number) || permanentlyFailedPRs.has(pr.number)) continue;
+              const status = getOverallStatus(pr);
+              if (status === "FAILURE" || status === "ERROR") {
+                permanentlyFailedPRs.add(pr.number);
+              }
+            }
@@
-            const unprocessedPRs = newRemainingPRs.filter(
-              (pr) => !processedPRs.has(pr.number) && !permanentlyFailedPRs.has(pr.number),
-            );
+            const unprocessedPRs = newRemainingPRs.filter(
+              (pr) => !processedPRs.has(pr.number) && !permanentlyFailedPRs.has(pr.number),
+            );

This way:

  • Truly failing PRs are surfaced in the final summary via finalSkippedPRs.
  • The loop eventually terminates once all mergeable PRs are processed and all others are marked as permanently failed.

You could extend this further to treat repeated timeouts from waitForPRsToSucceed similarly, but the above already prevents the infinite wait on known failing PRs.

🤖 Prompt for AI Agents
In cli/dependabot-cmd.ts around lines 918 to 1008, permanentlyFailedPRs is
declared but never populated, allowing the autoCLI/autoGH loop to spin forever
on PRs stuck in FAILURE/ERROR; update the loop after fetching newRemainingPRs to
detect PRs whose overall status is FAILURE or ERROR (or that have consistently
timed out from waitForPRsToSucceed) and add their numbers to
permanentlyFailedPRs so they are excluded from unprocessedPRs, ensure
failedToApply entries that are permanently failed are removed, and include those
permanently failed PRs in the final summary/skip list so the loop can terminate
once only processed or permanently failed PRs remain.

- Add repo format validation (owner/repo) in fetchDependabotPRs
- Add validation for mutually exclusive --autoCLI and --autoGH flags
- Improve rebase detection to check for Dependabot 'Rebasing' notice in PR body
- Fallback to mergeStateStatus=DIRTY heuristic for better reliability
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants