Add experimental GraphQL mutation for latest diff comments
Summary
- Adds a new
CreateLatestDiffNoteGraphQL mutation (marked experiment) that creates diff notes on merge requests with minimal parameters (body,filePath, andnewLine/oldLine) - Automatically resolves SHAs (
baseSha,startSha,headSha), file paths (oldPath,newPath), andpositionTypefrom the latest merge request diff - Includes a required
headShaargument to guard against race conditions - Uses
experiment: { milestone: '18.1' }so the interface can evolve without being bound by the deprecation policy
Why
The existing CreateDiffNote mutation (and REST discussions API) require callers to provide a full position with 7+ fields (3 SHAs, positionType, oldPath, newPath, line numbers) even though the backend already has all this information from the merge request diff. This new mutation reduces the required arguments to just 3-4 fields.
What's included
| File | Purpose |
|---|---|
app/graphql/mutations/notes/create/latest_diff_note.rb |
New experimental mutation |
app/services/merge_requests/resolve_diff_position_service.rb |
Service to resolve full position from minimal params |
app/graphql/types/mutation_type.rb |
Mount with experiment: annotation |
spec/requests/api/graphql/mutations/notes/create/latest_diff_note_spec.rb |
18 mutation specs including parity test |
spec/services/merge_requests/resolve_diff_position_service_spec.rb |
11 service specs |
Usage
mutation {
createLatestDiffNote(input: {
noteableId: "gid://gitlab/MergeRequest/1"
body: "Your comment"
filePath: "app/models/user.rb"
newLine: 42
headSha: "abc123..."
}) {
note { id body position { positionType filePath newLine } }
errors
}
}
Line arguments
| Scenario | Arguments | Example |
|---|---|---|
| Added line (green) |
newLine only |
newLine: 42 |
| Removed line (red) |
oldLine only |
oldLine: 15 |
| Unchanged/context line (white) | Both oldLine and newLine
|
oldLine: 10, newLine: 10 |
Renamed files
For renamed files, either the old or new path can be used in filePath. The mutation automatically resolves both oldPath and newPath from the merge request diff.
Manual testing
Tested locally against gitlab-org/gitlab-test MR with:
- A file with added and removed lines (
test-file.txt) - A renamed file with content changes (
CONTRIBUTING.md → Jimmy.md) - A pure rename with no content changes (
PROCESS.md → RIP.md)
| Test case | Result |
|---|---|
Comment on added line (newLine only) |
|
Comment on removed line (oldLine only) |
|
| Comment on context/unchanged line (both lines) | |
| Renamed file: comment on added line | |
| Renamed file: comment on removed line | |
| Renamed file: comment on context line | |
Renamed file: lookup by old path (CONTRIBUTING.md) |
|
Renamed file: lookup by new path (Jimmy.md) |
|
| Pure rename (no diff content): line comment |
CreateDiffNote mutation and REST API) |
Stale headSha
|
|
Invalid filePath
|
|
| Missing line arguments |
|
Quick action (/label) in body |
|
Parity test vs CreateDiffNote
|
|
Edited by Marc Shaw