Skip to content

Doctor: Add FixUpdatableCodeCommentReplies #13436

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

22 changes: 22 additions & 0 deletions cmd/doctor.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,31 @@ var checklist = []check{
isDefault: false,
f: runDoctorEnablePushOptions,
},
{
title: "Recalculate Code-comment-replies commitID",
name: "recalculate_code_comment_replies",
isDefault: true,
f: runDoctorUpdateCodeCommentReplies,
},
// more checks please append here
}

func runDoctorUpdateCodeCommentReplies(ctx *cli.Context) ([]string, error) {
if ctx.Bool("fix") {
_, result, err := models.CountOrFixUpdatableCodeCommentReplies(true)
if err != nil {
return nil, err
}
return result, nil
}
count, _, err := models.CountOrFixUpdatableCodeCommentReplies(false)
if err != nil {
return nil, err
}
result := fmt.Sprintf("%d code comment replies without commitID exist", count)
return []string{result}, nil
}

func runRecreateTable(ctx *cli.Context) error {
// Redirect the default golog to here
golog.SetFlags(0)
Expand Down
93 changes: 93 additions & 0 deletions models/consistency.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
package models

import (
"fmt"
"reflect"
"strconv"
"strings"
"testing"

"code.gitea.io/gitea/modules/setting"

"github.com/stretchr/testify/assert"
"xorm.io/builder"
)
Expand Down Expand Up @@ -295,3 +299,92 @@ func FixNullArchivedRepository() (int64, error) {
IsArchived: false,
})
}

// CountOrFixUpdatableCodeCommentReplies count or fix CodeCommentReplies missing the CommitSHA
func CountOrFixUpdatableCodeCommentReplies(fix bool) (int64, []string, error) {

var (
start = 0
batchSize = 100
sqlCmd string
count int64
result []string
)

sqlSelect := `SELECT comment.id as id, first.commit_sha as commit_sha, first.patch as patch, first.invalidated as invalidated`
sqlTail := ` FROM comment INNER JOIN (
SELECT C.id, C.review_id, C.line, C.tree_path, C.patch, C.commit_sha, C.invalidated
FROM comment AS C
WHERE C.type = 21
AND C.created_unix =
(SELECT MIN(comment.created_unix)
FROM comment
WHERE comment.review_id = C.review_id
AND comment.type = 21
AND comment.line = C.line
AND comment.tree_path = C.tree_path)
) AS first
ON comment.review_id = first.review_id
AND comment.tree_path = first.tree_path AND comment.line = first.line
WHERE comment.type = 21
AND comment.id != first.id
AND comment.commit_sha != first.commit_sha`

sess := x.NewSession()
defer sess.Close()
for {
if err := sess.Begin(); err != nil {
return 0, nil, err
}

if setting.Database.UseMSSQL {
if _, err := sess.Exec(sqlSelect + " INTO #temp_comments" + sqlTail); err != nil {
return 0, nil, fmt.Errorf("unable to create temporary table")
}
}

var comments = make([]*Comment, 0, batchSize)

switch {
case setting.Database.UseMySQL:
sqlCmd = sqlSelect + sqlTail + " LIMIT " + strconv.Itoa(batchSize) + ", " + strconv.Itoa(start)
case setting.Database.UsePostgreSQL:
fallthrough
case setting.Database.UseSQLite3:
sqlCmd = sqlSelect + sqlTail + " LIMIT " + strconv.Itoa(batchSize) + " OFFSET " + strconv.Itoa(start)
case setting.Database.UseMSSQL:
sqlCmd = "SELECT TOP " + strconv.Itoa(batchSize) + " * FROM #temp_comments WHERE " +
"(id NOT IN ( SELECT TOP " + strconv.Itoa(start) + " id FROM #temp_comments ORDER BY id )) ORDER BY id"
default:
return 0, nil, fmt.Errorf("Unsupported database type")
}

if err := sess.SQL(sqlCmd).Find(&comments); err != nil {
return 0, nil, fmt.Errorf("failed to select: %v", err)
}

if fix {
for _, comment := range comments {
if _, err := sess.Table("comment").ID(comment.ID).Cols("commit_sha", "patch", "invalidated").Update(comment); err != nil {
return 0, nil, fmt.Errorf("failed to update comment[%d]: %v %v", comment.ID, comment, err)
}
result = append(result, fmt.Sprintf("update comment[%d]: %s\n", comment.ID, comment.CommitSHA))
}
}

count += int64(len(comments))
start += len(comments)

if fix {
if err := sess.Commit(); err != nil {
return count, result, err
}
}

if len(comments) < batchSize {
break
}
}

return count, result, nil
}