diff --git a/src/common/dao/pgsql_test.go b/src/common/dao/pgsql_test.go index 2e046115175..f0615262e55 100644 --- a/src/common/dao/pgsql_test.go +++ b/src/common/dao/pgsql_test.go @@ -27,7 +27,7 @@ func TestMaxOpenConns(t *testing.T) { queryNum := 200 results := make([]bool, queryNum) - for i := 0; i < queryNum; i++ { + for i := range queryNum { wg.Add(1) go func(i int) { defer wg.Done() diff --git a/src/common/dao/testutils.go b/src/common/dao/testutils.go index fab162ef08c..cf2c777ba74 100644 --- a/src/common/dao/testutils.go +++ b/src/common/dao/testutils.go @@ -142,7 +142,7 @@ func ArrayEqual(arrayA, arrayB []int) bool { return false } size := len(arrayA) - for i := 0; i < size; i++ { + for i := range size { if arrayA[i] != arrayB[i] { return false } diff --git a/src/common/rbac/project/evaluator_test.go b/src/common/rbac/project/evaluator_test.go index 5a995fa8e0c..ff2e147f983 100644 --- a/src/common/rbac/project/evaluator_test.go +++ b/src/common/rbac/project/evaluator_test.go @@ -119,7 +119,7 @@ func BenchmarkProjectEvaluator(b *testing.B) { resource := NewNamespace(public.ProjectID).Resource(rbac.ResourceRepository) b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { evaluator.HasPermission(context.TODO(), resource, rbac.ActionPull) } } diff --git a/src/common/utils/utils.go b/src/common/utils/utils.go index 03560200e34..1df798f93cc 100644 --- a/src/common/utils/utils.go +++ b/src/common/utils/utils.go @@ -75,7 +75,7 @@ func GenerateRandomStringWithLen(length int) string { if err != nil { log.Warningf("Error reading random bytes: %v", err) } - for i := 0; i < length; i++ { + for i := range length { result[i] = chars[int(result[i])%l] } return string(result) @@ -337,13 +337,3 @@ func MostMatchSorter(a, b string, matchWord string) bool { func IsLocalPath(path string) bool { return len(path) == 0 || (strings.HasPrefix(path, "/") && !strings.HasPrefix(path, "//")) } - -// StringInSlice check if the string is in the slice -func StringInSlice(str string, slice []string) bool { - for _, s := range slice { - if s == str { - return true - } - } - return false -} diff --git a/src/controller/artifact/annotation/v1alpha1.go b/src/controller/artifact/annotation/v1alpha1.go index df88e42ee1e..f6abfdd8a8e 100644 --- a/src/controller/artifact/annotation/v1alpha1.go +++ b/src/controller/artifact/annotation/v1alpha1.go @@ -66,8 +66,7 @@ func parseV1alpha1SkipList(artifact *artifact.Artifact, manifest *v1.Manifest) { skipListAnnotationKey := fmt.Sprintf("%s.%s.%s", AnnotationPrefix, V1alpha1, SkipList) skipList, ok := manifest.Config.Annotations[skipListAnnotationKey] if ok { - skipKeyList := strings.Split(skipList, ",") - for _, skipKey := range skipKeyList { + for skipKey := range strings.SplitSeq(skipList, ",") { delete(metadata, skipKey) } artifact.ExtraAttrs = metadata diff --git a/src/controller/artifact/processor/cnai/parser/util_test.go b/src/controller/artifact/processor/cnai/parser/util_test.go index 1ebc9ad3060..f6c1b7f6b6a 100644 --- a/src/controller/artifact/processor/cnai/parser/util_test.go +++ b/src/controller/artifact/processor/cnai/parser/util_test.go @@ -156,7 +156,7 @@ func TestAddNode(t *testing.T) { // Verify the path exists. current := root parts := filepath.Clean(tt.path) - for _, part := range strings.Split(parts, string(filepath.Separator)) { + for part := range strings.SplitSeq(parts, string(filepath.Separator)) { if part == "" { continue } diff --git a/src/controller/blob/controller_test.go b/src/controller/blob/controller_test.go index 51a38c5ebb1..649dfab1982 100644 --- a/src/controller/blob/controller_test.go +++ b/src/controller/blob/controller_test.go @@ -232,7 +232,7 @@ func (suite *ControllerTestSuite) TestGet() { func (suite *ControllerTestSuite) TestSync() { var references []distribution.Descriptor - for i := 0; i < 5; i++ { + for i := range 5 { references = append(references, distribution.Descriptor{ MediaType: fmt.Sprintf("media type %d", i), Digest: suite.Digest(), diff --git a/src/controller/config/controller.go b/src/controller/config/controller.go index 5380d7634e2..083d97fe406 100644 --- a/src/controller/config/controller.go +++ b/src/controller/config/controller.go @@ -206,7 +206,7 @@ func maxValueLimitedByLength(length int) int64 { var value int64 // the times for multiple, should *10 for every time times := 1 - for i := 0; i < length; i++ { + for range length { value = value + int64(9*times) times = times * 10 } diff --git a/src/controller/event/handler/webhook/scan/scan.go b/src/controller/event/handler/webhook/scan/scan.go index 2057aa04d50..15491c11496 100644 --- a/src/controller/event/handler/webhook/scan/scan.go +++ b/src/controller/event/handler/webhook/scan/scan.go @@ -129,7 +129,7 @@ func constructScanImagePayload(ctx context.Context, event *event.ScanImageEvent, // Wait for reasonable time to make sure the report is ready // Interval=500ms and total time = 5s // If the report is still not ready in the total time, then failed at then - for i := 0; i < 10; i++ { + for range 10 { // First check in case it is ready if re, err := scan.DefaultController.GetReport(ctx, art, []string{v1.MimeTypeNativeReport, v1.MimeTypeGenericVulnerabilityReport}); err == nil { if len(re) > 0 && len(re[0].Report) > 0 { diff --git a/src/controller/health/controller.go b/src/controller/health/controller.go index c6c2bdc458e..4c56a653736 100644 --- a/src/controller/health/controller.go +++ b/src/controller/health/controller.go @@ -48,7 +48,7 @@ func (c *controller) GetHealth(_ context.Context) *OverallHealthStatus { for name, checker := range registry { go check(name, checker, timeout, ch) } - for i := 0; i < len(registry); i++ { + for range len(registry) { componentStatus := <-ch if len(componentStatus.Error) != 0 { isHealthy = false diff --git a/src/controller/jobmonitor/monitor.go b/src/controller/jobmonitor/monitor.go index 04ca93b553c..505f9d46e7c 100644 --- a/src/controller/jobmonitor/monitor.go +++ b/src/controller/jobmonitor/monitor.go @@ -17,6 +17,7 @@ package jobmonitor import ( "context" "fmt" + "slices" "strings" "time" @@ -278,12 +279,7 @@ func (w *monitorController) ListQueues(ctx context.Context) ([]*jm.Queue, error) } func skippedUnusedJobType(jobType string) bool { - for _, t := range skippedJobTypes { - if jobType == t { - return true - } - } - return false + return slices.Contains(skippedJobTypes, jobType) } func (w *monitorController) PauseJobQueues(ctx context.Context, jobType string) error { diff --git a/src/controller/proxy/manifestcache.go b/src/controller/proxy/manifestcache.go index 4cbe9c03499..c763c80b2d3 100644 --- a/src/controller/proxy/manifestcache.go +++ b/src/controller/proxy/manifestcache.go @@ -131,7 +131,7 @@ func (m *ManifestListCache) push(ctx context.Context, repo, reference string, ma // if time exceed, then push a updated manifest list which contains existing manifest var newMan distribution.Manifest var err error - for n := 0; n < maxManifestListWait; n++ { + for range maxManifestListWait { log.Debugf("waiting for the manifest ready, repo %v, tag:%v", repo, reference) time.Sleep(sleepIntervalSec * time.Second) newMan, err = m.updateManifestList(ctx, repo, man) @@ -177,7 +177,7 @@ type ManifestCache struct { // CacheContent ... func (m *ManifestCache) CacheContent(ctx context.Context, remoteRepo string, man distribution.Manifest, art lib.ArtifactInfo, r RemoteInterface, _ string) { var waitBlobs []distribution.Descriptor - for n := 0; n < maxManifestWait; n++ { + for n := range maxManifestWait { time.Sleep(sleepIntervalSec * time.Second) waitBlobs = m.local.CheckDependencies(ctx, art.Repository, man) if len(waitBlobs) == 0 { diff --git a/src/controller/quota/util_test.go b/src/controller/quota/util_test.go index 153aa3d9206..bbc4515eb6f 100644 --- a/src/controller/quota/util_test.go +++ b/src/controller/quota/util_test.go @@ -78,13 +78,13 @@ func (suite *RefreshForProjectsTestSuite) TestRefreshForProjects() { startProjectID := rand.Int63() var firstPageProjects, secondPageProjects []*models.Project - for i := 0; i < 50; i++ { + for i := range 50 { firstPageProjects = append(firstPageProjects, &models.Project{ ProjectID: startProjectID + int64(i), }) } - for i := 0; i < 10; i++ { + for i := range 10 { secondPageProjects = append(secondPageProjects, &models.Project{ ProjectID: startProjectID + 50 + int64(i), }) diff --git a/src/controller/replication/transfer/image/transfer.go b/src/controller/replication/transfer/image/transfer.go index bf76eee9559..d8982202668 100644 --- a/src/controller/replication/transfer/image/transfer.go +++ b/src/controller/replication/transfer/image/transfer.go @@ -423,10 +423,7 @@ func (t *transfer) copyBlobByChunk(srcRepo, dstRepo, digest string, sizeFromDesc // update the start and end for upload *start = *end + 1 // since both ends are closed intervals, it is necessary to subtract one byte - *end = *start + replicationChunkSize - 1 - if *end >= endRange { - *end = endRange - } + *end = min(*start+replicationChunkSize-1, endRange) t.logger.Infof("copying the blob chunk: %d-%d/%d", *start, *end, sizeFromDescriptor) _, data, err := t.src.PullBlobChunk(srcRepo, digest, sizeFromDescriptor, *start, *end) diff --git a/src/controller/scan/checker.go b/src/controller/scan/checker.go index 4b429b2bc30..2d3326b4590 100644 --- a/src/controller/scan/checker.go +++ b/src/controller/scan/checker.go @@ -16,6 +16,7 @@ package scan import ( "context" + "slices" "github.com/goharbor/harbor/src/controller/artifact" "github.com/goharbor/harbor/src/controller/artifact/processor/image" @@ -125,10 +126,8 @@ func hasCapability(r *models.Registration, a *artifact.Artifact) bool { // use allowlist here because currently only docker image is supported by the scanner // https://github.com/goharbor/pluggable-scanner-spec/issues/2 allowlist := []string{image.ArtifactTypeImage} - for _, t := range allowlist { - if a.Type == t { - return r.HasCapability(a.ManifestMediaType) - } + if slices.Contains(allowlist, a.Type) { + return r.HasCapability(a.ManifestMediaType) } return false diff --git a/src/controller/scanner/base_controller.go b/src/controller/scanner/base_controller.go index 623dd4b2865..f421df828a2 100644 --- a/src/controller/scanner/base_controller.go +++ b/src/controller/scanner/base_controller.go @@ -17,6 +17,7 @@ package scanner import ( "context" "fmt" + "slices" "sync" "time" @@ -383,13 +384,7 @@ var ( ) func isReservedName(name string) bool { - for _, reservedName := range reservedNames { - if name == reservedName { - return true - } - } - - return false + return slices.Contains(reservedNames, name) } // MetadataResult metadata or error saved in cache diff --git a/src/core/auth/ldap/ldap.go b/src/core/auth/ldap/ldap.go index 60d31f2b462..796eae9837c 100644 --- a/src/core/auth/ldap/ldap.go +++ b/src/core/auth/ldap/ldap.go @@ -150,7 +150,7 @@ func (l *Auth) attachGroupParallel(ctx context.Context, ldapUsers []model.User, g := new(errgroup.Group) g.SetLimit(workerCount) - for i := 0; i < workerCount; i++ { + for i := range workerCount { curIndex := i g.Go(func() error { userGroups := make([]ugModel.UserGroup, 0) diff --git a/src/core/service/token/token_test.go b/src/core/service/token/token_test.go index 2ea6a8f7106..29307011a4a 100644 --- a/src/core/service/token/token_test.go +++ b/src/core/service/token/token_test.go @@ -24,6 +24,7 @@ import ( "os" "path" "runtime" + "slices" "testing" "github.com/docker/distribution/registry/auth/token" @@ -239,10 +240,8 @@ func (f *fakeSecurityContext) IsSolutionUser() bool { } func (f *fakeSecurityContext) Can(ctx context.Context, action rbac.Action, resource rbac.Resource) bool { if actions, ok := f.rcActions[resource]; ok { - for _, a := range actions { - if a == action { - return true - } + if slices.Contains(actions, action) { + return true } } return false diff --git a/src/core/session/codec.go b/src/core/session/codec.go index d964055da88..408fa95cdb0 100644 --- a/src/core/session/codec.go +++ b/src/core/session/codec.go @@ -16,6 +16,7 @@ package session import ( "encoding/gob" + "maps" "github.com/beego/beego/v2/server/web/session" @@ -51,14 +52,10 @@ func (*gobCodec) Decode(data []byte, v any) error { switch in := v.(type) { case map[any]any: - for k, v := range vm { - in[k] = v - } + maps.Copy(in, vm) case *map[any]any: m := *in - for k, v := range vm { - m[k] = v - } + maps.Copy(m, vm) default: return errors.Errorf("object type invalid, %#v", v) } diff --git a/src/jobservice/job/impl/context.go b/src/jobservice/job/impl/context.go index 8bbe80fd0ee..7cd38b00443 100644 --- a/src/jobservice/job/impl/context.go +++ b/src/jobservice/job/impl/context.go @@ -18,6 +18,7 @@ import ( "context" "errors" "fmt" + "maps" "math" "sync" "time" @@ -116,9 +117,7 @@ func (c *Context) Build(tracker job.Tracker) (job.Context, error) { // Copy properties if len(c.properties) > 0 { - for k, v := range c.properties { - jContext.properties[k] = v - } + maps.Copy(jContext.properties, c.properties) } // Refresh config properties @@ -128,9 +127,7 @@ func (c *Context) Build(tracker job.Tracker) (job.Context, error) { } props := c.cfgMgr.GetAll(c.sysContext) - for k, v := range props { - jContext.properties[k] = v - } + maps.Copy(jContext.properties, props) // Set loggers for job c.lock.Lock() @@ -199,10 +196,7 @@ func createLoggers(jobID string) (logger.Interface, error) { if lc.Name == logger.NameFile || lc.Name == logger.NameDB { // Need extra param fSettings := map[string]any{} - for k, v := range lc.Settings { - // Copy settings - fSettings[k] = v - } + maps.Copy(fSettings, lc.Settings) if lc.Name == logger.NameFile { // Append file name param fSettings["filename"] = fmt.Sprintf("%s.log", jobID) diff --git a/src/jobservice/job/impl/default_context.go b/src/jobservice/job/impl/default_context.go index 47c1eb625d2..9381d4a4a5b 100644 --- a/src/jobservice/job/impl/default_context.go +++ b/src/jobservice/job/impl/default_context.go @@ -17,6 +17,7 @@ package impl import ( "context" "errors" + "maps" o "github.com/beego/beego/v2/client/orm" @@ -61,9 +62,7 @@ func (dc *DefaultContext) Build(t job.Tracker) (job.Context, error) { // Copy properties if len(dc.properties) > 0 { - for k, v := range dc.properties { - jContext.properties[k] = v - } + maps.Copy(jContext.properties, dc.properties) } // Set loggers for job diff --git a/src/jobservice/job/impl/gc/garbage_collection.go b/src/jobservice/job/impl/gc/garbage_collection.go index 9b6cfd3cc5f..b63fff7da59 100644 --- a/src/jobservice/job/impl/gc/garbage_collection.go +++ b/src/jobservice/job/impl/gc/garbage_collection.go @@ -299,10 +299,7 @@ func (gc *GarbageCollector) sweep(ctx job.Context) error { blobChunkCount := (total + blobChunkSize - 1) / blobChunkSize blobChunks := make([][]*blobModels.Blob, blobChunkCount) for i, start := 0, 0; i < blobChunkCount; i, start = i+1, start+blobChunkSize { - end := start + blobChunkSize - if end > total { - end = total - } + end := min(start+blobChunkSize, total) blobChunks[i] = gc.deleteSet[start:end] } diff --git a/src/jobservice/job/impl/gc/util_test.go b/src/jobservice/job/impl/gc/util_test.go index b290aac2ebd..5077a42eb85 100644 --- a/src/jobservice/job/impl/gc/util_test.go +++ b/src/jobservice/job/impl/gc/util_test.go @@ -59,7 +59,7 @@ func TestDelKeys(t *testing.T) { // helper function // mock the data in the redis mock := func(count int, prefix string) { - for i := 0; i < count; i++ { + for i := range count { err = c.Save(context.TODO(), fmt.Sprintf("%s-%d", prefix, i), "", 0) assert.NoError(t, err) } diff --git a/src/jobservice/job/impl/scandataexport/scan_data_export.go b/src/jobservice/job/impl/scandataexport/scan_data_export.go index 14b1e7c901d..040593c411e 100644 --- a/src/jobservice/job/impl/scandataexport/scan_data_export.go +++ b/src/jobservice/job/impl/scandataexport/scan_data_export.go @@ -17,6 +17,7 @@ package scandataexport import ( "encoding/json" "fmt" + "maps" "os" "path/filepath" "strconv" @@ -173,9 +174,8 @@ func (sde *ScanDataExport) updateExecAttributes(ctx job.Context, params job.Para } // copy old extra attrsToUpdate := exec.ExtraAttrs - for k, v := range attrs { - attrsToUpdate[k] = v - } + maps.Copy(attrsToUpdate, attrs) + return sde.execMgr.UpdateExtraAttrs(ctx.SystemContext(), execID, attrsToUpdate) } diff --git a/src/jobservice/logger/base_test.go b/src/jobservice/logger/base_test.go index 52813a51d08..6dfea69779b 100644 --- a/src/jobservice/logger/base_test.go +++ b/src/jobservice/logger/base_test.go @@ -1,7 +1,6 @@ package logger import ( - "context" "fmt" "os" "path" @@ -97,8 +96,7 @@ func TestGetLoggersMulti(t *testing.T) { // Test getting sweepers func TestGetSweeper(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() _, err := GetSweeper(ctx) if err == nil { @@ -170,8 +168,7 @@ func TestGetGetter(t *testing.T) { // Test init func TestLoggerInit(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() oldJobLoggerCfg := config.DefaultConfig.JobLoggerConfigs oldLoggerCfg := config.DefaultConfig.LoggerConfigs diff --git a/src/jobservice/logger/getter/file_getter.go b/src/jobservice/logger/getter/file_getter.go index 1c224de7f26..35763f22890 100644 --- a/src/jobservice/logger/getter/file_getter.go +++ b/src/jobservice/logger/getter/file_getter.go @@ -99,10 +99,8 @@ func tailLogFile(filename string, limit int64) ([]byte, error) { } defer fi.Close() - pos := size - sizeToRead - if pos < 0 { - pos = 0 - } + pos := max(size-sizeToRead, 0) + if pos != 0 { _, err = fi.Seek(pos, 0) if err != nil { diff --git a/src/jobservice/logger/known_loggers.go b/src/jobservice/logger/known_loggers.go index 78e0d575d20..c4d1f57084b 100644 --- a/src/jobservice/logger/known_loggers.go +++ b/src/jobservice/logger/known_loggers.go @@ -16,6 +16,7 @@ package logger import ( "reflect" + "slices" "strings" "github.com/goharbor/harbor/src/jobservice/logger/backend" @@ -89,13 +90,7 @@ func IsKnownLevel(level string) bool { return false } - for _, lvl := range debugLevels { - if lvl == strings.ToUpper(level) { - return true - } - } - - return false + return slices.Contains(debugLevels, strings.ToUpper(level)) } // GetLoggerName return a logger name by Interface diff --git a/src/jobservice/period/enqueuer.go b/src/jobservice/period/enqueuer.go index ff53f017fb6..ee2f9f87533 100644 --- a/src/jobservice/period/enqueuer.go +++ b/src/jobservice/period/enqueuer.go @@ -17,6 +17,7 @@ package period import ( "context" "fmt" + "maps" "math/rand" "time" @@ -303,9 +304,7 @@ func cloneParameters(params job.Parameters, epoch int64) job.Parameters { p := make(job.Parameters) // Clone parameters to a new param map - for k, v := range params { - p[k] = v - } + maps.Copy(p, params) p[PeriodicExecutionMark] = fmt.Sprintf("%d", epoch) diff --git a/src/lib/cache/codec_test.go b/src/lib/cache/codec_test.go index 3d2fae29df9..37fc07bcc76 100644 --- a/src/lib/cache/codec_test.go +++ b/src/lib/cache/codec_test.go @@ -19,7 +19,7 @@ import ( ) func BenchmarkDefaultCodecEncode(b *testing.B) { - for i := 0; i < b.N; i++ { + for b.Loop() { codec.Encode("abcdefghigklmopqrztuvwxyz") } } @@ -27,7 +27,7 @@ func BenchmarkDefaultCodecEncode(b *testing.B) { func BenchmarkDefaultCodecDecode(b *testing.B) { data := []byte("abcdefghigklmopqrztuvwxyz") - for i := 0; i < b.N; i++ { + for b.Loop() { var str string codec.Decode(data, &str) } diff --git a/src/lib/cache/helper_test.go b/src/lib/cache/helper_test.go index 5d6b68e0fa7..bc903c75608 100644 --- a/src/lib/cache/helper_test.go +++ b/src/lib/cache/helper_test.go @@ -103,7 +103,7 @@ func (suite *FetchOrSaveTestSuite) TestSaveCalledOnlyOneTime() { var wg sync.WaitGroup - for i := 0; i < 1000; i++ { + for range 1000 { wg.Add(1) go func() { diff --git a/src/lib/cache/memory/memory_test.go b/src/lib/cache/memory/memory_test.go index 218546fa2ad..1d665293b7b 100644 --- a/src/lib/cache/memory/memory_test.go +++ b/src/lib/cache/memory/memory_test.go @@ -112,14 +112,14 @@ func (suite *CacheTestSuite) TestPing() { func (suite *CacheTestSuite) TestScan() { seed := func(n int) { - for i := 0; i < n; i++ { + for i := range n { key := fmt.Sprintf("test-scan-%d", i) err := suite.cache.Save(suite.ctx, key, "") suite.NoError(err) } } clean := func(n int) { - for i := 0; i < n; i++ { + for i := range n { key := fmt.Sprintf("test-scan-%d", i) err := suite.cache.Delete(suite.ctx, key) suite.NoError(err) diff --git a/src/lib/cache/redis/redis_test.go b/src/lib/cache/redis/redis_test.go index b9749e7ce3d..c4e35befb9a 100644 --- a/src/lib/cache/redis/redis_test.go +++ b/src/lib/cache/redis/redis_test.go @@ -112,14 +112,14 @@ func (suite *CacheTestSuite) TestPing() { func (suite *CacheTestSuite) TestScan() { seed := func(n int) { - for i := 0; i < n; i++ { + for i := range n { key := fmt.Sprintf("test-scan-%d", i) err := suite.cache.Save(suite.ctx, key, "") suite.NoError(err) } } clean := func(n int) { - for i := 0; i < n; i++ { + for i := range n { key := fmt.Sprintf("test-scan-%d", i) err := suite.cache.Delete(suite.ctx, key) suite.NoError(err) diff --git a/src/lib/cache/util_test.go b/src/lib/cache/util_test.go index f3e046b99aa..aa09582d4da 100644 --- a/src/lib/cache/util_test.go +++ b/src/lib/cache/util_test.go @@ -26,7 +26,7 @@ func TestKeyMutex(t *testing.T) { key := "key" var wg sync.WaitGroup - for i := 0; i < 100; i++ { + for range 100 { wg.Add(1) go func() { diff --git a/src/lib/config/userconfig.go b/src/lib/config/userconfig.go index 8c3d9fc1d93..99f41658ef9 100644 --- a/src/lib/config/userconfig.go +++ b/src/lib/config/userconfig.go @@ -220,7 +220,7 @@ func RobotPrefix(ctx context.Context) string { // SplitAndTrim ... func SplitAndTrim(s, sep string) []string { res := make([]string, 0) - for _, s := range strings.Split(s, sep) { + for s := range strings.SplitSeq(s, sep) { if e := strings.TrimSpace(s); len(e) > 0 { res = append(res, e) } @@ -269,8 +269,7 @@ func AuditLogEventEnabled(ctx context.Context, eventType string) bool { return true } disableListStr := DefaultMgr().Get(ctx, common.AuditLogEventsDisabled).GetString() - disableList := strings.Split(disableListStr, ",") - for _, t := range disableList { + for t := range strings.SplitSeq(disableListStr, ",") { tName := strings.TrimSpace(t) if strings.EqualFold(tName, eventType) { return false diff --git a/src/lib/gtask/pool_test.go b/src/lib/gtask/pool_test.go index be9b857c22c..7f8944499ed 100644 --- a/src/lib/gtask/pool_test.go +++ b/src/lib/gtask/pool_test.go @@ -27,7 +27,7 @@ func TestAddTask(t *testing.T) { taskNum := 3 taskInterval := time.Duration(0) - for i := 0; i < taskNum; i++ { + for i := range taskNum { fn := func(ctx context.Context) { t.Logf("Task %d is running...", i) } @@ -64,8 +64,7 @@ func TestStartAndStop(t *testing.T) { pool.tasks = []*task{t1, t2} - ctx1, cancel1 := context.WithCancel(context.Background()) - defer cancel1() + ctx1 := t.Context() pool.Start(ctx1) // Let it run for a bit diff --git a/src/lib/link.go b/src/lib/link.go index 450f2e6683b..b97b2081574 100644 --- a/src/lib/link.go +++ b/src/lib/link.go @@ -54,11 +54,11 @@ func (l Links) String() string { // e.g. ; rel="previous"; title="previous chapter" , ; rel="next"; title="next chapter" func ParseLinks(str string) Links { var links Links - for _, lk := range strings.Split(str, ",") { + for lk := range strings.SplitSeq(str, ",") { link := &Link{ Attrs: map[string]string{}, } - for _, attr := range strings.Split(lk, ";") { + for attr := range strings.SplitSeq(lk, ";") { attr = strings.TrimSpace(attr) if len(attr) == 0 { continue diff --git a/src/lib/log/logger.go b/src/lib/log/logger.go index 66e5fecd24d..b36c47a16e7 100644 --- a/src/lib/log/logger.go +++ b/src/lib/log/logger.go @@ -17,6 +17,7 @@ package log import ( "fmt" "io" + "maps" "os" "runtime" "sort" @@ -122,12 +123,8 @@ func (l *Logger) WithFields(fields Fields) *Logger { if len(fields) > 0 { copyFields := make(map[string]any, len(l.fields)+len(fields)) - for key, value := range l.fields { - copyFields[key] = value - } - for key, value := range fields { - copyFields[key] = value - } + maps.Copy(copyFields, l.fields) + maps.Copy(copyFields, fields) sortedKeys := make([]string, 0, len(copyFields)) for key := range copyFields { diff --git a/src/lib/orm/metadata.go b/src/lib/orm/metadata.go index fc648b4b69d..f0523e9c85f 100644 --- a/src/lib/orm/metadata.go +++ b/src/lib/orm/metadata.go @@ -79,7 +79,7 @@ func parseModel(model any) *metadata { Keys: map[string]*key{}, } // parse fields of the provided model - for i := 0; i < t.NumField(); i++ { + for i := range t.NumField() { field := t.Field(i) orm := field.Tag.Get("orm") // isn't the database column, skip @@ -107,7 +107,7 @@ func parseModel(model any) *metadata { } // parse filter methods of the provided model - for i := 0; i < ptr.NumMethod(); i++ { + for i := range ptr.NumMethod() { methodName := ptr.Method(i).Name if !strings.HasPrefix(methodName, "FilterBy") { continue @@ -173,7 +173,7 @@ func parseFilterable(field reflect.StructField) bool { // } func parseSortable(field reflect.StructField) (*q.Sort, bool) { var defaultSort *q.Sort - for _, item := range strings.Split(field.Tag.Get("sort"), ";") { + for item := range strings.SplitSeq(field.Tag.Get("sort"), ";") { // isn't sortable, return directly if item == "false" { return nil, false @@ -202,7 +202,7 @@ func parseSortable(field reflect.StructField) (*q.Sort, bool) { // It returns "customized_field1" for "Field1" and returns "field2" for "Field2" func parseColumn(field reflect.StructField) string { column := "" - for _, item := range strings.Split(field.Tag.Get("orm"), ";") { + for item := range strings.SplitSeq(field.Tag.Get("orm"), ";") { if !strings.HasPrefix(item, "column") { continue } @@ -224,7 +224,7 @@ func snakeCase(str string) string { runes := []rune(str) var out []rune - for i := 0; i < len(runes); i++ { + for i := range len(runes) { if i > 0 && (unicode.IsUpper(runes[i])) && ((i+1 < len(runes) && unicode.IsLower(runes[i+1])) || unicode.IsLower(runes[i-1])) { diff --git a/src/lib/orm/orm.go b/src/lib/orm/orm.go index 03a4edf445f..a7c95ea6531 100644 --- a/src/lib/orm/orm.go +++ b/src/lib/orm/orm.go @@ -271,7 +271,7 @@ func Escape(str string) string { // e.g. n=3, returns "?,?,?" func ParamPlaceholderForIn(n int) string { placeholders := []string{} - for i := 0; i < n; i++ { + for range n { placeholders = append(placeholders, "?") } return strings.Join(placeholders, ",") diff --git a/src/lib/orm/test/orm_test.go b/src/lib/orm/test/orm_test.go index 9331f684224..128d0b434b9 100644 --- a/src/lib/orm/test/orm_test.go +++ b/src/lib/orm/test/orm_test.go @@ -387,7 +387,7 @@ func (suite *OrmSuite) TestReadOrCreateParallel() { arr := make([]int, count) var wg sync.WaitGroup - for i := 0; i < count; i++ { + for i := range count { wg.Add(1) go func(i int) { defer wg.Done() diff --git a/src/lib/q/builder.go b/src/lib/q/builder.go index da501c96112..66e625e2e6f 100644 --- a/src/lib/q/builder.go +++ b/src/lib/q/builder.go @@ -58,8 +58,8 @@ func parseKeywords(q string) (map[string]any, error) { } else { log.Errorf("failed to unescape the query %s: %v", q, err) } - params := strings.Split(q, ",") - for _, param := range params { + + for param := range strings.SplitSeq(q, ",") { strs := strings.SplitN(param, "=", 2) if len(strs) != 2 || len(strs[0]) == 0 || len(strs[1]) == 0 { return nil, errors.New(nil). @@ -82,7 +82,7 @@ func ParseSorting(sort string) []*Sort { return []*Sort{} } var sorts []*Sort - for _, sorting := range strings.Split(sort, ",") { + for sorting := range strings.SplitSeq(sort, ",") { key := sorting desc := false if strings.HasPrefix(sorting, "-") { @@ -176,8 +176,8 @@ func parseList(value string, c rune) ([]any, error) { return nil, fmt.Errorf(`and list must start with "(" and end with ")"`) } var vs []any - strs := strings.Split(value[1:length-1], " ") - for _, str := range strs { + + for str := range strings.SplitSeq(value[1:length-1], " ") { v := parseValue(str) if s, ok := v.(string); ok && len(s) == 0 { continue diff --git a/src/lib/q/query.go b/src/lib/q/query.go index 2b21a942a7b..a29b3fd878f 100644 --- a/src/lib/q/query.go +++ b/src/lib/q/query.go @@ -14,6 +14,8 @@ package q +import "maps" + // KeyWords ... type KeyWords = map[string]any @@ -56,9 +58,8 @@ func MustClone(query *Query) *Query { if query != nil { q.PageNumber = query.PageNumber q.PageSize = query.PageSize - for k, v := range query.Keywords { - q.Keywords[k] = v - } + maps.Copy(q.Keywords, query.Keywords) + for _, sort := range query.Sorts { q.Sorts = append(q.Sorts, &Sort{ Key: sort.Key, diff --git a/src/lib/redis/client_test.go b/src/lib/redis/client_test.go index 189d0f8eecd..e2f7446a66d 100644 --- a/src/lib/redis/client_test.go +++ b/src/lib/redis/client_test.go @@ -34,7 +34,7 @@ func TestGetRegistryClient(t *testing.T) { assert.NotNil(t, client) // multiple calls should return the same client - for i := 0; i < 10; i++ { + for range 10 { newClient, err := GetRegistryClient() assert.NoError(t, err) assert.Equal(t, client, newClient) @@ -55,7 +55,7 @@ func TestGetHarborClient(t *testing.T) { assert.NotNil(t, client) // multiple calls should return the same client - for i := 0; i < 10; i++ { + for range 10 { newClient, err := GetHarborClient() assert.NoError(t, err) assert.Equal(t, client, newClient) diff --git a/src/lib/selector/selectors/index/index.go b/src/lib/selector/selectors/index/index.go index 6fb40b2a9bc..ad7aaf955a0 100644 --- a/src/lib/selector/selectors/index/index.go +++ b/src/lib/selector/selectors/index/index.go @@ -15,6 +15,7 @@ package index import ( + "slices" "sync" "github.com/goharbor/harbor/src/lib/errors" @@ -80,11 +81,9 @@ func Get(kind, decoration, pattern, extras string) (selector.Selector, error) { } item := v.(*indexedItem) - for _, dec := range item.Meta.Decorations { - if dec == decoration { - factory := item.Factory - return factory(decoration, pattern, extras), nil - } + if slices.Contains(item.Meta.Decorations, decoration) { + factory := item.Factory + return factory(decoration, pattern, extras), nil } return nil, errors.Errorf("decoration %s of selector %s is not supported", decoration, kind) diff --git a/src/pkg/allowlist/dao/dao_test.go b/src/pkg/allowlist/dao/dao_test.go index fc8f86070c2..33fe19aefd6 100644 --- a/src/pkg/allowlist/dao/dao_test.go +++ b/src/pkg/allowlist/dao/dao_test.go @@ -28,7 +28,7 @@ func (s *testSuite) TestSetAndGet() { s.Nil(err) s.Nil(l) var longList []models.CVEAllowlistItem - for i := 0; i < 50; i++ { + for range 50 { longList = append(longList, models.CVEAllowlistItem{CVEID: "CVE-1999-0067"}) } diff --git a/src/pkg/auditext/dao/dao.go b/src/pkg/auditext/dao/dao.go index ad0e25421f3..07794dd002a 100644 --- a/src/pkg/auditext/dao/dao.go +++ b/src/pkg/auditext/dao/dao.go @@ -16,11 +16,11 @@ package dao import ( "context" + "slices" "strings" beegorm "github.com/beego/beego/v2/client/orm" - "github.com/goharbor/harbor/src/common/utils" "github.com/goharbor/harbor/src/lib/errors" "github.com/goharbor/harbor/src/lib/log" "github.com/goharbor/harbor/src/lib/orm" @@ -197,7 +197,7 @@ func permitEventTypes(includeEventTypes []string) []string { var filterEvents []string for _, e := range includeEventTypes { event := strings.ToLower(e) - if utils.StringInSlice(event, model.EventTypes) { + if slices.Contains(model.EventTypes, event) { filterEvents = append(filterEvents, e) } else if event == model.OtherEvents { // include all other events filterEvents = append(filterEvents, model.OtherEventTypes...) diff --git a/src/pkg/cached/manager.go b/src/pkg/cached/manager.go index 9ac21a28040..affd2bbbf96 100644 --- a/src/pkg/cached/manager.go +++ b/src/pkg/cached/manager.go @@ -75,7 +75,7 @@ func (ok *ObjectKey) Format(keysAndValues ...any) (string, error) { } s := ok.namespace - for i := 0; i < len(keysAndValues); i++ { + for i := range len(keysAndValues) { // even is key if i%2 == 0 { key, match := keysAndValues[i].(string) diff --git a/src/pkg/config/inmemory/manager.go b/src/pkg/config/inmemory/manager.go index 2ef9945daaf..3cbfaf3316c 100644 --- a/src/pkg/config/inmemory/manager.go +++ b/src/pkg/config/inmemory/manager.go @@ -16,6 +16,7 @@ package inmemory import ( "context" + "maps" "sync" "github.com/goharbor/harbor/src/common" @@ -41,9 +42,7 @@ func (d *Driver) Load(context.Context) (map[string]any, error) { d.Lock() defer d.Unlock() res := make(map[string]any) - for k, v := range d.cfgMap { - res[k] = v - } + maps.Copy(res, d.cfgMap) return res, nil } @@ -51,9 +50,7 @@ func (d *Driver) Load(context.Context) (map[string]any, error) { func (d *Driver) Save(_ context.Context, cfg map[string]any) error { d.Lock() defer d.Unlock() - for k, v := range cfg { - d.cfgMap[k] = v - } + maps.Copy(d.cfgMap, cfg) return nil } diff --git a/src/pkg/config/rest/rest_test.go b/src/pkg/config/rest/rest_test.go index 3be9a782946..663c4bcd6c4 100644 --- a/src/pkg/config/rest/rest_test.go +++ b/src/pkg/config/rest/rest_test.go @@ -18,6 +18,7 @@ import ( "context" "encoding/json" "io" + "maps" "net/http" "net/http/httptest" "testing" @@ -66,9 +67,7 @@ func ConfigPutHandler(w http.ResponseWriter, r *http.Request) { if err != nil { log.Fatal(err) } - for k, v := range cfgs { - configMapForTest[k] = v - } + maps.Copy(configMapForTest, cfgs) } func TestHTTPDriver_Save(t *testing.T) { diff --git a/src/pkg/jobmonitor/redis.go b/src/pkg/jobmonitor/redis.go index 7886673e4b5..63ab35bb762 100644 --- a/src/pkg/jobmonitor/redis.go +++ b/src/pkg/jobmonitor/redis.go @@ -88,10 +88,7 @@ func (r *redisClientImpl) StopPendingJobs(ctx context.Context, jobType string) ( // use batch to list the job in queue, because the too many object load from a list might cause the redis crash for startIndex := int64(0); startIndex < int64(size); startIndex += batchSize { - endIndex := startIndex + batchSize - if endIndex > int64(size) { - endIndex = int64(size) - } + endIndex := min(startIndex+batchSize, int64(size)) jobs, err := redis.Strings(conn.Do("LRANGE", redisKeyJobQueue, startIndex, endIndex)) if err != nil { return []string{}, err diff --git a/src/pkg/jobmonitor/redis_test.go b/src/pkg/jobmonitor/redis_test.go index 4eae1a49a3b..a2aefba813c 100644 --- a/src/pkg/jobmonitor/redis_test.go +++ b/src/pkg/jobmonitor/redis_test.go @@ -59,7 +59,7 @@ func (s *RedisClientTestSuite) TestUntrackJobStatusInBatch() { jobIDs := make([]string, 0) conn := s.redisClient.redisPool.Get() defer conn.Close() - for i := 0; i < 100; i++ { + for range 100 { k := utils.GenerateRandomStringWithLen(10) jobIDs = append(jobIDs, k) key := rds.KeyJobStats(fmt.Sprintf("{%s}", s.redisClient.namespace), k) @@ -92,7 +92,7 @@ func (s *RedisClientTestSuite) TestStopPendingJobs() { } conn := s.redisClient.redisPool.Get() defer conn.Close() - for i := 0; i < 100; i++ { + for range 100 { job := jobInfo{ ID: utils.GenerateRandomStringWithLen(10), Params: utils.GenerateRandomStringWithLen(10), @@ -107,7 +107,7 @@ func (s *RedisClientTestSuite) TestStopPendingJobs() { } } // job without id - for i := 0; i < 10; i++ { + for range 10 { job := jobInfo{ Params: utils.GenerateRandomStringWithLen(10), } diff --git a/src/pkg/notifier/notifier_test.go b/src/pkg/notifier/notifier_test.go index b4539d04881..856ed344d34 100644 --- a/src/pkg/notifier/notifier_test.go +++ b/src/pkg/notifier/notifier_test.go @@ -173,7 +173,7 @@ func TestConcurrentPublish(t *testing.T) { } // Publish in a short interval. - for i := 0; i < 10; i++ { + for range 10 { Publish(context.TODO(), "topic1", 100) } diff --git a/src/pkg/oidc/helper.go b/src/pkg/oidc/helper.go index db3ba7eab31..9d619f4fbed 100644 --- a/src/pkg/oidc/helper.go +++ b/src/pkg/oidc/helper.go @@ -22,6 +22,7 @@ import ( "net/http" "net/url" "regexp" + "slices" "strings" "sync" "sync/atomic" @@ -392,11 +393,8 @@ func userInfoFromClaims(c claimsProvider, setting cfgModels.OIDCSetting) (*UserI } res.Groups, res.hasGroupClaim = groupsFromClaims(c, setting.GroupsClaim) if len(setting.AdminGroup) > 0 { - for _, g := range res.Groups { - if g == setting.AdminGroup { - res.AdminGroupMember = true - break - } + if slices.Contains(res.Groups, setting.AdminGroup) { + res.AdminGroupMember = true } } return res, nil diff --git a/src/pkg/proxy/secret/manager_test.go b/src/pkg/proxy/secret/manager_test.go index 0e07ee0f221..cbb532477f1 100644 --- a/src/pkg/proxy/secret/manager_test.go +++ b/src/pkg/proxy/secret/manager_test.go @@ -36,13 +36,13 @@ func TestExpiration(t *testing.T) { func TestGC(t *testing.T) { manager := createManager(1*time.Second, 10, 1*time.Second).(*mgr) - for i := 0; i < 10; i++ { + for i := range 10 { rn := fmt.Sprintf("project%d/golang", i) manager.Generate(rn) } time.Sleep(2 * time.Second) assert.Equal(t, uint64(10), manager.size) - for i := 0; i < 1000; i++ { + for i := range 1000 { rn := fmt.Sprintf("project%d/redis", i) manager.Generate(rn) } diff --git a/src/pkg/reg/adapter/awsecr/adapter_test.go b/src/pkg/reg/adapter/awsecr/adapter_test.go index 8d910b840ce..f9590b2cc65 100644 --- a/src/pkg/reg/adapter/awsecr/adapter_test.go +++ b/src/pkg/reg/adapter/awsecr/adapter_test.go @@ -329,7 +329,7 @@ func compileRegexpEveryTime(url string) (string, string, error) { } func BenchmarkGetAccountRegion(b *testing.B) { - for i := 0; i < b.N; i++ { + for b.Loop() { for _, url := range urlForBenchmark { parseAccountRegion(url) } @@ -337,7 +337,7 @@ func BenchmarkGetAccountRegion(b *testing.B) { } func BenchmarkCompileRegexpEveryTime(b *testing.B) { - for i := 0; i < b.N; i++ { + for b.Loop() { for _, url := range urlForBenchmark { compileRegexpEveryTime(url) } diff --git a/src/pkg/reg/adapter/googlegcr/adapter.go b/src/pkg/reg/adapter/googlegcr/adapter.go index 75a33665c9f..ecfcb64654a 100644 --- a/src/pkg/reg/adapter/googlegcr/adapter.go +++ b/src/pkg/reg/adapter/googlegcr/adapter.go @@ -19,6 +19,7 @@ import ( "fmt" "io" "net/http" + "slices" "github.com/opencontainers/go-digest" @@ -195,10 +196,8 @@ func (a adapter) listGcrTagsByRef(repository, reference string) ([]string, strin } // for tag as reference for d, m := range tgs.Manifest { - for _, t := range m.Tag { - if t == reference { - return m.Tag, d, nil - } + if slices.Contains(m.Tag, reference) { + return m.Tag, d, nil } } return nil, "", nil diff --git a/src/pkg/reg/util/pattern.go b/src/pkg/reg/util/pattern.go index b0c15e6e367..63c11ce58f7 100644 --- a/src/pkg/reg/util/pattern.go +++ b/src/pkg/reg/util/pattern.go @@ -40,7 +40,7 @@ func IsSpecificPath(path string) ([]string, bool) { return nil, false } components := [][]string{} - for _, component := range strings.Split(path, "/") { + for component := range strings.SplitSeq(path, "/") { strs, ok := IsSpecificPathComponent(component) if !ok { return nil, false @@ -113,8 +113,7 @@ func IsSpecificPathComponent(component string) ([]string, bool) { suffix = component[j+1:] } components := []string{} - strs := strings.Split(component[i+1:j], ",") - for _, str := range strs { + for str := range strings.SplitSeq(component[i+1:j], ",") { components = append(components, prefix+str+suffix) } return components, true diff --git a/src/pkg/retention/policy/rule/latestk/evaluator.go b/src/pkg/retention/policy/rule/latestk/evaluator.go index 72cc87a4220..6d84ac0212d 100644 --- a/src/pkg/retention/policy/rule/latestk/evaluator.go +++ b/src/pkg/retention/policy/rule/latestk/evaluator.go @@ -49,11 +49,7 @@ func (e *evaluator) Process(artifacts []*selector.Candidate) ([]*selector.Candid return activeTime(artifacts[i]) > activeTime(artifacts[j]) }) - i := e.k - if i > len(artifacts) { - i = len(artifacts) - } - + i := min(e.k, len(artifacts)) return artifacts[:i], nil } diff --git a/src/pkg/retention/policy/rule/latestpl/evaluator.go b/src/pkg/retention/policy/rule/latestpl/evaluator.go index c550874eda7..65cb5869e00 100644 --- a/src/pkg/retention/policy/rule/latestpl/evaluator.go +++ b/src/pkg/retention/policy/rule/latestpl/evaluator.go @@ -46,11 +46,7 @@ func (e *evaluator) Process(artifacts []*selector.Candidate) ([]*selector.Candid return artifacts[i].PulledTime > artifacts[j].PulledTime }) - i := e.n - if i > len(artifacts) { - i = len(artifacts) - } - + i := min(e.n, len(artifacts)) return artifacts[:i], nil } diff --git a/src/pkg/retention/policy/rule/latestps/evaluator.go b/src/pkg/retention/policy/rule/latestps/evaluator.go index 61682dc593a..3f0c37f77b5 100644 --- a/src/pkg/retention/policy/rule/latestps/evaluator.go +++ b/src/pkg/retention/policy/rule/latestps/evaluator.go @@ -48,11 +48,7 @@ func (e *evaluator) Process(artifacts []*selector.Candidate) ([]*selector.Candid return artifacts[i].PushedTime > artifacts[j].PushedTime }) - i := e.k - if i > len(artifacts) { - i = len(artifacts) - } - + i := min(e.k, len(artifacts)) return artifacts[:i], nil } diff --git a/src/pkg/scan/dao/scanner/model.go b/src/pkg/scan/dao/scanner/model.go index 070dc410e99..8ef1de1e4bb 100644 --- a/src/pkg/scan/dao/scanner/model.go +++ b/src/pkg/scan/dao/scanner/model.go @@ -16,6 +16,7 @@ package scanner import ( "encoding/json" + "slices" "time" "github.com/goharbor/harbor/src/lib" @@ -140,15 +141,9 @@ func (r *Registration) HasCapability(manifestMimeType string) bool { return false } - for _, capability := range r.Metadata.Capabilities { - for _, mt := range capability.ConsumesMimeTypes { - if mt == manifestMimeType { - return true - } - } - } - - return false + return slices.ContainsFunc(r.Metadata.Capabilities, func(c *v1.ScannerCapability) bool { + return slices.Contains(c.ConsumesMimeTypes, manifestMimeType) + }) } // GetProducesMimeTypes returns produces mime types for the artifact @@ -162,10 +157,8 @@ func (r *Registration) GetProducesMimeTypes(mimeType string, scanType string) [] capType = v1.ScanTypeVulnerability } if scanType == capType { - for _, mt := range capability.ConsumesMimeTypes { - if mt == mimeType { - return capability.ProducesMimeTypes - } + if slices.Contains(capability.ConsumesMimeTypes, mimeType) { + return capability.ProducesMimeTypes } } } @@ -180,10 +173,8 @@ func (r *Registration) GetCapability(mimeType string) *v1.ScannerCapability { } for _, capability := range r.Metadata.Capabilities { - for _, mt := range capability.ConsumesMimeTypes { - if mt == mimeType { - return capability - } + if slices.Contains(capability.ConsumesMimeTypes, mimeType) { + return capability } } diff --git a/src/pkg/scan/export/filter_processor.go b/src/pkg/scan/export/filter_processor.go index 4353e847971..8281dda53f5 100644 --- a/src/pkg/scan/export/filter_processor.go +++ b/src/pkg/scan/export/filter_processor.go @@ -16,6 +16,7 @@ package export import ( "context" + "slices" "github.com/goharbor/harbor/src/common/utils" "github.com/goharbor/harbor/src/controller/artifact" @@ -170,10 +171,8 @@ func (dfp *DefaultFilterProcessor) ProcessLabelFilter(_ context.Context, labelID // TODO (as now there should not have many labels, so here just use // for^2, we can convert to use map to reduce the time complex if needed. ) for _, label := range art.Labels { - for _, labelID := range labelIDs { - if labelID == label.ID { - return true - } + if slices.Contains(labelIDs, label.ID) { + return true } } return false diff --git a/src/pkg/scan/report/summary.go b/src/pkg/scan/report/summary.go index 0fc907d049e..8513ee1fd34 100644 --- a/src/pkg/scan/report/summary.go +++ b/src/pkg/scan/report/summary.go @@ -101,10 +101,7 @@ func GenerateNativeSummary(r *scan.Report, _ ...Option) (any, error) { sum.ReportID = r.UUID sum.StartTime = r.StartTime sum.EndTime = r.EndTime - sum.Duration = r.EndTime.Unix() - r.StartTime.Unix() - if sum.Duration < 0 { - sum.Duration = 0 - } + sum.Duration = max(r.EndTime.Unix()-r.StartTime.Unix(), 0) sum.ScanStatus = job.ErrorStatus.String() if job.Status(r.Status).Code() != -1 { diff --git a/src/pkg/scan/rest/v1/models.go b/src/pkg/scan/rest/v1/models.go index 83fb29ec7d3..30a8e27610f 100644 --- a/src/pkg/scan/rest/v1/models.go +++ b/src/pkg/scan/rest/v1/models.go @@ -17,6 +17,7 @@ package v1 import ( "encoding/json" "fmt" + "slices" "github.com/goharbor/harbor/src/lib/errors" ) @@ -95,26 +96,15 @@ func (md *ScannerAdapterMetadata) Validate() error { for _, ca := range md.Capabilities { // v1.MimeTypeDockerArtifact is required now - found := false - for _, cm := range ca.ConsumesMimeTypes { - if cm == MimeTypeDockerArtifact { - found = true - break - } - } + found := slices.Contains(ca.ConsumesMimeTypes, MimeTypeDockerArtifact) if !found { return errors.Errorf("missing %s in consumes_mime_types", MimeTypeDockerArtifact) } // either of v1.MimeTypeNativeReport OR v1.MimeTypeGenericVulnerabilityReport is required - found = false - for _, pm := range ca.ProducesMimeTypes { - if isSupportedMimeType(pm) { - found = true - break - } - } - + found = slices.ContainsFunc(ca.ProducesMimeTypes, func(pm string) bool { + return isSupportedMimeType(pm) + }) if !found { return errors.Errorf("missing %s or %s in produces_mime_types", MimeTypeNativeReport, MimeTypeGenericVulnerabilityReport) } @@ -124,34 +114,21 @@ func (md *ScannerAdapterMetadata) Validate() error { } func isSupportedMimeType(mimeType string) bool { - for _, mt := range supportedMimeTypes { - if mt == mimeType { - return true - } - } - return false + return slices.Contains(supportedMimeTypes, mimeType) } // HasCapability returns true when mine type of the artifact support by the scanner func (md *ScannerAdapterMetadata) HasCapability(mimeType string) bool { - for _, capability := range md.Capabilities { - for _, mt := range capability.ConsumesMimeTypes { - if mt == mimeType { - return true - } - } - } - - return false + return slices.ContainsFunc(md.Capabilities, func(c *ScannerCapability) bool { + return slices.Contains(c.ConsumesMimeTypes, mimeType) + }) } // GetCapability returns capability for the mime type func (md *ScannerAdapterMetadata) GetCapability(mimeType string) *ScannerCapability { for _, capability := range md.Capabilities { - for _, mt := range capability.ConsumesMimeTypes { - if mt == mimeType { - return capability - } + if slices.Contains(capability.ConsumesMimeTypes, mimeType) { + return capability } } diff --git a/src/pkg/systemartifact/manager.go b/src/pkg/systemartifact/manager.go index 90057a4d396..1daea91bae3 100644 --- a/src/pkg/systemartifact/manager.go +++ b/src/pkg/systemartifact/manager.go @@ -18,6 +18,7 @@ import ( "context" "fmt" "io" + "maps" "sync" "time" @@ -206,9 +207,7 @@ func (mgr *systemArtifactManager) Cleanup(ctx context.Context) (int64, int64, er // iterate through this copy to invoke the cleanup registeredCriteria := make(map[string]Selector, 0) mgr.lock.Lock() - for key, val := range mgr.cleanupCriteria { - registeredCriteria[key] = val - } + maps.Copy(registeredCriteria, mgr.cleanupCriteria) mgr.lock.Unlock() for key, val := range registeredCriteria { diff --git a/src/pkg/task/dao/execution.go b/src/pkg/task/dao/execution.go index 819c5a091e4..faf5d1b695b 100644 --- a/src/pkg/task/dao/execution.go +++ b/src/pkg/task/dao/execution.go @@ -224,7 +224,7 @@ func (e *executionDAO) GetMetrics(ctx context.Context, id int64) (*Metrics, erro func (e *executionDAO) RefreshStatus(ctx context.Context, id int64) (bool, string, error) { // as the status of the execution can be refreshed by multiple operators concurrently // we use the optimistic locking to avoid the conflict and retry 5 times at most - for i := 0; i < 5; i++ { + for range 5 { statusChanged, currentStatus, retry, err := e.refreshStatus(ctx, id) if err != nil { return false, "", err diff --git a/src/pkg/task/dao/task_test.go b/src/pkg/task/dao/task_test.go index f2ac2a67a38..8333fb9b339 100644 --- a/src/pkg/task/dao/task_test.go +++ b/src/pkg/task/dao/task_test.go @@ -256,7 +256,7 @@ func (t *taskDAOTestSuite) TestGetMaxEndTime() { func (t *taskDAOTestSuite) TestUpdateStatusInBatch() { jobIDs := make([]string, 0) taskIDs := make([]int64, 0) - for i := 0; i < 300; i++ { + for i := range 300 { jobID := fmt.Sprintf("job-%d", i) tid, err := t.taskDAO.Create(t.ctx, &Task{ JobID: jobID, @@ -272,7 +272,7 @@ func (t *taskDAOTestSuite) TestUpdateStatusInBatch() { err := t.taskDAO.UpdateStatusInBatch(t.ctx, jobIDs, "Stopped", 10) t.Require().Nil(err) - for i := 0; i < 300; i++ { + for i := range 300 { tasks, err := t.taskDAO.List(t.ctx, &q.Query{ Keywords: q.KeyWords{"job_id": jobIDs[i]}}) t.Require().Nil(err) diff --git a/src/pkg/task/sweep_job.go b/src/pkg/task/sweep_job.go index 6ee7d49a0a5..c9760861669 100644 --- a/src/pkg/task/sweep_job.go +++ b/src/pkg/task/sweep_job.go @@ -165,11 +165,7 @@ func (sj *SweepJob) sweep(ctx job.Context, vendorType string, retainCount int64) return errStop } // calculate the batch position - j := i + sweepBatchSize - // avoid overflow - if j > total { - j = total - } + j := min(i+sweepBatchSize, total) if err = sj.mgr.Clean(ctx.SystemContext(), candidates[i:j]); err != nil { sj.logger.Errorf("[%s] failed to batch clean candidates, error: %v", vendorType, err) diff --git a/src/server/middleware/repoproxy/proxy.go b/src/server/middleware/repoproxy/proxy.go index d5a2dcbc684..75abdcae26a 100644 --- a/src/server/middleware/repoproxy/proxy.go +++ b/src/server/middleware/repoproxy/proxy.go @@ -329,7 +329,7 @@ func proxyManifestHead(ctx context.Context, w http.ResponseWriter, ctl proxy.Con // Then GET the image by digest, in order to associate the tag with the digest // Ensure tag after head request, make sure tags in proxy cache keep update bCtx := orm.Context() - for i := 0; i < ensureTagMaxRetry; i++ { + for range ensureTagMaxRetry { time.Sleep(ensureTagInterval) bArt := lib.ArtifactInfo{ProjectName: art.ProjectName, Repository: art.Repository, Digest: string(desc.Digest)} err := ctl.EnsureTag(bCtx, bArt, art.Tag) diff --git a/src/server/middleware/vulnerable/vulnerable.go b/src/server/middleware/vulnerable/vulnerable.go index 5fbd52ebb11..9a1ae56c4e9 100644 --- a/src/server/middleware/vulnerable/vulnerable.go +++ b/src/server/middleware/vulnerable/vulnerable.go @@ -17,6 +17,7 @@ package vulnerable import ( "fmt" "net/http" + "slices" "github.com/goharbor/harbor/src/controller/artifact/processor/cnab" "github.com/goharbor/harbor/src/controller/artifact/processor/image" @@ -110,12 +111,10 @@ func Middleware() func(http.Handler) http.Handler { if art.IsImageIndex() { // artifact is image index, skip the checking when it is in the allowlist skippingAllowlist := []string{image.ArtifactTypeImage, cnab.ArtifactTypeCNAB} - for _, t := range skippingAllowlist { - if art.Type == t { - logger.Debugf("artifact %s@%s is image index and its type is %s in skipping allowlist, "+ - "skip the vulnerability prevention checking", art.RepositoryName, art.Digest, art.Type) - return nil - } + if slices.Contains(skippingAllowlist, art.Type) { + logger.Debugf("artifact %s@%s is image index and its type is %s in skipping allowlist, "+ + "skip the vulnerability prevention checking", art.RepositoryName, art.Digest, art.Type) + return nil } } diff --git a/src/server/registry/util/util.go b/src/server/registry/util/util.go index 2915da71e85..aa9e175d5ef 100644 --- a/src/server/registry/util/util.go +++ b/src/server/registry/util/util.go @@ -147,12 +147,7 @@ func pickItems(items []string, n *int, last string) ([]string, string) { i = sort.Search(len(items), func(ix int) bool { return strings.Compare(items[ix], last) > 0 }) } - j := i + *n - - if j >= len(items) { - j = len(items) - } - + j := min(i+*n, len(items)) result := items[i:j] nextLast := "" diff --git a/src/server/v2.0/handler/project.go b/src/server/v2.0/handler/project.go index 683a4827bed..acc1d47b0d3 100644 --- a/src/server/v2.0/handler/project.go +++ b/src/server/v2.0/handler/project.go @@ -17,6 +17,7 @@ package handler import ( "context" "fmt" + "slices" "strconv" "strings" "sync" @@ -795,13 +796,12 @@ func (a *projectAPI) validateProjectReq(ctx context.Context, req *models.Project if err != nil { return fmt.Errorf("failed to get the registry %d: %v", *req.RegistryID, err) } + permitted := false - for _, t := range config.GetPermittedRegistryTypesForProxyCache() { - if string(registry.Type) == t { - permitted = true - break - } + if slices.Contains(config.GetPermittedRegistryTypesForProxyCache(), string(registry.Type)) { + permitted = true } + if !permitted { return errors.BadRequestError(fmt.Errorf("unsupported registry type %s", string(registry.Type))) } diff --git a/src/server/v2.0/handler/util.go b/src/server/v2.0/handler/util.go index f748fbbed90..0309c88d911 100644 --- a/src/server/v2.0/handler/util.go +++ b/src/server/v2.0/handler/util.go @@ -48,7 +48,7 @@ func parseScanReportMimeTypes(header *string) []string { var mimeTypes []string if header != nil { - for _, mimeType := range strings.Split(*header, ",") { + for mimeType := range strings.SplitSeq(*header, ",") { mimeType = strings.TrimSpace(mimeType) switch mimeType { case v1.MimeTypeNativeReport, v1.MimeTypeGenericVulnerabilityReport: diff --git a/src/testing/job/mock_client.go b/src/testing/job/mock_client.go index 69e001b0a34..d7f927c1e12 100644 --- a/src/testing/job/mock_client.go +++ b/src/testing/job/mock_client.go @@ -3,6 +3,7 @@ package job import ( "fmt" "math/rand" + "slices" "github.com/goharbor/harbor/src/common/http" "github.com/goharbor/harbor/src/common/job/models" @@ -54,10 +55,5 @@ func (mjc *MockJobClient) GetExecutions(uuid string) ([]job.Stats, error) { } func (mjc *MockJobClient) validUUID(uuid string) bool { - for _, u := range mjc.JobUUID { - if uuid == u { - return true - } - } - return false + return slices.Contains(mjc.JobUUID, uuid) } diff --git a/src/testing/mock/mock.go b/src/testing/mock/mock.go index 3cad03f62c0..b095535f411 100644 --- a/src/testing/mock/mock.go +++ b/src/testing/mock/mock.go @@ -53,7 +53,7 @@ func OnAnything(obj any, methodName string) *mock.Call { } args := []any{} - for i := 0; i < fnType.NumIn(); i++ { + for range fnType.NumIn() { args = append(args, mock.Anything) }