chore: add modernizer linter (#11936)

- Go has a suite of small linters that helps with modernizing Go code by using newer functions and catching small mistakes, https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize.
- Enable this linter in golangci-lint.
- There's also [`go fix`](https://go.dev/blog/gofix), which is not yet released as a linter in golangci-lint: https://github.com/golangci/golangci-lint/pull/6385

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11936
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Co-authored-by: Gusted <postmaster@gusted.xyz>
Co-committed-by: Gusted <postmaster@gusted.xyz>
This commit is contained in:
Gusted 2026-04-02 03:29:37 +02:00 committed by Gusted
commit 77dbc35138
249 changed files with 659 additions and 1010 deletions

View file

@ -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 {

View file

@ -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

View file

@ -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))

View file

@ -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
}

View file

@ -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

View file

@ -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
}

View file

@ -91,7 +91,7 @@ var registeredConfigs = map[Type]func() Config{}
// RegisterTypeConfig register a config for a provided type
func RegisterTypeConfig(typ Type, exemplar Config) {
if reflect.TypeOf(exemplar).Kind() == reflect.Ptr {
if reflect.TypeOf(exemplar).Kind() == reflect.Pointer {
// Pointer:
registeredConfigs[typ] = func() Config {
return reflect.New(reflect.ValueOf(exemplar).Elem().Type()).Interface().(Config)

View file

@ -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)

View file

@ -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 {

View file

@ -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) {

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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
}

View file

@ -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

View file

@ -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 {

View file

@ -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))

View file

@ -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 (<issue ids in current page>) group by issue_id
rows, err := db.GetEngine(ctx).Table("tracked_time").

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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 := "<Permission AccessMode=%s, %d Units, %d UnitsMode(s): [ "
var format strings.Builder
format.WriteString("<Permission AccessMode=%s, %d Units, %d UnitsMode(s): [ ")
args := []any{p.AccessMode.String(), len(p.Units), len(p.UnitsMode)}
for i, unit := range p.Units {
@ -127,15 +129,15 @@ func (p *Permission) LogString() string {
config = err.Error()
}
}
format += "\nUnits[%d]: ID: %d RepoID: %d Type: %s Config: %s"
format.WriteString("\nUnits[%d]: ID: %d RepoID: %d Type: %s Config: %s")
args = append(args, i, unit.ID, unit.RepoID, unit.Type.LogString(), config)
}
for key, value := range p.UnitsMode {
format += "\nUnitMode[%-v]: %-v"
format.WriteString("\nUnitMode[%-v]: %-v")
args = append(args, key.LogString(), value.LogString())
}
format += " ]>"
return fmt.Sprintf(format, args...)
format.WriteString(" ]>")
return fmt.Sprintf(format.String(), args...)
}
func GetActionRepoPermission(ctx context.Context, repo *repo_model.Repository, task *actions_model.ActionTask) (Permission, error) {

View file

@ -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,

View file

@ -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
}

View file

@ -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, "/")
}
}

View file

@ -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

View file

@ -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)

View file

@ -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 {

View file

@ -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

View file

@ -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
}

View file

@ -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

View file

@ -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)

View file

@ -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
}

View file

@ -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 }))

View file

@ -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))

View file

@ -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 {

View file

@ -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)

View file

@ -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)