Skip to content

Commit 91be855

Browse files
committed
Add inline commit coments
1 parent 793815a commit 91be855

File tree

18 files changed

+1442
-74
lines changed

18 files changed

+1442
-74
lines changed

models/git/commit.go

Lines changed: 542 additions & 0 deletions
Large diffs are not rendered by default.

routers/web/repo/commit.go

Lines changed: 488 additions & 4 deletions
Large diffs are not rendered by default.

routers/web/web.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1551,6 +1551,26 @@ func registerWebRoutes(m *web.Router) {
15511551
}, optSignIn, context.RepoAssignment, repo.MustAllowPulls, reqUnitPullsReader)
15521552
// end "/{username}/{reponame}/pulls/{index}": repo pull request
15531553

1554+
m.Group("/{username}/{reponame}", func() {
1555+
m.Group("/commit/{sha:([a-f0-9]{7,64})$}", func() {
1556+
m.Get("", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
1557+
m.Post("/attachments", repo.UploadCommitAttachment)
1558+
m.Get("/{id}/attachments/{uuid}", repo.GetCommitAttachmentByUUID)
1559+
m.Group("/comments", func() {
1560+
m.Get("/new_comment", repo.RenderCommitCommentForm)
1561+
m.Post("/cancel", repo.CancelCommitComment)
1562+
m.Post("/add", web.Bind(forms.CodeCommentForm{}), repo.SetShowOutdatedComments, repo.CreateCommitComment)
1563+
m.Post("/{id}/delete", repo.DeleteCommitComment)
1564+
m.Post("/{id}/update", repo.UpdateCommitComment)
1565+
m.Get("/{id}/attachments", repo.GetCommitAttachments)
1566+
m.Post("/attachments/remove", repo.DeleteCommitAttachment)
1567+
}, context.RepoMustNotBeArchived())
1568+
m.Group("/comments/{id}", func() {
1569+
m.Post("/reactions/{action}", web.Bind(forms.ReactionForm{}), repo.ChangeCommitCommentReaction)
1570+
})
1571+
})
1572+
}, optSignIn, context.RepoAssignment, repo.MustAllowPulls, reqUnitPullsReader)
1573+
15541574
m.Group("/{username}/{reponame}", func() {
15551575
m.Group("/activity_author_data", func() {
15561576
m.Get("", repo.ActivityAuthors)

services/context/upload/upload.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package upload
55

66
import (
7+
"fmt"
78
"mime"
89
"net/http"
910
"net/url"
@@ -89,6 +90,9 @@ func Verify(buf []byte, fileName, allowedTypesStr string) error {
8990

9091
// AddUploadContext renders template values for dropzone
9192
func AddUploadContext(ctx *context.Context, uploadType string) {
93+
PageIsDiff := ctx.Data["PageIsDiff"]
94+
ctx.Data["CommitSHA"] = ctx.PathParam("sha")
95+
CommitSHA := ctx.PathParam("sha")
9296
switch uploadType {
9397
case "release":
9498
ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/releases/attachments"
@@ -98,8 +102,14 @@ func AddUploadContext(ctx *context.Context, uploadType string) {
98102
ctx.Data["UploadMaxFiles"] = setting.Attachment.MaxFiles
99103
ctx.Data["UploadMaxSize"] = setting.Attachment.MaxSize
100104
case "comment":
101-
ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/issues/attachments"
102-
ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/issues/attachments/remove"
105+
if PageIsDiff == true {
106+
ctx.Data["UploadUrl"] = fmt.Sprintf("%s/commit/%s/attachments", ctx.Repo.RepoLink, CommitSHA)
107+
ctx.Data["UploadRemoveUrl"] = fmt.Sprintf("%s/commit/%s/comments/attachments/remove", ctx.Repo.RepoLink, CommitSHA)
108+
} else {
109+
ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/issues/attachments"
110+
ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/issues/attachments/remove"
111+
}
112+
103113
if len(ctx.PathParam("index")) > 0 {
104114
ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/issues/" + url.PathEscape(ctx.PathParam("index")) + "/attachments"
105115
} else {

services/git/commit.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package git
55

66
import (
77
"context"
8+
"sort"
89

910
asymkey_model "code.gitea.io/gitea/models/asymkey"
1011
"code.gitea.io/gitea/models/db"
@@ -14,6 +15,7 @@ import (
1415
"code.gitea.io/gitea/modules/container"
1516
"code.gitea.io/gitea/modules/git"
1617
asymkey_service "code.gitea.io/gitea/services/asymkey"
18+
"code.gitea.io/gitea/services/gitdiff"
1719
)
1820

1921
// ParseCommitsWithSignature checks if signaute of commits are corresponding to users gpg keys.
@@ -88,3 +90,69 @@ func ParseCommitsWithStatus(ctx context.Context, oldCommits []*asymkey_model.Sig
8890
}
8991
return newCommits, nil
9092
}
93+
94+
func CreateCommitComment(ctx context.Context, doer *user_model.User, gitRepo *git.Repository, opts git_model.CreateCommitDataOptions) (*git_model.CommitData, error) {
95+
comment, err := git_model.CreateCommitData(ctx, &opts)
96+
if err != nil {
97+
return nil, err
98+
}
99+
return comment, nil
100+
}
101+
102+
// LoadComments loads comments into each line
103+
func LoadCommitComments(ctx context.Context, diff *gitdiff.Diff, commitData *git_model.CommitData, currentUser *user_model.User) error {
104+
opts := git_model.FindCommitDataOptions{
105+
CommitSHA: commitData.CommitSHA,
106+
}
107+
108+
commitData, err := git_model.GetCommitDataBySHA(ctx, commitData.RefRepoID, commitData.CommitSHA)
109+
if err != nil {
110+
return err
111+
}
112+
commitComments, err := git_model.FindCommitCommentsByCommit(ctx, &opts, commitData)
113+
if err != nil {
114+
return err
115+
}
116+
117+
for _, file := range diff.Files {
118+
for _, cc := range commitComments {
119+
if cc.FileName == file.Name {
120+
for _, section := range file.Sections {
121+
for _, line := range section.Lines {
122+
if cc.Line == int64(line.LeftIdx*-1) {
123+
line.CommitComments = append(line.CommitComments, cc)
124+
cc.Repo = commitData.Repo
125+
cc.Poster = commitData.Poster
126+
}
127+
if cc.Line == int64(line.RightIdx) {
128+
line.CommitComments = append(line.CommitComments, cc)
129+
cc.Repo = commitData.Repo
130+
cc.Poster = commitData.Poster
131+
}
132+
sort.SliceStable(line.CommitComments, func(i, j int) bool {
133+
return line.CommitComments[i].CreatedUnix < line.CommitComments[j].CreatedUnix
134+
})
135+
}
136+
}
137+
}
138+
}
139+
}
140+
return nil
141+
}
142+
143+
// CreateCommentReaction creates a reaction on a comment.
144+
func CreateCommentReaction(ctx context.Context, doer *user_model.User, commitData *git_model.CommitData, reaction string) error {
145+
err := git_model.CreateCommitCommentReaction(ctx, reaction, doer.ID, commitData)
146+
if err != nil {
147+
return err
148+
}
149+
return nil
150+
}
151+
152+
func DeleteCommentReaction(ctx context.Context, doer *user_model.User, commitData *git_model.CommitData, reaction string) error {
153+
err := git_model.DeleteCommentReaction(ctx, reaction, doer.ID, commitData)
154+
if err != nil {
155+
return err
156+
}
157+
return nil
158+
}

services/gitdiff/gitdiff.go

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,14 @@ const (
7777

7878
// DiffLine represents a line difference in a DiffSection.
7979
type DiffLine struct {
80-
LeftIdx int // line number, 1-based
81-
RightIdx int // line number, 1-based
82-
Match int // the diff matched index. -1: no match. 0: plain and no need to match. >0: for add/del, "Lines" slice index of the other side
83-
Type DiffLineType
84-
Content string
85-
Comments issues_model.CommentList // related PR code comments
86-
SectionInfo *DiffLineSectionInfo
80+
LeftIdx int // line number, 1-based
81+
RightIdx int // line number, 1-based
82+
Match int // the diff matched index. -1: no match. 0: plain and no need to match. >0: for add/del, "Lines" slice index of the other side
83+
Type DiffLineType
84+
Content string
85+
Comments issues_model.CommentList // related PR code commzents
86+
CommitComments git_model.CommitDataList // related to commit comments
87+
SectionInfo *DiffLineSectionInfo
8788
}
8889

8990
// DiffLineSectionInfo represents diff line section meta data
@@ -133,6 +134,11 @@ func (d *DiffLine) CanComment() bool {
133134
return len(d.Comments) == 0 && d.Type != DiffLineSection
134135
}
135136

137+
// CanCommitComment returns whether a line can get commented
138+
func (d *DiffLine) CanCommitComment() bool {
139+
return len(d.CommitComments) == 0 && d.Type != DiffLineSection
140+
}
141+
136142
// GetCommentSide returns the comment side of the first comment, if not set returns empty string
137143
func (d *DiffLine) GetCommentSide() string {
138144
if len(d.Comments) == 0 {
@@ -141,6 +147,14 @@ func (d *DiffLine) GetCommentSide() string {
141147
return d.Comments[0].DiffSide()
142148
}
143149

150+
// GetCommentSide returns the comment side of the first comment, if not set returns empty string
151+
func (d *DiffLine) GetCommitCommentSide() string {
152+
if len(d.CommitComments) == 0 {
153+
return ""
154+
}
155+
return d.CommitComments[0].DiffSide()
156+
}
157+
144158
// GetLineTypeMarker returns the line type marker
145159
func (d *DiffLine) GetLineTypeMarker() string {
146160
if strings.IndexByte(" +-", d.Content[0]) > -1 {

templates/repo/diff/box.tmpl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,13 @@
184184
{{end}}
185185
</div>
186186
{{else}}
187-
<table class="chroma" data-new-comment-url="{{$.Issue.Link}}/files/reviews/new_comment" data-path="{{$file.Name}}">
187+
{{- $newCommentUrl := "" -}}
188+
{{if $.PageIsPullFiles}}
189+
{{$newCommentUrl = printf "%s/files/reviews/new_comment" $.Issue.Link -}}
190+
{{else if $.PageIsDiff}}
191+
{{$newCommentUrl = printf "%s/commit/%s/comments/new_comment" $.RepoLink $.CommitID -}}
192+
{{end}}
193+
<table class="chroma" data-new-comment-url="{{$newCommentUrl}}" data-path="{{$file.Name}}">
188194
{{if $.IsSplitStyle}}
189195
{{template "repo/diff/section_split" dict "file" . "root" $}}
190196
{{else}}

templates/repo/diff/comment_form.tmpl

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
{{if and $.root.SignedUserID (not $.Repository.IsArchived)}}
2-
<form class="ui form {{if $.hidden}}tw-hidden comment-form{{end}}" action="{{$.root.Issue.Link}}/files/reviews/comments" method="post">
2+
{{- $action := "" -}}
3+
{{- $origin := "" -}}
4+
{{if $.root.PageIsPullFiles}}
5+
{{$action = printf "%s/files/reviews/comments" $.root.Issue.Link -}}
6+
{{$origin = "diff"}}
7+
{{else if $.root.PageIsDiff}}
8+
{{$action = printf "%s/commit/%s/comments/add" $.root.RepoLink $.root.CommitSHA -}}
9+
{{$origin = "diff"}}
10+
{{else}}
11+
{{$origin = "timeline"}}
12+
{{end}}
13+
<form class="ui form {{if $.hidden}}tw-hidden comment-form{{end}}" action="{{$action}}" method="post">
314
{{$.root.CsrfTokenHtml}}
4-
<input type="hidden" name="origin" value="{{if $.root.PageIsPullFiles}}diff{{else}}timeline{{end}}">
15+
<input type="hidden" name="origin" value="{{$origin}}">
516
<input type="hidden" name="latest_commit_id" value="{{$.root.AfterCommitID}}">
617
<input type="hidden" name="side" value="{{if $.Side}}{{$.Side}}{{end}}">
718
<input type="hidden" name="line" value="{{if $.Line}}{{$.Line}}{{end}}">
@@ -36,12 +47,16 @@
3647
{{if $.root.CurrentReview}}
3748
<button name="pending_review" type="submit" class="ui submit primary tiny button btn-add-comment">{{ctx.Locale.Tr "repo.diff.comment.add_review_comment"}}</button>
3849
{{else}}
39-
<button name="pending_review" type="submit" class="ui submit primary tiny button btn-start-review">{{ctx.Locale.Tr "repo.diff.comment.start_review"}}</button>
40-
<button name="single_review" value="true" type="submit" class="ui submit tiny basic button btn-add-single">{{ctx.Locale.Tr "repo.diff.comment.add_single_comment"}}</button>
50+
{{if $.root.PageIsDiff}}
51+
<button type="submit" name="type" value="comment" class="ui submit tiny basic button btn-submit">{{ctx.Locale.Tr "repo.diff.review.comment"}}</button>
52+
{{else}}
53+
<button name="pending_review" type="submit" class="ui submit primary tiny button btn-start-review">{{ctx.Locale.Tr "repo.diff.comment.start_review"}}</button>
54+
<button name="single_review" value="true" type="submit" class="ui submit tiny basic button btn-add-single">{{ctx.Locale.Tr "repo.diff.comment.add_single_comment"}}</button>
55+
{{end}}
4156
{{end}}
4257
{{end}}
4358
{{if or (not $.HasComments) $.hidden}}
44-
<button type="button" class="ui submit tiny basic button btn-cancel cancel-code-comment">{{ctx.Locale.Tr "cancel"}}</button>
59+
<button type="button" data-global-click="onCancelCodeCommentButtonClick" class="ui submit tiny basic button btn-cancel cancel-code-comment">{{ctx.Locale.Tr "cancel"}}</button>
4560
{{end}}
4661
</div>
4762
</div>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{{range .comments}}
2+
{{$createdStr:= DateUtils.TimeSince .CreatedUnix}}
3+
<div class="comment" id="{{.HashTag}}">
4+
<div class="tw-mt-2 tw-mr-4">
5+
{{template "shared/user/avatarlink" dict "user" .Poster}}
6+
</div>
7+
<div class="content comment-container">
8+
<div class="comment-header avatar-content-left-arrow">
9+
<div class="comment-header-left">
10+
<span class="text grey muted-links">
11+
{{template "shared/user/namelink" .Poster}}
12+
{{ctx.Locale.Tr "repo.issues.commented_at" .HashTag $createdStr}}
13+
</span>
14+
</div>
15+
<div class="comment-header-right">
16+
{{if not $.root.Repository.IsArchived}}
17+
{{template "repo/issue/view_content/add_reaction" dict "ActionURL" (printf "%s/commit/%s/comments/%d/reactions" $.root.RepoLink .CommitSHA .ID)}}
18+
{{end}}
19+
{{template "repo/issue/view_content/context_menu" dict "item" . "delete" true "issue" false "diff" true "IsCommentPoster" (and $.root.IsSigned (eq $.root.SignedUserID .PosterID))}}
20+
</div>
21+
</div>
22+
<div class="ui attached segment comment-body">
23+
<div class="render-content markup" {{if or $.Permission.IsAdmin $.HasIssuesOrPullsWritePermission (and $.root.IsSigned (eq $.root.SignedUserID .PosterID))}}data-can-edit="true"{{end}}>
24+
{{if .RenderedComment}}
25+
{{.RenderedComment}}
26+
{{else}}
27+
<span class="no-content">{{ctx.Locale.Tr "repo.issues.no_content"}}</span>
28+
{{end}}
29+
</div>
30+
<div id="issuecomment-{{.ID}}-raw" class="raw-content tw-hidden">{{.Comment}}</div>
31+
<div class="edit-content-zone tw-hidden" data-update-url="{{(printf "%s/commit/%s/comments/%d/update" $.root.RepoLink .CommitSHA .ID)}}" data-content-version="{{.ContentVersion}}" data-context="{{$.root.RepoLink}}" data-attachment-url="{{(printf "%s/commit/%s/comments/%d/attachments" $.root.RepoLink .CommitSHA .ID)}}"></div>
32+
{{$attachments := .GroupAttachmentsByUUID}}
33+
{{if $attachments}}
34+
{{template "repo/issue/view_content/commit_attachments" dict "CommitData" . "Attachments" $attachments "RenderedContent" .RenderedComment}}
35+
{{end}}
36+
</div>
37+
{{$reactions := .GroupReactionsByType}}
38+
{{if $reactions}}
39+
{{template "repo/issue/view_content/commit_reactions" dict "CommitData" . "ActionURL" (printf "%s/commit/%s/comments/%d/reactions" $.root.RepoLink .CommitSHA .ID) "Reactions" $reactions}}
40+
{{end}}
41+
</div>
42+
</div>
43+
{{end}}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{{if len .comments}}
2+
{{$comment := index .comments 0}}
3+
<div class="conversation-holder" data-path="{{$comment.FileName}}" data-side="{{if lt $comment.Line 0}}left{{else}}right{{end}}" data-idx="{{$comment.Line}}">
4+
<div id="code-comments-{{$comment.ID}}" class="field comment-code-cloud">
5+
<div class="comment-list">
6+
<div class="ui comments">
7+
{{template "repo/diff/commit_comments" dict "root" $ "comments" .comments}}
8+
</div>
9+
</div>
10+
<div class="flex-text-block tw-mt-2 tw-flex-wrap tw-justify-end">
11+
<div class="ui buttons">
12+
<button class="ui icon tiny basic button previous-conversation">
13+
{{svg "octicon-arrow-up" 12}} {{ctx.Locale.Tr "repo.issues.previous"}}
14+
</button>
15+
<button class="ui icon tiny basic button next-conversation">
16+
{{svg "octicon-arrow-down" 12}} {{ctx.Locale.Tr "repo.issues.next"}}
17+
</button>
18+
</div>
19+
{{if and $.SignedUserID (not $.Repository.IsArchived)}}
20+
<button class="comment-form-reply ui primary icon tiny button">
21+
{{svg "octicon-reply" 12}}{{ctx.Locale.Tr "repo.diff.comment.reply"}}
22+
</button>
23+
{{end}}
24+
</div>
25+
{{template "repo/diff/comment_form_datahandler" dict "hidden" true "reply" $comment.ID "root" $ "comment" $comment}}
26+
</div>
27+
</div>
28+
{{else}}
29+
{{template "repo/diff/conversation_outdated"}}
30+
{{end}}

0 commit comments

Comments
 (0)