diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index d04ae57..553fed5 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -25,7 +25,7 @@ jobs: - name: Run golangci-lint uses: golangci/golangci-lint-action@v6 with: - version: v1.55.2 + version: v1.64.5 working-directory: ./ - name: Install dependencies diff --git a/.golangci.yml b/.golangci.yml index 84ed4c8..ef8211d 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -3,7 +3,47 @@ run: timeout: 5m linters: - disable-all: true + disable-all: + true + # Disabled linters: + # canonicalheader + # decorder + # dupword + # err113 + # exhaustruct + # forbidigo + # forcetypeassert # заменён на errcheck + # funlen + # ginkgolinter + # gofmt # заменён на goimports + # gofumpt # заменён на goimports + # goheader + # gomoddirectives + # gomodguard # используется более мощный depguard + # gosmopolitan + # grouper + # interfacebloat + # intrange + # ireturn + # lll + # loggercheck + # mirror + # misspell # бесполезный + # nonamedreturns + # nlreturn # слишком строгий и в основном код не более читабелен + # paralleltest # слишком много ложных срабатываний + # protogetter + # sloglint + # spancheck + # sqlclosecheck + # tagalign + # tenv # заменён на usetesting.os-setenv: true + # testableexamples + # testpackage + # varnamelen + # wastedassign + # wsl # слишком строгий и в основном код не более читабелен + # zerologlint enable: - asasalint - asciicheck @@ -11,7 +51,9 @@ linters: - bodyclose - containedctx - contextcheck + - copyloopvar - cyclop + - depguard - dogsled - dupl - durationcheck @@ -20,59 +62,86 @@ linters: - errname - errorlint - exhaustive - - exportloopref - - forcetypeassert + - exptostd + - fatcontext - gci - gocheckcompilerdirectives - gochecknoglobals - gochecknoinits + - gochecksumtype - gocognit - goconst - gocritic - gocyclo - godot - godox - - gofmt - goimports - - gomnd - goprintffuncname - gosec - gosimple - govet + - iface - importas + - inamedparam - ineffassign - maintidx - makezero - - misspell + - mnd # https://golangci-lint.run/usage/linters/#mnd - musttag - nakedret - nestif - nilerr + - nilnesserr - nilnil - - nlreturn - noctx - nolintlint - nosprintfhostport - - paralleltest + - perfsprint - prealloc - predeclared + - promlinter - reassign + - recvcheck - revive + - rowserrcheck - staticcheck - stylecheck - tagliatelle + - testifylint - thelper + - tparallel - typecheck - unconvert - unparam - unused - usestdlibvars + - usetesting - whitespace - wrapcheck linters-settings: + cyclop: + max-complexity: 15 + skip-tests: true + depguard: + rules: + main: + list-mode: lax + deny: + - pkg: "github.com/pkg/errors" + desc: Should be replaced by standard lib errors package + - pkg: "github.com/golang/protobuf" + desc: "Use google.golang.org/protobuf instead, see https://developers.google.com/protocol-buffers/docs/reference/go/faq#modules" + errcheck: + check-type-assertions: true errorlint: errorf: false + exhaustive: + # Presence of "default" case in switch statements satisfies exhaustiveness, + # even if all enum members are not listed. + default-signifies-exhaustive: true + # Only run exhaustive check on switches with "//exhaustive:enforce" comment. + explicit-exhaustive-switch: true gci: sections: - standard @@ -81,8 +150,70 @@ linters-settings: gocognit: min-complexity: 10 gocyclo: - min-complexity: 10 + min-complexity: 15 + goimports: + local-prefixes: capuchin + gosec: + excludes: + - G108 # Profiling endpoint automatically exposed on /debug/pprof + govet: + # Run `GL_DEBUG=govet golangci-lint run --enable=govet` to see default, all available analyzers, and enabled analyzers. + enable-all: true + disable: + - fieldalignment # Использовать при необходимости, ухудшается читаемость кода + - slog # На проекте используется zap + settings: + shadow: + strict: true + iface: + enable: + - identical + - unused + - opaque nestif: min-complexity: 4 + nolintlint: + require-explanation: true + require-specific: true + revive: + enable-all-rules: true + rules: + - name: add-constant + disabled: true + - name: cognitive-complexity + disabled: true + - name: comment-spacings + disabled: true + - name: cyclomatic + disabled: true + - name: function-length + disabled: true + - name: line-length-limit + disabled: true + - name: max-public-structs + disabled: true + - name: unused-parameter + disabled: true + rowserrcheck: + packages: + - github.com/jmoiron/sqlx + tagliatelle: + case: + use-field-name: true + testifylint: + enable-all: true + disable: + - require-error unparam: check-exported: true + +issues: + # Maximum count of issues with the same text. + # Set to 0 to disable. + # Default: 3 + max-same-issues: 50 + + exclude-rules: + - linters: + - govet + text: '^shadow: declaration of "err" shadows declaration.+' diff --git a/.tool-versions b/.tool-versions index 414c9e8..aa63be9 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -golang 1.21.4 -golangci-lint 1.55.2 +golang 1.23.6 +golangci-lint 1.64.5 diff --git a/Dockerfile b/Dockerfile index 354126b..a0bdd35 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ # STEP 1 build executable binary # ################################## -FROM golang:1.21.4-alpine as builder +FROM golang:1.23.6-alpine as builder LABEL org.opencontainers.image.source="https://github.com/phpgeeks-club/admin-bot" diff --git a/go.mod b/go.mod index 2e6b8f3..30b57a9 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module geeksonator -go 1.21 +go 1.23.6 require ( github.com/caarlos0/env/v10 v10.0.0 diff --git a/internal/app/geeksonator/app.go b/internal/app/geeksonator/app.go index dc13ed5..6b48520 100644 --- a/internal/app/geeksonator/app.go +++ b/internal/app/geeksonator/app.go @@ -43,7 +43,7 @@ func Start() error { if err != nil { return fmt.Errorf("newLogger: %v", err) } - defer logger.Sync() //nolint:errcheck + defer logger.Sync() //nolint:errcheck // it's ok var tgBotToken string if cfg.DebugMode { @@ -118,7 +118,7 @@ func Start() error { } // newLogger creates new logger. -func newLogger(debugMode bool) (*zap.Logger, error) { +func newLogger(debugMode bool) (*zap.Logger, error) { //nolint:revive // false positive if debugMode { logger, err := zap.NewDevelopment() if err != nil { diff --git a/internal/observer/manager.go b/internal/observer/manager.go index 9b1cd15..081f56b 100644 --- a/internal/observer/manager.go +++ b/internal/observer/manager.go @@ -200,7 +200,7 @@ func authorIsAdmin(admins []tgbotapi.ChatMember, userID int64) bool { } // getMessageText returns message text. -func getMessageText(text string) string { //nolint:cyclop,gocyclo +func getMessageText(text string) string { switch text { case "/help", "/хелп": return `БОТ РАБОТАЕТ ТОЛЬКО У АДМИНОВ. @@ -219,7 +219,8 @@ func getMessageText(text string) string { //nolint:cyclop,gocyclo [/fl, /фл] @freelanceGeeks - IT фриланс, ищем исполнителей и заказчиков, делимся опытом и проблемами связанными с фрилансом. [/job, /раб] Объединяет сразу две команды: /hr и /fl. [/code, /код] Код в нашем чате ложут на pastebin.org, gist.github.com или любой аналогичный ресурс (с)der_Igel -[/nometa, /номета] nometa.xyz` +[/nometa, /номета] nometa.xyz +[/wtf, /втф] А причём тут пхп?` case "/php", "/пхп": return "@phpGeeks - Best PHP chat" case "/jun", "/джун": @@ -243,6 +244,8 @@ func getMessageText(text string) string { //nolint:cyclop,gocyclo return "Код в нашем чате ложут на pastebin.org, gist.github.com или любой аналогичный ресурс (с)der_Igel" case "/nometa", "/номета": return "nometa.xyz" + case "/wtf", "/втф": + return "А причём тут пхп?" } return "" diff --git a/internal/observer/manager_test.go b/internal/observer/manager_test.go index 2b01014..93caa62 100644 --- a/internal/observer/manager_test.go +++ b/internal/observer/manager_test.go @@ -43,7 +43,6 @@ func TestNewManager(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -57,7 +56,7 @@ func TestNewManagerWithDebug(t *testing.T) { t.Parallel() m := NewManager(nil, nil, nil, WithDebug(zap.NewNop())) - assert.NotEqual(t, nil, m.logger) + assert.NotNil(t, m.logger) } func TestNewManagerWithSkipAdminCheck(t *testing.T) { @@ -183,7 +182,6 @@ func TestManager_processingUpdate(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -359,7 +357,6 @@ func TestManager_processingMessage(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -529,7 +526,6 @@ func TestManager_sendMessage(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -636,7 +632,6 @@ func TestManager_getAdmins(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -689,7 +684,6 @@ func Test_authorIsAdmin(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -719,7 +713,6 @@ func Test_getMessageText(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() diff --git a/internal/provider/telegram/service.go b/internal/provider/telegram/service.go index ddc664a..2fc82b6 100644 --- a/internal/provider/telegram/service.go +++ b/internal/provider/telegram/service.go @@ -33,7 +33,7 @@ func (s *Service) GetChatAdministrators(chatConfig tgbotapi.ChatConfig) ([]tgbot } // NewMessage creates new message. -func (s *Service) NewMessage(chatID int64, text string) tgbotapi.MessageConfig { +func (*Service) NewMessage(chatID int64, text string) tgbotapi.MessageConfig { return tgbotapi.NewMessage(chatID, text) } diff --git a/internal/provider/telegram/service_test.go b/internal/provider/telegram/service_test.go index bfc7d95..24461c4 100644 --- a/internal/provider/telegram/service_test.go +++ b/internal/provider/telegram/service_test.go @@ -31,7 +31,6 @@ func TestNewService(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -79,7 +78,6 @@ func TestService_GetChatAdministrators(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -121,7 +119,6 @@ func TestService_NewMessage(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -172,7 +169,6 @@ func TestService_Send(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() diff --git a/pkg/cache/cacher_test.go b/pkg/cache/cacher_test.go index 1345c98..b265bf8 100644 --- a/pkg/cache/cacher_test.go +++ b/pkg/cache/cacher_test.go @@ -31,11 +31,10 @@ func TestCacher_Cacher(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - assert.Equal(t, tt.wantLen, len(tt.cacher.items)) + assert.Len(t, tt.cacher.items, tt.wantLen) }) } } @@ -91,7 +90,6 @@ func TestNewCacher(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -111,7 +109,7 @@ func TestNewCacherWithDebug(t *testing.T) { _ = cacher.Set("k2", 2) _ = cacher.Set("k3", 3) - assert.NotEqual(t, nil, cacher.logger) + assert.NotNil(t, cacher.logger) } func TestNewCacherWithUpdateLastUsed(t *testing.T) { @@ -199,7 +197,6 @@ func TestCacher_LastUsed(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -320,7 +317,6 @@ func TestCacher_Get(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -384,7 +380,6 @@ func TestCacher_Set(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -469,7 +464,6 @@ func TestCacher_clearSpace(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -506,7 +500,6 @@ func Test_isEmpty(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel()