diff --git a/.golangci.yml b/.golangci.yml index de3f3a9255..fea9195be2 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -15,6 +15,7 @@ linters: - govet - importas - ineffassign + - modernize - nakedret - nolintlint - revive diff --git a/cmd/cert.go b/cmd/cert.go index baadcbda85..516ac4ce84 100644 --- a/cmd/cert.go +++ b/cmd/cert.go @@ -150,8 +150,8 @@ func runCert(ctx context.Context, c *cli.Command) error { BasicConstraintsValid: true, } - hosts := strings.Split(c.String("host"), ",") - for _, h := range hosts { + hosts := strings.SplitSeq(c.String("host"), ",") + for h := range hosts { if ip := net.ParseIP(h); ip != nil { template.IPAddresses = append(template.IPAddresses, ip) } else { diff --git a/cmd/dump.go b/cmd/dump.go index b94277e529..25459c7731 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -12,6 +12,7 @@ import ( "os" "path" "path/filepath" + "slices" "strings" "sync" "time" @@ -83,11 +84,9 @@ func (o outputType) Join() string { } func (o *outputType) Set(value string) error { - for _, enum := range o.Enum { - if enum == value { - o.selected = value - return nil - } + if slices.Contains(o.Enum, value) { + o.selected = value + return nil } return fmt.Errorf("allowed values are %s", o.Join()) @@ -250,8 +249,8 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error { setupConsoleLogger(log.FATAL, log.CanColorStderr, os.Stderr) } else { for _, suffix := range outputTypeEnum.Enum { - if strings.HasSuffix(fileName, "."+suffix) { - fileName = strings.TrimSuffix(fileName, "."+suffix) + if before, ok := strings.CutSuffix(fileName, "."+suffix); ok { + fileName = before break } } @@ -330,14 +329,12 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error { go dumpDatabase(ctx, archiveJobs, &wg, verbose) if len(setting.CustomConf) > 0 { - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { log.Info("Adding custom configuration file from %s", setting.CustomConf) if err := addFile(archiveJobs, "app.ini", setting.CustomConf, verbose); err != nil { fatal("Failed to include specified app.ini: %v", err) } - }() + }) } if ctx.IsSet("skip-custom-dir") && ctx.Bool("skip-custom-dir") { @@ -361,15 +358,13 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error { if ctx.IsSet("skip-attachment-data") && ctx.Bool("skip-attachment-data") { log.Info("Skipping attachment data") } else { - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { if err := storage.Attachments.IterateObjects("", func(objPath string, object storage.Object) error { return addObject(archiveJobs, object, path.Join("data", "attachments", objPath), verbose) }); err != nil { fatal("Failed to dump attachments: %v", err) } - }() + }) } if ctx.IsSet("skip-package-data") && ctx.Bool("skip-package-data") { @@ -377,15 +372,13 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error { } else if !setting.Packages.Enabled { log.Info("Package registry not enabled - skipping") } else { - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { if err := storage.Packages.IterateObjects("", func(objPath string, object storage.Object) error { return addObject(archiveJobs, object, path.Join("data", "packages", objPath), verbose) }); err != nil { fatal("Failed to dump packages: %v", err) } - }() + }) } // Doesn't check if LogRootPath exists before processing --skip-log intentionally, @@ -399,13 +392,11 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error { log.Error("Failed to check if %s exists: %v", setting.Log.RootPath, err) } if isExist { - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { if err := addRecursiveExclude(archiveJobs, "log", setting.Log.RootPath, []string{absFileName}, verbose); err != nil { fatal("Failed to include log: %v", err) } - }() + }) } } diff --git a/cmd/dump_repo.go b/cmd/dump_repo.go index 8e0ef0311f..60fffe1226 100644 --- a/cmd/dump_repo.go +++ b/cmd/dump_repo.go @@ -143,8 +143,8 @@ func runDumpRepository(stdCtx context.Context, ctx *cli.Command) error { opts.PullRequests = true opts.ReleaseAssets = true } else { - units := strings.Split(ctx.String("units"), ",") - for _, unit := range units { + units := strings.SplitSeq(ctx.String("units"), ",") + for unit := range units { switch strings.ToLower(strings.TrimSpace(unit)) { case "": continue diff --git a/models/actions/status.go b/models/actions/status.go index 1f6aa5e890..7f06b6231b 100644 --- a/models/actions/status.go +++ b/models/actions/status.go @@ -4,6 +4,8 @@ package actions import ( + "slices" + "forgejo.org/modules/translation" runnerv1 "code.forgejo.org/forgejo/actions-proto/runner/v1" @@ -107,12 +109,7 @@ func (s Status) IsBlocked() bool { // In returns whether s is one of the given statuses func (s Status) In(statuses ...Status) bool { - for _, v := range statuses { - if s == v { - return true - } - } - return false + return slices.Contains(statuses, s) } func (s Status) AsResult() runnerv1.Result { diff --git a/models/activities/action.go b/models/activities/action.go index 8fd7709e81..6b3fabfae0 100644 --- a/models/activities/action.go +++ b/models/activities/action.go @@ -132,12 +132,7 @@ func (at ActionType) String() string { } func (at ActionType) InActions(actions ...string) bool { - for _, action := range actions { - if action == at.String() { - return true - } - } - return false + return slices.Contains(actions, at.String()) } // Action represents user operation type and other information to diff --git a/models/activities/notification_list.go b/models/activities/notification_list.go index 02206b1d6b..bf6356021e 100644 --- a/models/activities/notification_list.go +++ b/models/activities/notification_list.go @@ -213,10 +213,7 @@ func (nl NotificationList) LoadRepos(ctx context.Context) (repo_model.Repository repos := make(map[int64]*repo_model.Repository, len(repoIDs)) left := len(repoIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) rows, err := db.GetEngine(ctx). In("id", repoIDs[:limit]). Rows(new(repo_model.Repository)) @@ -287,10 +284,7 @@ func (nl NotificationList) LoadIssues(ctx context.Context) ([]int, error) { issues := make(map[int64]*issues_model.Issue, len(issueIDs)) left := len(issueIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) rows, err := db.GetEngine(ctx). In("id", issueIDs[:limit]). Rows(new(issues_model.Issue)) @@ -382,10 +376,7 @@ func (nl NotificationList) LoadUsers(ctx context.Context) ([]int, error) { users := make(map[int64]*user_model.User, len(userIDs)) left := len(userIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) rows, err := db.GetEngine(ctx). In("id", userIDs[:limit]). Rows(new(user_model.User)) @@ -433,10 +424,7 @@ func (nl NotificationList) LoadComments(ctx context.Context) ([]int, error) { comments := make(map[int64]*issues_model.Comment, len(commentIDs)) left := len(commentIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) rows, err := db.GetEngine(ctx). In("id", commentIDs[:limit]). Rows(new(issues_model.Comment)) diff --git a/models/activities/repo_activity.go b/models/activities/repo_activity.go index 3d15c22e19..0b9522be1b 100644 --- a/models/activities/repo_activity.go +++ b/models/activities/repo_activity.go @@ -138,10 +138,7 @@ func GetActivityStatsTopAuthors(ctx context.Context, repo *repo_model.Repository return v[i].Commits > v[j].Commits }) - cnt := count - if cnt > len(v) { - cnt = len(v) - } + cnt := min(count, len(v)) return v[:cnt], nil } diff --git a/models/auth/access_token_scope.go b/models/auth/access_token_scope.go index d14838cf02..6dc143b122 100644 --- a/models/auth/access_token_scope.go +++ b/models/auth/access_token_scope.go @@ -5,6 +5,7 @@ package auth import ( "fmt" + "slices" "strings" "forgejo.org/models/perm" @@ -204,12 +205,7 @@ func GetRequiredScopes(level AccessTokenScopeLevel, scopeCategories ...AccessTok // ContainsCategory checks if a list of categories contains a specific category func ContainsCategory(categories []AccessTokenScopeCategory, category AccessTokenScopeCategory) bool { - for _, c := range categories { - if c == category { - return true - } - } - return false + return slices.Contains(categories, category) } // GetScopeLevelFromAccessMode converts permission access mode to scope level diff --git a/models/auth/oauth2.go b/models/auth/oauth2.go index fa68197cf0..9acd9a46b0 100644 --- a/models/auth/oauth2.go +++ b/models/auth/oauth2.go @@ -505,7 +505,7 @@ func (grant *OAuth2Grant) IncreaseCounter(ctx context.Context) error { // ScopeContains returns true if the grant scope contains the specified scope func (grant *OAuth2Grant) ScopeContains(scope string) bool { - for _, currentScope := range strings.Split(grant.Scope, " ") { + for currentScope := range strings.SplitSeq(grant.Scope, " ") { if scope == currentScope { return true } diff --git a/models/db/iterate.go b/models/db/iterate.go index d2315cb12c..c56871d503 100644 --- a/models/db/iterate.go +++ b/models/db/iterate.go @@ -80,7 +80,7 @@ func Iterate[Bean any](ctx context.Context, cond builder.Cond, f func(ctx contex func extractFieldValue(bean any, fieldName string) any { v := reflect.ValueOf(bean) - if v.Kind() == reflect.Ptr { + if v.Kind() == reflect.Pointer { v = v.Elem() } field := v.FieldByName(fieldName) diff --git a/models/db/name.go b/models/db/name.go index d456f49d9c..efd1c2b5f3 100644 --- a/models/db/name.go +++ b/models/db/name.go @@ -6,6 +6,7 @@ package db import ( "fmt" "regexp" + "slices" "strings" "unicode/utf8" @@ -114,10 +115,8 @@ func IsUsableName(names, patterns []string, name string) error { return ErrNameEmpty } - for i := range names { - if name == names[i] { - return ErrNameReserved{name} - } + if slices.Contains(names, name) { + return ErrNameReserved{name} } for _, pat := range patterns { diff --git a/models/dbfs/dbfile.go b/models/dbfs/dbfile.go index 8cd64177dd..7e7c58cc6c 100644 --- a/models/dbfs/dbfile.go +++ b/models/dbfs/dbfile.go @@ -46,10 +46,7 @@ func (f *file) readAt(fileMeta *DbfsMeta, offset int64, p []byte) (n int, err er blobPos := int(offset % f.blockSize) blobOffset := offset - int64(blobPos) blobRemaining := int(f.blockSize) - blobPos - needRead := len(p) - if needRead > blobRemaining { - needRead = blobRemaining - } + needRead := min(len(p), blobRemaining) if blobOffset+int64(blobPos)+int64(needRead) > fileMeta.FileSize { needRead = int(fileMeta.FileSize - blobOffset - int64(blobPos)) } @@ -66,14 +63,8 @@ func (f *file) readAt(fileMeta *DbfsMeta, offset int64, p []byte) (n int, err er blobData = nil } - canCopy := len(blobData) - blobPos - if canCopy <= 0 { - canCopy = 0 - } - realRead := needRead - if realRead > canCopy { - realRead = canCopy - } + canCopy := max(len(blobData)-blobPos, 0) + realRead := min(needRead, canCopy) if realRead > 0 { copy(p[:realRead], fileData.BlobData[blobPos:blobPos+realRead]) } @@ -113,10 +104,7 @@ func (f *file) Write(p []byte) (n int, err error) { blobPos := int(f.offset % f.blockSize) blobOffset := f.offset - int64(blobPos) blobRemaining := int(f.blockSize) - blobPos - needWrite := len(p) - if needWrite > blobRemaining { - needWrite = blobRemaining - } + needWrite := min(len(p), blobRemaining) buf := make([]byte, f.blockSize) readBytes, err := f.readAt(fileMeta, blobOffset, buf) if err != nil && !errors.Is(err, io.EOF) { diff --git a/models/git/protected_branch.go b/models/git/protected_branch.go index c1eb750230..3eaada2fdd 100644 --- a/models/git/protected_branch.go +++ b/models/git/protected_branch.go @@ -213,7 +213,7 @@ func (protectBranch *ProtectedBranch) GetUnprotectedFilePatterns() []glob.Glob { func getFilePatterns(filePatterns string) []glob.Glob { extarr := make([]glob.Glob, 0, 10) - for _, expr := range strings.Split(strings.ToLower(filePatterns), ";") { + for expr := range strings.SplitSeq(strings.ToLower(filePatterns), ";") { expr = strings.TrimSpace(expr) if expr != "" { if g, err := glob.Compile(expr, '.', '/'); err != nil { diff --git a/models/gitea_migrations/test/tests.go b/models/gitea_migrations/test/tests.go index fc54b65626..086127a2e8 100644 --- a/models/gitea_migrations/test/tests.go +++ b/models/gitea_migrations/test/tests.go @@ -265,7 +265,7 @@ func deleteDB() error { func removeAllWithRetry(dir string) error { var err error - for i := 0; i < 20; i++ { + for range 20 { err = os.RemoveAll(dir) if err == nil { break diff --git a/models/gitea_migrations/v1_11/v111.go b/models/gitea_migrations/v1_11/v111.go index fcd2ee7be3..59ca416af0 100644 --- a/models/gitea_migrations/v1_11/v111.go +++ b/models/gitea_migrations/v1_11/v111.go @@ -5,6 +5,7 @@ package v1_11 import ( "fmt" + "slices" "xorm.io/xorm" ) @@ -345,10 +346,8 @@ func AddBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error { } return AccessModeWrite <= perm.UnitsMode[UnitTypeCode], nil } - for _, id := range protectedBranch.ApprovalsWhitelistUserIDs { - if id == reviewer.ID { - return true, nil - } + if slices.Contains(protectedBranch.ApprovalsWhitelistUserIDs, reviewer.ID) { + return true, nil } // isUserInTeams diff --git a/models/gitea_migrations/v1_11/v115.go b/models/gitea_migrations/v1_11/v115.go index 65094df93d..84364e310b 100644 --- a/models/gitea_migrations/v1_11/v115.go +++ b/models/gitea_migrations/v1_11/v115.go @@ -146,7 +146,7 @@ func copyOldAvatarToNewLocation(userID int64, oldAvatar string) (string, error) return "", fmt.Errorf("io.ReadAll: %w", err) } - newAvatar := fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%d-%x", userID, md5.Sum(data))))) + newAvatar := fmt.Sprintf("%x", md5.Sum(fmt.Appendf(nil, "%d-%x", userID, md5.Sum(data)))) if newAvatar == oldAvatar { return newAvatar, nil } diff --git a/models/gitea_migrations/v1_20/v259.go b/models/gitea_migrations/v1_20/v259.go index 9b2b68263e..1ae8b2e30f 100644 --- a/models/gitea_migrations/v1_20/v259.go +++ b/models/gitea_migrations/v1_20/v259.go @@ -329,7 +329,7 @@ func ConvertScopedAccessTokens(x *xorm.Engine) error { for _, token := range tokens { var scopes []string allNewScopesMap := make(map[AccessTokenScope]bool) - for _, oldScope := range strings.Split(token.Scope, ",") { + for oldScope := range strings.SplitSeq(token.Scope, ",") { if newScopes, exists := accessTokenScopeMap[OldAccessTokenScope(oldScope)]; exists { for _, newScope := range newScopes { allNewScopesMap[newScope] = true diff --git a/models/issues/comment.go b/models/issues/comment.go index 325fcbe30b..fd0f595945 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -9,6 +9,7 @@ import ( "context" "fmt" "html/template" + "slices" "strconv" "unicode/utf8" @@ -198,12 +199,7 @@ func (t CommentType) HasMailReplySupport() bool { } func (t CommentType) CountedAsConversation() bool { - for _, ct := range ConversationCountedCommentType() { - if t == ct { - return true - } - } - return false + return slices.Contains(ConversationCountedCommentType(), t) } // ConversationCountedCommentType returns the comment types that are counted as a conversation @@ -619,7 +615,7 @@ func (c *Comment) UpdateAttachments(ctx context.Context, uuids []string) error { if err != nil { return fmt.Errorf("FindRepoAttachmentsByUUID[uuids=%q,repoID=%d]: %w", uuids, c.Issue.RepoID, err) } - for i := 0; i < len(attachments); i++ { + for i := range attachments { attachments[i].IssueID = c.IssueID attachments[i].CommentID = c.ID if err := repo_model.UpdateAttachment(ctx, attachments[i]); err != nil { diff --git a/models/issues/comment_list.go b/models/issues/comment_list.go index 3996dcb29a..53903bea31 100644 --- a/models/issues/comment_list.go +++ b/models/issues/comment_list.go @@ -54,10 +54,7 @@ func (comments CommentList) loadLabels(ctx context.Context) error { commentLabels := make(map[int64]*Label, len(labelIDs)) left := len(labelIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) rows, err := db.GetEngine(ctx). In("id", labelIDs[:limit]). Rows(new(Label)) @@ -104,10 +101,7 @@ func (comments CommentList) loadMilestones(ctx context.Context) error { milestones := make(map[int64]*Milestone, len(milestoneIDs)) left := len(milestoneIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) err := db.GetEngine(ctx). In("id", milestoneIDs[:limit]). Find(&milestones) @@ -143,10 +137,7 @@ func (comments CommentList) loadOldMilestones(ctx context.Context) error { milestones := make(map[int64]*Milestone, len(milestoneIDs)) left := len(milestoneIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) err := db.GetEngine(ctx). In("id", milestoneIDs[:limit]). Find(&milestones) @@ -178,10 +169,7 @@ func (comments CommentList) loadAssignees(ctx context.Context) error { assignees := make(map[int64]*user_model.User, len(assigneeIDs)) left := len(assigneeIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) rows, err := db.GetEngine(ctx). In("id", assigneeIDs[:limit]). Rows(new(user_model.User)) @@ -246,10 +234,7 @@ func (comments CommentList) LoadIssues(ctx context.Context) error { issues := make(map[int64]*Issue, len(issueIDs)) left := len(issueIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) rows, err := db.GetEngine(ctx). In("id", issueIDs[:limit]). Rows(new(Issue)) @@ -300,10 +285,7 @@ func (comments CommentList) loadDependentIssues(ctx context.Context) error { issues := make(map[int64]*Issue, len(issueIDs)) left := len(issueIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) rows, err := e. In("id", issueIDs[:limit]). Rows(new(Issue)) @@ -379,10 +361,7 @@ func (comments CommentList) LoadAttachments(ctx context.Context) (err error) { commentsIDs := comments.getAttachmentCommentIDs() left := len(commentsIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) rows, err := db.GetEngine(ctx). In("comment_id", commentsIDs[:limit]). Rows(new(repo_model.Attachment)) diff --git a/models/issues/issue_list.go b/models/issues/issue_list.go index 5a02baa428..34cfe35475 100644 --- a/models/issues/issue_list.go +++ b/models/issues/issue_list.go @@ -43,10 +43,7 @@ func (issues IssueList) LoadRepositories(ctx context.Context) (repo_model.Reposi repoMaps := make(map[int64]*repo_model.Repository, len(repoIDs)) left := len(repoIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) err := db.GetEngine(ctx). In("id", repoIDs[:limit]). Find(&repoMaps) @@ -99,10 +96,7 @@ func getPostersByIDs(ctx context.Context, posterIDs []int64) (map[int64]*user_mo posterMaps := make(map[int64]*user_model.User, len(posterIDs)) left := len(posterIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) err := db.GetEngine(ctx). In("id", posterIDs[:limit]). Find(&posterMaps) @@ -137,10 +131,7 @@ func (issues IssueList) LoadLabels(ctx context.Context) error { issueIDs := issues.getIssueIDs() left := len(issueIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) rows, err := db.GetEngine(ctx).Table("label"). Join("LEFT", "issue_label", "issue_label.label_id = label.id"). In("issue_label.issue_id", issueIDs[:limit]). @@ -192,10 +183,7 @@ func (issues IssueList) LoadMilestones(ctx context.Context) error { milestoneMaps := make(map[int64]*Milestone, len(milestoneIDs)) left := len(milestoneIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) err := db.GetEngine(ctx). In("id", milestoneIDs[:limit]). Find(&milestoneMaps) @@ -224,10 +212,7 @@ func (issues IssueList) LoadProjects(ctx context.Context) error { } for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) projects := make([]*projectWithIssueID, 0, limit) err := db.GetEngine(ctx). @@ -266,10 +251,7 @@ func (issues IssueList) LoadAssignees(ctx context.Context) error { issueIDs := issues.getIssueIDs() left := len(issueIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) rows, err := db.GetEngine(ctx).Table("issue_assignees"). Join("INNER", "`user`", "`user`.id = `issue_assignees`.assignee_id"). In("`issue_assignees`.issue_id", issueIDs[:limit]).OrderBy(user_model.GetOrderByName()). @@ -327,10 +309,7 @@ func (issues IssueList) LoadPullRequests(ctx context.Context) error { pullRequestMaps := make(map[int64]*PullRequest, len(issuesIDs)) left := len(issuesIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) rows, err := db.GetEngine(ctx). In("issue_id", issuesIDs[:limit]). Rows(new(PullRequest)) @@ -375,10 +354,7 @@ func (issues IssueList) LoadAttachments(ctx context.Context) (err error) { issuesIDs := issues.getIssueIDs() left := len(issuesIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) rows, err := db.GetEngine(ctx). In("issue_id", issuesIDs[:limit]). Rows(new(repo_model.Attachment)) @@ -420,10 +396,7 @@ func (issues IssueList) loadComments(ctx context.Context, cond builder.Cond) (er issuesIDs := issues.getIssueIDs() left := len(issuesIDs) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) rows, err := db.GetEngine(ctx).Table("comment"). Join("INNER", "issue", "issue.id = comment.issue_id"). In("issue.id", issuesIDs[:limit]). @@ -486,10 +459,7 @@ func (issues IssueList) loadTotalTrackedTimes(ctx context.Context) (err error) { left := len(ids) for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } + limit := min(left, db.DefaultMaxInSize) // select issue_id, sum(time) from tracked_time where issue_id in () group by issue_id rows, err := db.GetEngine(ctx).Table("tracked_time"). diff --git a/models/issues/issue_stats.go b/models/issues/issue_stats.go index 2fd2641d92..03660803a4 100644 --- a/models/issues/issue_stats.go +++ b/models/issues/issue_stats.go @@ -94,10 +94,7 @@ func GetIssueStats(ctx context.Context, opts *IssuesOptions) (*IssueStats, error // ids in a temporary table and join from them. accum := &IssueStats{} for i := 0; i < len(opts.IssueIDs); { - chunk := i + MaxQueryParameters - if chunk > len(opts.IssueIDs) { - chunk = len(opts.IssueIDs) - } + chunk := min(i+MaxQueryParameters, len(opts.IssueIDs)) stats, err := getIssueStatsChunk(ctx, opts, opts.IssueIDs[i:chunk]) if err != nil { return nil, err diff --git a/models/issues/issue_test.go b/models/issues/issue_test.go index e9617548e9..0c5da6a2aa 100644 --- a/models/issues/issue_test.go +++ b/models/issues/issue_test.go @@ -5,6 +5,7 @@ package issues_test import ( "fmt" + "slices" "sort" "sync" "testing" @@ -311,7 +312,7 @@ func TestIssue_ResolveMentions(t *testing.T) { for i, user := range resolved { ids[i] = user.ID } - sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] }) + slices.Sort(ids) assert.Equal(t, expected, ids) } @@ -338,7 +339,7 @@ func TestResourceIndex(t *testing.T) { require.NoError(t, err) var wg sync.WaitGroup - for i := 0; i < 100; i++ { + for i := range 100 { wg.Add(1) t.Run(fmt.Sprintf("issue %d", i+1), func(t *testing.T) { t.Parallel() @@ -369,7 +370,7 @@ func TestCorrectIssueStats(t *testing.T) { issueAmount := issues_model.MaxQueryParameters + 10 var wg sync.WaitGroup - for i := 0; i < issueAmount; i++ { + for i := range issueAmount { wg.Add(1) go func(i int) { testInsertIssue(t, fmt.Sprintf("Issue %d", i+1), "Bugs are nasty", 0) diff --git a/models/issues/issue_update.go b/models/issues/issue_update.go index 22e6fcb8d4..35f69e3a0b 100644 --- a/models/issues/issue_update.go +++ b/models/issues/issue_update.go @@ -244,7 +244,7 @@ func UpdateIssueAttachments(ctx context.Context, issue *Issue, uuids []string) ( if err != nil { return fmt.Errorf("FindRepoAttachmentsByUUID[uuids=%q,repoID=%d]: %w", uuids, issue.RepoID, err) } - for i := 0; i < len(attachments); i++ { + for i := range attachments { attachments[i].IssueID = issue.ID if err := repo_model.UpdateAttachment(ctx, attachments[i]); err != nil { return fmt.Errorf("update attachment [id: %d]: %w", attachments[i].ID, err) diff --git a/models/issues/review_list.go b/models/issues/review_list.go index 04c08bc5c4..878ceac9ce 100644 --- a/models/issues/review_list.go +++ b/models/issues/review_list.go @@ -20,7 +20,7 @@ type ReviewList []*Review // LoadReviewers loads reviewers func (reviews ReviewList) LoadReviewers(ctx context.Context) error { reviewerIDs := make([]int64, len(reviews)) - for i := 0; i < len(reviews); i++ { + for i := range reviews { reviewerIDs[i] = reviews[i].ReviewerID } reviewers, err := user_model.GetPossibleUserByIDs(ctx, reviewerIDs) diff --git a/models/issues/tracked_time.go b/models/issues/tracked_time.go index 2f050759d2..54173681bd 100644 --- a/models/issues/tracked_time.go +++ b/models/issues/tracked_time.go @@ -350,10 +350,7 @@ func GetIssueTotalTrackedTime(ctx context.Context, opts *IssuesOptions, isClosed // we get the statistics in smaller chunks and get accumulates var accum int64 for i := 0; i < len(opts.IssueIDs); { - chunk := i + MaxQueryParameters - if chunk > len(opts.IssueIDs) { - chunk = len(opts.IssueIDs) - } + chunk := min(i+MaxQueryParameters, len(opts.IssueIDs)) time, err := getIssueTotalTrackedTimeChunk(ctx, opts, isClosed, opts.IssueIDs[i:chunk]) if err != nil { return 0, err diff --git a/models/perm/access/repo_permission.go b/models/perm/access/repo_permission.go index 22639d1e42..fd1b93c867 100644 --- a/models/perm/access/repo_permission.go +++ b/models/perm/access/repo_permission.go @@ -6,6 +6,7 @@ package access import ( "context" "fmt" + "strings" actions_model "forgejo.org/models/actions" "forgejo.org/models/db" @@ -115,7 +116,8 @@ func (p *Permission) CanWriteIssuesOrPulls(isPull bool) bool { } func (p *Permission) LogString() string { - format := "") + return fmt.Sprintf(format.String(), args...) } func GetActionRepoPermission(ctx context.Context, repo *repo_model.Repository, task *actions_model.ActionTask) (Permission, error) { diff --git a/models/project/column_test.go b/models/project/column_test.go index aef7a6f9d4..2f4cc79367 100644 --- a/models/project/column_test.go +++ b/models/project/column_test.go @@ -164,7 +164,7 @@ func Test_NewColumn(t *testing.T) { require.NoError(t, err) assert.Len(t, columns, 3) - for i := 0; i < maxProjectColumns-3; i++ { + for i := range maxProjectColumns - 3 { err := NewColumn(db.DefaultContext, &Column{ Title: fmt.Sprintf("column-%d", i+4), ProjectID: project1.ID, diff --git a/models/pull/review_state.go b/models/pull/review_state.go index 2702d5d5a1..3fc3ab65c2 100644 --- a/models/pull/review_state.go +++ b/models/pull/review_state.go @@ -6,6 +6,7 @@ package pull import ( "context" "fmt" + "maps" "forgejo.org/models/db" "forgejo.org/modules/log" @@ -100,9 +101,7 @@ func mergeFiles(oldFiles, newFiles map[string]ViewedState) map[string]ViewedStat return oldFiles } - for file, viewed := range newFiles { - oldFiles[file] = viewed - } + maps.Copy(oldFiles, newFiles) return oldFiles } diff --git a/models/repo/repo.go b/models/repo/repo.go index cdb30aa1a9..0c45f483e4 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "html/template" + "maps" "net" "net/url" "path/filepath" @@ -543,9 +544,7 @@ func (repo *Repository) ComposeMetas(ctx context.Context) map[string]string { func (repo *Repository) ComposeDocumentMetas(ctx context.Context) map[string]string { if len(repo.DocumentRenderingMetas) == 0 { metas := map[string]string{} - for k, v := range repo.ComposeMetas(ctx) { - metas[k] = v - } + maps.Copy(metas, repo.ComposeMetas(ctx)) metas["mode"] = "document" repo.DocumentRenderingMetas = metas } @@ -786,8 +785,8 @@ func GetRepositoryByName(ctx context.Context, ownerID int64, name string) (*Repo // getRepositoryURLPathSegments returns segments (owner, reponame) extracted from a url func getRepositoryURLPathSegments(repoURL string) []string { - if strings.HasPrefix(repoURL, setting.AppURL) { - return strings.Split(strings.TrimPrefix(repoURL, setting.AppURL), "/") + if after, ok := strings.CutPrefix(repoURL, setting.AppURL); ok { + return strings.Split(after, "/") } sshURLVariants := [4]string{ @@ -798,8 +797,8 @@ func getRepositoryURLPathSegments(repoURL string) []string { } for _, sshURL := range sshURLVariants { - if strings.HasPrefix(repoURL, sshURL) { - return strings.Split(strings.TrimPrefix(repoURL, sshURL), "/") + if after, ok := strings.CutPrefix(repoURL, sshURL); ok { + return strings.Split(after, "/") } } diff --git a/models/repo/repo_list.go b/models/repo/repo_list.go index 732d7b627c..daa60c81e9 100644 --- a/models/repo/repo_list.go +++ b/models/repo/repo_list.go @@ -401,7 +401,7 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { if opts.Keyword != "" { // separate keyword subQueryCond := builder.NewCond() - for _, v := range strings.Split(opts.Keyword, ",") { + for v := range strings.SplitSeq(opts.Keyword, ",") { if opts.TopicOnly { subQueryCond = subQueryCond.Or(builder.Eq{"topic.name": strings.ToLower(v)}) } else { @@ -416,7 +416,7 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { keywordCond := builder.In("id", subQuery) if !opts.TopicOnly { likes := builder.NewCond() - for _, v := range strings.Split(opts.Keyword, ",") { + for v := range strings.SplitSeq(opts.Keyword, ",") { likes = likes.Or(builder.Like{"lower_name", strings.ToLower(v)}) // If the string looks like "org/repo", match against that pattern too diff --git a/models/repo/repo_unit.go b/models/repo/repo_unit.go index aa6f2fa0ae..3db6dc95e8 100644 --- a/models/repo/repo_unit.go +++ b/models/repo/repo_unit.go @@ -237,10 +237,8 @@ func (cfg *ActionsConfig) IsWorkflowDisabled(file string) bool { } func (cfg *ActionsConfig) DisableWorkflow(file string) { - for _, workflow := range cfg.DisabledWorkflows { - if file == workflow { - return - } + if slices.Contains(cfg.DisabledWorkflows, file) { + return } cfg.DisabledWorkflows = append(cfg.DisabledWorkflows, file) diff --git a/models/repo/upload.go b/models/repo/upload.go index a213cb1986..67b5409650 100644 --- a/models/repo/upload.go +++ b/models/repo/upload.go @@ -117,7 +117,7 @@ func DeleteUploads(ctx context.Context, uploads ...*Upload) (err error) { defer committer.Close() ids := make([]int64, len(uploads)) - for i := 0; i < len(uploads); i++ { + for i := range uploads { ids[i] = uploads[i].ID } if err = db.DeleteByIDs[Upload](ctx, ids...); err != nil { diff --git a/models/unit/unit.go b/models/unit/unit.go index 434e5f0acc..2a31c804aa 100644 --- a/models/unit/unit.go +++ b/models/unit/unit.go @@ -248,22 +248,12 @@ func LoadUnitConfig() error { // UnitGlobalDisabled checks if unit type is global disabled func (u Type) UnitGlobalDisabled() bool { - for _, ud := range DisabledRepoUnitsGet() { - if u == ud { - return true - } - } - return false + return slices.Contains(DisabledRepoUnitsGet(), u) } // CanBeDefault checks if the unit type can be a default repo unit func (u *Type) CanBeDefault() bool { - for _, nadU := range NotAllowedDefaultRepoUnits { - if *u == nadU { - return false - } - } - return true + return !slices.Contains(NotAllowedDefaultRepoUnits, *u) } // Unit is a section of one repository diff --git a/models/unittest/fixture_loader.go b/models/unittest/fixture_loader.go index 5aea06550c..3cf2efdced 100644 --- a/models/unittest/fixture_loader.go +++ b/models/unittest/fixture_loader.go @@ -151,8 +151,8 @@ func (l *loader) buildFixtureFile(fixturePath string) (*fixtureFile, error) { switch v := value.(type) { case string: // Try to decode hex. - if strings.HasPrefix(v, "0x") { - value, err = hex.DecodeString(strings.TrimPrefix(v, "0x")) + if after, ok := strings.CutPrefix(v, "0x"); ok { + value, err = hex.DecodeString(after) if err != nil { return nil, err } diff --git a/models/unittest/mock_http.go b/models/unittest/mock_http.go index b8413104b3..5e420533d8 100644 --- a/models/unittest/mock_http.go +++ b/models/unittest/mock_http.go @@ -102,13 +102,13 @@ func NewMockWebServer(t *testing.T, liveServerBaseURL, testDataDir string, liveM // parse back the fixture file into a series of HTTP headers followed by response body lines := strings.Split(stringFixture, "\n") for idx, line := range lines { - colonIndex := strings.Index(line, ": ") - if colonIndex != -1 { + before, after, ok := strings.Cut(line, ": ") + if ok { // Because we modified the body with ReplaceAll() above, we need to // remove Content-Length. w.Write() should add it back. - header := line[0:colonIndex] + header := before if !strings.EqualFold(header, "Content-Length") { - w.Header().Set(line[0:colonIndex], line[colonIndex+2:]) + w.Header().Set(before, after) } } else { // we reached the end of the headers (empty line), so what follows is the body diff --git a/models/unittest/reflection.go b/models/unittest/reflection.go index 141fc66b99..939891283d 100644 --- a/models/unittest/reflection.go +++ b/models/unittest/reflection.go @@ -9,7 +9,7 @@ import ( ) func fieldByName(v reflect.Value, field string) reflect.Value { - if v.Kind() == reflect.Ptr { + if v.Kind() == reflect.Pointer { v = v.Elem() } f := v.FieldByName(field) diff --git a/models/user/avatar.go b/models/user/avatar.go index cc1b1b7b9d..726d67f5e0 100644 --- a/models/user/avatar.go +++ b/models/user/avatar.go @@ -108,7 +108,7 @@ func (u *User) IsUploadAvatarChanged(data []byte) bool { if !u.UseCustomAvatar || len(u.Avatar) == 0 { return true } - avatarID := fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%d-%x", u.ID, md5.Sum(data))))) + avatarID := fmt.Sprintf("%x", md5.Sum(fmt.Appendf(nil, "%d-%x", u.ID, md5.Sum(data)))) return u.Avatar != avatarID } diff --git a/models/user/email_address_test.go b/models/user/email_address_test.go index 85f5b16c65..35b33933c2 100644 --- a/models/user/email_address_test.go +++ b/models/user/email_address_test.go @@ -5,6 +5,7 @@ package user_test import ( "fmt" + "slices" "testing" "forgejo.org/models/db" @@ -77,12 +78,7 @@ func TestListEmails(t *testing.T) { assert.Greater(t, count, int64(5)) contains := func(match func(s *user_model.SearchEmailResult) bool) bool { - for _, v := range emails { - if match(v) { - return true - } - } - return false + return slices.ContainsFunc(emails, match) } assert.True(t, contains(func(s *user_model.SearchEmailResult) bool { return s.UID == 18 })) diff --git a/models/user/moderation.go b/models/user/moderation.go index 7bc857489a..765414acc0 100644 --- a/models/user/moderation.go +++ b/models/user/moderation.go @@ -87,7 +87,7 @@ func newUserData(user *User) UserData { // (e.g. FieldName -> field_name) corresponding to UserData struct fields. var userDataColumnNames = sync.OnceValue(func() []string { mapper := new(names.GonicMapper) - udType := reflect.TypeOf(UserData{}) + udType := reflect.TypeFor[UserData]() columnNames := make([]string, 0, udType.NumField()) for i := 0; i < udType.NumField(); i++ { columnNames = append(columnNames, mapper.Obj2Table(udType.Field(i).Name)) diff --git a/models/user/user.go b/models/user/user.go index 7e2101d7cc..2c20cd977d 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -1243,8 +1243,8 @@ func GetUserByEmail(ctx context.Context, email string) (*User, error) { } // Finally, if email address is the protected email address: - if strings.HasSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) { - username := strings.TrimSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) + if before, ok := strings.CutSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)); ok { + username := before user := &User{} has, err := db.GetEngine(ctx).Where("lower_name=?", username).Get(user) if err != nil { diff --git a/models/user/user_test.go b/models/user/user_test.go index d1af3a750f..6da645d672 100644 --- a/models/user/user_test.go +++ b/models/user/user_test.go @@ -273,9 +273,9 @@ func TestHashPasswordDeterministic(t *testing.T) { b := make([]byte, 16) u := &user_model.User{} algos := hash.RecommendedHashAlgorithms - for j := 0; j < len(algos); j++ { + for j := range algos { u.PasswdHashAlgo = algos[j] - for i := 0; i < 50; i++ { + for range 50 { // generate a random password rand.Read(b) pass := string(b) diff --git a/models/webhook/webhook.go b/models/webhook/webhook.go index b23f3fd348..196a5313bc 100644 --- a/models/webhook/webhook.go +++ b/models/webhook/webhook.go @@ -429,7 +429,7 @@ func CreateWebhooks(ctx context.Context, ws []*Webhook) error { if len(ws) == 0 { return nil } - for i := 0; i < len(ws); i++ { + for i := range ws { ws[i].Type = strings.TrimSpace(ws[i].Type) } return db.Insert(ctx, ws) diff --git a/modules/actions/workflows.go b/modules/actions/workflows.go index 99c9446805..ed54ccc98b 100644 --- a/modules/actions/workflows.go +++ b/modules/actions/workflows.go @@ -7,6 +7,7 @@ import ( "bytes" "fmt" "io" + "slices" "strings" actions_model "forgejo.org/models/actions" @@ -609,11 +610,8 @@ func matchPullRequestReviewEvent(prPayload *api.PullRequestPayload, evt *jobpars matched := false for _, val := range vals { - for _, action := range actions { - if glob.MustCompile(val, '/').Match(action) { - matched = true - break - } + if slices.ContainsFunc(actions, glob.MustCompile(val, '/').Match) { + matched = true } if matched { break @@ -658,11 +656,8 @@ func matchPullRequestReviewCommentEvent(prPayload *api.PullRequestPayload, evt * matched := false for _, val := range vals { - for _, action := range actions { - if glob.MustCompile(val, '/').Match(action) { - matched = true - break - } + if slices.ContainsFunc(actions, glob.MustCompile(val, '/').Match) { + matched = true } if matched { break diff --git a/modules/auth/password/password.go b/modules/auth/password/password.go index fdbc4ff291..744a431ea8 100644 --- a/modules/auth/password/password.go +++ b/modules/auth/password/password.go @@ -101,7 +101,7 @@ func Generate(n int) (string, error) { buffer := make([]byte, n) max := big.NewInt(int64(len(validChars))) for { - for j := 0; j < n; j++ { + for j := range n { rnd, err := rand.Int(rand.Reader, max) if err != nil { return "", err diff --git a/modules/auth/password/password_test.go b/modules/auth/password/password_test.go index 1fe3fb5ce1..8f5d64514c 100644 --- a/modules/auth/password/password_test.go +++ b/modules/auth/password/password_test.go @@ -51,7 +51,7 @@ func TestComplexity_Generate(t *testing.T) { test := func(t *testing.T, modes []string) { testComplextity(modes) - for i := 0; i < maxCount; i++ { + for range maxCount { pwd, err := Generate(pwdLen) require.NoError(t, err) assert.Len(t, pwd, pwdLen) diff --git a/modules/auth/password/pwn/pwn.go b/modules/auth/password/pwn/pwn.go index 10693ec663..f3277ff616 100644 --- a/modules/auth/password/pwn/pwn.go +++ b/modules/auth/password/pwn/pwn.go @@ -101,7 +101,7 @@ func (c *Client) CheckPassword(pw string, padding bool) (int, error) { } defer resp.Body.Close() - for _, pair := range strings.Split(string(body), "\n") { + for pair := range strings.SplitSeq(string(body), "\n") { parts := strings.Split(pair, ":") if len(parts) != 2 { continue diff --git a/modules/avatar/identicon/block.go b/modules/avatar/identicon/block.go index cb1803a231..fc8ce90212 100644 --- a/modules/avatar/identicon/block.go +++ b/modules/avatar/identicon/block.go @@ -24,8 +24,8 @@ func drawBlock(img *image.Paletted, x, y, size, angle int, points []int) { rotate(points, m, m, angle) } - for i := 0; i < size; i++ { - for j := 0; j < size; j++ { + for i := range size { + for j := range size { if pointInPolygon(i, j, points) { img.SetColorIndex(x+i, y+j, 1) } diff --git a/modules/avatar/identicon/identicon.go b/modules/avatar/identicon/identicon.go index 13e8ec88e6..19f87da85a 100644 --- a/modules/avatar/identicon/identicon.go +++ b/modules/avatar/identicon/identicon.go @@ -134,7 +134,7 @@ func drawBlocks(p *image.Paletted, size int, c, b1, b2 blockFunc, b1Angle, b2Ang // then we make it left-right mirror, so we didn't draw 3/6/9 before for x := 0; x < size/2; x++ { - for y := 0; y < size; y++ { + for y := range size { p.SetColorIndex(size-x, y, p.ColorIndexAt(x, y)) } } diff --git a/modules/charset/charset.go b/modules/charset/charset.go index cb03deb966..d4121fb27f 100644 --- a/modules/charset/charset.go +++ b/modules/charset/charset.go @@ -164,7 +164,7 @@ func DetectEncoding(content []byte) (string, error) { } times := 1024 / len(content) detectContent = make([]byte, 0, times*len(content)) - for i := 0; i < times; i++ { + for range times { detectContent = append(detectContent, content...) } } else { diff --git a/modules/charset/charset_test.go b/modules/charset/charset_test.go index 358220494b..c29987beb6 100644 --- a/modules/charset/charset_test.go +++ b/modules/charset/charset_test.go @@ -243,7 +243,7 @@ func stringMustEndWith(t *testing.T, expected, value string) { func TestToUTF8WithFallbackReader(t *testing.T) { resetDefaultCharsetsOrder() - for testLen := 0; testLen < 2048; testLen++ { + for testLen := range 2048 { pattern := " test { () }\n" input := "" for len(input) < testLen { diff --git a/modules/forgefed/actor.go b/modules/forgefed/actor.go index 5383d5adaf..1f6e1f1fdf 100644 --- a/modules/forgefed/actor.go +++ b/modules/forgefed/actor.go @@ -6,6 +6,7 @@ package forgefed import ( "fmt" "net/url" + "slices" "strconv" "strings" @@ -107,12 +108,7 @@ func newActorID(uri string) (ActorID, error) { } func containsEmptyString(ar []string) bool { - for _, elem := range ar { - if elem == "" { - return true - } - } - return false + return slices.Contains(ar, "") } func removeEmptyStrings(ls []string) []string { diff --git a/modules/forgefed/repository.go b/modules/forgefed/repository.go index 63680ccd35..1e85d1e64c 100644 --- a/modules/forgefed/repository.go +++ b/modules/forgefed/repository.go @@ -88,7 +88,7 @@ func ToRepository(it ap.Item) (*Repository, error) { return (*Repository)(unsafe.Pointer(&i)), nil default: // NOTE(marius): this is an ugly way of dealing with the interface conversion error: types from different scopes - typ := reflect.TypeOf(new(Repository)) + typ := reflect.TypeFor[*Repository]() if i, ok := reflect.ValueOf(it).Convert(typ).Interface().(*Repository); ok { return i, nil } diff --git a/modules/git/commit.go b/modules/git/commit.go index 4fb13ecd4f..36ba8ef8ca 100644 --- a/modules/git/commit.go +++ b/modules/git/commit.go @@ -269,8 +269,8 @@ func NewSearchCommitsOptions(searchString string, forAllRefs bool) SearchCommits var keywords, authors, committers []string var after, before string - fields := strings.Fields(searchString) - for _, k := range fields { + fields := strings.FieldsSeq(searchString) + for k := range fields { switch { case strings.HasPrefix(k, "author:"): authors = append(authors, strings.TrimPrefix(k, "author:")) diff --git a/modules/git/commit_info.go b/modules/git/commit_info.go index 6511a1689a..62f58f8767 100644 --- a/modules/git/commit_info.go +++ b/modules/git/commit_info.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "io" + "maps" "path" "sort" @@ -45,9 +46,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath return nil, nil, err } - for pth, found := range commits { - revs[pth] = found - } + maps.Copy(revs, commits) } } else { sort.Strings(entryPaths) diff --git a/modules/git/foreachref/format.go b/modules/git/foreachref/format.go index 2f5ec08991..87c1c9a4ff 100644 --- a/modules/git/foreachref/format.go +++ b/modules/git/foreachref/format.go @@ -75,9 +75,9 @@ func (f Format) Parser(r io.Reader) *Parser { // hexEscaped produces hex-escaped characters from a string. For example, "\n\0" // would turn into "%0a%00". func (f Format) hexEscaped(delim []byte) string { - escaped := "" - for i := 0; i < len(delim); i++ { - escaped += "%" + hex.EncodeToString([]byte{delim[i]}) + var escaped strings.Builder + for i := range delim { + escaped.WriteString("%" + hex.EncodeToString([]byte{delim[i]})) } - return escaped + return escaped.String() } diff --git a/modules/git/hook.go b/modules/git/hook.go index bef4d024c8..3b650fe9db 100644 --- a/modules/git/hook.go +++ b/modules/git/hook.go @@ -9,6 +9,7 @@ import ( "os" "path" "path/filepath" + "slices" "strings" "forgejo.org/modules/log" @@ -27,12 +28,7 @@ var ErrNotValidHook = errors.New("not a valid Git hook") // IsValidHookName returns true if given name is a valid Git hook. func IsValidHookName(name string) bool { - for _, hn := range hookNames { - if hn == name { - return true - } - } - return false + return slices.Contains(hookNames, name) } // Hook represents a Git hook. diff --git a/modules/git/last_commit_cache.go b/modules/git/last_commit_cache.go index 1d7e74a0d7..9b49a18aaa 100644 --- a/modules/git/last_commit_cache.go +++ b/modules/git/last_commit_cache.go @@ -21,7 +21,7 @@ type Cache interface { } func getCacheKey(repoPath, commitID, entryPath string) string { - hashBytes := sha256.Sum256([]byte(fmt.Sprintf("%s:%s:%s", repoPath, commitID, entryPath))) + hashBytes := sha256.Sum256(fmt.Appendf(nil, "%s:%s:%s", repoPath, commitID, entryPath)) return fmt.Sprintf("last_commit:%x", hashBytes) } diff --git a/modules/git/log_name_status.go b/modules/git/log_name_status.go index 50786e7a42..800e83c4a4 100644 --- a/modules/git/log_name_status.go +++ b/modules/git/log_name_status.go @@ -346,10 +346,7 @@ func WalkGitLog(ctx context.Context, repo *Repository, head *Commit, treepath st results := make([]string, len(paths)) remaining := len(paths) - nextRestart := (len(paths) * 3) / 4 - if nextRestart > 70 { - nextRestart = 70 - } + nextRestart := min((len(paths)*3)/4, 70) lastEmptyParent := head.ID.String() commitSinceLastEmptyParent := uint64(0) commitSinceNextRestart := uint64(0) diff --git a/modules/git/notes.go b/modules/git/notes.go index a52314bdd7..1bc68b6366 100644 --- a/modules/git/notes.go +++ b/modules/git/notes.go @@ -8,6 +8,7 @@ import ( "context" "io" "os" + "strings" "forgejo.org/modules/log" ) @@ -33,7 +34,7 @@ func GetNote(ctx context.Context, repo *Repository, commitID string) (*Note, err return nil, err } - path := "" + var path strings.Builder tree := ¬es.Tree log.Trace("Found tree with ID %q while searching for git note corresponding to the commit %q", tree.ID, commitID) @@ -43,12 +44,12 @@ func GetNote(ctx context.Context, repo *Repository, commitID string) (*Note, err for len(commitID) > 2 { entry, err = tree.GetTreeEntryByPath(commitID) if err == nil { - path += commitID + path.WriteString(commitID) break } if IsErrNotExist(err) { tree, err = tree.SubTree(commitID[0:2]) - path += commitID[0:2] + "/" + path.WriteString(commitID[0:2] + "/") commitID = commitID[2:] } if err != nil { @@ -80,9 +81,9 @@ func GetNote(ctx context.Context, repo *Repository, commitID string) (*Note, err _ = dataRc.Close() closed = true - lastCommit, err := repo.getCommitByPathWithID(notes.ID, path) + lastCommit, err := repo.getCommitByPathWithID(notes.ID, path.String()) if err != nil { - log.Error("Unable to get the commit for the path %q. Error: %v", path, err) + log.Error("Unable to get the commit for the path %q. Error: %v", path.String(), err) return nil, err } diff --git a/modules/git/parse.go b/modules/git/parse.go index c7b84d7198..d2d70d4cfa 100644 --- a/modules/git/parse.go +++ b/modules/git/parse.go @@ -33,16 +33,16 @@ func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) { posEnd += pos } line := data[pos:posEnd] - posTab := bytes.IndexByte(line, '\t') - if posTab == -1 { + before, after, ok := bytes.Cut(line, []byte{'\t'}) + if !ok { return nil, fmt.Errorf("invalid ls-tree output (no tab): %q", line) } entry := new(TreeEntry) entry.ptree = ptree - entryAttrs := line[:posTab] - entryName := line[posTab+1:] + entryAttrs := before + entryName := after entryMode, entryAttrs, _ := bytes.Cut(entryAttrs, sepSpace) _ /* entryType */, entryAttrs, _ = bytes.Cut(entryAttrs, sepSpace) // the type is not used, the mode is enough to determine the type diff --git a/modules/git/pushoptions/pushoptions.go b/modules/git/pushoptions/pushoptions.go index 3fa2e01c44..14e2c5d283 100644 --- a/modules/git/pushoptions/pushoptions.go +++ b/modules/git/pushoptions/pushoptions.go @@ -52,7 +52,7 @@ func NewFromMap(o *map[string]string) Interface { func (o *gitPushOptions) ReadEnv() Interface { if pushCount, err := strconv.Atoi(os.Getenv(EnvCount)); err == nil { - for idx := 0; idx < pushCount; idx++ { + for idx := range pushCount { _ = o.Parse(os.Getenv(fmt.Sprintf(EnvFormat, idx))) } } diff --git a/modules/git/ref.go b/modules/git/ref.go index 1475d4dc5a..fdccd2b2e2 100644 --- a/modules/git/ref.go +++ b/modules/git/ref.go @@ -105,8 +105,8 @@ func (ref RefName) IsFor() bool { } func (ref RefName) nameWithoutPrefix(prefix string) string { - if strings.HasPrefix(string(ref), prefix) { - return strings.TrimPrefix(string(ref), prefix) + if after, ok := strings.CutPrefix(string(ref), prefix); ok { + return after } return "" } diff --git a/modules/git/repo.go b/modules/git/repo.go index 21845d9b55..6bd03f8e3c 100644 --- a/modules/git/repo.go +++ b/modules/git/repo.go @@ -46,9 +46,9 @@ func (repo *Repository) parsePrettyFormatLogToList(logs []byte) ([]*Commit, erro return commits, nil } - parts := bytes.Split(logs, []byte{'\n'}) + parts := bytes.SplitSeq(logs, []byte{'\n'}) - for _, commitID := range parts { + for commitID := range parts { commit, err := repo.GetCommit(string(commitID)) if err != nil { return nil, err diff --git a/modules/git/repo_attribute.go b/modules/git/repo_attribute.go index 2b07513162..56a86bde14 100644 --- a/modules/git/repo_attribute.go +++ b/modules/git/repo_attribute.go @@ -96,8 +96,8 @@ func (ca GitAttribute) String() string { // sometimes used within gitlab-language: https://docs.gitlab.com/ee/user/project/highlighting.html#override-syntax-highlighting-for-a-file-type func (ca GitAttribute) Prefix() string { s := ca.String() - if i := strings.IndexByte(s, '?'); i >= 0 { - return s[:i] + if before, _, ok := strings.Cut(s, "?"); ok { + return before } return s } diff --git a/modules/git/repo_index.go b/modules/git/repo_index.go index f58757a9a2..7fc5c573dd 100644 --- a/modules/git/repo_index.go +++ b/modules/git/repo_index.go @@ -95,7 +95,7 @@ func (repo *Repository) LsFiles(filenames ...string) ([]string, error) { return nil, err } filelist := make([]string, 0, len(filenames)) - for _, line := range bytes.Split(res, []byte{'\000'}) { + for line := range bytes.SplitSeq(res, []byte{'\000'}) { filelist = append(filelist, string(line)) } diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index f7f04e1f10..bd851a3be3 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -42,8 +42,8 @@ func (repo *Repository) GetTagNameBySHA(sha string) (string, error) { return "", err } - tagRefs := strings.Split(stdout, "\n") - for _, tagRef := range tagRefs { + tagRefs := strings.SplitSeq(stdout, "\n") + for tagRef := range tagRefs { if len(strings.TrimSpace(tagRef)) > 0 { fields := strings.Fields(tagRef) if strings.HasPrefix(fields[0], sha) && strings.HasPrefix(fields[1], TagPrefix) { @@ -65,7 +65,7 @@ func (repo *Repository) GetTagID(name string) (string, error) { return "", err } // Make sure exact match is used: "v1" != "release/v1" - for _, line := range strings.Split(stdout, "\n") { + for line := range strings.SplitSeq(stdout, "\n") { fields := strings.Fields(line) if len(fields) == 2 && fields[1] == "refs/tags/"+name { return fields[0], nil diff --git a/modules/git/tree.go b/modules/git/tree.go index f6201f6cc9..9a91787c9e 100644 --- a/modules/git/tree.go +++ b/modules/git/tree.go @@ -170,7 +170,7 @@ func (repo *Repository) LsTree(ref string, filenames ...string) ([]string, error return nil, err } filelist := make([]string, 0, len(filenames)) - for _, line := range bytes.Split(res, []byte{'\000'}) { + for line := range bytes.SplitSeq(res, []byte{'\000'}) { filelist = append(filelist, string(line)) } diff --git a/modules/git/tree_entry.go b/modules/git/tree_entry.go index 8b6c4c467c..5e3bb8ac21 100644 --- a/modules/git/tree_entry.go +++ b/modules/git/tree_entry.go @@ -171,7 +171,7 @@ func (te *TreeEntry) FollowLinks() (*TreeEntry, string, error) { } entry := te entryLink := "" - for i := 0; i < 999; i++ { + for range 999 { if entry.IsLink() { next, link, err := entry.FollowLink() entryLink = link diff --git a/modules/git/tree_test.go b/modules/git/tree_test.go index aa092cc56b..6277154acd 100644 --- a/modules/git/tree_test.go +++ b/modules/git/tree_test.go @@ -20,7 +20,7 @@ func TestSubTree_Issue29101(t *testing.T) { require.NoError(t, err) // old code could produce a different error if called multiple times - for i := 0; i < 10; i++ { + for range 10 { _, err = commit.SubTree("file1.txt") require.Error(t, err) assert.True(t, IsErrNotExist(err)) diff --git a/modules/hostmatcher/hostmatcher.go b/modules/hostmatcher/hostmatcher.go index 1069310316..15c6371422 100644 --- a/modules/hostmatcher/hostmatcher.go +++ b/modules/hostmatcher/hostmatcher.go @@ -6,6 +6,7 @@ package hostmatcher import ( "net" "path/filepath" + "slices" "strings" ) @@ -38,7 +39,7 @@ func isBuiltin(s string) bool { // ParseHostMatchList parses the host list HostMatchList func ParseHostMatchList(settingKeyHint, hostList string) *HostMatchList { hl := &HostMatchList{SettingKeyHint: settingKeyHint, SettingValue: hostList} - for _, s := range strings.Split(hostList, ",") { + for s := range strings.SplitSeq(hostList, ",") { s = strings.ToLower(strings.TrimSpace(s)) if s == "" { continue @@ -61,7 +62,7 @@ func ParseSimpleMatchList(settingKeyHint, matchList string) *HostMatchList { SettingKeyHint: settingKeyHint, SettingValue: matchList, } - for _, s := range strings.Split(matchList, ",") { + for s := range strings.SplitSeq(matchList, ",") { s = strings.ToLower(strings.TrimSpace(s)) if s == "" { continue @@ -98,10 +99,8 @@ func (hl *HostMatchList) checkPattern(host string) bool { } func (hl *HostMatchList) checkIP(ip net.IP) bool { - for _, pattern := range hl.patterns { - if pattern == "*" { - return true - } + if slices.Contains(hl.patterns, "*") { + return true } for _, builtin := range hl.builtins { switch builtin { diff --git a/modules/httpcache/httpcache.go b/modules/httpcache/httpcache.go index 7978fc38a1..311f7215b2 100644 --- a/modules/httpcache/httpcache.go +++ b/modules/httpcache/httpcache.go @@ -59,7 +59,7 @@ func HandleGenericETagCache(req *http.Request, w http.ResponseWriter, etag strin func checkIfNoneMatchIsValid(req *http.Request, etag string) bool { ifNoneMatch := req.Header.Get("If-None-Match") if len(ifNoneMatch) > 0 { - for _, item := range strings.Split(ifNoneMatch, ",") { + for item := range strings.SplitSeq(ifNoneMatch, ",") { item = strings.TrimPrefix(strings.TrimSpace(item), "W/") // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag#directives if item == etag { return true diff --git a/modules/httplib/serve.go b/modules/httplib/serve.go index d385ac21c9..4c71437fc5 100644 --- a/modules/httplib/serve.go +++ b/modules/httplib/serve.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "io" + "maps" "net/http" "net/url" "path" @@ -86,9 +87,7 @@ func ServeSetHeaders(w http.ResponseWriter, opts *ServeHeaderOptions) { } if opts.AdditionalHeaders != nil { - for k, v := range opts.AdditionalHeaders { - header[k] = v - } + maps.Copy(header, opts.AdditionalHeaders) } } diff --git a/modules/indexer/code/git.go b/modules/indexer/code/git.go index 14a43cf3be..8ec3c1181f 100644 --- a/modules/indexer/code/git.go +++ b/modules/indexer/code/git.go @@ -129,8 +129,8 @@ func nonGenesisChanges(ctx context.Context, repo *repo_model.Repository, revisio changes.Updates = append(changes.Updates, updates...) return nil } - lines := strings.Split(stdout, "\n") - for _, line := range lines { + lines := strings.SplitSeq(stdout, "\n") + for line := range lines { line = strings.TrimSpace(line) if len(line) == 0 { continue diff --git a/modules/issue/template/template.go b/modules/issue/template/template.go index 08c1b21c26..09dfe10e08 100644 --- a/modules/issue/template/template.go +++ b/modules/issue/template/template.go @@ -8,6 +8,7 @@ import ( "fmt" "net/url" "regexp" + "slices" "strconv" "strings" @@ -447,12 +448,7 @@ func (o *valuedOption) IsChecked() bool { case api.IssueFormFieldTypeDropdown: checks := strings.Split(o.field.Get(fmt.Sprintf("form-field-%s", o.field.ID)), ",") idx := strconv.Itoa(o.index) - for _, v := range checks { - if v == idx { - return true - } - } - return false + return slices.Contains(checks, idx) case api.IssueFormFieldTypeCheckboxes: return o.field.Get(fmt.Sprintf("form-field-%s-%d", o.field.ID, o.index)) == "on" } diff --git a/modules/label/parser.go b/modules/label/parser.go index 12fc176967..b27b2c9ee6 100644 --- a/modules/label/parser.go +++ b/modules/label/parser.go @@ -72,7 +72,7 @@ func parseYamlFormat(fileName string, data []byte) ([]*Label, error) { func parseLegacyFormat(fileName string, data []byte) ([]*Label, error) { lines := strings.Split(string(data), "\n") list := make([]*Label, 0, len(lines)) - for i := 0; i < len(lines); i++ { + for i := range lines { line := strings.TrimSpace(lines[i]) if len(line) == 0 { continue @@ -108,7 +108,7 @@ func LoadTemplateDescription(fileName string) (string, error) { return "", err } - for i := 0; i < len(list); i++ { + for i := range list { if i > 0 { buf.WriteString(", ") } diff --git a/modules/log/event_format.go b/modules/log/event_format.go index 6835a4ca5b..70df2cbce2 100644 --- a/modules/log/event_format.go +++ b/modules/log/event_format.go @@ -208,7 +208,7 @@ func EventFormatTextMessage(mode *WriterMode, event *Event, msgFormat string, ms } } if hasColorValue { - msg = []byte(fmt.Sprintf(msgFormat, msgArgs...)) + msg = fmt.Appendf(nil, msgFormat, msgArgs...) } } // try to reuse the pre-formatted simple text message @@ -227,8 +227,8 @@ func EventFormatTextMessage(mode *WriterMode, event *Event, msgFormat string, ms buf = append(buf, msg...) if event.Stacktrace != "" && mode.StacktraceLevel <= event.Level { - lines := bytes.Split([]byte(event.Stacktrace), []byte("\n")) - for _, line := range lines { + lines := bytes.SplitSeq([]byte(event.Stacktrace), []byte("\n")) + for line := range lines { buf = append(buf, "\n\t"...) buf = append(buf, line...) } diff --git a/modules/log/event_writer_conn_test.go b/modules/log/event_writer_conn_test.go index 0cf447149a..6d528a68d1 100644 --- a/modules/log/event_writer_conn_test.go +++ b/modules/log/event_writer_conn_test.go @@ -63,11 +63,9 @@ func TestConnLogger(t *testing.T) { } expected := fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.Filename, event.Line, event.Caller, strings.ToUpper(event.Level.String())[0], event.MsgSimpleText) var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { listenReadAndClose(t, l, expected) - }() + }) logger.SendLogEvent(&event) wg.Wait() diff --git a/modules/log/flags.go b/modules/log/flags.go index 1e4fe830c1..c428d58a1d 100644 --- a/modules/log/flags.go +++ b/modules/log/flags.go @@ -124,7 +124,7 @@ func FlagsFromString(from string, def ...uint32) Flags { return Flags{defined: true, flags: def[0]} } flags := uint32(0) - for _, flag := range strings.Split(strings.ToLower(from), ",") { + for flag := range strings.SplitSeq(strings.ToLower(from), ",") { flags |= flagFromString[strings.TrimSpace(flag)] } return Flags{defined: true, flags: flags} diff --git a/modules/log/level_test.go b/modules/log/level_test.go index e6cacc723b..73e2355960 100644 --- a/modules/log/level_test.go +++ b/modules/log/level_test.go @@ -33,11 +33,11 @@ func TestLevelMarshalUnmarshalJSON(t *testing.T) { require.NoError(t, err) assert.Equal(t, INFO, testLevel.Level) - err = json.Unmarshal([]byte(fmt.Sprintf(`{"level":%d}`, 2)), &testLevel) + err = json.Unmarshal(fmt.Appendf(nil, `{"level":%d}`, 2), &testLevel) require.NoError(t, err) assert.Equal(t, INFO, testLevel.Level) - err = json.Unmarshal([]byte(fmt.Sprintf(`{"level":%d}`, 10012)), &testLevel) + err = json.Unmarshal(fmt.Appendf(nil, `{"level":%d}`, 10012), &testLevel) require.NoError(t, err) assert.Equal(t, INFO, testLevel.Level) @@ -52,5 +52,5 @@ func TestLevelMarshalUnmarshalJSON(t *testing.T) { } func makeTestLevelBytes(level string) []byte { - return []byte(fmt.Sprintf(`{"level":"%s"}`, level)) + return fmt.Appendf(nil, `{"level":"%s"}`, level) } diff --git a/modules/markup/file_preview.go b/modules/markup/file_preview.go index dab6057cf4..22dcf93d75 100644 --- a/modules/markup/file_preview.go +++ b/modules/markup/file_preview.go @@ -80,8 +80,8 @@ func newFilePreview(ctx *RenderContext, node *html.Node, locale translation.Loca filePath := node.Data[m[6]:m[7]] hash := node.Data[m[8]:m[9]] urlFullSource := urlFull - if strings.HasSuffix(filePath, "?display=source") { - filePath = strings.TrimSuffix(filePath, "?display=source") + if before, ok := strings.CutSuffix(filePath, "?display=source"); ok { + filePath = before } else if Type(filePath) != "" { urlFullSource = node.Data[m[0]:m[6]] + filePath + "?display=source#" + hash } diff --git a/modules/markup/html.go b/modules/markup/html.go index d60021bfbb..77b5dc8029 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -11,6 +11,7 @@ import ( "path" "path/filepath" "regexp" + "slices" "strings" "sync" @@ -124,13 +125,7 @@ func CustomLinkURLSchemes(schemes []string) { if !validScheme.MatchString(s) { continue } - without := false - for _, sna := range xurls.SchemesNoAuthority { - if s == sna { - without = true - break - } - } + without := slices.Contains(xurls.SchemesNoAuthority, s) if without { s += ":" } else { @@ -675,9 +670,9 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) { // It makes page handling terrible, but we prefer GitHub syntax // And fall back to MediaWiki only when it is obvious from the look // Of text and link contents - sl := strings.Split(content, "|") - for _, v := range sl { - if equalPos := strings.IndexByte(v, '='); equalPos == -1 { + sl := strings.SplitSeq(content, "|") + for v := range sl { + if found := strings.Contains(v, "="); !found { // There is no equal in this argument; this is a mandatory arg if props["name"] == "" { if IsLinkStr(v) { @@ -1148,7 +1143,7 @@ func comparePatternProcessor(ctx *RenderContext, node *html.Node) { } // Ensure that every group (m[0]...m[9]) has a match - for i := 0; i < 10; i++ { + for i := range 10 { if m[i] == -1 { return } diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go index 2b19e0f1c9..9a112109dd 100644 --- a/modules/markup/markdown/markdown.go +++ b/modules/markup/markdown/markdown.go @@ -182,10 +182,7 @@ func actualRender(ctx *markup.RenderContext, input io.Reader, output io.Writer) } buf, _ = ExtractMetadataBytes(buf, rc) - metaLength := bufWithMetadataLength - len(buf) - if metaLength < 0 { - metaLength = 0 - } + metaLength := max(bufWithMetadataLength-len(buf), 0) rc.metaLength = metaLength pc.Set(markdownutil.RenderConfigKey, rc) diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index 82c2c7fe8c..61ded3cedc 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -319,7 +319,7 @@ func TestTotal_RenderWiki(t *testing.T) { answers := testAnswers(util.URLJoin(FullURL, "wiki"), util.URLJoin(FullURL, "wiki", "raw")) - for i := 0; i < len(sameCases); i++ { + for i := range sameCases { line, err := markdown.RenderString(&markup.RenderContext{ Ctx: git.DefaultContext, Links: markup.Links{ @@ -363,7 +363,7 @@ func TestTotal_RenderString(t *testing.T) { answers := testAnswers(util.URLJoin(FullURL, "src", "master"), util.URLJoin(FullURL, "media", "master")) - for i := 0; i < len(sameCases); i++ { + for i := range sameCases { line, err := markdown.RenderString(&markup.RenderContext{ Ctx: git.DefaultContext, Links: markup.Links{ diff --git a/modules/markup/markdown/math/block_renderer.go b/modules/markup/markdown/math/block_renderer.go index 84817ef1e4..d27318c623 100644 --- a/modules/markup/markdown/math/block_renderer.go +++ b/modules/markup/markdown/math/block_renderer.go @@ -24,7 +24,7 @@ func (r *BlockRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { func (r *BlockRenderer) writeLines(w util.BufWriter, source []byte, n gast.Node) { l := n.Lines().Len() - for i := 0; i < l; i++ { + for i := range l { line := n.Lines().At(i) _, _ = w.Write(util.EscapeHTML(line.Value(source))) } diff --git a/modules/markup/markdown/meta_test.go b/modules/markup/markdown/meta_test.go index aaf116ff20..9345dd528a 100644 --- a/modules/markup/markdown/meta_test.go +++ b/modules/markup/markdown/meta_test.go @@ -63,7 +63,7 @@ func TestExtractMetadata(t *testing.T) { func TestExtractMetadataBytes(t *testing.T) { t.Run("ValidFrontAndBody", func(t *testing.T) { var meta IssueTemplate - body, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s\n%s", sepTest, frontTest, sepTest, bodyTest)), &meta) + body, err := ExtractMetadataBytes(fmt.Appendf(nil, "%s\n%s\n%s\n%s", sepTest, frontTest, sepTest, bodyTest), &meta) require.NoError(t, err) assert.Equal(t, bodyTest, string(body)) assert.Equal(t, metaTest, meta) @@ -72,19 +72,19 @@ func TestExtractMetadataBytes(t *testing.T) { t.Run("NoFirstSeparator", func(t *testing.T) { var meta IssueTemplate - _, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s", frontTest, sepTest, bodyTest)), &meta) + _, err := ExtractMetadataBytes(fmt.Appendf(nil, "%s\n%s\n%s", frontTest, sepTest, bodyTest), &meta) require.Error(t, err) }) t.Run("NoLastSeparator", func(t *testing.T) { var meta IssueTemplate - _, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, bodyTest)), &meta) + _, err := ExtractMetadataBytes(fmt.Appendf(nil, "%s\n%s\n%s", sepTest, frontTest, bodyTest), &meta) require.Error(t, err) }) t.Run("NoBody", func(t *testing.T) { var meta IssueTemplate - body, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, sepTest)), &meta) + body, err := ExtractMetadataBytes(fmt.Appendf(nil, "%s\n%s\n%s", sepTest, frontTest, sepTest), &meta) require.NoError(t, err) assert.Empty(t, string(body)) assert.Equal(t, metaTest, meta) diff --git a/modules/markup/markdown/toc.go b/modules/markup/markdown/toc.go index dbfab3e9dc..53add219f5 100644 --- a/modules/markup/markdown/toc.go +++ b/modules/markup/markdown/toc.go @@ -44,7 +44,7 @@ func createTOCNode(toc []markup.Header, lang string, detailsAttrs map[string]str } li := ast.NewListItem(currentLevel * 2) a := ast.NewLink() - a.Destination = []byte(fmt.Sprintf("#%s", url.QueryEscape(header.ID))) + a.Destination = fmt.Appendf(nil, "#%s", url.QueryEscape(header.ID)) a.AppendChild(a, ast.NewString([]byte(header.Text))) li.AppendChild(li, a) ul.AppendChild(ul, li) diff --git a/modules/markup/markdown/transform_heading.go b/modules/markup/markdown/transform_heading.go index eedaf58556..16779d5099 100644 --- a/modules/markup/markdown/transform_heading.go +++ b/modules/markup/markdown/transform_heading.go @@ -17,7 +17,7 @@ import ( func (g *ASTTransformer) transformHeading(_ *markup.RenderContext, v *ast.Heading, reader text.Reader, tocList *[]markup.Header) { for _, attr := range v.Attributes() { if _, ok := attr.Value.([]byte); !ok { - v.SetAttribute(attr.Name, []byte(fmt.Sprintf("%v", attr.Value))) + v.SetAttribute(attr.Name, fmt.Appendf(nil, "%v", attr.Value)) } } txt := mdutil.Text(v, reader.Source()) diff --git a/modules/markup/renderer.go b/modules/markup/renderer.go index b1c3d35e73..0a66caf1d5 100644 --- a/modules/markup/renderer.go +++ b/modules/markup/renderer.go @@ -319,23 +319,19 @@ func render(ctx *RenderContext, renderer Renderer, input io.Reader, output io.Wr _ = pw2.Close() }() - wg.Add(1) - go func() { + wg.Go(func() { err = donotpanic.SafeFuncWithError(func() error { return SanitizeReader(pr2, renderer.Name(), output) }) _ = pr2.Close() - wg.Done() - }() + }) } else { pw2 = nopCloser{output} } - wg.Add(1) - go func() { + wg.Go(func() { err = donotpanic.SafeFuncWithError(func() error { return postProcessOrCopy(ctx, renderer, pr, pw2) }) _ = pr.Close() _ = pw2.Close() - wg.Done() - }() + }) if err1 := renderer.Render(ctx, input, pw); err1 != nil { return err1 diff --git a/modules/packages/npm/creator.go b/modules/packages/npm/creator.go index ed163d30ac..2f83d2ee7b 100644 --- a/modules/packages/npm/creator.go +++ b/modules/packages/npm/creator.go @@ -58,7 +58,7 @@ type PackageMetadata struct { Time map[string]time.Time `json:"time,omitempty"` Homepage string `json:"homepage,omitempty"` Keywords []string `json:"keywords,omitempty"` - Repository Repository `json:"repository,omitempty"` + Repository Repository `json:"repository"` Author User `json:"author"` ReadmeFilename string `json:"readmeFilename,omitempty"` Users map[string]bool `json:"users,omitempty"` @@ -75,7 +75,7 @@ type PackageMetadataVersion struct { Author User `json:"author"` Homepage string `json:"homepage,omitempty"` License string `json:"license,omitempty"` - Repository Repository `json:"repository,omitempty"` + Repository Repository `json:"repository"` Keywords []string `json:"keywords,omitempty"` Dependencies map[string]string `json:"dependencies,omitempty"` BundleDependencies []string `json:"bundleDependencies,omitempty"` diff --git a/modules/packages/npm/metadata.go b/modules/packages/npm/metadata.go index 6bb77f302b..0e5bf19ce7 100644 --- a/modules/packages/npm/metadata.go +++ b/modules/packages/npm/metadata.go @@ -22,5 +22,5 @@ type Metadata struct { OptionalDependencies map[string]string `json:"optional_dependencies,omitempty"` Bin map[string]string `json:"bin,omitempty"` Readme string `json:"readme,omitempty"` - Repository Repository `json:"repository,omitempty"` + Repository Repository `json:"repository"` } diff --git a/modules/packages/nuget/symbol_extractor.go b/modules/packages/nuget/symbol_extractor.go index 992ade7e8f..dd9fac96c6 100644 --- a/modules/packages/nuget/symbol_extractor.go +++ b/modules/packages/nuget/symbol_extractor.go @@ -142,8 +142,8 @@ func ParseDebugHeaderID(r io.ReadSeeker) (string, error) { if _, err := r.Read(b); err != nil { return "", err } - if i := bytes.IndexByte(b, 0); i != -1 { - buf.Write(b[:i]) + if before, _, ok := bytes.Cut(b, []byte{0}); ok { + buf.Write(before) return buf.String(), nil } buf.Write(b) diff --git a/modules/packages/rubygems/marshal.go b/modules/packages/rubygems/marshal.go index 191efc7c0e..7d498c66b8 100644 --- a/modules/packages/rubygems/marshal.go +++ b/modules/packages/rubygems/marshal.go @@ -91,7 +91,7 @@ func (e *MarshalEncoder) marshal(v any) error { val := reflect.ValueOf(v) typ := reflect.TypeOf(v) - if typ.Kind() == reflect.Ptr { + if typ.Kind() == reflect.Pointer { val = val.Elem() typ = typ.Elem() } @@ -250,7 +250,7 @@ func (e *MarshalEncoder) marshalArray(arr reflect.Value) error { return err } - for i := 0; i < length; i++ { + for i := range length { if err := e.marshal(arr.Index(i).Interface()); err != nil { return err } diff --git a/modules/packages/swift/metadata.go b/modules/packages/swift/metadata.go index 34fc4f1784..094fa0c7a4 100644 --- a/modules/packages/swift/metadata.go +++ b/modules/packages/swift/metadata.go @@ -47,7 +47,7 @@ type Metadata struct { Keywords []string `json:"keywords,omitempty"` RepositoryURL string `json:"repository_url,omitempty"` License string `json:"license,omitempty"` - Author Person `json:"author,omitempty"` + Author Person `json:"author"` Manifests map[string]*Manifest `json:"manifests,omitempty"` } diff --git a/modules/private/serv.go b/modules/private/serv.go index fb8496930e..ac5be3b767 100644 --- a/modules/private/serv.go +++ b/modules/private/serv.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "net/url" + "strings" asymkey_model "forgejo.org/models/asymkey" "forgejo.org/models/perm" @@ -47,17 +48,18 @@ type ServCommandResults struct { // ServCommand preps for a serv call func ServCommand(ctx context.Context, keyID int64, ownerName, repoName string, mode perm.AccessMode, verbs ...string) (*ServCommandResults, ResponseExtra) { - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/serv/command/%d/%s/%s?mode=%d", + var reqURL strings.Builder + reqURL.WriteString(setting.LocalURL + fmt.Sprintf("api/internal/serv/command/%d/%s/%s?mode=%d", keyID, url.PathEscape(ownerName), url.PathEscape(repoName), mode, - ) + )) for _, verb := range verbs { if verb != "" { - reqURL += fmt.Sprintf("&verb=%s", url.QueryEscape(verb)) + fmt.Fprintf(&reqURL, "&verb=%s", url.QueryEscape(verb)) } } - req := newInternalRequest(ctx, reqURL, "GET") + req := newInternalRequest(ctx, reqURL.String(), "GET") return requestJSONResp(req, &ServCommandResults{}) } diff --git a/modules/public/public.go b/modules/public/public.go index a7db5b62e9..52cb8757a0 100644 --- a/modules/public/public.go +++ b/modules/public/public.go @@ -45,7 +45,7 @@ func FileHandlerFunc() http.HandlerFunc { func parseAcceptEncoding(val string) container.Set[string] { parts := strings.Split(val, ";") types := make(container.Set[string]) - for _, v := range strings.Split(parts[0], ",") { + for v := range strings.SplitSeq(parts[0], ",") { types.Add(strings.TrimSpace(v)) } return types diff --git a/modules/queue/base_levelqueue_common.go b/modules/queue/base_levelqueue_common.go index 8b4f35c47d..c57bf8597b 100644 --- a/modules/queue/base_levelqueue_common.go +++ b/modules/queue/base_levelqueue_common.go @@ -83,7 +83,7 @@ func prepareLevelDB(cfg *BaseConfig) (conn string, db *leveldb.DB, err error) { } conn = cfg.ConnStr } - for i := 0; i < 10; i++ { + for range 10 { if db, err = nosql.GetManager().GetLevelDB(conn); err == nil { break } diff --git a/modules/queue/base_redis.go b/modules/queue/base_redis.go index ec3c6dc16d..8b20e0b443 100644 --- a/modules/queue/base_redis.go +++ b/modules/queue/base_redis.go @@ -49,7 +49,7 @@ func newBaseRedisGeneric(cfg *BaseConfig, unique bool, client nosql.RedisClient) } var err error - for i := 0; i < 10; i++ { + for range 10 { err = client.Ping(graceful.GetManager().ShutdownContext()).Err() if err == nil { break diff --git a/modules/queue/base_test.go b/modules/queue/base_test.go index caa930158c..758faf1459 100644 --- a/modules/queue/base_test.go +++ b/modules/queue/base_test.go @@ -88,7 +88,7 @@ func testQueueBasic(t *testing.T, newFn func(cfg *BaseConfig) (baseQueue, error) // test blocking push if queue is full for i := 0; i < cfg.Length; i++ { - err = q.PushItem(ctx, []byte(fmt.Sprintf("item-%d", i))) + err = q.PushItem(ctx, fmt.Appendf(nil, "item-%d", i)) require.NoError(t, err) } ctxTimed, cancel = context.WithTimeout(ctx, 10*time.Millisecond) diff --git a/modules/queue/manager.go b/modules/queue/manager.go index 8f1a93f273..9c655b7fdc 100644 --- a/modules/queue/manager.go +++ b/modules/queue/manager.go @@ -5,6 +5,7 @@ package queue import ( "context" + "maps" "sync" "time" @@ -68,9 +69,7 @@ func (m *Manager) ManagedQueues() map[int64]ManagedWorkerPoolQueue { defer m.mu.Unlock() queues := make(map[int64]ManagedWorkerPoolQueue, len(m.Queues)) - for k, v := range m.Queues { - queues[k] = v - } + maps.Copy(queues, m.Queues) return queues } diff --git a/modules/queue/workergroup.go b/modules/queue/workergroup.go index 2d1228db2c..87f01755aa 100644 --- a/modules/queue/workergroup.go +++ b/modules/queue/workergroup.go @@ -142,11 +142,7 @@ func (q *WorkerPoolQueue[T]) basePushForShutdown(items ...T) bool { // doStartNewWorker starts a new worker for the queue, the worker reads from worker's channel and handles the items. func (q *WorkerPoolQueue[T]) doStartNewWorker(wp *workerGroup[T]) { - wp.wg.Add(1) - - go func() { - defer wp.wg.Done() - + wp.wg.Go(func() { log.Debug("Queue %q starts new worker", q.GetName()) defer log.Debug("Queue %q stops idle worker", q.GetName()) @@ -187,7 +183,7 @@ func (q *WorkerPoolQueue[T]) doStartNewWorker(wp *workerGroup[T]) { q.workerNumMu.Unlock() } } - }() + }) } // doFlush flushes the queue: it tries to read all items from the queue and handles them. diff --git a/modules/queue/workerqueue_test.go b/modules/queue/workerqueue_test.go index 8d907ed8cd..da857b9405 100644 --- a/modules/queue/workerqueue_test.go +++ b/modules/queue/workerqueue_test.go @@ -78,17 +78,17 @@ func TestWorkerPoolQueueUnhandled(t *testing.T) { runCount := 2 // we can run these tests even hundreds times to see its stability t.Run("1/1", func(t *testing.T) { - for i := 0; i < runCount; i++ { + for range runCount { test(t, setting.QueueSettings{BatchLength: 1, MaxWorkers: 1}) } }) t.Run("3/1", func(t *testing.T) { - for i := 0; i < runCount; i++ { + for range runCount { test(t, setting.QueueSettings{BatchLength: 3, MaxWorkers: 1}) } }) t.Run("4/5", func(t *testing.T) { - for i := 0; i < runCount; i++ { + for range runCount { test(t, setting.QueueSettings{BatchLength: 4, MaxWorkers: 5}) } }) @@ -97,17 +97,17 @@ func TestWorkerPoolQueueUnhandled(t *testing.T) { func TestWorkerPoolQueuePersistence(t *testing.T) { runCount := 2 // we can run these tests even hundreds times to see its stability t.Run("1/1", func(t *testing.T) { - for i := 0; i < runCount; i++ { + for range runCount { testWorkerPoolQueuePersistence(t, setting.QueueSettings{BatchLength: 1, MaxWorkers: 1, Length: 100}) } }) t.Run("3/1", func(t *testing.T) { - for i := 0; i < runCount; i++ { + for range runCount { testWorkerPoolQueuePersistence(t, setting.QueueSettings{BatchLength: 3, MaxWorkers: 1, Length: 100}) } }) t.Run("4/5", func(t *testing.T) { - for i := 0; i < runCount; i++ { + for range runCount { testWorkerPoolQueuePersistence(t, setting.QueueSettings{BatchLength: 4, MaxWorkers: 5, Length: 100}) } }) @@ -142,7 +142,7 @@ func testWorkerPoolQueuePersistence(t *testing.T, queueSetting setting.QueueSett q, _ := newWorkerPoolQueueForTest("pr_patch_checker_test", queueSetting, testHandler, true) stop := runWorkerPoolQueue(q) - for i := 0; i < testCount; i++ { + for i := range testCount { _ = q.Push("task-" + strconv.Itoa(i)) } close(startWhenAllReady) @@ -187,7 +187,7 @@ func TestWorkerPoolQueueActiveWorkers(t *testing.T) { q, _ := newWorkerPoolQueueForTest("test-workpoolqueue", setting.QueueSettings{Type: "channel", BatchLength: 1, MaxWorkers: 1, Length: 100}, handler, false) stop := runWorkerPoolQueue(q) - for i := 0; i < 5; i++ { + for i := range 5 { require.NoError(t, q.Push(i)) } @@ -203,7 +203,7 @@ func TestWorkerPoolQueueActiveWorkers(t *testing.T) { q, _ = newWorkerPoolQueueForTest("test-workpoolqueue", setting.QueueSettings{Type: "channel", BatchLength: 1, MaxWorkers: 3, Length: 100}, handler, false) stop = runWorkerPoolQueue(q) - for i := 0; i < 15; i++ { + for i := range 15 { require.NoError(t, q.Push(i)) } @@ -264,12 +264,12 @@ func TestWorkerPoolQueueWorkerIdleReset(t *testing.T) { stop := runWorkerPoolQueue(q) const workloadSize = 12 - for i := 0; i < workloadSize; i++ { + for i := range workloadSize { require.NoError(t, q.Push(i)) } workerIDs := make(map[string]struct{}) - for i := 0; i < workloadSize; i++ { + for i := range workloadSize { c := <-chGoroutineIDs workerIDs[c] = struct{}{} t.Logf("%d workers: overall=%d current=%d", i, len(workerIDs), q.GetWorkerNumber()) diff --git a/modules/repository/init.go b/modules/repository/init.go index 7b1442be93..66a65599a8 100644 --- a/modules/repository/init.go +++ b/modules/repository/init.go @@ -152,7 +152,7 @@ func InitializeLabels(ctx context.Context, id int64, labelTemplate string, isOrg } labels := make([]*issues_model.Label, len(list)) - for i := 0; i < len(list); i++ { + for i := range list { labels[i] = &issues_model.Label{ Name: list[i].Name, Exclusive: list[i].Exclusive, diff --git a/modules/setting/config.go b/modules/setting/config.go index 6299640e61..90f3d12d11 100644 --- a/modules/setting/config.go +++ b/modules/setting/config.go @@ -4,6 +4,7 @@ package setting import ( + "strings" "sync" "forgejo.org/modules/log" @@ -23,11 +24,11 @@ type OpenWithEditorApp struct { type OpenWithEditorAppsType []OpenWithEditorApp func (t OpenWithEditorAppsType) ToTextareaString() string { - ret := "" + var ret strings.Builder for _, app := range t { - ret += app.DisplayName + " = " + app.OpenURL + "\n" + ret.WriteString(app.DisplayName + " = " + app.OpenURL + "\n") } - return ret + return ret.String() } func DefaultOpenWithEditorApps() OpenWithEditorAppsType { diff --git a/modules/setting/config_env.go b/modules/setting/config_env.go index 458dbb51bb..68a7c94db2 100644 --- a/modules/setting/config_env.go +++ b/modules/setting/config_env.go @@ -51,10 +51,10 @@ func decodeEnvSectionKey(encoded string) (ok bool, section, key string) { for _, unescapeIdx := range escapeStringIndices { preceding := encoded[last:unescapeIdx[0]] if !inKey { - if splitter := strings.Index(preceding, "__"); splitter > -1 { - section += preceding[:splitter] + if before, after, ok := strings.Cut(preceding, "__"); ok { + section += before inKey = true - key += preceding[splitter+2:] + key += after } else { section += preceding } @@ -77,9 +77,9 @@ func decodeEnvSectionKey(encoded string) (ok bool, section, key string) { } remaining := encoded[last:] if !inKey { - if splitter := strings.Index(remaining, "__"); splitter > -1 { - section += remaining[:splitter] - key += remaining[splitter+2:] + if before, after, ok := strings.Cut(remaining, "__"); ok { + section += before + key += after } else { section += remaining } @@ -113,25 +113,24 @@ func decodeEnvironmentKey(prefixRegexp *regexp.Regexp, suffixFile, envKey string func EnvironmentToConfig(cfg ConfigProvider, envs []string) (changed bool) { prefixRegexp := regexp.MustCompile(EnvConfigKeyPrefixGitea) for _, kv := range envs { - idx := strings.IndexByte(kv, '=') - if idx < 0 { + before, after, ok0 := strings.Cut(kv, "=") + if !ok0 { continue } // parse the environment variable to config section name and key name - envKey := kv[:idx] - envValue := kv[idx+1:] + envKey := before + keyValue := after ok, sectionName, keyName, useFileValue := decodeEnvironmentKey(prefixRegexp, EnvConfigKeySuffixFile, envKey) if !ok { continue } // use environment value as config value, or read the file content as value if the key indicates a file - keyValue := envValue if useFileValue { - fileContent, err := os.ReadFile(envValue) + fileContent, err := os.ReadFile(keyValue) if err != nil { - log.Error("Error reading file for %s : %v", envKey, envValue, err) + log.Error("Error reading file for %s : %v", envKey, keyValue, err) continue } if bytes.HasSuffix(fileContent, []byte("\r\n")) { diff --git a/modules/setting/indexer.go b/modules/setting/indexer.go index b112a50cfa..948dae0bea 100644 --- a/modules/setting/indexer.go +++ b/modules/setting/indexer.go @@ -108,7 +108,7 @@ func loadIndexerFrom(rootCfg ConfigProvider) { // IndexerGlobFromString parses a comma separated list of patterns and returns a glob.Glob slice suited for repo indexing func IndexerGlobFromString(globstr string) []Glob { extarr := make([]Glob, 0, 10) - for _, expr := range strings.Split(strings.ToLower(globstr), ",") { + for expr := range strings.SplitSeq(strings.ToLower(globstr), ",") { expr = strings.TrimSpace(expr) if expr != "" { if g, err := glob.Compile(expr, '.', '/'); err != nil { diff --git a/modules/setting/log.go b/modules/setting/log.go index ecc591fd35..7799f8187b 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -269,8 +269,8 @@ func initLoggerByName(manager *log.LoggerManager, rootCfg ConfigProvider, logger } var eventWriters []log.EventWriter - modes := strings.Split(modeVal, ",") - for _, modeName := range modes { + modes := strings.SplitSeq(modeVal, ",") + for modeName := range modes { modeName = strings.TrimSpace(modeName) if modeName == "" { continue diff --git a/modules/setting/markup.go b/modules/setting/markup.go index 4ab9e7b2d1..0ece86dfd1 100644 --- a/modules/setting/markup.go +++ b/modules/setting/markup.go @@ -85,8 +85,8 @@ func loadMarkupFrom(rootCfg ConfigProvider) { func newMarkupSanitizer(name string, sec ConfigSection) { rule, ok := createMarkupSanitizerRule(name, sec) if ok { - if strings.HasPrefix(name, "sanitizer.") { - names := strings.SplitN(strings.TrimPrefix(name, "sanitizer."), ".", 2) + if after, ok0 := strings.CutPrefix(name, "sanitizer."); ok0 { + names := strings.SplitN(after, ".", 2) name = names[0] } for _, renderer := range ExternalMarkupRenderers { diff --git a/modules/setting/mirror.go b/modules/setting/mirror.go index 58c57c5c95..083c67db45 100644 --- a/modules/setting/mirror.go +++ b/modules/setting/mirror.go @@ -48,11 +48,7 @@ func loadMirrorFrom(rootCfg ConfigProvider) { Mirror.MinInterval = 1 * time.Minute } if Mirror.DefaultInterval < Mirror.MinInterval { - if time.Hour*8 < Mirror.MinInterval { - Mirror.DefaultInterval = Mirror.MinInterval - } else { - Mirror.DefaultInterval = time.Hour * 8 - } + Mirror.DefaultInterval = max(time.Hour*8, Mirror.MinInterval) log.Warn("Mirror.DefaultInterval is less than Mirror.MinInterval, set to %s", Mirror.DefaultInterval.String()) } } diff --git a/modules/setting/storage.go b/modules/setting/storage.go index e458300727..93958219a8 100644 --- a/modules/setting/storage.go +++ b/modules/setting/storage.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "path/filepath" + "slices" "strings" ) @@ -27,12 +28,7 @@ var storageTypes = []StorageType{ // IsValidStorageType returns true if the given storage type is valid func IsValidStorageType(storageType StorageType) bool { - for _, t := range storageTypes { - if t == storageType { - return true - } - } - return false + return slices.Contains(storageTypes, storageType) } // MinioStorageConfig represents the configuration for a minio storage diff --git a/modules/structs/action.go b/modules/structs/action.go index a39ae11d65..cb6d76f3e3 100644 --- a/modules/structs/action.go +++ b/modules/structs/action.go @@ -70,13 +70,13 @@ type ActionRun struct { // the current status of this run Status string `json:"status"` // when the action run was started - Started time.Time `json:"started,omitempty"` + Started time.Time `json:"started"` // when the action run was stopped - Stopped time.Time `json:"stopped,omitempty"` + Stopped time.Time `json:"stopped"` // when the action run was created - Created time.Time `json:"created,omitempty"` + Created time.Time `json:"created"` // when the action run was last updated - Updated time.Time `json:"updated,omitempty"` + Updated time.Time `json:"updated"` // how long the action run ran for Duration time.Duration `json:"duration,omitempty"` // the url of this action run diff --git a/modules/structs/issue.go b/modules/structs/issue.go index 6208c28be1..37c71f5736 100644 --- a/modules/structs/issue.go +++ b/modules/structs/issue.go @@ -204,7 +204,7 @@ func (l *IssueTemplateLabels) UnmarshalYAML(value *yaml.Node) error { if err != nil { return err } - for _, v := range strings.Split(str, ",") { + for v := range strings.SplitSeq(str, ",") { if v = strings.TrimSpace(v); v == "" { continue } diff --git a/modules/structs/repo.go b/modules/structs/repo.go index 059f19c2bb..3fa43ce0cb 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -118,7 +118,7 @@ type Repository struct { // enum: ["sha1", "sha256"] ObjectFormatName string `json:"object_format_name"` // swagger:strfmt date-time - MirrorUpdated time.Time `json:"mirror_updated,omitempty"` + MirrorUpdated time.Time `json:"mirror_updated"` RepoTransfer *RepoTransfer `json:"repo_transfer"` Topics []string `json:"topics"` } diff --git a/modules/structs/user.go b/modules/structs/user.go index 49e4c495cf..e0767071d0 100644 --- a/modules/structs/user.go +++ b/modules/structs/user.go @@ -34,9 +34,9 @@ type User struct { // Is the user an administrator IsAdmin bool `json:"is_admin"` // swagger:strfmt date-time - LastLogin time.Time `json:"last_login,omitempty"` + LastLogin time.Time `json:"last_login"` // swagger:strfmt date-time - Created time.Time `json:"created,omitempty"` + Created time.Time `json:"created"` // Is user restricted Restricted bool `json:"restricted"` // Is user active diff --git a/modules/structs/user_gpgkey.go b/modules/structs/user_gpgkey.go index ff9b0aea1d..deae70de33 100644 --- a/modules/structs/user_gpgkey.go +++ b/modules/structs/user_gpgkey.go @@ -21,9 +21,9 @@ type GPGKey struct { CanCertify bool `json:"can_certify"` Verified bool `json:"verified"` // swagger:strfmt date-time - Created time.Time `json:"created_at,omitempty"` + Created time.Time `json:"created_at"` // swagger:strfmt date-time - Expires time.Time `json:"expires_at,omitempty"` + Expires time.Time `json:"expires_at"` } // GPGKeyEmail an email attached to a GPGKey diff --git a/modules/structs/user_key.go b/modules/structs/user_key.go index 08eed59a89..b92552b200 100644 --- a/modules/structs/user_key.go +++ b/modules/structs/user_key.go @@ -15,7 +15,7 @@ type PublicKey struct { Title string `json:"title,omitempty"` Fingerprint string `json:"fingerprint,omitempty"` // swagger:strfmt date-time - Created time.Time `json:"created_at,omitempty"` + Created time.Time `json:"created_at"` Owner *User `json:"user,omitempty"` ReadOnly bool `json:"read_only,omitempty"` KeyType string `json:"key_type,omitempty"` diff --git a/modules/templates/eval/eval_test.go b/modules/templates/eval/eval_test.go index 3e68203638..6b13d14007 100644 --- a/modules/templates/eval/eval_test.go +++ b/modules/templates/eval/eval_test.go @@ -13,7 +13,7 @@ import ( ) func tokens(s string) (a []any) { - for _, v := range strings.Fields(s) { + for v := range strings.FieldsSeq(s) { a = append(a, v) } return a diff --git a/modules/templates/htmlrenderer.go b/modules/templates/htmlrenderer.go index d60397df08..4290e1c29f 100644 --- a/modules/templates/htmlrenderer.go +++ b/modules/templates/htmlrenderer.go @@ -248,7 +248,7 @@ func extractErrorLine(code []byte, lineNum, posNum int, target string) string { b := bufio.NewReader(bytes.NewReader(code)) var line []byte var err error - for i := 0; i < lineNum; i++ { + for i := range lineNum { if line, err = b.ReadBytes('\n'); err != nil { if i == lineNum-1 && errors.Is(err, io.EOF) { err = nil diff --git a/modules/templates/scopedtmpl/scopedtmpl.go b/modules/templates/scopedtmpl/scopedtmpl.go index 41a8ca86e9..d9866b3513 100644 --- a/modules/templates/scopedtmpl/scopedtmpl.go +++ b/modules/templates/scopedtmpl/scopedtmpl.go @@ -7,6 +7,7 @@ import ( "fmt" "html/template" "io" + "maps" "reflect" "sync" texttemplate "text/template" @@ -40,9 +41,7 @@ func (t *ScopedTemplate) Funcs(funcMap template.FuncMap) { panic("cannot add new functions to frozen template set") } t.all.Funcs(funcMap) - for k, v := range funcMap { - t.parseFuncs[k] = v - } + maps.Copy(t.parseFuncs, funcMap) } func (t *ScopedTemplate) New(name string) *template.Template { @@ -159,9 +158,7 @@ func newScopedTemplateSet(all *template.Template, name string) (*scopedTemplateS textTmplPtr.muFuncs.Lock() ts.execFuncs = map[string]reflect.Value{} - for k, v := range textTmplPtr.execFuncs { - ts.execFuncs[k] = v - } + maps.Copy(ts.execFuncs, textTmplPtr.execFuncs) textTmplPtr.muFuncs.Unlock() var collectTemplates func(nodes []parse.Node) @@ -220,9 +217,7 @@ func (ts *scopedTemplateSet) newExecutor(funcMap map[string]any) TemplateExecuto tmpl := texttemplate.New("") tmplPtr := ptr[textTemplate](tmpl) tmplPtr.execFuncs = map[string]reflect.Value{} - for k, v := range ts.execFuncs { - tmplPtr.execFuncs[k] = v - } + maps.Copy(tmplPtr.execFuncs, ts.execFuncs) if funcMap != nil { tmpl.Funcs(funcMap) } diff --git a/modules/templates/util_render.go b/modules/templates/util_render.go index 02851ed75d..e1ad83b88d 100644 --- a/modules/templates/util_render.go +++ b/modules/templates/util_render.go @@ -246,7 +246,8 @@ func RenderMarkdownToHtml(ctx context.Context, input string) template.HTML { //n } func RenderLabels(ctx *Context, labels []*issues_model.Label, repoLink string, isPull bool) template.HTML { - htmlCode := `` + var htmlCode strings.Builder + htmlCode.WriteString(``) for _, label := range labels { // Protect against nil value in labels - shouldn't happen but would cause a panic if so if label == nil { @@ -257,11 +258,11 @@ func RenderLabels(ctx *Context, labels []*issues_model.Label, repoLink string, i if isPull { issuesOrPull = "pulls" } - htmlCode += fmt.Sprintf("%s ", + fmt.Fprintf(&htmlCode, "%s ", repoLink, issuesOrPull, label.ID, RenderLabel(ctx, label)) } - htmlCode += "" - return template.HTML(htmlCode) + htmlCode.WriteString("") + return template.HTML(htmlCode.String()) } func RenderUser(ctx context.Context, user user_model.User) template.HTML { diff --git a/modules/test/logchecker.go b/modules/test/logchecker.go index 8e8fc32216..af82ff0461 100644 --- a/modules/test/logchecker.go +++ b/modules/test/logchecker.go @@ -53,11 +53,11 @@ func (lc *LogChecker) checkLogEvent(event *log.EventFormatted) { } } -var checkerIndex int64 +var checkerIndex atomic.Int64 func NewLogChecker(namePrefix string, level log.Level) (logChecker *LogChecker, cancel func()) { logger := log.GetManager().GetLogger(namePrefix) - newCheckerIndex := atomic.AddInt64(&checkerIndex, 1) + newCheckerIndex := checkerIndex.Add(1) writerName := namePrefix + "-" + fmt.Sprint(newCheckerIndex) lc := &LogChecker{} diff --git a/modules/testlogger/testlogger.go b/modules/testlogger/testlogger.go index 6ced5f6780..54f0462703 100644 --- a/modules/testlogger/testlogger.go +++ b/modules/testlogger/testlogger.go @@ -501,7 +501,7 @@ func PrintCurrentTest(t testing.TB, skip ...int) func() { // Printf takes a format and args and prints the string to os.Stdout func Printf(format string, args ...any) { if log.CanColorStdout { - for i := 0; i < len(args); i++ { + for i := range args { args[i] = log.NewColoredValue(args[i]) } } diff --git a/modules/updatechecker/update_checker.go b/modules/updatechecker/update_checker.go index b0932ba663..8b524b6519 100644 --- a/modules/updatechecker/update_checker.go +++ b/modules/updatechecker/update_checker.go @@ -60,9 +60,9 @@ func getVersionDNS(domainEndpoint string) (version string, err error) { } for _, record := range records { - if strings.HasPrefix(record, "forgejo_versions=") { + if after, ok := strings.CutPrefix(record, "forgejo_versions="); ok { // Get all supported versions, separated by a comma. - supportedVersions := strings.Split(strings.TrimPrefix(record, "forgejo_versions="), ",") + supportedVersions := strings.Split(after, ",") // For now always return the latest supported version. return supportedVersions[len(supportedVersions)-1], nil } diff --git a/modules/util/remove.go b/modules/util/remove.go index 2a65a6b0aa..e2cffc92c9 100644 --- a/modules/util/remove.go +++ b/modules/util/remove.go @@ -12,7 +12,7 @@ import ( // Remove removes the named file or (empty) directory with at most 5 attempts. func Remove(name string) error { var err error - for i := 0; i < 5; i++ { + for range 5 { err = os.Remove(name) if err == nil { break @@ -35,7 +35,7 @@ func Remove(name string) error { // RemoveAll removes the named file or (empty) directory with at most 5 attempts. func RemoveAll(name string) error { var err error - for i := 0; i < 5; i++ { + for range 5 { err = os.RemoveAll(name) if err == nil { break @@ -58,7 +58,7 @@ func RemoveAll(name string) error { // Rename renames (moves) oldpath to newpath with at most 5 attempts. func Rename(oldpath, newpath string) error { var err error - for i := 0; i < 5; i++ { + for i := range 5 { err = os.Rename(oldpath, newpath) if err == nil { break diff --git a/modules/util/rotatingfilewriter/writer_test.go b/modules/util/rotatingfilewriter/writer_test.go index 5b3b351667..c3664d8c4f 100644 --- a/modules/util/rotatingfilewriter/writer_test.go +++ b/modules/util/rotatingfilewriter/writer_test.go @@ -24,7 +24,7 @@ func TestCompressOldFile(t *testing.T) { ng, err := os.OpenFile(nonGzip, os.O_CREATE|os.O_WRONLY, 0o660) require.NoError(t, err) - for i := 0; i < 999; i++ { + for range 999 { f.WriteString("This is a test file\n") ng.WriteString("This is a test file\n") } diff --git a/modules/util/timer_test.go b/modules/util/timer_test.go index 602800c248..1f9a4ac586 100644 --- a/modules/util/timer_test.go +++ b/modules/util/timer_test.go @@ -12,19 +12,19 @@ import ( ) func TestDebounce(t *testing.T) { - var c int64 + var c atomic.Int64 d := Debounce(50 * time.Millisecond) - d(func() { atomic.AddInt64(&c, 1) }) - assert.EqualValues(t, 0, atomic.LoadInt64(&c)) - d(func() { atomic.AddInt64(&c, 1) }) - d(func() { atomic.AddInt64(&c, 1) }) + d(func() { c.Add(1) }) + assert.EqualValues(t, 0, c.Load()) + d(func() { c.Add(1) }) + d(func() { c.Add(1) }) time.Sleep(100 * time.Millisecond) - assert.EqualValues(t, 1, atomic.LoadInt64(&c)) - d(func() { atomic.AddInt64(&c, 1) }) - assert.EqualValues(t, 1, atomic.LoadInt64(&c)) - d(func() { atomic.AddInt64(&c, 1) }) - d(func() { atomic.AddInt64(&c, 1) }) - d(func() { atomic.AddInt64(&c, 1) }) + assert.EqualValues(t, 1, c.Load()) + d(func() { c.Add(1) }) + assert.EqualValues(t, 1, c.Load()) + d(func() { c.Add(1) }) + d(func() { c.Add(1) }) + d(func() { c.Add(1) }) time.Sleep(100 * time.Millisecond) - assert.EqualValues(t, 2, atomic.LoadInt64(&c)) + assert.EqualValues(t, 2, c.Load()) } diff --git a/modules/util/truncate.go b/modules/util/truncate.go index 7207a89177..35836f745c 100644 --- a/modules/util/truncate.go +++ b/modules/util/truncate.go @@ -47,7 +47,7 @@ func SplitTrimSpace(input, sep string) []string { input = strings.ReplaceAll(input, "\r\n", "\n") var stringList []string - for _, s := range strings.Split(input, sep) { + for s := range strings.SplitSeq(input, sep) { // trim leading and trailing space stringList = append(stringList, strings.TrimSpace(s)) } diff --git a/modules/util/util_test.go b/modules/util/util_test.go index a85113b2f4..24fca75e7b 100644 --- a/modules/util/util_test.go +++ b/modules/util/util_test.go @@ -243,7 +243,7 @@ func TestGeneratingEd25519Keypair(t *testing.T) { // And another 32 bytes are required, which is included as random value // in the OpenSSH format. b := make([]byte, 64) - for i := 0; i < 64; i++ { + for i := range 64 { b[i] = byte(i) } rand.Reader = bytes.NewReader(b) diff --git a/modules/validation/binding.go b/modules/validation/binding.go index 463e7e8f7a..23d0622de4 100644 --- a/modules/validation/binding.go +++ b/modules/validation/binding.go @@ -266,17 +266,17 @@ func addEmailBindingRules() { } func portOnly(hostport string) string { - colon := strings.IndexByte(hostport, ':') - if colon == -1 { + _, after, ok := strings.Cut(hostport, ":") + if !ok { return "" } - if i := strings.Index(hostport, "]:"); i != -1 { - return hostport[i+len("]:"):] + if _, after, ok := strings.Cut(hostport, "]:"); ok { + return after } if strings.Contains(hostport, "]") { return "" } - return hostport[colon+len(":"):] + return after } func validPort(p string) bool { diff --git a/modules/validation/helpers.go b/modules/validation/helpers.go index 848fb70af5..ce451b8ff4 100644 --- a/modules/validation/helpers.go +++ b/modules/validation/helpers.go @@ -7,6 +7,7 @@ import ( "net" "net/url" "regexp" + "slices" "strings" "forgejo.org/modules/setting" @@ -40,12 +41,7 @@ func IsValidSiteURL(uri string) bool { return false } - for _, scheme := range setting.Service.ValidSiteURLSchemes { - if scheme == u.Scheme { - return true - } - } - return false + return slices.Contains(setting.Service.ValidSiteURLSchemes, u.Scheme) } // IsAPIURL checks if URL is current Gitea instance API URL diff --git a/modules/validation/validatable.go b/modules/validation/validatable.go index 1b0d4aa382..1751e727f3 100644 --- a/modules/validation/validatable.go +++ b/modules/validation/validatable.go @@ -6,6 +6,7 @@ package validation import ( "fmt" "reflect" + "slices" "strings" "unicode/utf8" @@ -87,10 +88,8 @@ func ValidateMaxLen(value string, maxLen int, name string) []string { } func ValidateOneOf(value any, allowed []any, name string) []string { - for _, allowedElem := range allowed { - if value == allowedElem { - return []string{} - } + if slices.Contains(allowed, value) { + return []string{} } return []string{fmt.Sprintf("Field %s contains the value %v, which is not in allowed subset %v", name, value, allowed)} } diff --git a/modules/web/handler.go b/modules/web/handler.go index 4a7f28b1fa..e3f0b029fd 100644 --- a/modules/web/handler.go +++ b/modules/web/handler.go @@ -17,7 +17,7 @@ import ( var responseStatusProviders = map[reflect.Type]func(req *http.Request) types.ResponseStatusProvider{} func RegisterResponseStatusProvider[T any](fn func(req *http.Request) types.ResponseStatusProvider) { - responseStatusProviders[reflect.TypeOf((*T)(nil)).Elem()] = fn + responseStatusProviders[reflect.TypeFor[T]()] = fn } // responseWriter is a wrapper of http.ResponseWriter, to check whether the response has been written @@ -49,9 +49,9 @@ func (r *responseWriter) WriteHeader(statusCode int) { } var ( - httpReqType = reflect.TypeOf((*http.Request)(nil)) - respWriterType = reflect.TypeOf((*http.ResponseWriter)(nil)).Elem() - cancelFuncType = reflect.TypeOf((*goctx.CancelFunc)(nil)).Elem() + httpReqType = reflect.TypeFor[*http.Request]() + respWriterType = reflect.TypeFor[http.ResponseWriter]() + cancelFuncType = reflect.TypeFor[goctx.CancelFunc]() ) // preCheckHandler checks whether the handler is valid, developers could get first-time feedback, all mistakes could be found at startup diff --git a/modules/web/middleware/binding.go b/modules/web/middleware/binding.go index 123eb29015..06bf55b571 100644 --- a/modules/web/middleware/binding.go +++ b/modules/web/middleware/binding.go @@ -30,7 +30,7 @@ func AssignForm(form any, data map[string]any) { typ := reflect.TypeOf(form) val := reflect.ValueOf(form) - for typ.Kind() == reflect.Ptr { + for typ.Kind() == reflect.Pointer { typ = typ.Elem() val = val.Elem() } @@ -51,7 +51,7 @@ func AssignForm(form any, data map[string]any) { } func getRuleBody(field reflect.StructField, prefix string) string { - for _, rule := range strings.Split(field.Tag.Get("binding"), ";") { + for rule := range strings.SplitSeq(field.Tag.Get("binding"), ";") { if strings.HasPrefix(rule, prefix) { return rule[len(prefix) : len(rule)-1] } @@ -99,7 +99,7 @@ func Validate(errs binding.Errors, data map[string]any, f any, l translation.Loc typ := reflect.TypeOf(f) - if typ.Kind() == reflect.Ptr { + if typ.Kind() == reflect.Pointer { typ = typ.Elem() } diff --git a/modules/web/middleware/data.go b/modules/web/middleware/data.go index 4603e64052..c8bb8276c5 100644 --- a/modules/web/middleware/data.go +++ b/modules/web/middleware/data.go @@ -5,6 +5,7 @@ package middleware import ( "context" + "maps" "time" "forgejo.org/modules/setting" @@ -22,9 +23,7 @@ func (ds ContextData) GetData() ContextData { } func (ds ContextData) MergeFrom(other ContextData) ContextData { - for k, v := range other { - ds[k] = v - } + maps.Copy(ds, other) return ds } diff --git a/modules/web/route.go b/modules/web/route.go index ceb97ba333..dc83178f74 100644 --- a/modules/web/route.go +++ b/modules/web/route.go @@ -107,8 +107,8 @@ func (r *Route) Methods(methods, pattern string, h ...any) { middlewares, handlerFunc := r.wrapMiddlewareAndHandler(h) fullPattern := r.getPattern(pattern) if strings.Contains(methods, ",") { - methods := strings.Split(methods, ",") - for _, method := range methods { + methods := strings.SplitSeq(methods, ",") + for method := range methods { r.R.With(middlewares...).Method(strings.TrimSpace(method), fullPattern, handlerFunc) } } else { diff --git a/routers/api/actions/oidc.go b/routers/api/actions/oidc.go index 92341e4f66..d824030ca7 100644 --- a/routers/api/actions/oidc.go +++ b/routers/api/actions/oidc.go @@ -99,8 +99,7 @@ func OIDCRoutes(prefix string) *web.Route { // Add custom claims by iterating over [actions_service.IDTokenCustomClaims] // and inspecting the names of the json struct tags - customClaims := actions_service.IDTokenCustomClaims{} - rt := reflect.TypeOf(customClaims) + rt := reflect.TypeFor[actions_service.IDTokenCustomClaims]() for i := 0; i < rt.NumField(); i++ { f := rt.Field(i) diff --git a/routers/api/packages/cargo/cargo.go b/routers/api/packages/cargo/cargo.go index 50dc8d1c3d..9d4539a732 100644 --- a/routers/api/packages/cargo/cargo.go +++ b/routers/api/packages/cargo/cargo.go @@ -95,10 +95,7 @@ type SearchResultMeta struct { // https://doc.rust-lang.org/cargo/reference/registries.html#search func SearchPackages(ctx *context.Context) { - page := ctx.FormInt("page") - if page < 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) perPage := ctx.FormInt("per_page") paginator := db.ListOptions{ Page: page, diff --git a/routers/api/packages/composer/composer.go b/routers/api/packages/composer/composer.go index 9e67d419ec..8f87d27f3f 100644 --- a/routers/api/packages/composer/composer.go +++ b/routers/api/packages/composer/composer.go @@ -53,10 +53,7 @@ func ServiceIndex(ctx *context.Context) { // SearchPackages searches packages, only "q" is supported // https://packagist.org/apidoc#search-packages func SearchPackages(ctx *context.Context) { - page := ctx.FormInt("page") - if page < 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) perPage := ctx.FormInt("per_page") paginator := db.ListOptions{ Page: page, diff --git a/routers/api/v1/repo/issue_dependency.go b/routers/api/v1/repo/issue_dependency.go index 7c087e28b9..3d3ca58bd4 100644 --- a/routers/api/v1/repo/issue_dependency.go +++ b/routers/api/v1/repo/issue_dependency.go @@ -78,10 +78,7 @@ func GetIssueDependencies(ctx *context.APIContext) { return } - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) limit := ctx.FormInt("limit") if limit == 0 { limit = setting.API.DefaultPagingNum @@ -332,10 +329,7 @@ func GetIssueBlocks(ctx *context.APIContext) { return } - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) limit := ctx.FormInt("limit") if limit <= 1 { limit = setting.API.DefaultPagingNum diff --git a/routers/api/v1/repo/wiki.go b/routers/api/v1/repo/wiki.go index 71d29d026b..2b14bacf89 100644 --- a/routers/api/v1/repo/wiki.go +++ b/routers/api/v1/repo/wiki.go @@ -303,10 +303,7 @@ func ListWikiPages(ctx *context.APIContext) { return } - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) limit := ctx.FormInt("limit") if limit <= 1 { limit = setting.API.DefaultPagingNum @@ -439,10 +436,7 @@ func ListPageRevisions(ctx *context.APIContext) { // get commit count - wiki revisions commitsCount, _ := wikiRepo.FileCommitsCount(ctx.Repo.Repository.GetWikiBranchName(), pageFilename) - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) // get Commit Count commitsHistory, err := wikiRepo.CommitsByFileAndRange( diff --git a/routers/install/install.go b/routers/install/install.go index 243f4a8f19..95452e64dd 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -11,6 +11,7 @@ import ( "os" "os/exec" "path/filepath" + "slices" "strconv" "strings" "time" @@ -103,11 +104,8 @@ func Install(ctx *context.Context) { curDBType := setting.Database.Type.String() var isCurDBTypeSupported bool - for _, dbType := range setting.SupportedDatabaseTypes { - if dbType == curDBType { - isCurDBTypeSupported = true - break - } + if slices.Contains(setting.SupportedDatabaseTypes, curDBType) { + isCurDBTypeSupported = true } if !isCurDBTypeSupported { curDBType = "mysql" diff --git a/routers/private/serv.go b/routers/private/serv.go index 7c4a5b8bb7..26f7e288cd 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -6,6 +6,7 @@ package private import ( "fmt" "net/http" + "slices" "strings" asymkey_model "forgejo.org/models/asymkey" @@ -165,15 +166,13 @@ func ServCommand(ctx *context.PrivateContext) { if err != nil { if repo_model.IsErrRepoNotExist(err) { repoExist = false - for _, verb := range ctx.FormStrings("verb") { - if verb == "git-upload-pack" { - // User is fetching/cloning a non-existent repository - sshLogger.Warn("Failed authentication attempt (cannot find repository: %s/%s) from %s", results.OwnerName, results.RepoName, ctx.RemoteAddr()) - ctx.JSON(http.StatusNotFound, private.Response{ - UserMsg: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName), - }) - return - } + if slices.Contains(ctx.FormStrings("verb"), "git-upload-pack") { + // User is fetching/cloning a non-existent repository + sshLogger.Warn("Failed authentication attempt (cannot find repository: %s/%s) from %s", results.OwnerName, results.RepoName, ctx.RemoteAddr()) + ctx.JSON(http.StatusNotFound, private.Response{ + UserMsg: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName), + }) + return } } else { sshLogger.Error("Unable to get repository: %s/%s Error: %v", results.OwnerName, results.RepoName, err) diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go index 27a241f508..e03fea9da2 100644 --- a/routers/web/admin/auths.go +++ b/routers/web/admin/auths.go @@ -166,7 +166,7 @@ func parseOAuth2Config(form forms.AuthenticationForm) *oauth2.Source { customURLMapping = nil } var scopes []string - for _, s := range strings.Split(form.Oauth2Scopes, ",") { + for s := range strings.SplitSeq(form.Oauth2Scopes, ",") { s = strings.TrimSpace(s) if s != "" { scopes = append(scopes, s) diff --git a/routers/web/admin/config.go b/routers/web/admin/config.go index e1c3a5f9ee..2d3ea78052 100644 --- a/routers/web/admin/config.go +++ b/routers/web/admin/config.go @@ -62,7 +62,7 @@ func TestCache(ctx *context.Context) { func shadowPasswordKV(cfgItem, splitter string) string { fields := strings.Split(cfgItem, splitter) - for i := 0; i < len(fields); i++ { + for i := range fields { if strings.HasPrefix(fields[i], "password=") { fields[i] = "password=******" break diff --git a/routers/web/admin/notice.go b/routers/web/admin/notice.go index 8bcaadf915..f67430f386 100644 --- a/routers/web/admin/notice.go +++ b/routers/web/admin/notice.go @@ -26,10 +26,7 @@ func Notices(ctx *context.Context) { ctx.Data["PageIsAdminNotices"] = true total := system_model.CountNotices(ctx) - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) notices, err := system_model.Notices(ctx, page, setting.UI.Admin.NoticePagingNum) if err != nil { diff --git a/routers/web/admin/packages.go b/routers/web/admin/packages.go index 5c80a1eada..032d10fc41 100644 --- a/routers/web/admin/packages.go +++ b/routers/web/admin/packages.go @@ -24,10 +24,7 @@ const ( // Packages shows all packages func Packages(ctx *context.Context) { - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) query := ctx.FormTrim("q") packageType := ctx.FormTrim("type") sort := ctx.FormTrim("sort") diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 89d2fd37ce..eba2b441c4 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -283,8 +283,8 @@ type userInfoResponse struct { func ifOnlyPublicGroups(scopes string) bool { scopes = strings.ReplaceAll(scopes, ",", " ") - scopesList := strings.Fields(scopes) - for _, scope := range scopesList { + scopesList := strings.FieldsSeq(scopes) + for scope := range scopesList { if scope == "all" || scope == "read:organization" || scope == "read:admin" { return false } @@ -424,11 +424,11 @@ func AuthorizeOAuth(ctx *context.Context) { errs := binding.Errors{} errs = form.Validate(ctx.Req, errs) if len(errs) > 0 { - errstring := "" + var errstring strings.Builder for _, e := range errs { - errstring += e.Error() + "\n" + errstring.WriteString(e.Error() + "\n") } - ctx.ServerError("AuthorizeOAuth: Validate: ", fmt.Errorf("errors occurred during validation: %s", errstring)) + ctx.ServerError("AuthorizeOAuth: Validate: ", fmt.Errorf("errors occurred during validation: %s", errstring.String())) return } diff --git a/routers/web/org/members.go b/routers/web/org/members.go index 65e2b032e8..3237e23ab9 100644 --- a/routers/web/org/members.go +++ b/routers/web/org/members.go @@ -27,10 +27,7 @@ func Members(ctx *context.Context) { ctx.Data["Title"] = org.FullName ctx.Data["PageIsOrgMembers"] = true - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) opts := &organization.FindOrgMembersOpts{ Doer: ctx.Doer, diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index a492d85d84..6e5f4079ac 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -48,10 +48,7 @@ func Projects(ctx *context.Context) { isShowClosed := strings.ToLower(ctx.FormTrim("state")) == "closed" keyword := ctx.FormTrim("q") - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) var projectType project_model.Type if ctx.ContextUser.IsOrganization() { diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index 0fe52bfb48..3c32a3b9e5 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -46,10 +46,7 @@ func Branches(ctx *context.Context) { ctx.Data["PageIsViewCode"] = true ctx.Data["PageIsBranches"] = true - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) pageSize := setting.Git.BranchesRangeSize kw := ctx.FormString("q") diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 3db8a091b0..5b8f35f5b1 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -68,10 +68,7 @@ func Commits(ctx *context.Context) { return } - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) pageSize := ctx.FormInt("limit") if pageSize <= 0 { @@ -241,10 +238,7 @@ func FileHistory(ctx *context.Context) { return } - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) commits, err := ctx.Repo.GitRepo.CommitsByFileAndRange( git.CommitsByFileAndRangeOptions{ diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index 2948c1db3c..fb1aaf042a 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -832,7 +832,7 @@ func cleanUploadFileName(name string) string { // Rebase the filename name = util.PathJoinRel(name) // Git disallows any filenames to have a .git directory in them. - for _, part := range strings.Split(name, "/") { + for part := range strings.SplitSeq(name, "/") { if strings.ToLower(part) == ".git" { return "" } diff --git a/routers/web/repo/githttp.go b/routers/web/repo/githttp.go index 403245596d..de05d99a3e 100644 --- a/routers/web/repo/githttp.go +++ b/routers/web/repo/githttp.go @@ -13,6 +13,7 @@ import ( "os" "path/filepath" "regexp" + "slices" "strconv" "strings" "sync" @@ -363,12 +364,7 @@ func containsParentDirectorySeparator(v string) bool { if !strings.Contains(v, "..") { return false } - for _, ent := range strings.FieldsFunc(v, isSlashRune) { - if ent == ".." { - return true - } - } - return false + return slices.Contains(strings.FieldsFunc(v, isSlashRune), "..") } func isSlashRune(r rune) bool { return r == '/' || r == '\\' } diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index cc09651e97..3852c4c18f 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "html/template" + "maps" "math/big" "net/http" "net/url" @@ -267,10 +268,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt archived := ctx.FormBool("archived") - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) var total int switch { @@ -1014,9 +1012,7 @@ func NewIssue(ctx *context.Context) { _, templateErrs := issue_service.GetTemplatesFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo) templateLoaded, errs := setTemplateIfExists(ctx, issueTemplateKey, issueTemplateCandidates) - for k, v := range errs { - templateErrs[k] = v - } + maps.Copy(templateErrs, errs) if ctx.Written() { return } @@ -2190,7 +2186,7 @@ func getActionIssues(ctx *context.Context) issues_model.IssueList { return nil } issueIDs := make([]int64, 0, 10) - for _, stringIssueID := range strings.Split(commaSeparatedIssueIDs, ",") { + for stringIssueID := range strings.SplitSeq(commaSeparatedIssueIDs, ",") { issueID, err := strconv.ParseInt(stringIssueID, 10, 64) if err != nil { ctx.ServerError("ParseInt", err) diff --git a/routers/web/repo/issue_label_test.go b/routers/web/repo/issue_label_test.go index 0adcc39499..b4d350b31d 100644 --- a/routers/web/repo/issue_label_test.go +++ b/routers/web/repo/issue_label_test.go @@ -6,6 +6,7 @@ package repo import ( "net/http" "strconv" + "strings" "testing" issues_model "forgejo.org/models/issues" @@ -21,14 +22,14 @@ import ( ) func int64SliceToCommaSeparated(a []int64) string { - s := "" + var s strings.Builder for i, n := range a { if i > 0 { - s += "," + s.WriteString(",") } - s += strconv.Itoa(int(n)) + s.WriteString(strconv.Itoa(int(n))) } - return s + return s.String() } func TestInitializeLabels(t *testing.T) { diff --git a/routers/web/repo/milestone.go b/routers/web/repo/milestone.go index 920a9ee12a..5ede62d992 100644 --- a/routers/web/repo/milestone.go +++ b/routers/web/repo/milestone.go @@ -40,10 +40,7 @@ func Milestones(ctx *context.Context) { isShowClosed := ctx.FormString("state") == "closed" sortType := ctx.FormString("sort") keyword := ctx.FormTrim("q") - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) miles, total, err := db.FindAndCount[issues_model.Milestone](ctx, issues_model.FindMilestoneOptions{ ListOptions: db.ListOptions{ diff --git a/routers/web/repo/packages.go b/routers/web/repo/packages.go index c947fb99bf..fd7e886557 100644 --- a/routers/web/repo/packages.go +++ b/routers/web/repo/packages.go @@ -21,10 +21,7 @@ const ( // Packages displays a list of all packages in the repository func Packages(ctx *context.Context) { - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) query := ctx.FormTrim("q") packageType := ctx.FormTrim("type") diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index e3e9ce0eb7..98e4c35fa2 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -57,10 +57,7 @@ func Projects(ctx *context.Context) { isShowClosed := strings.ToLower(ctx.FormTrim("state")) == "closed" keyword := ctx.FormTrim("q") repo := ctx.Repo.Repository - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) ctx.Data["OpenCount"] = repo.NumOpenProjects ctx.Data["ClosedCount"] = repo.NumClosedProjects diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 6b6ec55720..e5ede13bf5 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -92,7 +92,7 @@ func checkContextUser(ctx *context.Context, uid int64) *user_model.User { if !ctx.Doer.IsAdmin { orgsAvailable := []*organization.Organization{} - for i := 0; i < len(orgs); i++ { + for i := range orgs { if orgs[i].CanCreateRepo() { orgsAvailable = append(orgsAvailable, orgs[i]) } diff --git a/routers/web/repo/setting/lfs.go b/routers/web/repo/setting/lfs.go index 78184930d3..40181ebb52 100644 --- a/routers/web/repo/setting/lfs.go +++ b/routers/web/repo/setting/lfs.go @@ -44,10 +44,7 @@ func LFSFiles(ctx *context.Context) { ctx.NotFound("LFSFiles", nil) return } - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) total, err := git_model.CountLFSMetaObjects(ctx, ctx.Repo.Repository.ID) if err != nil { ctx.ServerError("LFSFiles", err) @@ -76,10 +73,7 @@ func LFSLocks(ctx *context.Context) { } ctx.Data["LFSFilesLink"] = ctx.Repo.RepoLink + "/settings/lfs" - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) total, err := git_model.CountLFSLockByRepoID(ctx, ctx.Repo.Repository.ID) if err != nil { ctx.ServerError("LFSLocks", err) diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go index 1b5265978a..8153288312 100644 --- a/routers/web/repo/wiki.go +++ b/routers/web/repo/wiki.go @@ -374,10 +374,7 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) ctx.Data["CommitCount"] = commitsCount // get page - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) // get Commit Count commitsHistory, err := wikiRepo.CommitsByFileAndRange( diff --git a/routers/web/shared/actions/runners.go b/routers/web/shared/actions/runners.go index 012ec246fd..93543f92df 100644 --- a/routers/web/shared/actions/runners.go +++ b/routers/web/shared/actions/runners.go @@ -134,10 +134,7 @@ func RunnersList(ctx *context.Context) { return } - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) opts := actions_model.FindRunnerOptions{ ListOptions: db.ListOptions{ @@ -216,10 +213,7 @@ func RunnerDetails(ctx *context.Context) { } runnerID := ctx.ParamsInt64(":runnerid") - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) runner, err := actions_model.GetVisibleRunnerByID(ctx, runnerID, rCtx.OwnerID, rCtx.RepoID) if errors.Is(err, util.ErrNotExist) { diff --git a/routers/web/user/home.go b/routers/web/user/home.go index 9c40236475..60d6fc2bd0 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -191,7 +191,7 @@ func Milestones(ctx *context.Context) { reposQuery = reposQuery[1 : len(reposQuery)-1] // for each ID (delimiter ",") add to int to repoIDs - for _, rID := range strings.Split(reposQuery, ",") { + for rID := range strings.SplitSeq(reposQuery, ",") { // Ensure nonempty string entries if rID != "" && rID != "0" { rIDint64, err := strconv.ParseInt(rID, 10, 64) @@ -532,10 +532,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { opts.IsClosed = optional.Some(isShowClosed) // Make sure page number is at least 1. Will be posted to ctx.Data. - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) opts.Paginator = &db.ListOptions{ Page: page, PageSize: setting.UI.IssuePagingNum, diff --git a/routers/web/user/notification.go b/routers/web/user/notification.go index 3b69e5bddf..1445658c18 100644 --- a/routers/web/user/notification.go +++ b/routers/web/user/notification.go @@ -226,10 +226,7 @@ func NotificationPurgePost(ctx *context.Context) { // NotificationSubscriptions returns the list of subscribed issues func NotificationSubscriptions(ctx *context.Context) { - page := ctx.FormInt("page") - if page < 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) sortType := ctx.FormString("sort") ctx.Data["SortType"] = sortType @@ -358,10 +355,7 @@ func NotificationSubscriptions(ctx *context.Context) { // NotificationWatching returns the list of watching repos func NotificationWatching(ctx *context.Context) { - page := ctx.FormInt("page") - if page < 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) keyword := ctx.FormTrim("q") ctx.Data["Keyword"] = keyword diff --git a/routers/web/user/package.go b/routers/web/user/package.go index 9a77af0bb2..0c403a2613 100644 --- a/routers/web/user/package.go +++ b/routers/web/user/package.go @@ -42,10 +42,7 @@ const ( // ListPackages displays a list of all packages of the context user func ListPackages(ctx *context.Context) { shared_user.PrepareContextForProfileBigAvatar(ctx) - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) query := ctx.FormTrim("q") packageType := ctx.FormTrim("type") @@ -314,10 +311,7 @@ func ListPackageVersions(ctx *context.Context) { return } - page := ctx.FormInt("page") - if page <= 1 { - page = 1 - } + page := max(ctx.FormInt("page"), 1) pagination := &db.ListOptions{ PageSize: setting.UI.PackagesPagingNum, Page: page, diff --git a/services/actions/rerun.go b/services/actions/rerun.go index f6dd4af5c7..61aede5d7c 100644 --- a/services/actions/rerun.go +++ b/services/actions/rerun.go @@ -4,6 +4,8 @@ package actions import ( + "slices" + actions_model "forgejo.org/models/actions" "forgejo.org/modules/container" ) @@ -20,13 +22,10 @@ func GetAllRerunJobs(job *actions_model.ActionRunJob, allJobs []*actions_model.A if rerunJobsIDSet.Contains(j.JobID) { continue } - for _, need := range j.Needs { - if rerunJobsIDSet.Contains(need) { - found = true - rerunJobs = append(rerunJobs, j) - rerunJobsIDSet.Add(j.JobID) - break - } + if slices.ContainsFunc(j.Needs, rerunJobsIDSet.Contains) { + found = true + rerunJobs = append(rerunJobs, j) + rerunJobsIDSet.Add(j.JobID) } } if !found { diff --git a/services/auth/oauth2.go b/services/auth/oauth2.go index 1c1809b092..a23f586ffd 100644 --- a/services/auth/oauth2.go +++ b/services/auth/oauth2.go @@ -39,7 +39,7 @@ func grantAdditionalScopes(grantScopes string) string { } var apiTokenScopes []string - for _, apiTokenScope := range strings.Split(grantScopes, " ") { + for apiTokenScope := range strings.SplitSeq(grantScopes, " ") { if slices.Index(scopesSupported, apiTokenScope) == -1 { apiTokenScopes = append(apiTokenScopes, apiTokenScope) } diff --git a/services/auth/source/oauth2/urlmapping.go b/services/auth/source/oauth2/urlmapping.go index d0442d58a8..b9f445caa7 100644 --- a/services/auth/source/oauth2/urlmapping.go +++ b/services/auth/source/oauth2/urlmapping.go @@ -14,11 +14,11 @@ type CustomURLMapping struct { // CustomURLSettings describes the urls values and availability to use when customizing OAuth2 provider URLs type CustomURLSettings struct { - AuthURL Attribute `json:",omitempty"` - TokenURL Attribute `json:",omitempty"` - ProfileURL Attribute `json:",omitempty"` - EmailURL Attribute `json:",omitempty"` - Tenant Attribute `json:",omitempty"` + AuthURL Attribute + TokenURL Attribute + ProfileURL Attribute + EmailURL Attribute + Tenant Attribute } // Attribute describes the availability, and required status for a custom url configuration diff --git a/services/auth/source/pam/source_authenticate.go b/services/auth/source/pam/source_authenticate.go index 8a84683d29..f368d7e0b1 100644 --- a/services/auth/source/pam/source_authenticate.go +++ b/services/auth/source/pam/source_authenticate.go @@ -37,9 +37,9 @@ func (source *Source) Authenticate(ctx context.Context, user *user_model.User, u // Allow PAM sources with `@` in their name, like from Active Directory username := pamLogin email := pamLogin - idx := strings.Index(pamLogin, "@") - if idx > -1 { - username = pamLogin[:idx] + before, _, ok := strings.Cut(pamLogin, "@") + if ok { + username = before } if validation.ValidateEmail(email) != nil { if source.EmailDomain != "" { diff --git a/services/auth/source/smtp/source_authenticate.go b/services/auth/source/smtp/source_authenticate.go index 3d7ccd0669..919a7d0b5b 100644 --- a/services/auth/source/smtp/source_authenticate.go +++ b/services/auth/source/smtp/source_authenticate.go @@ -21,10 +21,10 @@ import ( func (source *Source) Authenticate(ctx context.Context, user *user_model.User, userName, password string) (*user_model.User, error) { // Verify allowed domains. if len(source.AllowedDomains) > 0 { - idx := strings.Index(userName, "@") - if idx == -1 { + _, after, ok := strings.Cut(userName, "@") + if !ok { return nil, user_model.ErrUserNotExist{Name: userName} - } else if !util.SliceContainsString(strings.Split(source.AllowedDomains, ","), userName[idx+1:], true) { + } else if !util.SliceContainsString(strings.Split(source.AllowedDomains, ","), after, true) { return nil, user_model.ErrUserNotExist{Name: userName} } } @@ -61,9 +61,9 @@ func (source *Source) Authenticate(ctx context.Context, user *user_model.User, u } username := userName - idx := strings.Index(userName, "@") - if idx > -1 { - username = userName[:idx] + before, _, ok := strings.Cut(userName, "@") + if ok { + username = before } user = &user_model.User{ diff --git a/services/context/api.go b/services/context/api.go index 434da29906..1064b1ab4a 100644 --- a/services/context/api.go +++ b/services/context/api.go @@ -10,6 +10,7 @@ import ( "fmt" "net/http" "net/url" + "slices" "strings" issues_model "forgejo.org/models/issues" @@ -466,13 +467,7 @@ func (ctx *APIContext) IsUserRepoAdmin() bool { // IsUserRepoWriter returns true if current user has write privilege in current repo func (ctx *APIContext) IsUserRepoWriter(unitTypes []unit.Type) bool { - for _, unitType := range unitTypes { - if ctx.Repo.CanWrite(unitType) { - return true - } - } - - return false + return slices.ContainsFunc(unitTypes, ctx.Repo.CanWrite) } // Returns true when the requests indicates that it accepts a Github response. diff --git a/services/context/context_model.go b/services/context/context_model.go index 1a8751ee63..dae244f843 100644 --- a/services/context/context_model.go +++ b/services/context/context_model.go @@ -4,6 +4,8 @@ package context import ( + "slices" + "forgejo.org/models/unit" ) @@ -19,11 +21,5 @@ func (ctx *Context) IsUserRepoAdmin() bool { // IsUserRepoWriter returns true if current user has write privilege in current repo func (ctx *Context) IsUserRepoWriter(unitTypes []unit.Type) bool { - for _, unitType := range unitTypes { - if ctx.Repo.CanWrite(unitType) { - return true - } - } - - return false + return slices.ContainsFunc(unitTypes, ctx.Repo.CanWrite) } diff --git a/services/context/permission.go b/services/context/permission.go index 49504e5043..f898bd98ae 100644 --- a/services/context/permission.go +++ b/services/context/permission.go @@ -5,6 +5,7 @@ package context import ( "net/http" + "slices" auth_model "forgejo.org/models/auth" "forgejo.org/models/perm" @@ -47,10 +48,8 @@ func CanEnableEditor() func(ctx *Context) { // RequireRepoWriterOr returns a middleware for requiring repository write to one of the unit permission func RequireRepoWriterOr(unitTypes ...unit.Type) func(ctx *Context) { return func(ctx *Context) { - for _, unitType := range unitTypes { - if ctx.Repo.CanWrite(unitType) { - return - } + if slices.ContainsFunc(unitTypes, ctx.Repo.CanWrite) { + return } ctx.NotFound(ctx.Req.URL.RequestURI(), nil) } @@ -85,10 +84,8 @@ func RequireRepoReader(unitType unit.Type) func(ctx *Context) { // RequireRepoReaderOr returns a middleware for requiring repository write to one of the unit permission func RequireRepoReaderOr(unitTypes ...unit.Type) func(ctx *Context) { return func(ctx *Context) { - for _, unitType := range unitTypes { - if ctx.Repo.CanRead(unitType) { - return - } + if slices.ContainsFunc(unitTypes, ctx.Repo.CanRead) { + return } if log.IsTrace() { var format string diff --git a/services/context/repo.go b/services/context/repo.go index ebc9109c96..583eb35474 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -395,14 +395,14 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) { followingRepoList, err := repo_model.FindFollowingReposByRepoID(ctx, repo.ID) if err == nil { - followingRepoString := "" + var followingRepoString strings.Builder for idx, followingRepo := range followingRepoList { if idx > 0 { - followingRepoString += ";" + followingRepoString.WriteString(";") } - followingRepoString += followingRepo.URI + followingRepoString.WriteString(followingRepo.URI) } - ctx.Data["FollowingRepos"] = followingRepoString + ctx.Data["FollowingRepos"] = followingRepoString.String() } else if err != repo_model.ErrMirrorNotExist { ctx.ServerError("FindFollowingRepoByRepoID", err) return diff --git a/services/context/upload/upload.go b/services/context/upload/upload.go index e71fc50c1f..79f4d66f5f 100644 --- a/services/context/upload/upload.go +++ b/services/context/upload/upload.go @@ -38,7 +38,7 @@ func Verify(buf []byte, fileName, allowedTypesStr string) error { allowedTypesStr = strings.ReplaceAll(allowedTypesStr, "|", ",") // compat for old config format allowedTypes := []string{} - for _, entry := range strings.Split(allowedTypesStr, ",") { + for entry := range strings.SplitSeq(allowedTypesStr, ",") { entry = strings.ToLower(strings.TrimSpace(entry)) if entry != "" { allowedTypes = append(allowedTypes, entry) diff --git a/services/convert/activitypub_user_action.go b/services/convert/activitypub_user_action.go index b08eaa14c7..6db3834ef2 100644 --- a/services/convert/activitypub_user_action.go +++ b/services/convert/activitypub_user_action.go @@ -8,6 +8,7 @@ import ( "fmt" "html" "net/url" + "strings" "time" activities_model "forgejo.org/models/activities" @@ -73,7 +74,7 @@ func ActionToForgeUserActivity(ctx context.Context, action *activities_model.Act if err := json.Unmarshal([]byte(action.GetContent()), commits); err != nil { return fm.ForgeUserActivity{}, err } - commitsHTML := "" + var commitsHTML strings.Builder renderCommit := func(commit *PushCommit) string { return fmt.Sprintf(`
  • %s
    %s
  • `, fmt.Sprintf("%s/commit/%s", action.GetRepoAbsoluteLink(ctx), url.PathEscape(commit.Sha1)), @@ -82,9 +83,9 @@ func ActionToForgeUserActivity(ctx context.Context, action *activities_model.Act ) } for _, commit := range commits.Commits { - commitsHTML += renderCommit(commit) + commitsHTML.WriteString(renderCommit(commit)) } - return makeUserActivity("pushed to %s at %s: ", renderBranch(), renderRepo(), commitsHTML) + return makeUserActivity("pushed to %s at %s: ", renderBranch(), renderRepo(), commitsHTML.String()) case activities_model.ActionCreateIssue: if err := action.LoadIssue(ctx); err != nil { return fm.ForgeUserActivity{}, err diff --git a/services/cron/tasks.go b/services/cron/tasks.go index b547acdf05..bd64dd081d 100644 --- a/services/cron/tasks.go +++ b/services/cron/tasks.go @@ -54,7 +54,7 @@ func (t *Task) IsEnabled() bool { // GetConfig will return a copy of the task's config func (t *Task) GetConfig() Config { - if reflect.TypeOf(t.config).Kind() == reflect.Ptr { + if reflect.TypeOf(t.config).Kind() == reflect.Pointer { // Pointer: return reflect.New(reflect.ValueOf(t.config).Elem().Type()).Interface().(Config) } diff --git a/services/doctor/push_mirror_consistency.go b/services/doctor/push_mirror_consistency.go index 07986770b2..e85b1740a4 100644 --- a/services/doctor/push_mirror_consistency.go +++ b/services/doctor/push_mirror_consistency.go @@ -23,7 +23,7 @@ func FixPushMirrorsWithoutGitRemote(ctx context.Context, logger log.Logger, auto return err } - for i := 0; i < len(pushMirrors); i++ { + for i := range pushMirrors { _, err = repo_model.GetPushMirrorRemoteAddress(repo.OwnerName, repo.Name, pushMirrors[i].RemoteName) if err != nil { if strings.Contains(err.Error(), "No such remote") { diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index e894b79a14..f9443b8b6c 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -10,6 +10,7 @@ import ( "net/http" "net/url" "regexp" + "slices" "strings" "forgejo.org/models" @@ -383,13 +384,7 @@ func (i IssueLockForm) HasValidReason() bool { return true } - for _, v := range setting.Repository.Issue.LockReasons { - if v == i.Reason { - return true - } - } - - return false + return slices.Contains(setting.Repository.Issue.LockReasons, i.Reason) } // CreateProjectForm form for creating a project diff --git a/services/gitdiff/csv.go b/services/gitdiff/csv.go index 8db73c56a3..c10ee14490 100644 --- a/services/gitdiff/csv.go +++ b/services/gitdiff/csv.go @@ -134,7 +134,7 @@ func createCsvDiffSingle(reader *csv.Reader, celltype TableDiffCellType) ([]*Tab return nil, err } cells := make([]*TableDiffCell, len(row)) - for j := 0; j < len(row); j++ { + for j := range row { if celltype == TableDiffCellDel { cells[j] = &TableDiffCell{LeftCell: row[j], Type: celltype} } else { @@ -365,11 +365,11 @@ func getColumnMapping(baseCSVReader, headCSVReader *csvReader) ([]int, []int) { } // Loops through the baseRow and see if there is a match in the head row - for i := 0; i < len(baseRow); i++ { + for i := range baseRow { base2HeadColMap[i] = unmappedColumn baseCell, err := getCell(baseRow, i) if err == nil { - for j := 0; j < len(headRow); j++ { + for j := range headRow { if head2BaseColMap[j] == -1 { headCell, err := getCell(headRow, j) if err == nil && baseCell == headCell { @@ -390,7 +390,7 @@ func getColumnMapping(baseCSVReader, headCSVReader *csvReader) ([]int, []int) { // tryMapColumnsByContent tries to map missing columns by the content of the first lines. func tryMapColumnsByContent(baseCSVReader *csvReader, base2HeadColMap []int, headCSVReader *csvReader, head2BaseColMap []int) { - for i := 0; i < len(base2HeadColMap); i++ { + for i := range base2HeadColMap { headStart := 0 for base2HeadColMap[i] == unmappedColumn && headStart < len(head2BaseColMap) { if head2BaseColMap[headStart] == unmappedColumn { @@ -424,7 +424,7 @@ func getCell(row []string, column int) (string, error) { // countUnmappedColumns returns the count of unmapped columns. func countUnmappedColumns(mapping []int) int { count := 0 - for i := 0; i < len(mapping); i++ { + for i := range mapping { if mapping[i] == unmappedColumn { count++ } diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 544c664ca2..c1d0bc0107 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -524,10 +524,7 @@ func ParsePatch(ctx context.Context, maxLines, maxLineCharacters, maxFiles int, // OK let's set a reasonable buffer size. // This should be at least the size of maxLineCharacters or 4096 whichever is larger. - readerSize := maxLineCharacters - if readerSize < 4096 { - readerSize = 4096 - } + readerSize := max(maxLineCharacters, 4096) input := bufio.NewReaderSize(reader, readerSize) line, err := input.ReadString('\n') diff --git a/services/gitdiff/gitdiff_test.go b/services/gitdiff/gitdiff_test.go index d4d1cd4460..7ba439be35 100644 --- a/services/gitdiff/gitdiff_test.go +++ b/services/gitdiff/gitdiff_test.go @@ -445,7 +445,7 @@ index 0000000..6bb8f39 ` diffBuilder.WriteString(diff) - for i := 0; i < 35; i++ { + for i := range 35 { diffBuilder.WriteString("+line" + strconv.Itoa(i) + "\n") } diff = diffBuilder.String() @@ -482,11 +482,11 @@ index 0000000..6bb8f39 diffBuilder.Reset() diffBuilder.WriteString(diff) - for i := 0; i < 33; i++ { + for i := range 33 { diffBuilder.WriteString("+line" + strconv.Itoa(i) + "\n") } diffBuilder.WriteString("+line33") - for i := 0; i < 512; i++ { + for range 512 { diffBuilder.WriteString("0123456789ABCDEF") } diffBuilder.WriteByte('\n') diff --git a/services/gitdiff/highlightdiff_test.go b/services/gitdiff/highlightdiff_test.go index 0070173b9f..f5486b3f34 100644 --- a/services/gitdiff/highlightdiff_test.go +++ b/services/gitdiff/highlightdiff_test.go @@ -101,7 +101,7 @@ func TestDiffWithHighlightPlaceholderExhausted(t *testing.T) { func TestDiffWithHighlightTagMatch(t *testing.T) { totalOverflow := 0 - for i := 0; i < 100; i++ { + for i := range 100 { hcd := NewHighlightCodeDiff() hcd.placeholderMaxCount = i diffs := hcd.diffWithHighlight( diff --git a/services/issue/issue.go b/services/issue/issue.go index ab42916017..41a6000d52 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -8,6 +8,7 @@ import ( "context" "errors" "fmt" + "slices" "time" activities_model "forgejo.org/models/activities" @@ -127,11 +128,8 @@ func UpdateAssignees(ctx context.Context, issue *issues_model.Issue, oneAssignee if oneAssignee != "" { // Prevent double adding assignees var isDouble bool - for _, assignee := range multipleAssignees { - if assignee == oneAssignee { - isDouble = true - break - } + if slices.Contains(multipleAssignees, oneAssignee) { + isDouble = true } if !isDouble { diff --git a/services/issue/milestone.go b/services/issue/milestone.go index 928979d74e..158abb0663 100644 --- a/services/issue/milestone.go +++ b/services/issue/milestone.go @@ -26,10 +26,7 @@ func updateMilestoneCounters(ctx context.Context, issue *issues_model.Issue, id if err != nil { return fmt.Errorf("GetMilestoneByRepoID: %w", err) } - updatedUnix := milestone.UpdatedUnix - if issue.UpdatedUnix > updatedUnix { - updatedUnix = issue.UpdatedUnix - } + updatedUnix := max(issue.UpdatedUnix, milestone.UpdatedUnix) stats.QueueRecalcMilestoneByIDWithDate(ctx, id, updatedUnix) } else { stats.QueueRecalcMilestoneByID(ctx, id) diff --git a/services/lfs/locks.go b/services/lfs/locks.go index a45b2cc93b..16f6dc1631 100644 --- a/services/lfs/locks.go +++ b/services/lfs/locks.go @@ -74,10 +74,7 @@ func GetListLockHandler(ctx *context.Context) { } ctx.Resp.Header().Set("Content-Type", lfs_module.MediaType) - cursor := ctx.FormInt("cursor") - if cursor < 0 { - cursor = 0 - } + cursor := max(ctx.FormInt("cursor"), 0) limit := ctx.FormInt("limit") if limit > setting.LFS.LocksPagingNum && setting.LFS.LocksPagingNum > 0 { limit = setting.LFS.LocksPagingNum @@ -239,10 +236,7 @@ func VerifyLockHandler(ctx *context.Context) { ctx.Resp.Header().Set("Content-Type", lfs_module.MediaType) - cursor := ctx.FormInt("cursor") - if cursor < 0 { - cursor = 0 - } + cursor := max(ctx.FormInt("cursor"), 0) limit := ctx.FormInt("limit") if limit > setting.LFS.LocksPagingNum && setting.LFS.LocksPagingNum > 0 { limit = setting.LFS.LocksPagingNum diff --git a/services/lfs/server.go b/services/lfs/server.go index 30878d8edd..cc8afc2aa8 100644 --- a/services/lfs/server.go +++ b/services/lfs/server.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "io" + "maps" "net/http" "net/url" "path" @@ -503,9 +504,7 @@ func buildObjectResponse(rc *requestContext, pointer lfs_module.Pointer, downloa rep.Actions["upload"] = &lfs_module.Link{Href: rc.UploadLink(pointer), Header: header} verifyHeader := make(map[string]string) - for key, value := range header { - verifyHeader[key] = value - } + maps.Copy(verifyHeader, header) // This is only needed to workaround https://github.com/git-lfs/git-lfs/issues/3662 verifyHeader["Accept"] = lfs_module.AcceptHeader diff --git a/services/mailer/mailer_test.go b/services/mailer/mailer_test.go index 34fd847c05..855e424ab2 100644 --- a/services/mailer/mailer_test.go +++ b/services/mailer/mailer_test.go @@ -114,9 +114,9 @@ func extractMailHeaderAndContent(t *testing.T, mail string) (map[string]string, } content := strings.TrimSpace("boundary=" + parts[1]) - hParts := strings.Split(parts[0], "\n") + hParts := strings.SplitSeq(parts[0], "\n") - for _, hPart := range hParts { + for hPart := range hParts { parts := strings.SplitN(hPart, ":", 2) hk := strings.TrimSpace(parts[0]) if hk != "" { diff --git a/services/migrations/gitea_uploader_test.go b/services/migrations/gitea_uploader_test.go index e33d597cdc..dc0210a8cc 100644 --- a/services/migrations/gitea_uploader_test.go +++ b/services/migrations/gitea_uploader_test.go @@ -361,7 +361,7 @@ func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) { require.NoError(t, git.InitRepository(git.DefaultContext, fromRepo.RepoPath(), false, fromRepo.ObjectFormatName)) err := git.NewCommand(git.DefaultContext, "symbolic-ref").AddDynamicArguments("HEAD", git.BranchPrefix+baseRef).Run(&git.RunOpts{Dir: fromRepo.RepoPath()}) require.NoError(t, err) - require.NoError(t, os.WriteFile(filepath.Join(fromRepo.RepoPath(), "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", fromRepo.RepoPath())), 0o644)) + require.NoError(t, os.WriteFile(filepath.Join(fromRepo.RepoPath(), "README.md"), fmt.Appendf(nil, "# Testing Repository\n\nOriginally created in: %s", fromRepo.RepoPath()), 0o644)) require.NoError(t, git.AddChanges(fromRepo.RepoPath(), true)) signature := git.Signature{ Email: "test@example.com", @@ -409,7 +409,7 @@ func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) { })) _, _, err = git.NewCommand(git.DefaultContext, "checkout", "-b").AddDynamicArguments(forkHeadRef).RunStdString(&git.RunOpts{Dir: forkRepo.RepoPath()}) require.NoError(t, err) - require.NoError(t, os.WriteFile(filepath.Join(forkRepo.RepoPath(), "README.md"), []byte(fmt.Sprintf("# branch2 %s", forkRepo.RepoPath())), 0o644)) + require.NoError(t, os.WriteFile(filepath.Join(forkRepo.RepoPath(), "README.md"), fmt.Appendf(nil, "# branch2 %s", forkRepo.RepoPath()), 0o644)) require.NoError(t, git.AddChanges(forkRepo.RepoPath(), true)) require.NoError(t, git.CommitChanges(forkRepo.RepoPath(), git.CommitChangesOptions{ Committer: &signature, diff --git a/services/migrations/github.go b/services/migrations/github.go index 7cfb626a15..540dfdd9d4 100644 --- a/services/migrations/github.go +++ b/services/migrations/github.go @@ -108,8 +108,8 @@ func NewGithubDownloaderV3(ctx context.Context, baseURL string, getPullRequests, downloader.SetContext(ctx) if token != "" { - tokens := strings.Split(token, ",") - for _, token := range tokens { + tokens := strings.SplitSeq(token, ",") + for token := range tokens { token = strings.TrimSpace(token) ts := oauth2.StaticTokenSource( &oauth2.Token{AccessToken: token}, diff --git a/services/packages/alt/repository.go b/services/packages/alt/repository.go index 9693f4322e..5eed86fb67 100644 --- a/services/packages/alt/repository.go +++ b/services/packages/alt/repository.go @@ -12,6 +12,7 @@ import ( "fmt" "io" "path" + "strings" "time" packages_model "forgejo.org/models/packages" @@ -734,15 +735,15 @@ NotAutomatic: false codename := time.Now().Unix() date := time.Now().UTC().Format(time.RFC1123) - var md5Sum string - var blake2b string + var md5Sum strings.Builder + var blake2b strings.Builder for _, pkglistByArch := range pkglist[architecture] { - md5Sum += fmt.Sprintf(" %s %d %s\n", pkglistByArch.MD5Checksum.Value, pkglistByArch.Size, "base/"+pkglistByArch.Type) - blake2b += fmt.Sprintf(" %s %d %s\n", pkglistByArch.Blake2bHash.Value, pkglistByArch.Size, "base/"+pkglistByArch.Type) + fmt.Fprintf(&md5Sum, " %s %d %s\n", pkglistByArch.MD5Checksum.Value, pkglistByArch.Size, "base/"+pkglistByArch.Type) + fmt.Fprintf(&blake2b, " %s %d %s\n", pkglistByArch.Blake2bHash.Value, pkglistByArch.Size, "base/"+pkglistByArch.Type) } - md5Sum += fmt.Sprintf(" %s %d %s\n", fileInfo.MD5Checksum.Value, fileInfo.Size, "base/"+fileInfo.Type) - blake2b += fmt.Sprintf(" %s %d %s\n", fileInfo.Blake2bHash.Value, fileInfo.Size, "base/"+fileInfo.Type) + fmt.Fprintf(&md5Sum, " %s %d %s\n", fileInfo.MD5Checksum.Value, fileInfo.Size, "base/"+fileInfo.Type) + fmt.Fprintf(&blake2b, " %s %d %s\n", fileInfo.Blake2bHash.Value, fileInfo.Size, "base/"+fileInfo.Type) data = fmt.Sprintf(`Origin: %s Label: %s @@ -755,7 +756,7 @@ MD5Sum: %s `, - origin, label, codename, date, architecture, md5Sum, blake2b) + origin, label, codename, date, architecture, md5Sum.String(), blake2b.String()) _, err = addReleaseAsFileToRepo(ctx, pv, "release", data, group, architecture) if err != nil { return err diff --git a/services/packages/arch/repository.go b/services/packages/arch/repository.go index 2a865e6dbd..384895fd65 100644 --- a/services/packages/arch/repository.go +++ b/services/packages/arch/repository.go @@ -47,8 +47,8 @@ func BuildAllRepositoryFiles(ctx context.Context, ownerID int64) error { return err } for _, pf := range pfs { - if strings.HasSuffix(pf.Name, ".db") { - arch := strings.TrimSuffix(pf.Name, ".db") + if before, ok := strings.CutSuffix(pf.Name, ".db"); ok { + arch := before if err := BuildPacmanDB(ctx, ownerID, pf.CompositeKey, arch); err != nil { return err } diff --git a/services/pull/merge.go b/services/pull/merge.go index 1d5e82e969..aa9b25d738 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -7,6 +7,7 @@ package pull import ( "context" "fmt" + "maps" "os" "path/filepath" "regexp" @@ -139,9 +140,7 @@ func getMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr *issue vars["HeadRepoOwnerName"] = pr.HeadRepo.OwnerName vars["HeadRepoName"] = pr.HeadRepo.Name } - for extraKey, extraValue := range extraVars { - vars[extraKey] = extraValue - } + maps.Copy(vars, extraVars) refs, err := pr.ResolveCrossReferences(ctx) if err == nil { closeIssueIndexes := make([]string, 0, len(refs)) diff --git a/services/repository/adopt_test.go b/services/repository/adopt_test.go index 79e4fc0023..b133deb7c1 100644 --- a/services/repository/adopt_test.go +++ b/services/repository/adopt_test.go @@ -28,7 +28,7 @@ func TestCheckUnadoptedRepositories_Add(t *testing.T) { } total := 30 - for i := 0; i < total; i++ { + for range total { unadopted.add("something") } diff --git a/services/repository/commitstatus/commitstatus.go b/services/repository/commitstatus/commitstatus.go index 23b4a6a132..5a48aa64b4 100644 --- a/services/repository/commitstatus/commitstatus.go +++ b/services/repository/commitstatus/commitstatus.go @@ -23,7 +23,7 @@ import ( ) func getCacheKey(repoID int64, branchName string) string { - hashBytes := sha256.Sum256([]byte(fmt.Sprintf("%d:%s", repoID, branchName))) + hashBytes := sha256.Sum256(fmt.Appendf(nil, "%d:%s", repoID, branchName)) return fmt.Sprintf("commit_status:%x", hashBytes) } diff --git a/services/repository/create.go b/services/repository/create.go index 4491b12497..b7232b27cc 100644 --- a/services/repository/create.go +++ b/services/repository/create.go @@ -97,8 +97,8 @@ func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir, // .gitignore if len(opts.Gitignores) > 0 { var buf bytes.Buffer - names := strings.Split(opts.Gitignores, ",") - for _, name := range names { + names := strings.SplitSeq(opts.Gitignores, ",") + for name := range names { data, err = options.Gitignore(name) if err != nil { return fmt.Errorf("GetRepoInitFile[%s]: %w", name, err) diff --git a/services/repository/create_test.go b/services/repository/create_test.go index 0a6c34b6fe..bd14a5e520 100644 --- a/services/repository/create_test.go +++ b/services/repository/create_test.go @@ -54,7 +54,7 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) { // Create repos. repoIDs := make([]int64, 0) - for i := 0; i < 3; i++ { + for i := range 3 { r, err := CreateRepositoryDirectly(db.DefaultContext, user, org.AsUser(), CreateRepoOptions{Name: fmt.Sprintf("repo-%d", i)}) require.NoError(t, err, "CreateRepository %d", i) if r != nil { diff --git a/services/repository/files/file.go b/services/repository/files/file.go index 5b93258840..2e9ba628af 100644 --- a/services/repository/files/file.go +++ b/services/repository/files/file.go @@ -151,7 +151,7 @@ func CleanUploadFileName(name string) string { // Rebase the filename name = util.PathJoinRel(name) // Git disallows any filenames to have a .git directory in them. - for _, part := range strings.Split(name, "/") { + for part := range strings.SplitSeq(name, "/") { if strings.ToLower(part) == ".git" { return "" } diff --git a/services/repository/files/temp_repo.go b/services/repository/files/temp_repo.go index 3ce6a3413c..17a8467e01 100644 --- a/services/repository/files/temp_repo.go +++ b/services/repository/files/temp_repo.go @@ -128,7 +128,7 @@ func (t *TemporaryUploadRepository) LsFiles(filenames ...string) ([]string, erro } fileList := make([]string, 0, len(filenames)) - for _, line := range bytes.Split(stdOut.Bytes(), []byte{'\000'}) { + for line := range bytes.SplitSeq(stdOut.Bytes(), []byte{'\000'}) { fileList = append(fileList, string(line)) } diff --git a/services/repository/files/tree.go b/services/repository/files/tree.go index 5a369b27a5..3e99655261 100644 --- a/services/repository/files/tree.go +++ b/services/repository/files/tree.go @@ -69,11 +69,7 @@ func GetTreeBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git if len(entries) > perPage { tree.Truncated = true } - if rangeStart+perPage < len(entries) { - rangeEnd = rangeStart + perPage - } else { - rangeEnd = len(entries) - } + rangeEnd = min(rangeStart+perPage, len(entries)) tree.Entries = make([]api.GitEntry, rangeEnd-rangeStart) for e := rangeStart; e < rangeEnd; e++ { i := e - rangeStart diff --git a/services/repository/files/update.go b/services/repository/files/update.go index 9c2fde1c0e..e97c487846 100644 --- a/services/repository/files/update.go +++ b/services/repository/files/update.go @@ -8,6 +8,7 @@ import ( "fmt" "io" "path" + "slices" "strings" "time" @@ -187,13 +188,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use } // Find the file we want to delete in the index - inFilelist := false - for _, indexFile := range filesInIndex { - if indexFile == file.TreePath { - inFilelist = true - break - } - } + inFilelist := slices.Contains(filesInIndex, file.TreePath) if !inFilelist { return nil, models.ErrRepoFileDoesNotExist{ Path: file.TreePath, @@ -390,11 +385,9 @@ func CreateOrUpdateFile(ctx context.Context, t *TemporaryUploadRepository, file } // If is a new file (not updating) then the given path shouldn't exist if file.Operation == "create" { - for _, indexFile := range filesInIndex { - if indexFile == file.TreePath { - return models.ErrRepoFileAlreadyExists{ - Path: file.TreePath, - } + if slices.Contains(filesInIndex, file.TreePath) { + return models.ErrRepoFileAlreadyExists{ + Path: file.TreePath, } } } diff --git a/services/repository/gitgraph/graph_models.go b/services/repository/gitgraph/graph_models.go index 2c4133e1f2..4b5f630679 100644 --- a/services/repository/gitgraph/graph_models.go +++ b/services/repository/gitgraph/graph_models.go @@ -304,8 +304,8 @@ func newRefsFromRefNames(refNames []byte) []git.Reference { continue } refName := string(refNameBytes) - if strings.HasPrefix(refName, "tag: ") { - refName = strings.TrimPrefix(refName, "tag: ") + if after, ok := strings.CutPrefix(refName, "tag: "); ok { + refName = after } else { refName = strings.TrimPrefix(refName, "HEAD -> ") } diff --git a/services/repository/gitgraph/graph_test.go b/services/repository/gitgraph/graph_test.go index 6dafaf03fd..776b8cacab 100644 --- a/services/repository/gitgraph/graph_test.go +++ b/services/repository/gitgraph/graph_test.go @@ -6,6 +6,7 @@ package gitgraph import ( "bytes" "fmt" + "slices" "strings" "testing" @@ -118,13 +119,7 @@ func TestReleaseUnusedColors(t *testing.T) { if parser.firstAvailable == -1 { // All in use for _, color := range parser.availableColors { - found := false - for _, oldColor := range parser.oldColors { - if oldColor == color { - found = true - break - } - } + found := slices.Contains(parser.oldColors, color) if !found { t.Errorf("In testcase:\n%d\t%d\t%d %d =>\n%d\t%d\t%d %d: %d should be available but is not", testcase.availableColors, @@ -142,13 +137,7 @@ func TestReleaseUnusedColors(t *testing.T) { // Some in use for i := parser.firstInUse; i != parser.firstAvailable; i = (i + 1) % len(parser.availableColors) { color := parser.availableColors[i] - found := false - for _, oldColor := range parser.oldColors { - if oldColor == color { - found = true - break - } - } + found := slices.Contains(parser.oldColors, color) if !found { t.Errorf("In testcase:\n%d\t%d\t%d %d =>\n%d\t%d\t%d %d: %d should be available but is not", testcase.availableColors, @@ -164,13 +153,7 @@ func TestReleaseUnusedColors(t *testing.T) { } for i := parser.firstAvailable; i != parser.firstInUse; i = (i + 1) % len(parser.availableColors) { color := parser.availableColors[i] - found := false - for _, oldColor := range parser.oldColors { - if oldColor == color { - found = true - break - } - } + found := slices.Contains(parser.oldColors, color) if found { t.Errorf("In testcase:\n%d\t%d\t%d %d =>\n%d\t%d\t%d %d: %d should not be available but is", testcase.availableColors, @@ -258,8 +241,8 @@ func TestCommitStringParsing(t *testing.T) { for _, test := range tests { t.Run(test.testName, func(t *testing.T) { testString := fmt.Sprintf("%s%s", dataFirstPart, test.commitMessage) - idx := strings.Index(testString, "DATA:") - commit, err := NewCommit(0, 0, []byte(testString[idx+5:])) + _, after, _ := strings.Cut(testString, "DATA:") + commit, err := NewCommit(0, 0, []byte(after)) if err != nil && test.shouldPass { t.Errorf("Could not parse %s", testString) return diff --git a/services/repository/gitgraph/parser.go b/services/repository/gitgraph/parser.go index fcbc666f7e..2331e02207 100644 --- a/services/repository/gitgraph/parser.go +++ b/services/repository/gitgraph/parser.go @@ -44,11 +44,11 @@ func (parser *Parser) Reset() { // AddLineToGraph adds the line as a row to the graph func (parser *Parser) AddLineToGraph(graph *Graph, row int, line []byte) error { - idx := bytes.Index(line, []byte("DATA:")) - if idx < 0 { + before, after, ok := bytes.Cut(line, []byte("DATA:")) + if !ok { parser.ParseGlyphs(line) } else { - parser.ParseGlyphs(line[:idx]) + parser.ParseGlyphs(before) } var err error @@ -72,7 +72,7 @@ func (parser *Parser) AddLineToGraph(graph *Graph, row int, line []byte) error { } } commitDone = true - if idx < 0 { + if !ok { if err != nil { err = fmt.Errorf("missing data section on line %d with commit: %s. %w", row, string(line), err) } else { @@ -83,7 +83,7 @@ func (parser *Parser) AddLineToGraph(graph *Graph, row int, line []byte) error { if column < len(parser.oldGlyphs) && parser.oldGlyphs[column] == '|' { graph.continuationAbove[[2]int{row, column}] = true } - err2 := graph.AddCommit(row, column, flowID, line[idx+5:]) + err2 := graph.AddCommit(row, column, flowID, after) if err != nil && err2 != nil { err = fmt.Errorf("%v %w", err2, err) continue diff --git a/services/webhook/deliver_test.go b/services/webhook/deliver_test.go index 13890621c6..303a3d9bb1 100644 --- a/services/webhook/deliver_test.go +++ b/services/webhook/deliver_test.go @@ -281,8 +281,6 @@ func TestWebhookDeliverSpecificTypes(t *testing.T) { require.NoError(t, err) for typ, hc := range cases { - typ := typ - hc := hc t.Run(typ, func(t *testing.T) { t.Parallel() hook := &webhook_model.Webhook{ diff --git a/services/webhook/dingtalk.go b/services/webhook/dingtalk.go index e7dece30d3..96d4c18c11 100644 --- a/services/webhook/dingtalk.go +++ b/services/webhook/dingtalk.go @@ -110,22 +110,22 @@ func (dc dingtalkConvertor) Push(p *api.PushPayload) (DingtalkPayload, error) { title := fmt.Sprintf("[%s:%s] %s", p.Repo.FullName, branchName, commitDesc) - var text string + var text strings.Builder // for each commit, generate attachment text for i, commit := range p.Commits { var authorName string if commit.Author != nil { authorName = " - " + commit.Author.Name } - text += fmt.Sprintf("[%s](%s) %s", commit.ID[:7], commit.URL, - strings.TrimRight(commit.Message, "\r\n")) + authorName + text.WriteString(fmt.Sprintf("[%s](%s) %s", commit.ID[:7], commit.URL, + strings.TrimRight(commit.Message, "\r\n")) + authorName) // add linebreak to each commit but the last if i < len(p.Commits)-1 { - text += "\r\n" + text.WriteString("\r\n") } } - return createDingtalkPayload(title, text, linkText, titleLink), nil + return createDingtalkPayload(title, text.String(), linkText, titleLink), nil } // Issue implements PayloadConvertor Issue method diff --git a/services/webhook/discord.go b/services/webhook/discord.go index 2383a1402b..cb7584e157 100644 --- a/services/webhook/discord.go +++ b/services/webhook/discord.go @@ -210,7 +210,7 @@ func (d discordConvertor) Push(p *api.PushPayload) (DiscordPayload, error) { title := fmt.Sprintf("[%s:%s] %s", p.Repo.FullName, branchName, commitDesc) - var text string + var text strings.Builder // for each commit, generate attachment text for i, commit := range p.Commits { // limit the commit message display to just the summary, otherwise it would be hard to read @@ -223,14 +223,14 @@ func (d discordConvertor) Push(p *api.PushPayload) (DiscordPayload, error) { if utf8.RuneCountInString(message) > 50 { message = fmt.Sprintf("%.47s...", message) } - text += fmt.Sprintf("[`%s`](%s) %s \\- %s", commit.ID[:7], commit.URL, message, commit.Author.Name) + fmt.Fprintf(&text, "[`%s`](%s) %s \\- %s", commit.ID[:7], commit.URL, message, commit.Author.Name) // add linebreak to each commit but the last if i < len(p.Commits)-1 { - text += "\n" + text.WriteString("\n") } } - return d.createPayload(p.Sender, title, text, titleLink, greenColor), nil + return d.createPayload(p.Sender, title, text.String(), titleLink, greenColor), nil } // Issue implements PayloadConvertor Issue method diff --git a/services/webhook/feishu.go b/services/webhook/feishu.go index f6ffea9acc..ffbd4eb469 100644 --- a/services/webhook/feishu.go +++ b/services/webhook/feishu.go @@ -95,22 +95,23 @@ func (fc feishuConvertor) Push(p *api.PushPayload) (FeishuPayload, error) { commitDesc string ) - text := fmt.Sprintf("[%s:%s] %s\r\n", p.Repo.FullName, branchName, commitDesc) + var text strings.Builder + fmt.Fprintf(&text, "[%s:%s] %s\r\n", p.Repo.FullName, branchName, commitDesc) // for each commit, generate attachment text for i, commit := range p.Commits { var authorName string if commit.Author != nil { authorName = " - " + commit.Author.Name } - text += fmt.Sprintf("[%s](%s) %s", commit.ID[:7], commit.URL, - strings.TrimRight(commit.Message, "\r\n")) + authorName + text.WriteString(fmt.Sprintf("[%s](%s) %s", commit.ID[:7], commit.URL, + strings.TrimRight(commit.Message, "\r\n")) + authorName) // add linebreak to each commit but the last if i < len(p.Commits)-1 { - text += "\r\n" + text.WriteString("\r\n") } } - return newFeishuTextPayload(text), nil + return newFeishuTextPayload(text.String()), nil } // Issue implements PayloadConvertor Issue method diff --git a/services/webhook/matrix.go b/services/webhook/matrix.go index d11933f16a..a4bd774f50 100644 --- a/services/webhook/matrix.go +++ b/services/webhook/matrix.go @@ -206,18 +206,19 @@ func (m matrixConvertor) Push(p *api.PushPayload) (MatrixPayload, error) { } refName := html.EscapeString(git.RefName(p.Ref).ShortName()) - text := fmt.Sprintf("[%s] %s pushed %s to %s:
    ", p.Repo.FullName, p.Pusher.UserName, commitDesc, refName) + var text strings.Builder + fmt.Fprintf(&text, "[%s] %s pushed %s to %s:
    ", p.Repo.FullName, p.Pusher.UserName, commitDesc, refName) // for each commit, generate a new line text for i, commit := range p.Commits { - text += fmt.Sprintf("%s: %s - %s", htmlLinkFormatter(commit.URL, commit.ID[:7]), commit.Message, commit.Author.Name) + fmt.Fprintf(&text, "%s: %s - %s", htmlLinkFormatter(commit.URL, commit.ID[:7]), commit.Message, commit.Author.Name) // add linebreak to each commit but the last if i < len(p.Commits)-1 { - text += "
    " + text.WriteString("
    ") } } - return m.newPayload(text, p.Commits...) + return m.newPayload(text.String(), p.Commits...) } // PullRequest implements payloadConvertor PullRequest method diff --git a/services/webhook/msteams.go b/services/webhook/msteams.go index 798d7fb5fc..43ab588230 100644 --- a/services/webhook/msteams.go +++ b/services/webhook/msteams.go @@ -154,14 +154,14 @@ func (m msteamsConvertor) Push(p *api.PushPayload) (MSTeamsPayload, error) { title := fmt.Sprintf("[%s:%s] %s", p.Repo.FullName, branchName, commitDesc) - var text string + var text strings.Builder // for each commit, generate attachment text for i, commit := range p.Commits { - text += fmt.Sprintf("[%s](%s) %s - %s", commit.ID[:7], commit.URL, + fmt.Fprintf(&text, "[%s](%s) %s - %s", commit.ID[:7], commit.URL, strings.TrimRight(commit.Message, "\r\n"), commit.Author.Name) // add linebreak to each commit but the last if i < len(p.Commits)-1 { - text += "\n\n" + text.WriteString("\n\n") } } @@ -169,7 +169,7 @@ func (m msteamsConvertor) Push(p *api.PushPayload) (MSTeamsPayload, error) { p.Repo, p.Sender, title, - text, + text.String(), titleLink, greenColor, &MSTeamsFact{"Commit count:", fmt.Sprintf("%d", p.TotalCommits)}, diff --git a/services/webhook/slack.go b/services/webhook/slack.go index 1804c866f4..fe1bfc8aa4 100644 --- a/services/webhook/slack.go +++ b/services/webhook/slack.go @@ -245,13 +245,13 @@ func (s slackConvertor) Push(p *api.PushPayload) (SlackPayload, error) { branchLink := SlackLinkToRef(p.Repo.HTMLURL, p.Ref) text := fmt.Sprintf("[%s:%s] %s pushed by %s", p.Repo.FullName, branchLink, commitString, SlackNameFormatter(p.Pusher.UserName)) - var attachmentText string + var attachmentText strings.Builder // for each commit, generate attachment text for i, commit := range p.Commits { - attachmentText += fmt.Sprintf("%s: %s - %s", SlackLinkFormatter(commit.URL, commit.ID[:7]), SlackShortTextFormatter(commit.Message), SlackNameFormatter(commit.Author.Name)) + fmt.Fprintf(&attachmentText, "%s: %s - %s", SlackLinkFormatter(commit.URL, commit.ID[:7]), SlackShortTextFormatter(commit.Message), SlackNameFormatter(commit.Author.Name)) // add linebreak to each commit but the last if i < len(p.Commits)-1 { - attachmentText += "\n" + attachmentText.WriteString("\n") } } @@ -259,7 +259,7 @@ func (s slackConvertor) Push(p *api.PushPayload) (SlackPayload, error) { Color: s.Color, Title: p.Repo.HTMLURL, TitleLink: p.Repo.HTMLURL, - Text: attachmentText, + Text: attachmentText.String(), }}), nil } diff --git a/services/webhook/telegram.go b/services/webhook/telegram.go index f8fdea7ae9..47a7514968 100644 --- a/services/webhook/telegram.go +++ b/services/webhook/telegram.go @@ -116,22 +116,22 @@ func (t telegramConvertor) Push(p *api.PushPayload) (TelegramPayload, error) { title := fmt.Sprintf(`[%s:%s] %s`, p.Repo.FullName, branchName, commitDesc) - var text string + var text strings.Builder // for each commit, generate attachment text for i, commit := range p.Commits { var authorName string if commit.Author != nil { authorName = " - " + commit.Author.Name } - text += fmt.Sprintf(`[%s] %s`, commit.URL, commit.ID[:7], - strings.TrimRight(commit.Message, "\r\n")) + authorName + text.WriteString(fmt.Sprintf(`[%s] %s`, commit.URL, commit.ID[:7], + strings.TrimRight(commit.Message, "\r\n")) + authorName) // add linebreak to each commit but the last if i < len(p.Commits)-1 { - text += "\n" + text.WriteString("\n") } } - return createTelegramPayload(title + "\n" + text), nil + return createTelegramPayload(title + "\n" + text.String()), nil } // Issue implements PayloadConvertor Issue method diff --git a/services/webhook/wechatwork.go b/services/webhook/wechatwork.go index 01db3f0cd9..b22935be81 100644 --- a/services/webhook/wechatwork.go +++ b/services/webhook/wechatwork.go @@ -104,7 +104,7 @@ func (wc wechatworkConvertor) Push(p *api.PushPayload) (WechatworkPayload, error title := fmt.Sprintf("# %s:%s %s ", p.Repo.FullName, branchName, commitDesc) - var text string + var text strings.Builder // for each commit, generate attachment text for i, commit := range p.Commits { var authorName string @@ -113,15 +113,15 @@ func (wc wechatworkConvertor) Push(p *api.PushPayload) (WechatworkPayload, error } message := strings.ReplaceAll(commit.Message, "\n\n", "\r\n") - text += fmt.Sprintf(" > [%s](%s) \r\n >%s \n >%s", commit.ID[:7], commit.URL, + fmt.Fprintf(&text, " > [%s](%s) \r\n >%s \n >%s", commit.ID[:7], commit.URL, message, authorName) // add linebreak to each commit but the last if i < len(p.Commits)-1 { - text += "\n" + text.WriteString("\n") } } - return newWechatworkMarkdownPayload(title + "\r\n\r\n" + text), nil + return newWechatworkMarkdownPayload(title + "\r\n\r\n" + text.String()), nil } // Issue implements PayloadConvertor Issue method diff --git a/services/wiki/wiki_path.go b/services/wiki/wiki_path.go index ca312388af..a7963e9be4 100644 --- a/services/wiki/wiki_path.go +++ b/services/wiki/wiki_path.go @@ -129,8 +129,8 @@ func GitPathToWebPath(s string) (wp WebPath, err error) { func WebPathToUserTitle(s WebPath) (dir, display string) { dir = path.Dir(string(s)) display = path.Base(string(s)) - if strings.HasSuffix(display, ".md") { - display = strings.TrimSuffix(display, ".md") + if before, ok := strings.CutSuffix(display, ".md"); ok { + display = before display, _ = url.PathUnescape(display) } display, _ = unescapeSegment(display) diff --git a/services/wiki/wiki_test.go b/services/wiki/wiki_test.go index 9471904e38..551c251d97 100644 --- a/services/wiki/wiki_test.go +++ b/services/wiki/wiki_test.go @@ -116,9 +116,9 @@ func TestGitPathToWebPath(t *testing.T) { func TestUserWebGitPathConsistency(t *testing.T) { maxLen := 20 b := make([]byte, maxLen) - for i := 0; i < 1000; i++ { + for range 1000 { l := rand.Intn(maxLen) - for j := 0; j < l; j++ { + for j := range l { r := rand.Intn(0x80-0x20) + 0x20 b[j] = byte(r) } diff --git a/tests/integration/actions_trigger_test.go b/tests/integration/actions_trigger_test.go index 925434204c..4de8d625ab 100644 --- a/tests/integration/actions_trigger_test.go +++ b/tests/integration/actions_trigger_test.go @@ -88,7 +88,7 @@ jobs: labelStr := "/api/v1/repos/user2/repo-pull-request/labels" labelsCount := 2 labels := make([]*api.Label, labelsCount) - for i := 0; i < labelsCount; i++ { + for i := range labelsCount { color := "abcdef" req := NewRequestWithJSON(t, "POST", labelStr, &api.CreateLabelOption{ Name: fmt.Sprintf("label%d", i), diff --git a/tests/integration/api_activitypub_person_inbox_follow_test.go b/tests/integration/api_activitypub_person_inbox_follow_test.go index 7270d46a0c..5a0b452447 100644 --- a/tests/integration/api_activitypub_person_inbox_follow_test.go +++ b/tests/integration/api_activitypub_person_inbox_follow_test.go @@ -48,13 +48,13 @@ func TestActivityPubPersonInboxFollow(t *testing.T) { ctx, _ := contexttest.MockAPIContext(t, localUser2Inbox) // distant follows local - followActivity := []byte(fmt.Sprintf( + followActivity := fmt.Appendf(nil, `{"type":"Follow",`+ `"actor":"%s",`+ `"object":"%s"}`, distantUser15URL, localUser2URL, - )) + ) cf, err := activitypub.NewClientFactoryWithTimeout(60 * time.Second) require.NoError(t, err) c, err := cf.WithKeysDirect(ctx, mock.ApActor.PrivKey, @@ -84,7 +84,7 @@ func TestActivityPubPersonInboxFollow(t *testing.T) { assert.Contains(t, mock.LastPost, "\"type\":\"Accept\"") // distant undoes follow - undoFollowActivity := []byte(fmt.Sprintf( + undoFollowActivity := fmt.Appendf(nil, `{"type":"Undo",`+ `"actor":"%s",`+ `"object":{"type":"Follow",`+ @@ -93,7 +93,7 @@ func TestActivityPubPersonInboxFollow(t *testing.T) { distantUser15URL, distantUser15URL, localUser2URL, - )) + ) c, err = cf.WithKeysDirect(ctx, mock.ApActor.PrivKey, mock.ApActor.KeyID(federatedSrv.URL)) require.NoError(t, err) diff --git a/tests/integration/api_activitypub_person_inbox_useractivity_test.go b/tests/integration/api_activitypub_person_inbox_useractivity_test.go index 4201fd94bf..55fd62a3fe 100644 --- a/tests/integration/api_activitypub_person_inbox_useractivity_test.go +++ b/tests/integration/api_activitypub_person_inbox_useractivity_test.go @@ -53,13 +53,13 @@ func TestActivityPubPersonInboxNoteToDistant(t *testing.T) { defer f() // follow (distant follows local) - followActivity := []byte(fmt.Sprintf( + followActivity := fmt.Appendf(nil, `{"type":"Follow",`+ `"actor":"%s",`+ `"object":"%s"}`, distantUser15URL, localUser2URL, - )) + ) ctx, _ := contexttest.MockAPIContext(t, localUser2Inbox) cf, err := activitypub.NewClientFactoryWithTimeout(60 * time.Second) require.NoError(t, err) diff --git a/tests/integration/api_activitypub_repository_test.go b/tests/integration/api_activitypub_repository_test.go index 29221bb682..3d17f9b281 100644 --- a/tests/integration/api_activitypub_repository_test.go +++ b/tests/integration/api_activitypub_repository_test.go @@ -89,13 +89,13 @@ func TestActivityPubRepositoryInboxValid(t *testing.T) { mock.Persons[0].KeyID(federatedSrv.URL)) require.NoError(t, err) - activity1 := []byte(fmt.Sprintf( + activity1 := fmt.Appendf(nil, `{"type":"Like",`+ `"startTime":"%s",`+ `"actor":"%s/api/v1/activitypub/user-id/15",`+ `"object":"%s"}`, timeNow.Format(time.RFC3339), - federatedSrv.URL, u.JoinPath(fmt.Sprintf("/api/v1/activitypub/repository-id/%d", repositoryID)).String())) + federatedSrv.URL, u.JoinPath(fmt.Sprintf("/api/v1/activitypub/repository-id/%d", repositoryID)).String()) t.Logf("activity: %s", activity1) resp, err := c.Post(activity1, localRepoInbox) @@ -107,14 +107,14 @@ func TestActivityPubRepositoryInboxValid(t *testing.T) { unittest.AssertExistsAndLoadBean(t, &user.User{ID: federatedUser.UserID}) // A like activity by a different user of the same federated host. - activity2 := []byte(fmt.Sprintf( + activity2 := fmt.Appendf(nil, `{"type":"Like",`+ `"startTime":"%s",`+ `"actor":"%s/api/v1/activitypub/user-id/30",`+ `"object":"%s"}`, // Make sure this activity happens later then the one before timeNow.Add(time.Second).Format(time.RFC3339), - federatedSrv.URL, u.JoinPath(fmt.Sprintf("/api/v1/activitypub/repository-id/%d", repositoryID)).String())) + federatedSrv.URL, u.JoinPath(fmt.Sprintf("/api/v1/activitypub/repository-id/%d", repositoryID)).String()) t.Logf("activity: %s", activity2) resp, err = c.Post(activity2, localRepoInbox) @@ -127,14 +127,14 @@ func TestActivityPubRepositoryInboxValid(t *testing.T) { // The same user sends another like activity otherRepositoryID := 3 otherRepoInboxURL := u.JoinPath(fmt.Sprintf("/api/v1/activitypub/repository-id/%d/inbox", otherRepositoryID)).String() - activity3 := []byte(fmt.Sprintf( + activity3 := fmt.Appendf(nil, `{"type":"Like",`+ `"startTime":"%s",`+ `"actor":"%s/api/v1/activitypub/user-id/30",`+ `"object":"%s"}`, // Make sure this activity happens later then the ones before timeNow.Add(time.Second*2).Format(time.RFC3339), - federatedSrv.URL, u.JoinPath(fmt.Sprintf("/api/v1/activitypub/repository-id/%d", otherRepositoryID)).String())) + federatedSrv.URL, u.JoinPath(fmt.Sprintf("/api/v1/activitypub/repository-id/%d", otherRepositoryID)).String()) t.Logf("activity: %s", activity3) resp, err = c.Post(activity3, otherRepoInboxURL) diff --git a/tests/integration/api_helper_for_declarative_test.go b/tests/integration/api_helper_for_declarative_test.go index ada6a2c311..6f33322253 100644 --- a/tests/integration/api_helper_for_declarative_test.go +++ b/tests/integration/api_helper_for_declarative_test.go @@ -273,7 +273,7 @@ func doAPIMergePullRequestForm(t *testing.T, ctx APITestContext, owner, repo str var req *RequestWrapper var resp *httptest.ResponseRecorder - for i := 0; i < 6; i++ { + for range 6 { req = NewRequestWithJSON(t, http.MethodPost, urlStr, merge).AddTokenAuth(ctx.Token) resp = ctx.Session.MakeRequest(t, req, NoExpectedStatus) diff --git a/tests/integration/api_issue_test.go b/tests/integration/api_issue_test.go index 6267065602..7f601fa303 100644 --- a/tests/integration/api_issue_test.go +++ b/tests/integration/api_issue_test.go @@ -228,7 +228,7 @@ func TestAPICreateIssueParallel(t *testing.T) { urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues?state=all", owner.Name, repoBefore.Name) var wg sync.WaitGroup - for i := 0; i < 100; i++ { + for i := range 100 { wg.Add(1) go func(parentT *testing.T, i int) { parentT.Run(fmt.Sprintf("ParallelCreateIssue_%d", i), func(t *testing.T) { @@ -499,10 +499,9 @@ func TestAPISearchIssues(t *testing.T) { defer tests.PrepareTestEnv(t)() // as this API was used in the frontend, it uses UI page size - expectedIssueCount := 20 // from the fixtures - if expectedIssueCount > setting.UI.IssuePagingNum { - expectedIssueCount = setting.UI.IssuePagingNum - } + expectedIssueCount := min( + // from the fixtures + 20, setting.UI.IssuePagingNum) link, _ := url.Parse("/api/v1/repos/issues/search") token := getUserToken(t, "user1", auth_model.AccessTokenScopeReadIssue) @@ -603,10 +602,9 @@ func TestAPISearchIssuesWithLabels(t *testing.T) { defer tests.PrepareTestEnv(t)() // as this API was used in the frontend, it uses UI page size - expectedIssueCount := 20 // from the fixtures - if expectedIssueCount > setting.UI.IssuePagingNum { - expectedIssueCount = setting.UI.IssuePagingNum - } + expectedIssueCount := min( + // from the fixtures + 20, setting.UI.IssuePagingNum) link, _ := url.Parse("/api/v1/repos/issues/search") token := getUserToken(t, "user1", auth_model.AccessTokenScopeReadIssue) diff --git a/tests/integration/api_packages_alt_test.go b/tests/integration/api_packages_alt_test.go index a15accdbbd..fe299ac14f 100644 --- a/tests/integration/api_packages_alt_test.go +++ b/tests/integration/api_packages_alt_test.go @@ -181,9 +181,9 @@ enabled=1`, var result ReleaseClassic - lines := strings.Split(resp, "\n") + lines := strings.SplitSeq(resp, "\n") - for _, line := range lines { + for line := range lines { parts := strings.SplitN(line, ": ", 2) if len(parts) < 2 { continue @@ -406,7 +406,7 @@ enabled=1`, if typ == 6 || typ == 8 || typ == 9 { elem := data[offset:] - for j := uint32(0); j < count; j++ { + for range count { strEnd := bytes.IndexByte(elem, 0) if strEnd == -1 { require.NoError(t, err) @@ -420,13 +420,13 @@ enabled=1`, result.Release = string(elem[:strEnd]) case 1004: var summaries []string - for i := uint32(0); i < count; i++ { + for range count { summaries = append(summaries, string(elem[:strEnd])) } result.Summary = summaries case 1005: var descriptions []string - for i := uint32(0); i < count; i++ { + for range count { descriptions = append(descriptions, string(elem[:strEnd])) } result.Description = descriptions @@ -436,7 +436,7 @@ enabled=1`, result.Packager = string(elem[:strEnd]) case 1016: var groups []string - for i := uint32(0); i < count; i++ { + for range count { groups = append(groups, string(elem[:strEnd])) } result.Group = groups @@ -448,49 +448,49 @@ enabled=1`, result.SourceRpm = string(elem[:strEnd]) case 1047: var provideNames []string - for i := uint32(0); i < count; i++ { + for range count { provideNames = append(provideNames, string(elem[:strEnd])) } result.ProvideNames = provideNames case 1049: var requireNames []string - for i := uint32(0); i < count; i++ { + for range count { requireNames = append(requireNames, string(elem[:strEnd])) } result.RequireNames = requireNames case 1050: var requireVersions []string - for i := uint32(0); i < count; i++ { + for range count { requireVersions = append(requireVersions, string(elem[:strEnd])) } result.RequireVersions = requireVersions case 1081: var changeLogNames []string - for i := uint32(0); i < count; i++ { + for range count { changeLogNames = append(changeLogNames, string(elem[:strEnd])) } result.ChangeLogNames = changeLogNames case 1082: var changeLogTexts []string - for i := uint32(0); i < count; i++ { + for range count { changeLogTexts = append(changeLogTexts, string(elem[:strEnd])) } result.ChangeLogTexts = changeLogTexts case 1113: var provideVersions []string - for i := uint32(0); i < count; i++ { + for range count { provideVersions = append(provideVersions, string(elem[:strEnd])) } result.ProvideVersions = provideVersions case 1117: var baseNames []string - for i := uint32(0); i < count; i++ { + for range count { baseNames = append(baseNames, string(elem[:strEnd])) } result.BaseNames = baseNames case 1118: var dirNames []string - for i := uint32(0); i < count; i++ { + for range count { dirNames = append(dirNames, string(elem[:strEnd])) } result.DirNames = dirNames @@ -509,7 +509,7 @@ enabled=1`, } } else if typ == 4 { elem := data[offset:] - for j := uint32(0); j < count; j++ { + for range count { val := binary.BigEndian.Uint32(elem) switch tag { case 1006: @@ -518,25 +518,25 @@ enabled=1`, result.Size = int(val) case 1048: var requireFlags []int - for i := uint32(0); i < count; i++ { + for range count { requireFlags = append(requireFlags, int(val)) } result.RequireFlags = requireFlags case 1080: var changeLogTimes []int - for i := uint32(0); i < count; i++ { + for range count { changeLogTimes = append(changeLogTimes, int(val)) } result.ChangeLogTimes = changeLogTimes case 1112: var provideFlags []int - for i := uint32(0); i < count; i++ { + for range count { provideFlags = append(provideFlags, int(val)) } result.ProvideFlags = provideFlags case 1116: var dirIndexes []int - for i := uint32(0); i < count; i++ { + for range count { dirIndexes = append(dirIndexes, int(val)) } result.DirIndexes = dirIndexes diff --git a/tests/integration/api_packages_chef_test.go b/tests/integration/api_packages_chef_test.go index 390ac50688..cadf46b03f 100644 --- a/tests/integration/api_packages_chef_test.go +++ b/tests/integration/api_packages_chef_test.go @@ -182,7 +182,7 @@ nwIDAQAB var data []byte if version == "1.3" { - data = []byte(fmt.Sprintf( + data = fmt.Appendf(nil, "Method:%s\nPath:%s\nX-Ops-Content-Hash:%s\nX-Ops-Sign:version=%s\nX-Ops-Timestamp:%s\nX-Ops-UserId:%s\nX-Ops-Server-API-Version:%s", req.Method, path.Clean(req.URL.Path), @@ -191,17 +191,17 @@ nwIDAQAB req.Header.Get("X-Ops-Timestamp"), username, req.Header.Get("X-Ops-Server-Api-Version"), - )) + ) } else { sum := sha1.Sum([]byte(path.Clean(req.URL.Path))) - data = []byte(fmt.Sprintf( + data = fmt.Appendf(nil, "Method:%s\nHashed Path:%s\nX-Ops-Content-Hash:%s\nX-Ops-Timestamp:%s\nX-Ops-UserId:%s", req.Method, base64.StdEncoding.EncodeToString(sum[:]), req.Header.Get("X-Ops-Content-Hash"), req.Header.Get("X-Ops-Timestamp"), username, - )) + ) } for k := range req.Header { diff --git a/tests/integration/api_packages_container_test.go b/tests/integration/api_packages_container_test.go index 6775f3d228..13ce7dc136 100644 --- a/tests/integration/api_packages_container_test.go +++ b/tests/integration/api_packages_container_test.go @@ -873,7 +873,7 @@ func TestPackageContainer(t *testing.T) { url := fmt.Sprintf("%sv2/%s/parallel", setting.AppURL, user.Name) var wg sync.WaitGroup - for i := 0; i < 10; i++ { + for i := range 10 { wg.Add(1) content := []byte{byte(i)} diff --git a/tests/integration/api_packages_maven_test.go b/tests/integration/api_packages_maven_test.go index 74e7883443..2fa43b6b61 100644 --- a/tests/integration/api_packages_maven_test.go +++ b/tests/integration/api_packages_maven_test.go @@ -291,7 +291,7 @@ func TestPackageMavenConcurrent(t *testing.T) { defer tests.PrintCurrentTest(t)() var wg sync.WaitGroup - for i := 0; i < 10; i++ { + for i := range 10 { wg.Add(1) go func(i int) { putFile(t, fmt.Sprintf("/%s/%s.jar", packageVersion, strconv.Itoa(i)), "test", http.StatusCreated) diff --git a/tests/integration/api_repo_topic_test.go b/tests/integration/api_repo_topic_test.go index 69008bbf64..a43e49b0ff 100644 --- a/tests/integration/api_repo_topic_test.go +++ b/tests/integration/api_repo_topic_test.go @@ -31,7 +31,7 @@ func TestAPITopicSearchPaging(t *testing.T) { token2 := getUserToken(t, user2.Name, auth_model.AccessTokenScopeWriteRepository) repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) - for i := 0; i < 20; i++ { + for i := range 20 { req := NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/paging-topic-%d", user2.Name, repo2.Name, i). AddTokenAuth(token2) MakeRequest(t, req, http.StatusNoContent) diff --git a/tests/integration/cmd_forgejo_actions_test.go b/tests/integration/cmd_forgejo_actions_test.go index 653ff65a9d..088cb5860b 100644 --- a/tests/integration/cmd_forgejo_actions_test.go +++ b/tests/integration/cmd_forgejo_actions_test.go @@ -183,7 +183,7 @@ func TestActions_CmdForgejo_Actions(t *testing.T) { // // Run twice to verify it is idempotent // - for i := 0; i < 2; i++ { + for range 2 { uuid, err := runMainApp("forgejo-cli", cmd...) require.NoError(t, err) if assert.Equal(t, testCase.uuid, uuid) { diff --git a/tests/integration/git_helper_for_declarative_test.go b/tests/integration/git_helper_for_declarative_test.go index 1d8f44c8dc..e1f08509df 100644 --- a/tests/integration/git_helper_for_declarative_test.go +++ b/tests/integration/git_helper_for_declarative_test.go @@ -143,7 +143,7 @@ func doGitInitTestRepository(dstPath string, objectFormat git.ObjectFormat) func // forcibly set default branch to master _, _, err := git.NewCommand(git.DefaultContext, "symbolic-ref", "HEAD", git.BranchPrefix+"master").RunStdString(&git.RunOpts{Dir: dstPath}) require.NoError(t, err) - require.NoError(t, os.WriteFile(filepath.Join(dstPath, "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", dstPath)), 0o644)) + require.NoError(t, os.WriteFile(filepath.Join(dstPath, "README.md"), fmt.Appendf(nil, "# Testing Repository\n\nOriginally created in: %s", dstPath), 0o644)) require.NoError(t, git.AddChanges(dstPath, true)) signature := git.Signature{ Email: "test@example.com", @@ -194,7 +194,7 @@ func doGitAddSomeCommits(dstPath, branch string) func(*testing.T) { return func(t *testing.T) { doGitCheckoutBranch(dstPath, branch)(t) - require.NoError(t, os.WriteFile(filepath.Join(dstPath, fmt.Sprintf("file-%s.txt", branch)), []byte(fmt.Sprintf("file %s", branch)), 0o644)) + require.NoError(t, os.WriteFile(filepath.Join(dstPath, fmt.Sprintf("file-%s.txt", branch)), fmt.Appendf(nil, "file %s", branch), 0o644)) require.NoError(t, git.AddChanges(dstPath, true)) signature := git.Signature{ Email: "test@test.test", diff --git a/tests/integration/git_push_test.go b/tests/integration/git_push_test.go index bf8ad8ac12..c7c4f6750e 100644 --- a/tests/integration/git_push_test.go +++ b/tests/integration/git_push_test.go @@ -45,7 +45,7 @@ func testGitPush(t *testing.T, u *url.URL) { forEachObjectFormat(t, func(t *testing.T, objectFormat git.ObjectFormat) { t.Run("Push branches at once", func(t *testing.T) { runTestGitPush(t, u, objectFormat, func(t *testing.T, gitPath string) (pushed, deleted []string) { - for i := 0; i < 10; i++ { + for i := range 10 { branchName := fmt.Sprintf("branch-%d", i) pushed = append(pushed, branchName) doGitCreateBranch(gitPath, branchName)(t) @@ -58,7 +58,7 @@ func testGitPush(t *testing.T, u *url.URL) { t.Run("Push branches exists", func(t *testing.T) { runTestGitPush(t, u, objectFormat, func(t *testing.T, gitPath string) (pushed, deleted []string) { - for i := 0; i < 10; i++ { + for i := range 10 { branchName := fmt.Sprintf("branch-%d", i) if i < 5 { pushed = append(pushed, branchName) @@ -72,7 +72,7 @@ func testGitPush(t *testing.T, u *url.URL) { pushed = pushed[:0] // do some changes for the first 5 branches created above - for i := 0; i < 5; i++ { + for i := range 5 { branchName := fmt.Sprintf("branch-%d", i) pushed = append(pushed, branchName) @@ -93,7 +93,7 @@ func testGitPush(t *testing.T, u *url.URL) { t.Run("Push branches one by one", func(t *testing.T) { runTestGitPush(t, u, objectFormat, func(t *testing.T, gitPath string) (pushed, deleted []string) { - for i := 0; i < 10; i++ { + for i := range 10 { branchName := fmt.Sprintf("branch-%d", i) doGitCreateBranch(gitPath, branchName)(t) doGitPushTestRepository(gitPath, "origin", branchName)(t) @@ -108,14 +108,14 @@ func testGitPush(t *testing.T, u *url.URL) { doGitPushTestRepository(gitPath, "origin", "master")(t) // make sure master is the default branch instead of a branch we are going to delete pushed = append(pushed, "master") - for i := 0; i < 10; i++ { + for i := range 10 { branchName := fmt.Sprintf("branch-%d", i) pushed = append(pushed, branchName) doGitCreateBranch(gitPath, branchName)(t) } doGitPushTestRepository(gitPath, "origin", "--all")(t) - for i := 0; i < 10; i++ { + for i := range 10 { branchName := fmt.Sprintf("branch-%d", i) doGitPushTestRepository(gitPath, "origin", "--delete", branchName)(t) deleted = append(deleted, branchName) diff --git a/tests/integration/git_test.go b/tests/integration/git_test.go index f61338e4ee..a5a242b912 100644 --- a/tests/integration/git_test.go +++ b/tests/integration/git_test.go @@ -9,6 +9,7 @@ import ( "encoding/hex" "fmt" "io" + "maps" "net/http" "net/url" "os" @@ -487,9 +488,7 @@ func doProtectBranch(ctx APITestContext, branch string, addParameter ...paramete "rule_name": branch, } if len(addParameter) > 0 { - for k, v := range addParameter[0] { - parameter[k] = v - } + maps.Copy(parameter, addParameter[0]) } // Change branch to protected @@ -1162,15 +1161,15 @@ func doLFSNoAccess(ctx APITestContext, publicKeyID int64, objectFormat git.Objec } func extractRemoteMessages(stderr string) string { - var remoteMsg string + var remoteMsg strings.Builder for line := range strings.SplitSeq(stderr, "\n") { msg, found := strings.CutPrefix(line, "remote: ") if found { - remoteMsg += msg - remoteMsg += "\n" + remoteMsg.WriteString(msg) + remoteMsg.WriteString("\n") } } - return remoteMsg + return remoteMsg.String() } func doTestForkPushMessages(apictx APITestContext, dstPath string) func(*testing.T) { diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go index 8657af839c..6cde9be4df 100644 --- a/tests/integration/integration_test.go +++ b/tests/integration/integration_test.go @@ -471,14 +471,14 @@ func loginUserMaybeTOTP(t testing.TB, user *user_model.User, useTOTP bool) *Test } // token has to be unique this counter take care of -var tokenCounter int64 +var tokenCounter atomic.Int64 // getTokenForLoggedInUser returns a token for a logged in user. // The scope is an optional list of snake_case strings like the frontend form fields, // but without the "scope_" prefix. func getTokenForLoggedInUser(t testing.TB, session *TestSession, scopes ...auth.AccessTokenScope) string { t.Helper() - accessTokenName := fmt.Sprintf("api-testing-token-%d", atomic.AddInt64(&tokenCounter, 1)) + accessTokenName := fmt.Sprintf("api-testing-token-%d", tokenCounter.Add(1)) createApplicationSettingsToken(t, session, accessTokenName, scopes...) token := assertAccessToken(t, session) return token diff --git a/tests/integration/issue_comment_test.go b/tests/integration/issue_comment_test.go index a6c4d6c923..2f72ab766e 100644 --- a/tests/integration/issue_comment_test.go +++ b/tests/integration/issue_comment_test.go @@ -5,6 +5,7 @@ package integration import ( "net/http" + "slices" "strconv" "strings" "testing" @@ -71,13 +72,7 @@ func testIssueCommentChangeEvent(t *testing.T, htmlDoc *HTMLDoc, commentID, badg // Check links (href) issueCommentLink := "#issuecomment-" + commentID - found := false - for _, link := range links { - if link == issueCommentLink { - found = true - break - } - } + found := slices.Contains(links, issueCommentLink) if !found { links = append(links, issueCommentLink) } diff --git a/tests/integration/issue_test.go b/tests/integration/issue_test.go index 19fe59a10a..d764870bab 100644 --- a/tests/integration/issue_test.go +++ b/tests/integration/issue_test.go @@ -114,14 +114,11 @@ func TestViewIssuesSortByType(t *testing.T) { htmlDoc := NewHTMLParser(t, resp.Body) issuesSelection := getIssuesSelection(t, htmlDoc) - expectedNumIssues := unittest.GetCount(t, + expectedNumIssues := min(unittest.GetCount(t, &issues_model.Issue{RepoID: repo.ID, PosterID: user.ID}, unittest.Cond("is_closed=?", false), unittest.Cond("is_pull=?", false), - ) - if expectedNumIssues > setting.UI.IssuePagingNum { - expectedNumIssues = setting.UI.IssuePagingNum - } + ), setting.UI.IssuePagingNum) assert.Equal(t, expectedNumIssues, issuesSelection.Length()) issuesSelection.Each(func(_ int, selection *goquery.Selection) { @@ -891,10 +888,9 @@ func TestSearchIssues(t *testing.T) { session := loginUser(t, "user2") - expectedIssueCount := 20 // from the fixtures - if expectedIssueCount > setting.UI.IssuePagingNum { - expectedIssueCount = setting.UI.IssuePagingNum - } + expectedIssueCount := min( + // from the fixtures + 20, setting.UI.IssuePagingNum) req := NewRequest(t, "GET", "/issues/search") resp := session.MakeRequest(t, req, http.StatusOK) @@ -1017,10 +1013,9 @@ func TestSearchIssues(t *testing.T) { func TestSearchIssuesWithLabels(t *testing.T) { defer tests.PrepareTestEnv(t)() - expectedIssueCount := 20 // from the fixtures - if expectedIssueCount > setting.UI.IssuePagingNum { - expectedIssueCount = setting.UI.IssuePagingNum - } + expectedIssueCount := min( + // from the fixtures + 20, setting.UI.IssuePagingNum) session := loginUser(t, "user1") link, _ := url.Parse("/issues/search") diff --git a/tests/integration/org_test.go b/tests/integration/org_test.go index 157ed5dbcd..ddfaf2fa55 100644 --- a/tests/integration/org_test.go +++ b/tests/integration/org_test.go @@ -46,7 +46,7 @@ func TestOrgRepos(t *testing.T) { sel := htmlDoc.doc.Find("a.name") assert.Len(t, repos, len(sel.Nodes)) - for i := 0; i < len(repos); i++ { + for i := range repos { assert.Equal(t, repos[i], strings.TrimSpace(sel.Eq(i).Text())) } } diff --git a/tests/integration/project_test.go b/tests/integration/project_test.go index 955caaf6f7..629793602b 100644 --- a/tests/integration/project_test.go +++ b/tests/integration/project_test.go @@ -45,7 +45,7 @@ func TestMoveRepoProjectColumns(t *testing.T) { err := project_model.NewProject(db.DefaultContext, &project1) require.NoError(t, err) - for i := 0; i < 3; i++ { + for i := range 3 { err = project_model.NewColumn(db.DefaultContext, &project_model.Column{ Title: fmt.Sprintf("column %d", i+1), ProjectID: project1.ID, diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go index a987603ce7..14399fc936 100644 --- a/tests/integration/pull_merge_test.go +++ b/tests/integration/pull_merge_test.go @@ -8,6 +8,7 @@ import ( "context" "encoding/base64" "fmt" + "maps" "math/rand/v2" "net/http" "net/http/httptest" @@ -71,9 +72,7 @@ func testPullMergeForm(t *testing.T, session *TestSession, expectedCode int, use link := path.Join(user, repo, "pulls", pullnum, "merge") options := map[string]string{} - for k, v := range addOptions { - options[k] = v - } + maps.Copy(options, addOptions) req := NewRequestWithValues(t, "POST", link, options) resp := session.MakeRequest(t, req, expectedCode) diff --git a/tests/integration/quota_use_test.go b/tests/integration/quota_use_test.go index 33d987af36..dd5afd1aed 100644 --- a/tests/integration/quota_use_test.go +++ b/tests/integration/quota_use_test.go @@ -7,6 +7,7 @@ import ( "bytes" "fmt" "io" + "maps" "mime/multipart" "net/http" "net/http/httptest" @@ -656,9 +657,7 @@ func (ctx *quotaWebEnvAsContext) With(opts Context) *quotaWebEnvAsContext { ctx.Repo = opts.Repo } if opts.Payload != nil { - for key, value := range *opts.Payload { - ctx.Payload[key] = value - } + maps.Copy(ctx.Payload, *opts.Payload) } return ctx } diff --git a/tests/integration/release_test.go b/tests/integration/release_test.go index 483822e2ac..b54e921fa4 100644 --- a/tests/integration/release_test.go +++ b/tests/integration/release_test.go @@ -231,7 +231,7 @@ func TestCreateReleasePaging(t *testing.T) { session := loginUser(t, "user2") // Create enough releases to have paging - for i := 0; i < 12; i++ { + for i := range 12 { version := fmt.Sprintf("v0.0.%d", i) createNewRelease(t, session, "/user2/repo1", version, version, false, false) } diff --git a/tests/integration/repo_commits_test.go b/tests/integration/repo_commits_test.go index 47cf7e8534..d2bb4e8849 100644 --- a/tests/integration/repo_commits_test.go +++ b/tests/integration/repo_commits_test.go @@ -146,7 +146,7 @@ func TestRepoCommitsStatusParallel(t *testing.T) { assert.NotEmpty(t, commitURL) var wg sync.WaitGroup - for i := 0; i < 10; i++ { + for i := range 10 { wg.Add(1) go func(parentT *testing.T, i int) { parentT.Run(fmt.Sprintf("ParallelCreateStatus_%d", i), func(t *testing.T) { diff --git a/tests/integration/repo_flags_test.go b/tests/integration/repo_flags_test.go index bb489f678c..279feefe73 100644 --- a/tests/integration/repo_flags_test.go +++ b/tests/integration/repo_flags_test.go @@ -135,7 +135,7 @@ func TestRepositoryFlagsAPI(t *testing.T) { assert.Empty(t, flags) // Replacing all tags works, twice in a row - for i := 0; i < 2; i++ { + for range 2 { req = NewRequestWithJSON(t, "PUT", fmt.Sprintf(baseURLFmtStr, ""), &api.ReplaceFlagsOption{ Flags: []string{"flag-1", "flag-2", "flag-3"}, }).AddTokenAuth(token) @@ -160,7 +160,7 @@ func TestRepositoryFlagsAPI(t *testing.T) { MakeRequest(t, req, http.StatusNotFound) // We can add the same flag twice - for i := 0; i < 2; i++ { + for range 2 { req = NewRequestf(t, "PUT", baseURLFmtStr, "/brand-new-flag").AddTokenAuth(token) MakeRequest(t, req, http.StatusNoContent) } @@ -170,7 +170,7 @@ func TestRepositoryFlagsAPI(t *testing.T) { MakeRequest(t, req, http.StatusNoContent) // We can delete a flag, twice - for i := 0; i < 2; i++ { + for range 2 { req = NewRequestf(t, "DELETE", baseURLFmtStr, "/flag-3").AddTokenAuth(token) MakeRequest(t, req, http.StatusNoContent) } diff --git a/tests/integration/repo_topic_test.go b/tests/integration/repo_topic_test.go index 0f11d451d6..7331f23218 100644 --- a/tests/integration/repo_topic_test.go +++ b/tests/integration/repo_topic_test.go @@ -62,7 +62,7 @@ func TestTopicSearchPaging(t *testing.T) { token2 := getUserToken(t, user2.Name, auth_model.AccessTokenScopeWriteRepository) repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) - for i := 0; i < 20; i++ { + for i := range 20 { req := NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/paging-topic-%d", user2.Name, repo2.Name, i). AddTokenAuth(token2) MakeRequest(t, req, http.StatusNoContent) diff --git a/tests/integration/repo_webhook_test.go b/tests/integration/repo_webhook_test.go index 5320c85de1..bbde44892e 100644 --- a/tests/integration/repo_webhook_test.go +++ b/tests/integration/repo_webhook_test.go @@ -4,6 +4,7 @@ package integration import ( + "maps" "net/http" "net/http/httptest" "net/url" @@ -408,9 +409,7 @@ func testWebhookFormsShared(t *testing.T, endpoint, name string, session *TestSe payload := map[string]string{ "events": "send_everything", } - for k, v := range validFields { - payload[k] = v - } + maps.Copy(payload, validFields) for k, v := range invalidPatch { if v == "" { delete(payload, k) @@ -448,9 +447,7 @@ func assertHasFlashMessages(t *testing.T, resp *httptest.ResponseRecorder, expec for key, value := range flash { // the key is itself url-encoded if flash, err := url.ParseQuery(key); err == nil { - for key, value := range flash { - seenKeys[key] = value - } + maps.Copy(seenKeys, flash) } else { seenKeys[key] = value } diff --git a/tests/integration/signing_git_test.go b/tests/integration/signing_git_test.go index 5dee5b4801..2fbdb22b6f 100644 --- a/tests/integration/signing_git_test.go +++ b/tests/integration/signing_git_test.go @@ -433,7 +433,7 @@ func crudActionCreateFile(_ *testing.T, ctx APITestContext, user *user_model.Use Email: user.Email, }, }, - ContentBase64: base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("This is new text for %s", path))), + ContentBase64: base64.StdEncoding.EncodeToString(fmt.Appendf(nil, "This is new text for %s", path)), }, callback...) } diff --git a/tests/integration/signup_test.go b/tests/integration/signup_test.go index e66b193e15..eee022f7ab 100644 --- a/tests/integration/signup_test.go +++ b/tests/integration/signup_test.go @@ -185,10 +185,10 @@ func TestSignupImageCaptcha(t *testing.T) { assert.True(t, ok) assert.Len(t, digits, 6) - digitStr := "" + var digitStr strings.Builder // Convert digits to ASCII digits. for _, digit := range digits { - digitStr += string(digit + '0') + digitStr.WriteString(string(digit + '0')) } req = NewRequestWithValues(t, "POST", "/user/sign_up", map[string]string{ @@ -197,7 +197,7 @@ func TestSignupImageCaptcha(t *testing.T) { "password": "examplePassword!1", "retype": "examplePassword!1", "img-captcha-id": idCaptcha, - "img-captcha-response": digitStr, + "img-captcha-response": digitStr.String(), }) MakeRequest(t, req, http.StatusSeeOther) diff --git a/tests/integration/ssh_key_test.go b/tests/integration/ssh_key_test.go index 156bcb137e..747b6c4eb0 100644 --- a/tests/integration/ssh_key_test.go +++ b/tests/integration/ssh_key_test.go @@ -28,7 +28,7 @@ func doCheckRepositoryEmptyStatus(ctx APITestContext, isEmpty bool) func(*testin func doAddChangesToCheckout(dstPath, filename string) func(*testing.T) { return func(t *testing.T) { - require.NoError(t, os.WriteFile(filepath.Join(dstPath, filename), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s at time: %v", dstPath, time.Now())), 0o644)) + require.NoError(t, os.WriteFile(filepath.Join(dstPath, filename), fmt.Appendf(nil, "# Testing Repository\n\nOriginally created in: %s at time: %v", dstPath, time.Now()), 0o644)) require.NoError(t, git.AddChanges(dstPath, true)) signature := git.Signature{ Email: "test@example.com", diff --git a/tests/integration/user_test.go b/tests/integration/user_test.go index f1acafbde8..0f7c099c70 100644 --- a/tests/integration/user_test.go +++ b/tests/integration/user_test.go @@ -1030,7 +1030,7 @@ func TestUserRepos(t *testing.T) { sel := htmlDoc.doc.Find("a.name") assert.Len(t, repos, len(sel.Nodes)) - for i := 0; i < len(repos); i++ { + for i := range repos { assert.Equal(t, repos[i], strings.TrimSpace(sel.Eq(i).Text())) } } diff --git a/tests/test_utils.go b/tests/test_utils.go index dff1c283d0..5e5b04c860 100644 --- a/tests/test_utils.go +++ b/tests/test_utils.go @@ -15,6 +15,7 @@ import ( "path" "path/filepath" "runtime" + "slices" "strings" "sync/atomic" "testing" @@ -524,23 +525,20 @@ func CreateDeclarativeRepo(t *testing.T, owner *user_model.User, name string, en if enabledUnits != nil { opts.EnabledUnits = optional.Some(enabledUnits) - for _, unitType := range enabledUnits { - if unitType == unit_model.TypePullRequests { - opts.UnitConfig = optional.Some(map[unit_model.Type]convert.Conversion{ - unit_model.TypePullRequests: &repo_model.PullRequestsConfig{ - AllowMerge: true, - AllowRebase: true, - AllowRebaseMerge: true, - AllowSquash: true, - AllowFastForwardOnly: true, - AllowManualMerge: true, - AllowRebaseUpdate: true, - DefaultMergeStyle: repo_model.MergeStyleMerge, - DefaultUpdateStyle: repo_model.UpdateStyleMerge, - }, - }) - break - } + if slices.Contains(enabledUnits, unit_model.TypePullRequests) { + opts.UnitConfig = optional.Some(map[unit_model.Type]convert.Conversion{ + unit_model.TypePullRequests: &repo_model.PullRequestsConfig{ + AllowMerge: true, + AllowRebase: true, + AllowRebaseMerge: true, + AllowSquash: true, + AllowFastForwardOnly: true, + AllowManualMerge: true, + AllowRebaseUpdate: true, + DefaultMergeStyle: repo_model.MergeStyleMerge, + DefaultUpdateStyle: repo_model.UpdateStyleMerge, + }, + }) } } if disabledUnits != nil {