Skip to content

Commit 2c0e19d

Browse files
authored
Merge branch 'main' into private-readme
2 parents bc5718d + c09656e commit 2c0e19d

File tree

11 files changed

+144
-72
lines changed

11 files changed

+144
-72
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ _test
99

1010
# IntelliJ
1111
.idea
12+
13+
# IntelliJ Gateway
14+
.uuid
15+
1216
# Goland's output filename can not be set manually
1317
/go_build_*
1418
/gitea_*

models/issues/comment.go

Lines changed: 53 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,20 @@ func (t CommentType) HasMailReplySupport() bool {
197197
return false
198198
}
199199

200+
func (t CommentType) CountedAsConversation() bool {
201+
for _, ct := range ConversationCountedCommentType() {
202+
if t == ct {
203+
return true
204+
}
205+
}
206+
return false
207+
}
208+
209+
// ConversationCountedCommentType returns the comment types that are counted as a conversation
210+
func ConversationCountedCommentType() []CommentType {
211+
return []CommentType{CommentTypeComment, CommentTypeReview}
212+
}
213+
200214
// RoleInRepo presents the user's participation in the repo
201215
type RoleInRepo string
202216

@@ -592,26 +606,26 @@ func (c *Comment) LoadAttachments(ctx context.Context) error {
592606
return nil
593607
}
594608

595-
// UpdateAttachments update attachments by UUIDs for the comment
596-
func (c *Comment) UpdateAttachments(ctx context.Context, uuids []string) error {
597-
ctx, committer, err := db.TxContext(ctx)
598-
if err != nil {
599-
return err
600-
}
601-
defer committer.Close()
602-
603-
attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, uuids)
604-
if err != nil {
605-
return fmt.Errorf("getAttachmentsByUUIDs [uuids: %v]: %w", uuids, err)
609+
// UpdateCommentAttachments update attachments by UUIDs for the comment
610+
func UpdateCommentAttachments(ctx context.Context, c *Comment, uuids []string) error {
611+
if len(uuids) == 0 {
612+
return nil
606613
}
607-
for i := 0; i < len(attachments); i++ {
608-
attachments[i].IssueID = c.IssueID
609-
attachments[i].CommentID = c.ID
610-
if err := repo_model.UpdateAttachment(ctx, attachments[i]); err != nil {
611-
return fmt.Errorf("update attachment [id: %d]: %w", attachments[i].ID, err)
614+
return db.WithTx(ctx, func(ctx context.Context) error {
615+
attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, uuids)
616+
if err != nil {
617+
return fmt.Errorf("getAttachmentsByUUIDs [uuids: %v]: %w", uuids, err)
612618
}
613-
}
614-
return committer.Commit()
619+
for i := 0; i < len(attachments); i++ {
620+
attachments[i].IssueID = c.IssueID
621+
attachments[i].CommentID = c.ID
622+
if err := repo_model.UpdateAttachment(ctx, attachments[i]); err != nil {
623+
return fmt.Errorf("update attachment [id: %d]: %w", attachments[i].ID, err)
624+
}
625+
}
626+
c.Attachments = attachments
627+
return nil
628+
})
615629
}
616630

617631
// LoadAssigneeUserAndTeam if comment.Type is CommentTypeAssignees, then load assignees
@@ -878,7 +892,7 @@ func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment
878892
// Check comment type.
879893
switch opts.Type {
880894
case CommentTypeCode:
881-
if err = updateAttachments(ctx, opts, comment); err != nil {
895+
if err = UpdateCommentAttachments(ctx, comment, opts.Attachments); err != nil {
882896
return err
883897
}
884898
if comment.ReviewID != 0 {
@@ -893,12 +907,12 @@ func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment
893907
}
894908
fallthrough
895909
case CommentTypeComment:
896-
if _, err = db.Exec(ctx, "UPDATE `issue` SET num_comments=num_comments+1 WHERE id=?", opts.Issue.ID); err != nil {
910+
if err := UpdateIssueNumComments(ctx, opts.Issue.ID); err != nil {
897911
return err
898912
}
899913
fallthrough
900914
case CommentTypeReview:
901-
if err = updateAttachments(ctx, opts, comment); err != nil {
915+
if err = UpdateCommentAttachments(ctx, comment, opts.Attachments); err != nil {
902916
return err
903917
}
904918
case CommentTypeReopen, CommentTypeClose:
@@ -910,23 +924,6 @@ func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment
910924
return UpdateIssueCols(ctx, opts.Issue, "updated_unix")
911925
}
912926

913-
func updateAttachments(ctx context.Context, opts *CreateCommentOptions, comment *Comment) error {
914-
attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, opts.Attachments)
915-
if err != nil {
916-
return fmt.Errorf("getAttachmentsByUUIDs [uuids: %v]: %w", opts.Attachments, err)
917-
}
918-
for i := range attachments {
919-
attachments[i].IssueID = opts.Issue.ID
920-
attachments[i].CommentID = comment.ID
921-
// No assign value could be 0, so ignore AllCols().
922-
if _, err = db.GetEngine(ctx).ID(attachments[i].ID).Update(attachments[i]); err != nil {
923-
return fmt.Errorf("update attachment [%d]: %w", attachments[i].ID, err)
924-
}
925-
}
926-
comment.Attachments = attachments
927-
return nil
928-
}
929-
930927
func createDeadlineComment(ctx context.Context, doer *user_model.User, issue *Issue, newDeadlineUnix timeutil.TimeStamp) (*Comment, error) {
931928
var content string
932929
var commentType CommentType
@@ -1182,8 +1179,8 @@ func DeleteComment(ctx context.Context, comment *Comment) error {
11821179
return err
11831180
}
11841181

1185-
if comment.Type == CommentTypeComment {
1186-
if _, err := e.ID(comment.IssueID).Decr("num_comments").Update(new(Issue)); err != nil {
1182+
if comment.Type.CountedAsConversation() {
1183+
if err := UpdateIssueNumComments(ctx, comment.IssueID); err != nil {
11871184
return err
11881185
}
11891186
}
@@ -1300,6 +1297,21 @@ func (c *Comment) HasOriginalAuthor() bool {
13001297
return c.OriginalAuthor != "" && c.OriginalAuthorID != 0
13011298
}
13021299

1300+
func UpdateIssueNumCommentsBuilder(issueID int64) *builder.Builder {
1301+
subQuery := builder.Select("COUNT(*)").From("`comment`").Where(
1302+
builder.Eq{"issue_id": issueID}.And(
1303+
builder.In("`type`", ConversationCountedCommentType()),
1304+
))
1305+
1306+
return builder.Update(builder.Eq{"num_comments": subQuery}).
1307+
From("`issue`").Where(builder.Eq{"id": issueID})
1308+
}
1309+
1310+
func UpdateIssueNumComments(ctx context.Context, issueID int64) error {
1311+
_, err := db.GetEngine(ctx).Exec(UpdateIssueNumCommentsBuilder(issueID))
1312+
return err
1313+
}
1314+
13031315
// InsertIssueComments inserts many comments of issues.
13041316
func InsertIssueComments(ctx context.Context, comments []*Comment) error {
13051317
if len(comments) == 0 {
@@ -1332,8 +1344,7 @@ func InsertIssueComments(ctx context.Context, comments []*Comment) error {
13321344
}
13331345

13341346
for _, issueID := range issueIDs {
1335-
if _, err := db.Exec(ctx, "UPDATE issue set num_comments = (SELECT count(*) FROM comment WHERE issue_id = ? AND `type`=?) WHERE id = ?",
1336-
issueID, CommentTypeComment, issueID); err != nil {
1347+
if err := UpdateIssueNumComments(ctx, issueID); err != nil {
13371348
return err
13381349
}
13391350
}

models/issues/comment_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,24 @@ func TestCreateComment(t *testing.T) {
4545
unittest.AssertInt64InRange(t, now, then, int64(updatedIssue.UpdatedUnix))
4646
}
4747

48+
func Test_UpdateCommentAttachment(t *testing.T) {
49+
assert.NoError(t, unittest.PrepareTestDatabase())
50+
51+
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 1})
52+
attachment := repo_model.Attachment{
53+
Name: "test.txt",
54+
}
55+
assert.NoError(t, db.Insert(db.DefaultContext, &attachment))
56+
57+
err := issues_model.UpdateCommentAttachments(db.DefaultContext, comment, []string{attachment.UUID})
58+
assert.NoError(t, err)
59+
60+
attachment2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: attachment.ID})
61+
assert.EqualValues(t, attachment.Name, attachment2.Name)
62+
assert.EqualValues(t, comment.ID, attachment2.CommentID)
63+
assert.EqualValues(t, comment.IssueID, attachment2.IssueID)
64+
}
65+
4866
func TestFetchCodeComments(t *testing.T) {
4967
assert.NoError(t, unittest.PrepareTestDatabase())
5068

@@ -97,3 +115,12 @@ func TestMigrate_InsertIssueComments(t *testing.T) {
97115

98116
unittest.CheckConsistencyFor(t, &issues_model.Issue{})
99117
}
118+
119+
func Test_UpdateIssueNumComments(t *testing.T) {
120+
assert.NoError(t, unittest.PrepareTestDatabase())
121+
issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
122+
123+
assert.NoError(t, issues_model.UpdateIssueNumComments(db.DefaultContext, issue2.ID))
124+
issue2 = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
125+
assert.EqualValues(t, 1, issue2.NumComments)
126+
}

models/issues/issue_update.go

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -405,19 +405,10 @@ func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssue
405405
return err
406406
}
407407

408-
if len(opts.Attachments) > 0 {
409-
attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, opts.Attachments)
410-
if err != nil {
411-
return fmt.Errorf("getAttachmentsByUUIDs [uuids: %v]: %w", opts.Attachments, err)
412-
}
413-
414-
for i := 0; i < len(attachments); i++ {
415-
attachments[i].IssueID = opts.Issue.ID
416-
if _, err = e.ID(attachments[i].ID).Update(attachments[i]); err != nil {
417-
return fmt.Errorf("update attachment [id: %d]: %w", attachments[i].ID, err)
418-
}
419-
}
408+
if err := UpdateIssueAttachments(ctx, opts.Issue.ID, opts.Attachments); err != nil {
409+
return err
420410
}
411+
421412
if err = opts.Issue.LoadAttributes(ctx); err != nil {
422413
return err
423414
}

models/issues/review.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,10 @@ func InsertReviews(ctx context.Context, reviews []*Review) error {
639639
return err
640640
}
641641
}
642+
643+
if err := UpdateIssueNumComments(ctx, review.IssueID); err != nil {
644+
return err
645+
}
642646
}
643647

644648
return committer.Commit()

models/repo.go

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import (
1616
"code.gitea.io/gitea/models/unit"
1717
user_model "code.gitea.io/gitea/models/user"
1818
"code.gitea.io/gitea/modules/log"
19+
20+
"xorm.io/builder"
1921
)
2022

2123
// Init initialize model
@@ -24,7 +26,7 @@ func Init(ctx context.Context) error {
2426
}
2527

2628
type repoChecker struct {
27-
querySQL func(ctx context.Context) ([]map[string][]byte, error)
29+
querySQL func(ctx context.Context) ([]int64, error)
2830
correctSQL func(ctx context.Context, id int64) error
2931
desc string
3032
}
@@ -35,8 +37,7 @@ func repoStatsCheck(ctx context.Context, checker *repoChecker) {
3537
log.Error("Select %s: %v", checker.desc, err)
3638
return
3739
}
38-
for _, result := range results {
39-
id, _ := strconv.ParseInt(string(result["id"]), 10, 64)
40+
for _, id := range results {
4041
select {
4142
case <-ctx.Done():
4243
log.Warn("CheckRepoStats: Cancelled before checking %s for with id=%d", checker.desc, id)
@@ -51,21 +52,23 @@ func repoStatsCheck(ctx context.Context, checker *repoChecker) {
5152
}
5253
}
5354

54-
func StatsCorrectSQL(ctx context.Context, sql string, id int64) error {
55-
_, err := db.GetEngine(ctx).Exec(sql, id, id)
55+
func StatsCorrectSQL(ctx context.Context, sql any, ids ...any) error {
56+
args := []any{sql}
57+
args = append(args, ids...)
58+
_, err := db.GetEngine(ctx).Exec(args...)
5659
return err
5760
}
5861

5962
func repoStatsCorrectNumWatches(ctx context.Context, id int64) error {
60-
return StatsCorrectSQL(ctx, "UPDATE `repository` SET num_watches=(SELECT COUNT(*) FROM `watch` WHERE repo_id=? AND mode<>2) WHERE id=?", id)
63+
return StatsCorrectSQL(ctx, "UPDATE `repository` SET num_watches=(SELECT COUNT(*) FROM `watch` WHERE repo_id=? AND mode<>2) WHERE id=?", id, id)
6164
}
6265

6366
func repoStatsCorrectNumStars(ctx context.Context, id int64) error {
64-
return StatsCorrectSQL(ctx, "UPDATE `repository` SET num_stars=(SELECT COUNT(*) FROM `star` WHERE repo_id=?) WHERE id=?", id)
67+
return StatsCorrectSQL(ctx, "UPDATE `repository` SET num_stars=(SELECT COUNT(*) FROM `star` WHERE repo_id=?) WHERE id=?", id, id)
6568
}
6669

6770
func labelStatsCorrectNumIssues(ctx context.Context, id int64) error {
68-
return StatsCorrectSQL(ctx, "UPDATE `label` SET num_issues=(SELECT COUNT(*) FROM `issue_label` WHERE label_id=?) WHERE id=?", id)
71+
return StatsCorrectSQL(ctx, "UPDATE `label` SET num_issues=(SELECT COUNT(*) FROM `issue_label` WHERE label_id=?) WHERE id=?", id, id)
6972
}
7073

7174
func labelStatsCorrectNumIssuesRepo(ctx context.Context, id int64) error {
@@ -102,11 +105,11 @@ func milestoneStatsCorrectNumIssuesRepo(ctx context.Context, id int64) error {
102105
}
103106

104107
func userStatsCorrectNumRepos(ctx context.Context, id int64) error {
105-
return StatsCorrectSQL(ctx, "UPDATE `user` SET num_repos=(SELECT COUNT(*) FROM `repository` WHERE owner_id=?) WHERE id=?", id)
108+
return StatsCorrectSQL(ctx, "UPDATE `user` SET num_repos=(SELECT COUNT(*) FROM `repository` WHERE owner_id=?) WHERE id=?", id, id)
106109
}
107110

108111
func repoStatsCorrectIssueNumComments(ctx context.Context, id int64) error {
109-
return StatsCorrectSQL(ctx, "UPDATE `issue` SET num_comments=(SELECT COUNT(*) FROM `comment` WHERE issue_id=? AND type=0) WHERE id=?", id)
112+
return StatsCorrectSQL(ctx, issues_model.UpdateIssueNumCommentsBuilder(id))
110113
}
111114

112115
func repoStatsCorrectNumIssues(ctx context.Context, id int64) error {
@@ -125,9 +128,12 @@ func repoStatsCorrectNumClosedPulls(ctx context.Context, id int64) error {
125128
return repo_model.UpdateRepoIssueNumbers(ctx, id, true, true)
126129
}
127130

128-
func statsQuery(args ...any) func(context.Context) ([]map[string][]byte, error) {
129-
return func(ctx context.Context) ([]map[string][]byte, error) {
130-
return db.GetEngine(ctx).Query(args...)
131+
// statsQuery returns a function that queries the database for a list of IDs
132+
// sql could be a string or a *builder.Builder
133+
func statsQuery(sql any, args ...any) func(context.Context) ([]int64, error) {
134+
return func(ctx context.Context) ([]int64, error) {
135+
var ids []int64
136+
return ids, db.GetEngine(ctx).SQL(sql, args...).Find(&ids)
131137
}
132138
}
133139

@@ -198,7 +204,16 @@ func CheckRepoStats(ctx context.Context) error {
198204
},
199205
// Issue.NumComments
200206
{
201-
statsQuery("SELECT `issue`.id FROM `issue` WHERE `issue`.num_comments!=(SELECT COUNT(*) FROM `comment` WHERE issue_id=`issue`.id AND type=0)"),
207+
statsQuery(builder.Select("`issue`.id").From("`issue`").Where(
208+
builder.Neq{
209+
"`issue`.num_comments": builder.Select("COUNT(*)").From("`comment`").Where(
210+
builder.Expr("issue_id = `issue`.id").And(
211+
builder.In("type", issues_model.ConversationCountedCommentType()),
212+
),
213+
),
214+
},
215+
),
216+
),
202217
repoStatsCorrectIssueNumComments,
203218
"issue count 'num_comments'",
204219
},

models/repo_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"testing"
88

99
"code.gitea.io/gitea/models/db"
10+
issues_model "code.gitea.io/gitea/models/issues"
1011
"code.gitea.io/gitea/models/unittest"
1112

1213
"github.com/stretchr/testify/assert"
@@ -22,3 +23,16 @@ func TestDoctorUserStarNum(t *testing.T) {
2223

2324
assert.NoError(t, DoctorUserStarNum(db.DefaultContext))
2425
}
26+
27+
func Test_repoStatsCorrectIssueNumComments(t *testing.T) {
28+
assert.NoError(t, unittest.PrepareTestDatabase())
29+
30+
issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
31+
assert.NotNil(t, issue2)
32+
assert.EqualValues(t, 0, issue2.NumComments) // the fixture data is wrong, but we don't fix it here
33+
34+
assert.NoError(t, repoStatsCorrectIssueNumComments(db.DefaultContext, 2))
35+
// reload the issue
36+
issue2 = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
37+
assert.EqualValues(t, 1, issue2.NumComments)
38+
}

routers/web/repo/issue.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ func updateAttachments(ctx *context.Context, item any, files []string) error {
602602
case *issues_model.Issue:
603603
err = issues_model.UpdateIssueAttachments(ctx, content.ID, files)
604604
case *issues_model.Comment:
605-
err = content.UpdateAttachments(ctx, files)
605+
err = issues_model.UpdateCommentAttachments(ctx, content, files)
606606
default:
607607
return fmt.Errorf("unknown Type: %T", content)
608608
}

services/pull/merge_squash.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package pull
55

66
import (
77
"fmt"
8+
"strings"
89

910
repo_model "code.gitea.io/gitea/models/repo"
1011
user_model "code.gitea.io/gitea/models/user"
@@ -65,7 +66,10 @@ func doMergeStyleSquash(ctx *mergeContext, message string) error {
6566

6667
if setting.Repository.PullRequest.AddCoCommitterTrailers && ctx.committer.String() != sig.String() {
6768
// add trailer
68-
message += fmt.Sprintf("\nCo-authored-by: %s\nCo-committed-by: %s\n", sig.String(), sig.String())
69+
if !strings.Contains(message, fmt.Sprintf("Co-authored-by: %s", sig.String())) {
70+
message += fmt.Sprintf("\nCo-authored-by: %s", sig.String())
71+
}
72+
message += fmt.Sprintf("\nCo-committed-by: %s\n", sig.String())
6973
}
7074
cmdCommit := git.NewCommand(ctx, "commit").
7175
AddOptionFormat("--author='%s <%s>'", sig.Name, sig.Email).

0 commit comments

Comments
 (0)