From 18c65965abea6a97d075678edd55cf9eccc561a9 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Thu, 19 Mar 2026 07:13:55 +0800 Subject: [PATCH] Fix various trivial problems (#36921) * Fix #36915 * Fix #36919 * Close #36600 * Close #36601 * Fix incorrect oauth2 error message display --- go.mod | 2 +- models/issues/pull.go | 7 ++++--- models/migrations/base/db.go | 14 ++++++------- modules/markup/common/linkify.go | 3 ++- routers/web/auth/oauth.go | 2 +- services/issue/pull.go | 4 +++- services/repository/files/tree.go | 35 ++++++++----------------------- 7 files changed, 27 insertions(+), 40 deletions(-) diff --git a/go.mod b/go.mod index f0bb361f2d..24c18d5703 100644 --- a/go.mod +++ b/go.mod @@ -37,6 +37,7 @@ require ( github.com/charmbracelet/git-lfs-transfer v0.1.1-0.20251013092601-6327009efd21 github.com/chi-middleware/proxy v1.1.1 github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21 + github.com/dlclark/regexp2 v1.11.5 github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 github.com/dustin/go-humanize v1.0.1 github.com/editorconfig/editorconfig-core-go/v2 v2.6.4 @@ -183,7 +184,6 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davidmz/go-pageant v1.0.2 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/dlclark/regexp2 v1.11.5 // indirect github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6 // indirect github.com/fatih/color v1.18.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect diff --git a/models/issues/pull.go b/models/issues/pull.go index 9f180f9ac9..c07044f301 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -9,7 +9,6 @@ import ( "errors" "fmt" "io" - "regexp" "strings" "code.gitea.io/gitea/models/db" @@ -24,6 +23,7 @@ import ( "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" + "github.com/dlclark/regexp2" "xorm.io/builder" ) @@ -861,7 +861,7 @@ func GetCodeOwnersFromContent(ctx context.Context, data string) ([]*CodeOwnerRul } type CodeOwnerRule struct { - Rule *regexp.Regexp + Rule *regexp2.Regexp // it supports negative lookahead, does better for end users Negative bool Users []*user_model.User Teams []*org_model.Team @@ -877,7 +877,8 @@ func ParseCodeOwnersLine(ctx context.Context, tokens []string) (*CodeOwnerRule, warnings := make([]string, 0) - rule.Rule, err = regexp.Compile(fmt.Sprintf("^%s$", strings.TrimPrefix(tokens[0], "!"))) + expr := fmt.Sprintf("^%s$", strings.TrimPrefix(tokens[0], "!")) + rule.Rule, err = regexp2.Compile(expr, regexp2.None) if err != nil { warnings = append(warnings, fmt.Sprintf("incorrect codeowner regexp: %s", err)) return nil, warnings diff --git a/models/migrations/base/db.go b/models/migrations/base/db.go index 3b8f0e00a0..16048c2073 100644 --- a/models/migrations/base/db.go +++ b/models/migrations/base/db.go @@ -402,7 +402,7 @@ func DropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin cols += "DROP COLUMN `" + col + "` CASCADE" } if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` %s", tableName, cols)); err != nil { - return fmt.Errorf("Drop table `%s` columns %v: %v", tableName, columnNames, err) + return fmt.Errorf("drop table `%s` columns %v: %w", tableName, columnNames, err) } case setting.Database.Type.IsMySQL(): // Drop indexes on columns first @@ -430,7 +430,7 @@ func DropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin cols += "DROP COLUMN `" + col + "`" } if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` %s", tableName, cols)); err != nil { - return fmt.Errorf("Drop table `%s` columns %v: %v", tableName, columnNames, err) + return fmt.Errorf("drop table `%s` columns %v: %w", tableName, columnNames, err) } case setting.Database.Type.IsMSSQL(): cols := "" @@ -444,27 +444,27 @@ func DropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin tableName, strings.ReplaceAll(cols, "`", "'")) constraints := make([]string, 0) if err := sess.SQL(sql).Find(&constraints); err != nil { - return fmt.Errorf("Find constraints: %v", err) + return fmt.Errorf("find constraints: %w", err) } for _, constraint := range constraints { if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` DROP CONSTRAINT `%s`", tableName, constraint)); err != nil { - return fmt.Errorf("Drop table `%s` default constraint `%s`: %v", tableName, constraint, err) + return fmt.Errorf("drop table `%s` default constraint `%s`: %w", tableName, constraint, err) } } sql = fmt.Sprintf("SELECT DISTINCT Name FROM sys.indexes INNER JOIN sys.index_columns ON indexes.index_id = index_columns.index_id AND indexes.object_id = index_columns.object_id WHERE indexes.object_id = OBJECT_ID('%[1]s') AND index_columns.column_id IN (SELECT column_id FROM sys.columns WHERE LOWER(name) IN (%[2]s) AND object_id = OBJECT_ID('%[1]s'))", tableName, strings.ReplaceAll(cols, "`", "'")) constraints = make([]string, 0) if err := sess.SQL(sql).Find(&constraints); err != nil { - return fmt.Errorf("Find constraints: %v", err) + return fmt.Errorf("find constraints: %w", err) } for _, constraint := range constraints { if _, err := sess.Exec(fmt.Sprintf("DROP INDEX `%[2]s` ON `%[1]s`", tableName, constraint)); err != nil { - return fmt.Errorf("Drop index `%[2]s` on `%[1]s`: %v", tableName, constraint, err) + return fmt.Errorf("drop index `%[2]s` on `%[1]s`: %[3]w", tableName, constraint, err) } } if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` DROP COLUMN %s", tableName, cols)); err != nil { - return fmt.Errorf("Drop table `%s` columns %v: %v", tableName, columnNames, err) + return fmt.Errorf("drop table `%s` columns %v: %w", tableName, columnNames, err) } default: log.Fatal("Unrecognized DB") diff --git a/modules/markup/common/linkify.go b/modules/markup/common/linkify.go index aff1813803..54e40a02d6 100644 --- a/modules/markup/common/linkify.go +++ b/modules/markup/common/linkify.go @@ -96,6 +96,7 @@ func (s *linkifyParser) Parse(parent ast.Node, block text.Reader, pc parser.Cont m[1] -= closing } } else if lastChar == ';' { + // exclude HTML entity reference, e.g.: exclude " " from "http://example.com?foo=1 " i := m[1] - 2 for ; i >= m[0]; i-- { if util.IsAlphaNumeric(line[i]) { @@ -105,7 +106,7 @@ func (s *linkifyParser) Parse(parent ast.Node, block text.Reader, pc parser.Cont } if i != m[1]-2 { if line[i] == '&' { - m[1] -= m[1] - i + m[1] = i } } } diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index bb0784e434..3b1744669d 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -118,7 +118,7 @@ func SignInOAuthCallback(ctx *context.Context) { return } if err, ok := err.(*go_oauth2.RetrieveError); ok { - ctx.Flash.Error("OAuth2 RetrieveError: "+err.Error(), true) + ctx.Flash.Error("OAuth2 RetrieveError: " + err.Error()) ctx.Redirect(setting.AppSubURL + "/user/login") return } diff --git a/services/issue/pull.go b/services/issue/pull.go index 778bbefc28..f415ebe759 100644 --- a/services/issue/pull.go +++ b/services/issue/pull.go @@ -95,7 +95,9 @@ func PullRequestCodeOwnersReview(ctx context.Context, pr *issues_model.PullReque uniqTeams := make(map[string]*org_model.Team) for _, rule := range rules { for _, f := range changedFiles { - if (rule.Rule.MatchString(f) && !rule.Negative) || (!rule.Rule.MatchString(f) && rule.Negative) { + shouldMatch := !rule.Negative + matched, _ := rule.Rule.MatchString(f) // err only happens when timeouts, any error can be considered as not matched + if matched == shouldMatch { for _, u := range rule.Users { uniqUsers[u.ID] = u } diff --git a/services/repository/files/tree.go b/services/repository/files/tree.go index e481a3e7d2..e678b07f56 100644 --- a/services/repository/files/tree.go +++ b/services/repository/files/tree.go @@ -61,33 +61,18 @@ func GetTreeBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git return nil, err } apiURL := repo.APIURL() - apiURLLen := len(apiURL) - objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName) - hashLen := objectFormat.FullLength() - - const gitBlobsPath = "/git/blobs/" - blobURL := make([]byte, apiURLLen+hashLen+len(gitBlobsPath)) - copy(blobURL, apiURL) - copy(blobURL[apiURLLen:], []byte(gitBlobsPath)) - - const gitTreePath = "/git/trees/" - treeURL := make([]byte, apiURLLen+hashLen+len(gitTreePath)) - copy(treeURL, apiURL) - copy(treeURL[apiURLLen:], []byte(gitTreePath)) - - // copyPos is at the start of the hash - copyPos := len(treeURL) - hashLen + blobURLBase := apiURL + "/git/blobs/" + treeURLBase := apiURL + "/git/trees/" if perPage <= 0 || perPage > setting.API.DefaultGitTreesPerPage { perPage = setting.API.DefaultGitTreesPerPage } - if page <= 0 { - page = 1 - } + page = max(page, 1) + tree.Page = page tree.TotalCount = len(entries) - rangeStart := perPage * (page - 1) - if rangeStart >= len(entries) { + rangeStart := perPage * (page - 1) // int might overflow + if rangeStart < 0 || rangeStart >= len(entries) { return tree, nil } rangeEnd := min(rangeStart+perPage, len(entries)) @@ -103,16 +88,14 @@ func GetTreeBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git tree.Entries[i].SHA = entries[e].ID.String() if entries[e].IsDir() { - copy(treeURL[copyPos:], entries[e].ID.String()) - tree.Entries[i].URL = string(treeURL) + tree.Entries[i].URL = treeURLBase + entries[e].ID.String() } else if entries[e].IsSubModule() { - // In Github Rest API Version=2022-11-28, if a tree entry is a submodule, + // In GitHub Rest API Version=2022-11-28, if a tree entry is a submodule, // its url will be returned as an empty string. // So the URL will be set to "" here. tree.Entries[i].URL = "" } else { - copy(blobURL[copyPos:], entries[e].ID.String()) - tree.Entries[i].URL = string(blobURL) + tree.Entries[i].URL = blobURLBase + entries[e].ID.String() } } return tree, nil