From bd4651fb0b6b03f930b377cbc897db9a1581a2c5 Mon Sep 17 00:00:00 2001 From: Amir Raminfar Date: Thu, 9 Jul 2026 10:51:26 -0700 Subject: [PATCH] chore: apply go fix modernizations (#4822) Co-authored-by: Claude Opus 4.8 --- internal/auth/simple.go | 2 +- internal/cloud/log_streamer.go | 6 +-- internal/container/event_generator_test.go | 3 +- internal/container/types.go | 62 +++++++++++----------- internal/container/volume_monitor.go | 2 +- internal/docker/log_reader.go | 2 +- internal/k8s/client.go | 14 ++--- internal/profile/disk.go | 14 ++--- internal/support/cli/args.go | 2 +- internal/support/cli/valid_env.go | 11 ++-- internal/support/web/escape.go | 18 +++---- internal/support/web/regex.go | 10 ++-- internal/web/debug.go | 2 +- internal/web/index.go | 14 ++--- internal/web/logs.go | 4 +- lint-staged.config.mjs | 9 ++++ package.json | 5 -- 17 files changed, 87 insertions(+), 93 deletions(-) create mode 100644 lint-staged.config.mjs diff --git a/internal/auth/simple.go b/internal/auth/simple.go index 244c1b52..90cb7723 100644 --- a/internal/auth/simple.go +++ b/internal/auth/simple.go @@ -39,7 +39,7 @@ func (a *simpleAuthContext) CreateToken(username, password string) (string, erro return "", ErrInvalidCredentials } - claims := map[string]interface{}{"username": user.Username, "email": user.Email, "name": user.Name, "filter": user.Filter, "roles": user.Roles} + claims := map[string]any{"username": user.Username, "email": user.Email, "name": user.Name, "filter": user.Filter, "roles": user.Roles} jwtauth.SetIssuedNow(claims) if a.ttl > 0 { diff --git a/internal/cloud/log_streamer.go b/internal/cloud/log_streamer.go index bb12e445..2abf660b 100644 --- a/internal/cloud/log_streamer.go +++ b/internal/cloud/log_streamer.go @@ -162,9 +162,7 @@ func (ls *logStreamer) startReader(parent context.Context, c container.Container return } - ls.wg.Add(1) - go func() { - defer ls.wg.Done() + ls.wg.Go(func() { defer func() { ls.mu.Lock() delete(ls.readers, key) @@ -172,7 +170,7 @@ func (ls *logStreamer) startReader(parent context.Context, c container.Container cancel() }() ls.runReader(readerCtx, cs, minRank) - }() + }) } // runReader follows logs from a single container and pushes batches directly diff --git a/internal/container/event_generator_test.go b/internal/container/event_generator_test.go index c6ca0684..12cce74a 100644 --- a/internal/container/event_generator_test.go +++ b/internal/container/event_generator_test.go @@ -117,8 +117,7 @@ func TestEventGenerator_doesNotStallOnSustainedLevellessStream(t *testing.T) { // maxGroupTimeDelta, every line looks like an orphaned continuation, so the // skip loop buffers forever and the UI shows "no logs". The generator must // give up and emit instead. - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() reader := &steadyLevellessReader{ctx: ctx, base: time.Now(), step: time.Millisecond, delay: time.Millisecond} // startedAt far in the past so the near-start short-circuit cannot fire diff --git a/internal/container/types.go b/internal/container/types.go index ff8bb099..3b6915b6 100644 --- a/internal/container/types.go +++ b/internal/container/types.go @@ -99,19 +99,19 @@ func (container Container) ToProto() pb.Container { } return pb.Container{ - Id: container.ID, - Name: container.Name, - Image: container.Image, - Created: timestamppb.New(container.Created), - State: container.State, - Health: container.Health, - Host: container.Host, - Tty: container.Tty, - Labels: container.Labels, - Group: container.Group, - Started: timestamppb.New(container.StartedAt), - Finished: timestamppb.New(container.FinishedAt), - Stats: pbStats, + Id: container.ID, + Name: container.Name, + Image: container.Image, + Created: timestamppb.New(container.Created), + State: container.State, + Health: container.Health, + Host: container.Host, + Tty: container.Tty, + Labels: container.Labels, + Group: container.Group, + Started: timestamppb.New(container.StartedAt), + Finished: timestamppb.New(container.FinishedAt), + Stats: pbStats, Command: container.Command, MemoryLimit: container.MemoryLimit, CpuLimit: container.CPULimit, @@ -176,20 +176,20 @@ func FromProto(c *pb.Container) Container { } return Container{ - ID: c.Id, - Name: c.Name, - Image: c.Image, - Labels: labels, - Group: c.Group, - Created: c.Created.AsTime(), - State: c.State, - Health: c.Health, - Host: c.Host, - Tty: c.Tty, - Command: c.Command, - StartedAt: c.Started.AsTime(), - FinishedAt: c.Finished.AsTime(), - Stats: utils.RingBufferFrom(300, stats), + ID: c.Id, + Name: c.Name, + Image: c.Image, + Labels: labels, + Group: c.Group, + Created: c.Created.AsTime(), + State: c.State, + Health: c.Health, + Host: c.Host, + Tty: c.Tty, + Command: c.Command, + StartedAt: c.Started.AsTime(), + FinishedAt: c.Finished.AsTime(), + Stats: utils.RingBufferFrom(300, stats), MemoryLimit: c.MemoryLimit, CPULimit: c.CpuLimit, FullyLoaded: c.FullyLoaded, @@ -233,12 +233,12 @@ func ParseContainerFilter(commaValues string) (ContainerLabels, error) { } for val := range strings.SplitSeq(commaValues, ",") { - pos := strings.Index(val, "=") - if pos == -1 { + before, after, ok := strings.Cut(val, "=") + if !ok { return nil, fmt.Errorf("invalid filter: %s", filter) } - key := val[:pos] - val := val[pos+1:] + key := before + val := after filter[key] = append(filter[key], val) } diff --git a/internal/container/volume_monitor.go b/internal/container/volume_monitor.go index f2f82b81..ebecfc86 100644 --- a/internal/container/volume_monitor.go +++ b/internal/container/volume_monitor.go @@ -46,7 +46,7 @@ func newVolumeMonitor(store *ContainerStore) *volumeMonitor { } func (v *volumeMonitor) start(ctx context.Context) { - for i := 0; i < volumeWorkerCount; i++ { + for range volumeWorkerCount { go v.worker(ctx) } } diff --git a/internal/docker/log_reader.go b/internal/docker/log_reader.go index 0f12ccc8..f4c8cc67 100644 --- a/internal/docker/log_reader.go +++ b/internal/docker/log_reader.go @@ -32,7 +32,7 @@ func NewLogReader(r io.Reader, tty bool) *LogReader { reader: bufio.NewReader(r), tty: tty, pool: &sync.Pool{ - New: func() interface{} { + New: func() any { return bytes.NewBuffer(make([]byte, 0, 4096)) }, }, diff --git a/internal/k8s/client.go b/internal/k8s/client.go index 48631954..59dd4bff 100644 --- a/internal/k8s/client.go +++ b/internal/k8s/client.go @@ -6,7 +6,9 @@ import ( "errors" "fmt" "io" + "maps" "regexp" + "slices" "strings" "sync" "time" @@ -154,9 +156,7 @@ func (k *K8sClient) podToContainers(ctx context.Context, pod *corev1.Pod) []cont // Build labels map with pod labels, namespace, and owner reference labels := make(map[string]string) - for k, v := range pod.Labels { - labels[k] = v - } + maps.Copy(labels, pod.Labels) labels["namespace"] = pod.Namespace labels["@k8s.namespace"] = pod.Namespace @@ -444,13 +444,7 @@ func matchesContainerLabels(labels map[string]string, filters container.Containe if !ok { return false } - matched := false - for _, expected := range values { - if value == expected { - matched = true - break - } - } + matched := slices.Contains(values, value) if !matched { return false } diff --git a/internal/profile/disk.go b/internal/profile/disk.go index 21d1dc9c..3a51277a 100644 --- a/internal/profile/disk.go +++ b/internal/profile/disk.go @@ -13,8 +13,8 @@ import ( ) const ( - profileFilename = "profile.json" - DefaultUsername = "__default__" + profileFilename = "profile.json" + DefaultUsername = "__default__" ) var errMissingProfileErr = errors.New("Profile file does not exist") @@ -39,11 +39,11 @@ type Settings struct { } type Profile struct { - Settings *Settings `json:"settings,omitempty"` - Pinned []string `json:"pinned"` - VisibleKeys []interface{} `json:"visibleKeys,omitempty"` - ReleaseSeen string `json:"releaseSeen,omitempty"` - CollapsedGroups []string `json:"collapsedGroups"` + Settings *Settings `json:"settings,omitempty"` + Pinned []string `json:"pinned"` + VisibleKeys []any `json:"visibleKeys,omitempty"` + ReleaseSeen string `json:"releaseSeen,omitempty"` + CollapsedGroups []string `json:"collapsedGroups"` } var dataPath string diff --git a/internal/support/cli/args.go b/internal/support/cli/args.go index 978a610b..2af680cc 100644 --- a/internal/support/cli/args.go +++ b/internal/support/cli/args.go @@ -54,7 +54,7 @@ func (Args) Version() string { return Version } -func ParseArgs() (Args, interface{}) { +func ParseArgs() (Args, any) { var args Args parser := arg.MustParse(&args) diff --git a/internal/support/cli/valid_env.go b/internal/support/cli/valid_env.go index 845ab954..22548897 100644 --- a/internal/support/cli/valid_env.go +++ b/internal/support/cli/valid_env.go @@ -8,16 +8,15 @@ import ( "github.com/rs/zerolog/log" ) -func ValidateEnvVars(types ...interface{}) { +func ValidateEnvVars(types ...any) { expectedEnvs := make(map[string]bool) for _, t := range types { typ := reflect.TypeOf(t) - for i := 0; i < typ.NumField(); i++ { - field := typ.Field(i) - for _, tag := range strings.Split(field.Tag.Get("arg"), ",") { - if strings.HasPrefix(tag, "env:") { - expectedEnvs[strings.TrimPrefix(tag, "env:")] = true + for field := range typ.Fields() { + for tag := range strings.SplitSeq(field.Tag.Get("arg"), ",") { + if after, ok := strings.CutPrefix(tag, "env:"); ok { + expectedEnvs[after] = true } } } diff --git a/internal/support/web/escape.go b/internal/support/web/escape.go index a281b015..7790b24f 100644 --- a/internal/support/web/escape.go +++ b/internal/support/web/escape.go @@ -34,7 +34,7 @@ func EscapeHTMLValues(logEvent *container.LogEvent) { case *orderedmap.OrderedMap[string, string]: escapeStringMap(value) - case map[string]interface{}: + case map[string]any: panic("not implemented") case map[string]string: @@ -66,11 +66,11 @@ func escapeAnyMap(orderedMap *orderedmap.OrderedMap[string, any]) { escapeAnyMap(value) case *orderedmap.OrderedMap[string, string]: escapeStringMap(value) - case map[string]interface{}: + case map[string]any: escapeMapStringInterface(value) case map[string]string: escapeStringMapString(value) - case []interface{}: + case []any: escapeSlice(value) orderedMap.Set(pair.Key, value) default: @@ -85,16 +85,16 @@ func escapeStringMap(orderedMap *orderedmap.OrderedMap[string, string]) { } } -func escapeMapStringInterface(value map[string]interface{}) { +func escapeMapStringInterface(value map[string]any) { for key, val := range value { switch val := val.(type) { case string: value[key] = escapeAndProcessMarkers(val) - case map[string]interface{}: + case map[string]any: escapeMapStringInterface(val) case map[string]string: escapeStringMapString(val) - case []interface{}: + case []any: escapeSlice(val) } } @@ -106,7 +106,7 @@ func escapeStringMapString(value map[string]string) { } } -func escapeSlice(slice []interface{}) { +func escapeSlice(slice []any) { for i, val := range slice { switch val := val.(type) { case string: @@ -115,11 +115,11 @@ func escapeSlice(slice []interface{}) { escapeAnyMap(val) case *orderedmap.OrderedMap[string, string]: escapeStringMap(val) - case map[string]interface{}: + case map[string]any: escapeMapStringInterface(val) case map[string]string: escapeStringMapString(val) - case []interface{}: + case []any: escapeSlice(val) } } diff --git a/internal/support/web/regex.go b/internal/support/web/regex.go index c8b764fa..55d334a5 100644 --- a/internal/support/web/regex.go +++ b/internal/support/web/regex.go @@ -67,7 +67,7 @@ func (pm *PatternMatcher) MarkInLogEvent(logEvent *container.LogEvent) bool { case *orderedmap.OrderedMap[string, string]: return pm.markMapString(value) - case map[string]interface{}: + case map[string]any: return pm.markMap(value) case map[string]string: @@ -105,7 +105,7 @@ func (pm *PatternMatcher) markMapAny(orderedMap *orderedmap.OrderedMap[string, a found = true } - case map[string]interface{}: + case map[string]any: if pm.markMap(value) { found = true } @@ -125,7 +125,7 @@ func (pm *PatternMatcher) markMapAny(orderedMap *orderedmap.OrderedMap[string, a return found } -func (pm *PatternMatcher) markMap(data map[string]interface{}) bool { +func (pm *PatternMatcher) markMap(data map[string]any) bool { found := false for key, value := range data { switch value := value.(type) { @@ -139,7 +139,7 @@ func (pm *PatternMatcher) markMap(data map[string]interface{}) bool { found = true } - case map[string]interface{}: + case map[string]any: if pm.markMap(value) { found = true } @@ -188,7 +188,7 @@ func (pm *PatternMatcher) markArray(data []any) bool { if pm.markArray(value) { found = true } - case map[string]interface{}: + case map[string]any: if pm.markMap(value) { found = true } diff --git a/internal/web/debug.go b/internal/web/debug.go index 1b29e404..150aaf5e 100644 --- a/internal/web/debug.go +++ b/internal/web/debug.go @@ -8,7 +8,7 @@ import ( ) func (h *handler) debugStore(w http.ResponseWriter, r *http.Request) { - respone := make(map[string]interface{}) + respone := make(map[string]any) respone["hosts"] = h.hostService.Hosts() containers, errors := h.hostService.ListAllContainers(container.ContainerLabels{}) respone["containers"] = containers diff --git a/internal/web/index.go b/internal/web/index.go index 2e695016..05417239 100644 --- a/internal/web/index.go +++ b/internal/web/index.go @@ -55,7 +55,7 @@ func (h *handler) executeTemplate(w http.ResponseWriter, req *http.Request) { } } - config := map[string]interface{}{ + config := map[string]any{ "base": base, } @@ -100,7 +100,7 @@ func (h *handler) executeTemplate(w http.ResponseWriter, req *http.Request) { config["profile"] = struct{}{} } - data := map[string]interface{}{ + data := map[string]any{ "Config": config, "Dev": h.config.Dev, "Manifest": h.readManifest(), @@ -115,7 +115,7 @@ func (h *handler) executeTemplate(w http.ResponseWriter, req *http.Request) { log.Fatal().Err(err).Msg("Could not read index.html") } tmpl, err := template.New("index.html").Funcs(template.FuncMap{ - "marshal": func(v interface{}) template.JS { + "marshal": func(v any) template.JS { var p []byte if h.config.Dev { p, _ = json.MarshalIndent(v, "", " ") @@ -136,20 +136,20 @@ func (h *handler) executeTemplate(w http.ResponseWriter, req *http.Request) { } } -func (h *handler) readManifest() map[string]interface{} { +func (h *handler) readManifest() map[string]any { if h.config.Dev { - return map[string]interface{}{} + return map[string]any{} } else { file, err := h.content.Open(".vite/manifest.json") if err != nil { // this should only happen during test. In production, the file is embedded in the binary and checked in main.go - return map[string]interface{}{} + return map[string]any{} } bytes, err := io.ReadAll(file) if err != nil { log.Fatal().Err(err).Msg("Could not read .vite/manifest.json") } - var manifest map[string]interface{} + var manifest map[string]any err = json.Unmarshal(bytes, &manifest) if err != nil { log.Fatal().Err(err).Msg("Could not unmarshal .vite/manifest.json") diff --git a/internal/web/logs.go b/internal/web/logs.go index 2dd10d84..e6247e83 100644 --- a/internal/web/logs.go +++ b/internal/web/logs.go @@ -269,7 +269,7 @@ func (h *handler) streamContainerLogs(w http.ResponseWriter, r *http.Request) { func (h *handler) streamLogsMerged(w http.ResponseWriter, r *http.Request) { ids := make(map[string]bool) - for _, id := range strings.Split(chi.URLParam(r, "ids"), ",") { + for id := range strings.SplitSeq(chi.URLParam(r, "ids"), ",") { ids[id] = true } @@ -285,7 +285,7 @@ func (h *handler) streamLogsWithLabels(w http.ResponseWriter, r *http.Request) { labelFilters := make(map[string]string) if labelsParam != "" { - for _, pair := range strings.Split(labelsParam, ",") { + for pair := range strings.SplitSeq(labelsParam, ",") { parts := strings.SplitN(pair, ":", 2) if len(parts) == 2 { labelFilters[parts[0]] = parts[1] diff --git a/lint-staged.config.mjs b/lint-staged.config.mjs new file mode 100644 index 00000000..2d80e878 --- /dev/null +++ b/lint-staged.config.mjs @@ -0,0 +1,9 @@ +import path from "node:path"; + +export default { + "*.{js,vue,css,ts,html,md}": ["prettier --write"], + "*.go": (files) => { + const dirs = [...new Set(files.map((f) => path.dirname(f)))]; + return [`go fix ${dirs.join(" ")}`, `gofmt -w ${files.join(" ")}`]; + }, +}; diff --git a/package.json b/package.json index 45155d2a..f9656a07 100644 --- a/package.json +++ b/package.json @@ -110,11 +110,6 @@ "vue-component-type-helpers": "3.3.6", "vue-tsc": "3.3.6" }, - "lint-staged": { - "*.{js,vue,css,ts,html,md}": [ - "prettier --write" - ] - }, "simple-git-hooks": { "pre-commit": "pnpm lint-staged --allow-empty" }