-
Notifications
You must be signed in to change notification settings - Fork 52
chore: cli dependabot updates #1278
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
WalkthroughAdds 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
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)
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~60 minutes
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used🧠 Learnings (2)📓 Common learnings📚 Learning: 2025-08-05T07:28:12.473ZApplied to files:
⏰ 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)
🔇 Additional comments (13)
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.
Example instruction:
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. Comment |
There was a problem hiding this 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
📒 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 actualgh pr listoutput returnsstatusCheckRollupas a flat array directly, not nested under anodeskey. The code at lines 46, 51, and 297 correctly uses it as an array without transformation.However, the
authorfield type is indeed mismatched: it's typed asstringin the PR interface butghreturns an object{is_bot, login}. This type mismatch is harmless sinceauthoris unused throughout the codebase, but the type definition should be corrected or the unused field removed.Likely an incorrect or invalid review comment.
cli/dependabot-cmd.ts
Outdated
| // 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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
There was a problem hiding this 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 theuseAutoMergeparameter. The current code appears to haveuseAutoMerge = falsewithout 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
: booleantype on the defaulteduseAutoMergeparameter is flagged by ESLint'sno-inferrable-typesrule. The type is trivially inferred from thefalseliteral.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 = falseshould beuseAutoMerge = false. But looking at line 238 in the provided code, I don't see: booleanthere. 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
: booleanannotation. 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
repoparameter is passed directly to shell commands without format validation. Whilezxhandles escaping, validating the expectedowner/repoformat 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
--autoGHand--autoCLIflags 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
📒 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 undefinedstatusCheckRollup. 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
There was a problem hiding this 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
📒 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 andgetOverallStatuslook solid and readable.The
PRStatusunion +StatusCheckshape plusgetOverallStatuslogic (includingREBASE-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
detectLockfileConflictsroutine plus the--map-dependenciesCLI 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 andmergeOrdersequencing (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 reopenactually does what we expect inretryFailedPR.
retryFailedPRcurrently:
- 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 reopenisn’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 reopento deterministically reopen the PR.- Optionally still add a
@dependabot rebaseor 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
reopensupport and adjusting the implementation if needed.Also applies to: 619-683
| 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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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
--autoGHguard/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.tsLength 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 -50Length 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
--autoGHguard/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().
| 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.", | ||
| }), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--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.
| 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)); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AutoCLI/autoGH processing loop can spin forever on permanently failing PRs.
In the --rebase + (--autoCLI or --autoGH) path:
permanentlyFailedPRsis declared but never populated.unprocessedPRsis derived fromnewRemainingPRsbut only excludesprocessedPRsandpermanentlyFailedPRs.- PRs that stay in
FAILURE/ERRORstate remain “unprocessed” forever. - When there are no
currentSuccessPRsorcurrentPendingPRs, 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
Updated the 2 option commands:
Updated the --rebase CLI Print out
Summary by CodeRabbit
New Features
Chores