0
0
Fork 0
mirror of https://codeberg.org/forgejo/forgejo.git synced 2025-01-31 18:05:00 -05:00

Compare commits

..

4 commits

Author SHA1 Message Date
Litchi Pi
233c3f4819 lint templates
Signed-off-by: Litchi Pi <litchi.pi@proton.me>
2025-01-20 17:26:25 +01:00
Litchi Pi
c993e4a157 Fixup the lint required for CI
Signed-off-by: Litchi Pi <litchi.pi@proton.me>
2025-01-20 17:17:53 +01:00
Litchi Pi
8ae2e4b2ef format with gofumpt also
Signed-off-by: Litchi Pi <litchi.pi@proton.me>
2025-01-20 16:54:49 +01:00
Litchi Pi
faad7e0017 models: issue: create a comment aggregator to reduce noise in issue
Signed-off-by: Litchi Pi <litchi.pi@proton.me>
2025-01-20 16:47:07 +01:00
4 changed files with 613 additions and 927 deletions

View file

@ -238,10 +238,30 @@ func (r RoleInRepo) LocaleHelper(lang translation.Locale) string {
return lang.TrString("repo.issues.role." + string(r) + "_helper")
}
type RequestReviewTarget interface {
ID() int64
Name() string
Type() string
type RequestReviewTarget struct {
User *user_model.User
Team *organization.Team
}
func (t *RequestReviewTarget) ID() int64 {
if t.User != nil {
return t.User.ID
}
return t.Team.ID
}
func (t *RequestReviewTarget) Name() string {
if t.User != nil {
return t.User.GetDisplayName()
}
return t.Team.Name
}
func (t *RequestReviewTarget) Type() string {
if t.User != nil {
return "user"
}
return "team"
}
// Comment represents a comment in commit and issue page.

View file

@ -5,24 +5,20 @@ package issues
import (
"slices"
"code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
)
type CommentAggregator struct {
StartUnix int64
Indexes []int
PosterID int64
Indexes []int
PosterID int64
PrevClosed bool
IsClosed bool
IsClosed bool
AddedLabels []*Label
AddedLabels []*Label
RemovedLabels []*Label
AddedRequestReview []RequestReviewTarget
AddedRequestReview []RequestReviewTarget
RemovedRequestReview []RequestReviewTarget
}
@ -33,46 +29,41 @@ type CommentAggregator struct {
func (agg *CommentAggregator) aggregateComment(c *Comment, index int) {
agg.Indexes = append(agg.Indexes, index)
if (c.Type == CommentTypeClose) {
if c.Type == CommentTypeClose {
agg.IsClosed = true
} else if (c.Type == CommentTypeReopen) {
} else if c.Type == CommentTypeReopen {
agg.IsClosed = false
} else if (c.Type == CommentTypeReviewRequest) {
if c.AssigneeID >= 0 {
req := ReqReviewTarget { User: c.Assignee }
} else if c.Type == CommentTypeReviewRequest {
if c.AssigneeID > 0 {
req := RequestReviewTarget{User: c.Assignee}
if c.RemovedAssignee {
agg.delReviewRequest(&req)
agg.delReviewRequest(req)
} else {
agg.addReviewRequest(&req)
agg.addReviewRequest(req)
}
} else if c.AssigneeTeamID >= 0 {
req := ReqReviewTarget { Team: c.AssigneeTeam }
} else if c.AssigneeTeamID > 0 {
req := RequestReviewTarget{Team: c.AssigneeTeam}
if c.RemovedAssignee {
agg.delReviewRequest(&req)
agg.delReviewRequest(req)
} else {
agg.addReviewRequest(&req)
agg.addReviewRequest(req)
}
}
for _, r := range c.RemovedRequestReview {
agg.delReviewRequest(r)
}
for _, r := range c.AddedRequestReview {
agg.addReviewRequest(r)
}
} else if (c.Type == CommentTypeLabel) {
log.Warn("Aggregated label comment %v %v %v", c.Type, c.Label.Name, c.Label.ID)
} else if c.Type == CommentTypeLabel {
if c.Content == "1" {
agg.addLabel(c.Label)
} else {
agg.delLabel(c.Label)
}
} else if (c.Type == CommentTypeAggregator) {
} else if c.Type == CommentTypeAggregator {
agg.Merge(c.Aggregator)
}
}
@ -114,7 +105,7 @@ func (agg *CommentAggregator) addLabel(lbl *Label) {
for l, agglbl := range agg.RemovedLabels {
if agglbl.ID == lbl.ID {
agg.RemovedLabels = append(agg.RemovedLabels[:l], agg.RemovedLabels[l+1:]...)
return;
return
}
}
@ -128,7 +119,7 @@ func (agg *CommentAggregator) delLabel(lbl *Label) {
for l, agglbl := range agg.AddedLabels {
if agglbl.ID == lbl.ID {
agg.AddedLabels = append(agg.AddedLabels[:l], agg.AddedLabels[l+1:]...)
return;
return
}
}
@ -142,9 +133,9 @@ func (agg *CommentAggregator) addReviewRequest(req RequestReviewTarget) {
reqid := req.ID()
reqty := req.Type()
for r, aggreq := range agg.RemovedRequestReview {
if (aggreq.ID() == reqid) && (aggreq.Type() == reqty){
if (aggreq.ID() == reqid) && (aggreq.Type() == reqty) {
agg.RemovedRequestReview = append(agg.RemovedRequestReview[:r], agg.RemovedRequestReview[r+1:]...)
return;
return
}
}
@ -158,9 +149,9 @@ func (agg *CommentAggregator) delReviewRequest(req RequestReviewTarget) {
reqid := req.ID()
reqty := req.Type()
for r, aggreq := range agg.AddedRequestReview {
if (aggreq.ID() == reqid) && (aggreq.Type() == reqty){
if (aggreq.ID() == reqid) && (aggreq.Type() == reqty) {
agg.AddedRequestReview = append(agg.AddedRequestReview[:r], agg.AddedRequestReview[r+1:]...)
return;
return
}
}
@ -215,6 +206,12 @@ func (agg *CommentAggregator) Reset(cur *Comment) {
agg.RemovedRequestReview = []RequestReviewTarget{}
}
// Function that replaces all the comments aggregated with a single one
// Its CommentType depend on whether multiple type of comments are been aggregated or not
// If nothing has changed, we remove all the comments that get nullified
//
// The function returns how many comments has been removed, in order for the "for" loop
// of the main algorithm to change its index
func (agg *CommentAggregator) createAggregatedComment(issue *Issue, final bool) int {
endind := agg.Indexes[len(agg.Indexes)-1]
startind := agg.Indexes[0]
@ -223,21 +220,24 @@ func (agg *CommentAggregator) createAggregatedComment(issue *Issue, final bool)
if !agg.Changed() {
if final {
issue.Comments = issue.Comments[:startind]
log.Warn("Case 1: [:%v]", startind)
} else {
issue.Comments = append(issue.Comments[:startind], issue.Comments[endind+1:]...)
log.Warn("Case 2: [:%v] + [:%v]", startind, endind+1)
}
return endind - startind
}
new_agg := *agg // Trigger a memory allocation, get a COPY of the aggregator
newAgg := *agg // Trigger a memory allocation, get a COPY of the aggregator
// Keep the same author, time, etc... But reset the parts we may want to use
comment := issue.Comments[startind]
comment.Content = ""
comment.Label = nil
comment.Aggregator = nil
comment.Assignee = nil
comment.AssigneeID = -1
comment.AssigneeTeam = nil
comment.AssigneeTeamID = -1
comment.RemovedAssignee = false
comment.AddedLabels = nil
comment.RemovedLabels = nil
@ -245,42 +245,38 @@ func (agg *CommentAggregator) createAggregatedComment(issue *Issue, final bool)
// instead of an aggregator
if agg.OnlyLabelsChanged() {
comment.Type = CommentTypeLabel
} else if agg.OnlyClosedReopened() {
if agg.IsClosed {
comment.Type = CommentTypeClose
} else {
comment.Type = CommentTypeReopen
}
} else if agg.OnlyRequestReview() {
comment.Type = CommentTypeReviewRequest
} else {
comment.Type = CommentTypeAggregator
comment.Aggregator = &new_agg
comment.Aggregator = &newAgg
}
if len(new_agg.AddedLabels) > 0 {
comment.AddedLabels = new_agg.AddedLabels
if len(newAgg.AddedLabels) > 0 {
comment.AddedLabels = newAgg.AddedLabels
}
if len(new_agg.RemovedLabels) > 0 {
comment.RemovedLabels = new_agg.RemovedLabels
if len(newAgg.RemovedLabels) > 0 {
comment.RemovedLabels = newAgg.RemovedLabels
}
if len(new_agg.AddedRequestReview) > 0 {
comment.AddedRequestReview = new_agg.AddedRequestReview
if len(newAgg.AddedRequestReview) > 0 {
comment.AddedRequestReview = newAgg.AddedRequestReview
}
if len(new_agg.RemovedRequestReview) > 0 {
comment.RemovedRequestReview = new_agg.RemovedRequestReview
if len(newAgg.RemovedRequestReview) > 0 {
comment.RemovedRequestReview = newAgg.RemovedRequestReview
}
if final {
log.Warn("Case 3: [:%v] + [%v]", startind, comment.Type)
issue.Comments = append(issue.Comments[:startind], comment)
} else {
log.Warn("Case 4: [:%v] + [%v] + [%v:]", startind, comment.Type, endind + 1)
issue.Comments = append(append(issue.Comments[:startind], comment), issue.Comments[endind+1:]...)
}
return endind - startind
@ -288,29 +284,25 @@ func (agg *CommentAggregator) createAggregatedComment(issue *Issue, final bool)
// combineCommentsHistory combines nearby elements in the history as one
func CombineCommentsHistory(issue *Issue) {
log.Warn("=== START ===")
// Initialise a new empty aggregator, ready to combine comments
var agg CommentAggregator;
var agg CommentAggregator
agg.StartUnix = 0
agg.PosterID = -1
req_reset := false
reqReset := false
for i := 0; i < len(issue.Comments); i++ {
cur := issue.Comments[i]
log.Warn("%v %v %v", i, cur.Type, int64(cur.CreatedUnix) - agg.StartUnix)
if req_reset {
if reqReset {
agg.Reset(cur)
req_reset = false
reqReset = false
}
// If the comment we encounter is not accepted inside an aggregator
if !agg.IsAggregated(&cur.Type) {
// If we aggregated some data, create the resulting comment for it
if len(agg.Indexes) > 1 {
if len(agg.Indexes) > 0 {
i -= agg.createAggregatedComment(issue, false)
}
req_reset = true
reqReset = true
// Do not need to continue the aggregation loop, skip to next comment
continue
@ -320,7 +312,7 @@ func CombineCommentsHistory(issue *Issue) {
// we create a new empty aggregator
if ((int64(cur.CreatedUnix) - agg.StartUnix) > 60) || (cur.PosterID != agg.PosterID) {
// First, create the aggregated comment if there's data in it
if len(agg.Indexes) > 1 {
if len(agg.Indexes) > 0 {
i -= agg.createAggregatedComment(issue, false)
}
agg.Reset(cur)
@ -330,34 +322,7 @@ func CombineCommentsHistory(issue *Issue) {
}
// Create the aggregated comment if there's data in it
if !req_reset && len(agg.Indexes) > 1 {
if !reqReset && len(agg.Indexes) > 0 {
agg.createAggregatedComment(issue, true)
}
log.Warn("=== END ===")
}
type ReqReviewTarget struct {
User *user_model.User
Team *organization.Team
}
func (t *ReqReviewTarget) ID() int64 {
if t.User != nil {
return t.User.ID
}
return t.Team.ID
}
func (t *ReqReviewTarget) Name() string {
if t.User != nil {
return t.User.GetDisplayName()
}
return t.Team.Name
}
func (t *ReqReviewTarget) Type() string {
if t.User != nil {
return "user"
}
return "team"
}

File diff suppressed because it is too large Load diff

View file

@ -524,7 +524,7 @@
</div>
</div>
{{else if eq .Type 27}}
{{if or .AddedRequestReview .RemovedRequestReview}}
{{if or .AddedRequestReview .RemovedRequestReview}}
<div class="timeline-item event" id="{{.HashTag}}">
<span class="badge">{{svg "octicon-tag"}}</span>
{{template "shared/user/avatarlink" dict "user" .Poster}}
@ -540,7 +540,7 @@
{{end}}
</span>
</div>
{{end}}
{{end}}
{{else if and (eq .Type 29) (or (gt .CommitsNum 0) .IsForcePush)}}
<!-- If PR is closed, the comments whose type is CommentTypePullRequestPush(29) after latestCloseCommentID won't be rendered. //-->
{{if and .Issue.IsClosed (gt .ID $.LatestCloseCommentID)}}
@ -683,12 +683,12 @@
<span class="text grey muted-links">
{{template "shared/user/authorlink" .Poster}}
{{ $createdStr }}
{{$createdStr}}
<ul class="comment-aggregator">
<!-- OPEN / CLOSE -->
{{if and .Aggregator.PrevClosed (not .Aggregator.IsClosed) }}
{{if and .Aggregator.PrevClosed (not .Aggregator.IsClosed)}}
<li>
<span class="badge tw-bg-green tw-text-white">{{svg "octicon-dot-fill"}}</span>
{{if .Issue.IsPull}}