Skip to content

feat: [CODE-5104]: Change fork-sync API status code for conflicts#101

Open
abhinavcode wants to merge 2 commits into
mainfrom
mg/fork/sync-branch-conflict-status-code
Open

feat: [CODE-5104]: Change fork-sync API status code for conflicts#101
abhinavcode wants to merge 2 commits into
mainfrom
mg/fork/sync-branch-conflict-status-code

Conversation

@abhinavcode

@abhinavcode abhinavcode commented Feb 26, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Fork sync now returns a dedicated HTTP 409 Conflict with a distinct conflict payload when merges conflict, separating conflicts from successful syncs.
  • Breaking Changes

    • Conflict details (files and message) moved into a new conflict response type; successful sync responses no longer include those conflict fields.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai

coderabbitai Bot commented Feb 26, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Controller ForkSync now returns (output, conflict, error); conflict details moved to a new ForkSyncConflict type. Handlers map conflict results to HTTP 409. ForkSyncInput.sanitize defaults BranchUpstream to Branch and upstream usage is standardized throughout the flow.

Changes

Cohort / File(s) Summary
Controller
app/api/controller/repo/fork_sync.go
Signature changed to return (*types.ForkSyncOutput, *types.ForkSyncConflict, error). ForkSyncInput.sanitize defaults BranchUpstream to Branch. Upstream fetch/merge use in.BranchUpstream. Error returns and success paths updated to the new triple-return shape; conflicts now return a ForkSyncConflict.
Handler
app/api/handler/repo/fork_sync.go
Handler updated to accept two return values (resultMerge, resultConflict) from controller; returns HTTP 409 with the conflict payload when resultConflict is non-nil, otherwise HTTP 200 with success.
Types
types/fork.go
Removed ConflictFiles and Message from ForkSyncOutput. Added new exported ForkSyncConflict type containing ConflictFiles []string and Message string.
OpenAPI
app/api/openapi/repo.go
Added a 409 Conflict response schema for the fork-sync operation referencing the new ForkSyncConflict type alongside existing 200 and error responses.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client
  participant Handler as Handler
  participant Controller as Controller
  Note over Handler,Controller: types: ForkSyncInput, ForkSyncOutput, ForkSyncConflict
  Client->>Handler: POST /repo/{repo}/fork/sync (ForkSyncInput)
  Handler->>Controller: ForkSync(ctx, session, repoRef, in)
  alt No conflict
    Controller-->>Handler: (*ForkSyncOutput, nil, nil)
    Handler-->>Client: 200 OK (ForkSyncOutput)
  else Conflict detected
    Controller-->>Handler: (nil, *ForkSyncConflict, nil)
    Handler-->>Client: 409 Conflict (ForkSyncConflict)
  else Error
    Controller-->>Handler: (nil, nil, error)
    Handler-->>Client: 5xx / error response
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇
I hopped through branches, soft and quick,
Split conflicts out — a tidy trick.
Now if a merge begins to fight,
I show the clash in clear daylight.
Nibble a carrot, code feels right.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: modifying the fork-sync API to return a specific HTTP status code (409 Conflict) when merge conflicts occur, which aligns with the refactoring of the ForkSync function signature and the introduction of ForkSyncConflict as a distinct return value.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mg/fork/sync-branch-conflict-status-code

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/api/controller/repo/fork_sync.go`:
- Around line 176-180: The code currently treats an empty mergeOutput.MergeSHA
as a conflict (HTTP 409) because the condition uses "||"; instead only classify
as a conflict when mergeOutput.ConflictFiles has entries. Change the logic
around mergeOutput (the variable in fork_sync.go) so: if
len(mergeOutput.ConflictFiles) > 0 return the types.ForkSyncConflict as before;
else if mergeOutput.MergeSHA.IsEmpty() return a non-conflict/internal error
(e.g., a standard error or a specific internal error type) so callers map it to
a 5xx rather than a 409; update any tests/handlers expecting the previous
behavior accordingly.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 33be763 and 2458e82.

📒 Files selected for processing (2)
  • app/api/controller/repo/fork_sync.go
  • types/fork.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • types/fork.go

Comment on lines 176 to 180
if mergeOutput.MergeSHA.IsEmpty() || len(mergeOutput.ConflictFiles) > 0 {
return &types.ForkSyncOutput{
return nil, &types.ForkSyncConflict{
ConflictFiles: mergeOutput.ConflictFiles,
Message: fmt.Sprintf("Branch synchronization blocked by conflicting files: %v",
mergeOutput.ConflictFiles),
Message: "Branch synchronization blocked by conflicting files.",
}, nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don’t classify empty MergeSHA as conflict by default.

mergeOutput.MergeSHA.IsEmpty() || len(mergeOutput.ConflictFiles) > 0 can incorrectly return a conflict (HTTP 409) for non-conflict merge anomalies. That masks internal failure modes and can misreport status codes.

Suggested fix
-	if mergeOutput.MergeSHA.IsEmpty() || len(mergeOutput.ConflictFiles) > 0 {
+	if mergeOutput == nil {
+		return nil, nil, fmt.Errorf("fork branch sync merge returned nil output")
+	}
+
+	if len(mergeOutput.ConflictFiles) > 0 {
 		return nil, &types.ForkSyncConflict{
 			ConflictFiles: mergeOutput.ConflictFiles,
 			Message:       "Branch synchronization blocked by conflicting files.",
 		}, nil
 	}
+
+	if mergeOutput.MergeSHA.IsEmpty() {
+		return nil, nil, fmt.Errorf("fork branch sync merge returned empty merge SHA without conflicts")
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/controller/repo/fork_sync.go` around lines 176 - 180, The code
currently treats an empty mergeOutput.MergeSHA as a conflict (HTTP 409) because
the condition uses "||"; instead only classify as a conflict when
mergeOutput.ConflictFiles has entries. Change the logic around mergeOutput (the
variable in fork_sync.go) so: if len(mergeOutput.ConflictFiles) > 0 return the
types.ForkSyncConflict as before; else if mergeOutput.MergeSHA.IsEmpty() return
a non-conflict/internal error (e.g., a standard error or a specific internal
error type) so callers map it to a 5xx rather than a 409; update any
tests/handlers expecting the previous behavior accordingly.

@abhinavcode abhinavcode force-pushed the mg/fork/sync-branch-conflict-status-code branch from 2458e82 to db14735 Compare February 26, 2026 14:58

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
app/api/controller/repo/fork_sync.go (1)

176-180: ⚠️ Potential issue | 🟠 Major

Avoid treating empty merge SHA as conflict (409).

Line 176 still maps MergeSHA.IsEmpty() to conflict. That can mask internal merge anomalies as HTTP 409 instead of surfacing them as server errors.

Suggested fix
-	if mergeOutput.MergeSHA.IsEmpty() || len(mergeOutput.ConflictFiles) > 0 {
+	if len(mergeOutput.ConflictFiles) > 0 {
 		return nil, &types.ForkSyncConflict{
 			ConflictFiles: mergeOutput.ConflictFiles,
 			Message:       "Branch synchronization blocked by conflicting files.",
 		}, nil
 	}
+
+	if mergeOutput.MergeSHA.IsEmpty() {
+		return nil, nil, fmt.Errorf("fork branch sync merge returned empty merge SHA without conflicts")
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/controller/repo/fork_sync.go` around lines 176 - 180, The current
check treats mergeOutput.MergeSHA.IsEmpty() as a conflict
(types.ForkSyncConflict) which masks internal merge failures as HTTP 409; update
the logic in fork_sync.go (the block handling mergeOutput) so only
len(mergeOutput.ConflictFiles) > 0 produces and returns a types.ForkSyncConflict
(409). If mergeOutput.MergeSHA.IsEmpty() is true, return an internal/server
error instead (e.g., a non-conflict error or wrapped error) so it surfaces as a
5xx; adjust the conditional and return paths around mergeOutput,
MergeSHA.IsEmpty(), and types.ForkSyncConflict accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@app/api/controller/repo/fork_sync.go`:
- Around line 176-180: The current check treats mergeOutput.MergeSHA.IsEmpty()
as a conflict (types.ForkSyncConflict) which masks internal merge failures as
HTTP 409; update the logic in fork_sync.go (the block handling mergeOutput) so
only len(mergeOutput.ConflictFiles) > 0 produces and returns a
types.ForkSyncConflict (409). If mergeOutput.MergeSHA.IsEmpty() is true, return
an internal/server error instead (e.g., a non-conflict error or wrapped error)
so it surfaces as a 5xx; adjust the conditional and return paths around
mergeOutput, MergeSHA.IsEmpty(), and types.ForkSyncConflict accordingly.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2458e82 and db14735.

📒 Files selected for processing (2)
  • app/api/controller/repo/fork_sync.go
  • types/fork.go

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.

2 participants