diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c5d51d5eb..64284b907 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,84 +4,4 @@ updates: - package-ecosystem: "github-actions" directory: "/" schedule: - interval: "daily" - - package-ecosystem: "gomod" - directory: "/contrib/config/apollo" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/config/consul" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/config/etcd" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/config/kubernetes" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/config/nacos" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/encoding/msgpack" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/log/aliyun" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/log/zap" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/log/fluent" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/metrics/datadog" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/metrics/prometheus" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/opensergo" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/registry/apollo" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/registry/consul" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/registry/etcd" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/registry/kubernetes" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/registry/nacos" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/registry/zookeeper" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/registry/eureka" - schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/contrib/registry/polaris" - schedule: - interval: "weekly" + interval: "monthly" diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 977e4ea32..7979eb96e 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -13,7 +13,7 @@ jobs: build: strategy: matrix: - go: [ 1.21.x, 1.22.x, 1.23.x ] + go: [1.22.x, 1.23.x, 1.24.x] name: build & test runs-on: ubuntu-latest services: @@ -44,7 +44,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v5.4.0 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.go }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index e6cb88482..b2fdab47d 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -29,7 +29,8 @@ jobs: steps: - uses: actions/checkout@v4 - name: Lint - uses: golangci/golangci-lint-action@v6 + uses: golangci/golangci-lint-action@v7 with: - version: v1.61.0 - working-directory: ${{ matrix.workdir }} \ No newline at end of file + version: v2.0 + working-directory: ${{ matrix.workdir }} + skip-pkg-cache: true diff --git a/.golangci.yml b/.golangci.yml index 6d021062f..145559c53 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,73 +1,71 @@ +version: "2" run: - timeout: 5m modules-download-mode: readonly - linters: - disable-all: true - fast: false + default: none enable: - bodyclose - dogsled - durationcheck - errcheck - # - copyloopvar # need upgrade to Go 1.22 - - govet - - staticcheck - - gosimple - - gofmt - - gofumpt - goconst - - goimports - - mnd - gocyclo + - govet - ineffassign - lll + - misspell + - mnd - prealloc - revive - staticcheck - - typecheck - - unused - - whitespace - - wastedassign - unconvert - - misspell - - # don't enable: - # - asciicheck - # - scopelint - # - gochecknoglobals - # - gocognit - # - godot - # - godox - # - goerr113 - # - interfacer - # - maligned - # - nestif - # - prealloc - # - testpackage - # - stylecheck - # - wsl - -linters-settings: - govet: - enable: - - shadow - whitespace: - multi-func: true - lll: - line-length: 160 - mnd: - # don't include the "operation", "argument" and "assign" - checks: - - case - - condition - - return - goconst: - ignore-tests: true - gocyclo: - # recommend 10-20 - min-complexity: 50 - goimports: - local-prefixes: github.com/go-kratos # Put imports beginning with prefix after 3rd-party packages - misspell: # Finds commonly misspelled English words in comments - locale: US + - unused + - wastedassign + - whitespace + settings: + gocyclo: + min-complexity: 50 + govet: + enable: + - shadow + lll: + line-length: 160 + misspell: + locale: US + mnd: + checks: + - case + - condition + - return + whitespace: + multi-func: true + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + rules: + - linters: + - goconst + path: (.+)_test\.go + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gofmt + - gofumpt + - goimports + settings: + goimports: + local-prefixes: + - github.com/go-kratos + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/cmd/kratos/internal/base/path.go b/cmd/kratos/internal/base/path.go index d24647fd3..9a6d8654e 100644 --- a/cmd/kratos/internal/base/path.go +++ b/cmd/kratos/internal/base/path.go @@ -101,7 +101,7 @@ func hasSets(name string, sets []string) bool { func Tree(path string, dir string) { _ = filepath.Walk(path, func(path string, info os.FileInfo, err error) error { if err == nil && info != nil && !info.IsDir() { - fmt.Printf("%s %s (%v bytes)\n", color.GreenString("CREATED"), strings.Replace(path, dir+"/", "", -1), info.Size()) + fmt.Printf("%s %s (%v bytes)\n", color.GreenString("CREATED"), strings.ReplaceAll(path, dir+"/", ""), info.Size()) } return nil }) diff --git a/contrib/polaris/router.go b/contrib/polaris/router.go index 93202eb5d..c60fc464e 100644 --- a/contrib/polaris/router.go +++ b/contrib/polaris/router.go @@ -54,7 +54,7 @@ func (p *Polaris) NodeFilter(opts ...RouterOption) selector.NodeFilter { req.SourceService.Service = appInfo.Name() } - req.AddArguments(model.BuildCallerServiceArgument(p.namespace, req.ProcessRoutersRequest.SourceService.Service)) + req.AddArguments(model.BuildCallerServiceArgument(p.namespace, req.SourceService.Service)) // process transport if tr, ok := transport.FromClientContext(ctx); ok { diff --git a/contrib/registry/discovery/impl_discover.go b/contrib/registry/discovery/impl_discover.go index 38b1fc5c1..3be0865ee 100644 --- a/contrib/registry/discovery/impl_discover.go +++ b/contrib/registry/discovery/impl_discover.go @@ -44,21 +44,21 @@ func (d *Discovery) GetService(ctx context.Context, serviceName string) ([]*regi func (d *Discovery) Watch(ctx context.Context, serviceName string) (registry.Watcher, error) { return &watcher{ - Resolve: d.resolveBuild(serviceName), + resolve: d.resolveBuild(serviceName), serviceName: serviceName, cancelCtx: ctx, }, nil } type watcher struct { - *Resolve + resolve *Resolve cancelCtx context.Context serviceName string } func (w *watcher) Next() ([]*registry.ServiceInstance, error) { - event := w.Resolve.Watch() + event := w.resolve.Watch() select { case <-event: @@ -70,12 +70,12 @@ func (w *watcher) Next() ([]*registry.ServiceInstance, error) { ctx, cancel := context.WithTimeout(context.TODO(), 15*time.Second) defer cancel() - ins, ok := w.Resolve.fetch(ctx) + ins, ok := w.resolve.fetch(ctx) if !ok { return nil, errors.New("Discovery.GetService fetch failed") } - out := filterInstancesByZone(ins, w.Resolve.d.config.Zone) + out := filterInstancesByZone(ins, w.resolve.d.config.Zone) if len(out) == 0 { return nil, fmt.Errorf("Discovery.GetService(%s) not found", w.serviceName) } @@ -84,5 +84,5 @@ func (w *watcher) Next() ([]*registry.ServiceInstance, error) { } func (w *watcher) Stop() error { - return w.Resolve.Close() + return w.resolve.Close() } diff --git a/encoding/form/form_test.go b/encoding/form/form_test.go index de13a65b9..819f8e9f9 100644 --- a/encoding/form/form_test.go +++ b/encoding/form/form_test.go @@ -148,6 +148,7 @@ func TestFormCodecUnmarshal(t *testing.T) { } } +//nolint:staticcheck func TestProtoEncodeDecode(t *testing.T) { in := &complex.Complex{ Id: 2233, @@ -227,6 +228,7 @@ func TestProtoEncodeDecode(t *testing.T) { } } +//nolint:staticcheck func TestDecodeStructPb(t *testing.T) { req := new(ectest.StructPb) query := `data={"name":"kratos"}&data_list={"name1": "kratos"}&data_list={"name2": "go-kratos"}` diff --git a/internal/group/group.go b/internal/group/group.go index 04340e371..23fae95ae 100644 --- a/internal/group/group.go +++ b/internal/group/group.go @@ -5,26 +5,29 @@ package group import "sync" +// Factory is a function that creates an object of type T. +type Factory[T any] func() T + // Group is a lazy load container. -type Group struct { - new func() any - vals map[string]any +type Group[T any] struct { + factory func() T + vals map[string]T sync.RWMutex } // NewGroup news a group container. -func NewGroup(new func() any) *Group { - if new == nil { +func NewGroup[T any](factory Factory[T]) *Group[T] { + if factory == nil { panic("container.group: can't assign a nil to the new function") } - return &Group{ - new: new, - vals: make(map[string]any), + return &Group[T]{ + factory: factory, + vals: make(map[string]T), } } // Get gets the object by the given key. -func (g *Group) Get(key string) any { +func (g *Group[T]) Get(key string) T { g.RLock() v, ok := g.vals[key] if ok { @@ -40,25 +43,25 @@ func (g *Group) Get(key string) any { if ok { return v } - v = g.new() + v = g.factory() g.vals[key] = v return v } // Reset resets the new function and deletes all existing objects. -func (g *Group) Reset(new func() any) { - if new == nil { +func (g *Group[T]) Reset(factory Factory[T]) { + if factory == nil { panic("container.group: can't assign a nil to the new function") } g.Lock() - g.new = new + g.factory = factory g.Unlock() g.Clear() } // Clear deletes all objects. -func (g *Group) Clear() { +func (g *Group[T]) Clear() { g.Lock() - g.vals = make(map[string]any) + g.vals = make(map[string]T) g.Unlock() } diff --git a/internal/group/group_test.go b/internal/group/group_test.go index 53a973da5..9de4ffba7 100644 --- a/internal/group/group_test.go +++ b/internal/group/group_test.go @@ -7,22 +7,22 @@ import ( func TestGroupGet(t *testing.T) { count := 0 - g := NewGroup(func() any { + g := NewGroup[int](func() int { count++ return count }) v := g.Get("key_0") - if !reflect.DeepEqual(v.(int), 1) { + if !reflect.DeepEqual(v, 1) { t.Errorf("expect 1, actual %v", v) } v = g.Get("key_1") - if !reflect.DeepEqual(v.(int), 2) { + if !reflect.DeepEqual(v, 2) { t.Errorf("expect 2, actual %v", v) } v = g.Get("key_0") - if !reflect.DeepEqual(v.(int), 1) { + if !reflect.DeepEqual(v, 1) { t.Errorf("expect 1, actual %v", v) } if !reflect.DeepEqual(count, 2) { @@ -31,12 +31,12 @@ func TestGroupGet(t *testing.T) { } func TestGroupReset(t *testing.T) { - g := NewGroup(func() any { + g := NewGroup(func() int { return 1 }) g.Get("key") call := false - g.Reset(func() any { + g.Reset(func() int { call = true return 1 }) @@ -56,7 +56,7 @@ func TestGroupReset(t *testing.T) { } func TestGroupClear(t *testing.T) { - g := NewGroup(func() any { + g := NewGroup(func() int { return 1 }) g.Get("key") diff --git a/middleware/circuitbreaker/circuitbreaker.go b/middleware/circuitbreaker/circuitbreaker.go index 33fc1fd06..bcf2d479f 100644 --- a/middleware/circuitbreaker/circuitbreaker.go +++ b/middleware/circuitbreaker/circuitbreaker.go @@ -20,7 +20,7 @@ type Option func(*options) // WithGroup with circuit breaker group. // NOTE: implements generics circuitbreaker.CircuitBreaker -func WithGroup(g *group.Group) Option { +func WithGroup(g *group.Group[circuitbreaker.CircuitBreaker]) Option { return func(o *options) { o.group = g } @@ -29,21 +29,21 @@ func WithGroup(g *group.Group) Option { // WithCircuitBreaker with circuit breaker genFunc. func WithCircuitBreaker(genBreakerFunc func() circuitbreaker.CircuitBreaker) Option { return func(o *options) { - o.group = group.NewGroup(func() any { + o.group = group.NewGroup(func() circuitbreaker.CircuitBreaker { return genBreakerFunc() }) } } type options struct { - group *group.Group + group *group.Group[circuitbreaker.CircuitBreaker] } // Client circuitbreaker middleware will return errBreakerTriggered when the circuit // breaker is triggered and the request is rejected directly. func Client(opts ...Option) middleware.Middleware { opt := &options{ - group: group.NewGroup(func() any { + group: group.NewGroup(func() circuitbreaker.CircuitBreaker { return sre.NewBreaker() }), } @@ -53,7 +53,7 @@ func Client(opts ...Option) middleware.Middleware { return func(handler middleware.Handler) middleware.Handler { return func(ctx context.Context, req any) (any, error) { info, _ := transport.FromClientContext(ctx) - breaker := opt.group.Get(info.Operation()).(circuitbreaker.CircuitBreaker) + breaker := opt.group.Get(info.Operation()) if err := breaker.Allow(); err != nil { // rejected // NOTE: when client reject requests locally, diff --git a/middleware/circuitbreaker/circuitbreaker_test.go b/middleware/circuitbreaker/circuitbreaker_test.go index 01ce43b91..6981d6564 100644 --- a/middleware/circuitbreaker/circuitbreaker_test.go +++ b/middleware/circuitbreaker/circuitbreaker_test.go @@ -5,6 +5,7 @@ import ( "errors" "testing" + "github.com/go-kratos/aegis/circuitbreaker" kratoserrors "github.com/go-kratos/kratos/v2/errors" "github.com/go-kratos/kratos/v2/internal/group" "github.com/go-kratos/kratos/v2/transport" @@ -46,8 +47,8 @@ func (c *circuitBreakerMock) MarkFailed() {} func Test_WithGroup(t *testing.T) { o := options{ - group: group.NewGroup(func() any { - return "" + group: group.NewGroup(func() circuitbreaker.CircuitBreaker { + return &circuitBreakerMock{} }), } @@ -68,7 +69,7 @@ func TestServer(_ *testing.T) { ctx := transport.NewClientContext(context.Background(), &transportMock{}) _, _ = Client(func(o *options) { - o.group = group.NewGroup(func() any { + o.group = group.NewGroup(func() circuitbreaker.CircuitBreaker { return &circuitBreakerMock{err: errors.New("circuitbreaker error")} }) })(nextValid)(ctx, nil) diff --git a/transport/grpc/server.go b/transport/grpc/server.go index 02bdb706d..6d2f8969b 100644 --- a/transport/grpc/server.go +++ b/transport/grpc/server.go @@ -244,7 +244,7 @@ func (s *Server) Stop(ctx context.Context) error { go func() { defer close(done) log.Info("[gRPC] server stopping") - s.Server.GracefulStop() + s.GracefulStop() }() select { diff --git a/transport/http/server.go b/transport/http/server.go index dc92e7890..19c019c06 100644 --- a/transport/http/server.go +++ b/transport/http/server.go @@ -347,7 +347,7 @@ func (s *Server) Stop(ctx context.Context) error { if err != nil { if ctx.Err() != nil { log.Warn("[HTTP] server couldn't stop gracefully in time, doing force stop") - err = s.Server.Close() + err = s.Close() } } return err