feat(api,ui): add multiline comment on pullrequest (#12582)

Closes https://codeberg.org/forgejo/forgejo/issues/6093

This PR adds support for **multi-line review comments** on pull requests, allowing reviewers to select a range of lines in diffs instead of only a single line — similar to GitHub's implementation.

### Tests for Go changes

- I added test coverage for Go changes...
  - [X] in their respective `*_test.go` for unit tests.
  - [X] `make pr-go` before pushing

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/12582
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
This commit is contained in:
steven.guiheux 2026-06-03 16:06:29 +02:00 committed by Mathieu Fenniak
commit 6a27eb051d
26 changed files with 1185 additions and 103 deletions

View file

@ -5,6 +5,7 @@
<input type="hidden" name="latest_commit_id" value="{{$.root.AfterCommitID}}">
<input type="hidden" name="side" value="{{if $.Side}}{{$.Side}}{{end}}">
<input type="hidden" name="line" value="{{if $.Line}}{{$.Line}}{{end}}">
<input type="hidden" name="extra_lines_count" value="{{if $.ExtraLinesCount}}{{$.ExtraLinesCount}}{{else}}0{{end}}">
<input type="hidden" name="path" value="{{if $.File}}{{$.File}}{{end}}">
<input type="hidden" name="diff_start_cid">
<input type="hidden" name="diff_end_cid">

View file

@ -31,6 +31,9 @@
{{end}}
</div>
<div class="comment-header-right actions tw-flex tw-items-center">
{{if gt .ExtraLinesCount 0}}
<span class="ui label">Lines {{.UnsignedLine}}-{{.UnsignedDisplayLine}}</span>
{{end}}
{{if .Invalidated}}
{{$referenceUrl := printf "%s#%s" $.root.Issue.Link .HashTag}}
<a href="{{AppSubUrl}}{{$referenceUrl}}" class="ui label" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.review.outdated_description"}}">

View file

@ -3,7 +3,7 @@
{{$resolveDoer := (index .comments 0).ResolveDoer}}
{{$isNotPending := (not (eq (index .comments 0).Review.Type 0))}}
{{$referenceUrl := printf "%s#%s" $.Issue.Link (index .comments 0).HashTag}}
<div class="conversation-holder" data-path="{{(index .comments 0).TreePath}}" data-side="{{if lt (index .comments 0).Line 0}}left{{else}}right{{end}}" data-idx="{{(index .comments 0).UnsignedLine}}">
<div class="conversation-holder" data-path="{{(index .comments 0).TreePath}}" data-side="{{if lt (index .comments 0).Line 0}}left{{else}}right{{end}}" data-idx="{{(index .comments 0).UnsignedLine}}" data-extra-lines-count="{{(index .comments 0).ExtraLinesCount}}">
{{if $resolved}}
<div class="ui attached header resolved-placeholder tw-flex tw-items-center tw-justify-between">
<div class="ui grey text tw-flex tw-items-center tw-flex-wrap tw-gap-1">

View file

@ -12,7 +12,10 @@
</span>
{{end}}
</div>
<div>
<div class="tw-flex tw-items-center tw-gap-2">
{{if gt (index .comments 0).ExtraLinesCount 0}}
<span class="ui label">Lines {{(index .comments 0).UnsignedLine}}-{{(index .comments 0).UnsignedDisplayLine}}</span>
{{end}}
{{if or $invalid $resolved}}
<button id="show-outdated-{{(index .comments 0).ID}}" data-comment="{{(index .comments 0).ID}}" class="{{if not $resolved}}tw-hidden {{end}}show-outdated">
{{svg "octicon-unfold" 16 "tw-mr-2"}}

View file

@ -25052,6 +25052,12 @@
"type": "string",
"x-go-name": "Body"
},
"extra_lines_count": {
"description": "number of additional lines after the commented line (0 = single line comment)",
"type": "integer",
"format": "int64",
"x-go-name": "ExtraLinesCount"
},
"new_position": {
"description": "if comment to new file line or 0",
"type": "integer",
@ -28954,6 +28960,12 @@
"type": "string",
"x-go-name": "DiffHunk"
},
"extra_lines_count": {
"description": "number of additional lines after the commented line (0 = single line comment)",
"type": "integer",
"format": "int64",
"x-go-name": "ExtraLinesCount"
},
"html_url": {
"type": "string",
"x-go-name": "HTMLURL"