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