feat: show conflicting files and blame in failed-merge comments#416
Conversation
When a dev-branch rebuild fails to merge a PR, the failure comment now lists the specific files that conflicted and, where possible, points at the other dev-labeled PR that was merged earlier in the same run and touched those files. - FailedPull carries conflictingFileToPulls: Map<string, Pull[]>, replacing the flat conflictFiles + mergedFirstInThisRun pair. The map is per-file so blame is accurate even when multiple files conflict for different reasons. - commentFail receives base + failedPull as parameters; getInput removed from the formatter. - Gate simplified to `if (mergeResult)`: failure labels and comments now fire even when no PR merged cleanly, fixing a pre-existing bug. - updateLabels receives failedPulls, making the success/failed/skipped classification explicit instead of implicit !successful. - diff-tree moved outside the merge try/catch so a diff failure cannot trigger git merge --abort on an already-successful merge. Co-authored-by: opencode <opencode@noreply.opencode.ai> Co-authored-by: GitHub Copilot <copilot@noreply.github.com>
|
All contributors have signed the CLA ✍️ ✅ |
…for mixed cases When a conflicting file has no culprit PR (empty pullers list), the per-file suffix now says 'conflicts with `base` — rebase this PR onto `base` to resolve' instead of emitting nothing. The surrounding body copy is reworded to be accurate for mixed cases (some files blamed on a sibling PR, some on base) — the old copy falsely implied all conflicts were caused by another dev PR. Two new unit tests cover the pure base-conflict and mixed cases. Co-authored-by: opencode <opencode@noreply.opencode.ai> Co-authored-by: GitHub Copilot <copilot@noreply.github.com>
|
I have read the CLA Document and I hereby sign the CLA |
|
Related to #415 ? |
I've worked on this after talking with Kai about this problem, not realizing he's already opened a PR already. 🙈 I have however did a couple of iterations on it myself having an agent review it and feel like was a bit more involved. Sorry that it creates an additional review burden. But yes, it's basically solves the same problem. |
|
@harikaduyu @kaitimmer Can you please decide which PR you would like to move forward? |
There was a problem hiding this comment.
Pull request overview
This PR enhances AutoDev’s failed-merge notifications by tracking merge-conflict files per failed PR and attributing (“blaming”) conflicts to dev-labeled PRs merged earlier in the same run when possible, then using that data in failure comments and label updates.
Changes:
- Introduces
FailedPullwithconflictingFileToPulls: Map<string, Pull[]>and updates failure comment formatting to list conflicting files and per-file “culprit” PRs. - Captures
git mergestderr to extract conflict paths, records per-merge changed files viagit diff-tree, and plumbsfailedPullsthrough comment/label update flows. - Adds Vitest coverage for
commentFailrendering, label behavior for “skipped” PRs, and conflict-file extraction/plumbing.
Reviewed changes
Copilot reviewed 3 out of 5 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/utils.ts | Adds FailedPull, enriches failure comments with per-file conflict attribution, and updates label/comment APIs to accept failedPulls. |
| src/autodev.ts | Captures merge stderr to extract conflicting file paths, builds per-file attribution map across the merge loop, and always returns failed pulls. |
| src/autodev.test.ts | Adds focused tests for commentFail, updateLabels, and failed-merge conflict extraction/attribution plumbing. |
| dist/index.js | Updates built distribution output to reflect the new failure-comment, conflict extraction, and labeling behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if ( | ||
| (successful && hasSuccessfulLabel) || | ||
| (!successful && hasFailureLabel) | ||
| (targetLabel === customSuccessLabel && hasSuccessfulLabel) || | ||
| (targetLabel === customFailureLabel && hasFailureLabel) | ||
| ) { | ||
| continue |
| for (const m of stderr.matchAll( | ||
| /^CONFLICT \(rename\/rename\): \S+ renamed to (\S+) in \S+ and to (\S+) in/gm | ||
| )) { | ||
| files.add(m[1].trim()) | ||
| files.add(m[2].trim()) | ||
| } |
0x46616c6b
left a comment
There was a problem hiding this comment.
Can you provide a living example? Sometimes it is hard to review without validation. You could use this change in another repository and try to create a conflict.
git writes CONFLICT lines to stdout, not stderr. Capturing only stderr caused extractConflictFiles to always return an empty list, falling back to the generic failure comment instead of the blame comment. Co-authored-by: opencode <opencode@noreply.opencode.ai> Co-authored-by: GitHub Copilot <copilot@noreply.github.com>
- Drop dead delete/modify regex: git always emits modify/delete regardless of which side deleted the file - Fix rename/rename: extract the original path (what diff-tree records) instead of the two target names (which never match fileToPulls) - Switch diff-tree to -M --name-status to detect renames; index both old and new paths so later conflict lookups find the right PR Co-authored-by: opencode <opencode@noreply.opencode.ai> Co-authored-by: GitHub Copilot <copilot@noreply.github.com>
diff-tree HEAD after a fast-forward merge shows the incoming commit's diff against its own parent, not the files that changed vs the pre-merge state. Snapshot HEAD before the merge and diff against that instead, so fast-forwarded PRs correctly populate fileToPulls. Co-authored-by: opencode <opencode@noreply.opencode.ai> Co-authored-by: GitHub Copilot <copilot@noreply.github.com>
0x46616c6b
left a comment
There was a problem hiding this comment.
Thanks a lot for your effort. LGTM.
Type of Change
Description
When a dev-branch rebuild fails to merge a PR, the failure comment now lists the specific files that conflicted and, where possible, points at the other dev-labeled PR that was merged earlier in the same run and touched those files.
Key changes:
FailedPullcarriesconflictingFileToPulls: Map<string, Pull[]>, replacing the flatconflictFiles+mergedFirstInThisRunpair. The map is per-file so blame is accurate even when multiple files conflict for different reasons.commentFailreceivesbase+failedPullas parameters;getInputremoved from the formatter (boundary fix).if (mergeResult): failure labels and comments now fire even when no PR merged cleanly, fixing a pre-existing bug where all-fail runs never applied failure labels.updateLabelsnow receivesfailedPulls, making success/failed/skipped classification explicit rather than implicit!successful.diff-treemoved outside the merge try/catch so a diff failure cannot incorrectly triggergit merge --aborton an already-successful merge.Checklist
This PR was created with opencode.