Migrate golangci-lint to v2 and update Go version (#1965)

* migrate golangci-lint to v2 and update go version

- migrated .golangci.yml to version 2 format
- updated go.mod from 1.23.0 to 1.24
- removed deprecated run.timeout configuration

* update to go 1.25 and baseimage v1.17.0

- updated go.mod to go 1.25
- updated Dockerfile to use buildgo-v1.17.0 (go 1.25.0)
- updated Dockerfile to use app-v1.17.0

* fix flaky tests with proper synchronization

- use assert.Eventually instead of fixed sleep in TestService_Many
- wait for webhook before shutdown in TestMain_WithWebhook
- fixes race conditions exposed by Go 1.25 scheduler changes

* fix data race in MockDest.closed field

- add IsClosed() method with proper locking
- add locking to String() method
- use IsClosed() in tests instead of direct field access
- fixes race condition detected by go test -race

* update example go.mod to go 1.25

* update golangci-lint to v2.6.0 for go 1.25 support

* fix linter issue and update CLAUDE.md

- merge conditional assignment in example accessor/data.go
- add reminder in CLAUDE.md to always test and lint examples before committing

* update example Dockerfile to baseimage v1.17.0 for go 1.25
This commit is contained in:
Umputun
2025-11-02 14:17:39 -06:00
committed by GitHub
parent 8112f445f4
commit 34ea4c3e83
11 changed files with 85 additions and 73 deletions
+5 -5
View File
@@ -32,7 +32,7 @@ jobs:
- name: install go
uses: actions/setup-go@v5
with:
go-version: "1.23"
go-version: "1.25"
cache-dependency-path: backend
- name: test and build backend
@@ -53,15 +53,15 @@ jobs:
TZ: "America/Chicago"
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
uses: golangci/golangci-lint-action@v7
with:
version: "v1.64.7"
version: "v2.6.0"
working-directory: backend/app
- name: golangci-lint on example directory
uses: golangci/golangci-lint-action@v6
uses: golangci/golangci-lint-action@v7
with:
version: "v1.64.7"
version: "v2.6.0"
args: --config ../../.golangci.yml
working-directory: backend/_example/memory_store
+4 -1
View File
@@ -8,12 +8,15 @@
- **Backend Testing**:
- Run all tests: `cd backend/app && go test -timeout=60s -count 1 ./...`
- Run single test: `cd backend/app && go test -run TestName ./path/to/package`
- **IMPORTANT**: Run example tests: `cd backend/_example/memory_store && go test -race ./... && go build -race ./...`
- **Frontend**:
- Development: `cd frontend && pnpm dev:app`
- Tests: `cd frontend && pnpm test`
- **Lint**:
- Backend: `golangci-lint run`
- Backend: `cd backend && golangci-lint run`
- **IMPORTANT**: Example lint: `cd backend/_example/memory_store && golangci-lint run --config ../../.golangci.yml`
- Frontend: `cd frontend && pnpm lint`
- **Before committing**: Always run tests and linter on both main backend AND examples
## Code Style
- **Backend**: Formatting with golangci-lint, strict error handling
+2 -2
View File
@@ -45,7 +45,7 @@ RUN \
echo 'Skip frontend build'; \
fi
FROM umputun/baseimage:buildgo-v1.14.0 AS build-backend
FROM umputun/baseimage:buildgo-v1.17.0 AS build-backend
ARG CI
ARG GITHUB_REF
@@ -81,7 +81,7 @@ RUN \
echo "version=$version" && \
go build -o remark42 -ldflags "-X main.revision=${version} -s -w" ./app
FROM umputun/baseimage:app-v1.14.0
FROM umputun/baseimage:app-v1.17.0
ARG GITHUB_SHA
+47 -46
View File
@@ -1,29 +1,6 @@
run:
timeout: 5m
linters-settings:
govet:
enable:
- shadow
goconst:
min-len: 2
min-occurrences: 2
misspell:
locale: US
lll:
line-length: 140
gocritic:
enabled-tags:
- performance
- style
- experimental
disabled-checks:
- wrapperFunc
# TODO: feel free to remove these excludes and fix the code
- hugeParam
- rangeValCopy
version: "2"
linters:
default: none
enable:
- bodyclose
- copyloopvar
@@ -32,7 +9,6 @@ linters:
- gocritic
- gocyclo
- gosec
- gosimple
- govet
- ineffassign
- misspell
@@ -40,26 +16,51 @@ linters:
- prealloc
- revive
- staticcheck
- stylecheck
- typecheck
- unconvert
- unparam
- unused
fast: false
disable-all: true
issues:
exclude-dirs:
- vendor
exclude-rules:
- text: "at least one file in a package should have a package comment"
linters:
- stylecheck
- text: "package-comments: should have a package comment"
linters:
- revive
- path: _test\.go
linters:
- gosec
- dupl
exclude-use-default: false
settings:
goconst:
min-len: 2
min-occurrences: 2
gocritic:
disabled-checks:
- wrapperFunc
- hugeParam
- rangeValCopy
enabled-tags:
- performance
- style
- experimental
govet:
enable:
- shadow
lll:
line-length: 140
misspell:
locale: US
exclusions:
generated: lax
rules:
- linters:
- staticcheck
text: at least one file in a package should have a package comment
- linters:
- revive
text: 'package-comments: should have a package comment'
- linters:
- dupl
- gosec
path: _test\.go
paths:
- vendor
- third_party$
- builtin$
- examples$
formatters:
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
+2 -2
View File
@@ -1,11 +1,11 @@
FROM umputun/baseimage:buildgo-v1.14.0 AS build-backend
FROM umputun/baseimage:buildgo-v1.17.0 AS build-backend
ADD backend /build/backend
WORKDIR /build/backend/_example/memory_store
RUN go build -o /build/bin/memory_store -ldflags "-X main.revision=0.0.0 -s -w"
FROM umputun/baseimage:app-v1.14.0
FROM umputun/baseimage:app-v1.17.0
ARG GITHUB_SHA
@@ -391,10 +391,7 @@ func (m *MemData) checkFlag(req engine.FlagRequest) (val bool) {
func (m *MemData) setFlag(req engine.FlagRequest) (res bool, err error) {
status := false
if req.Update == engine.FlagTrue {
status = true
}
status := req.Update == engine.FlagTrue
switch req.Flag {
+1 -3
View File
@@ -1,8 +1,6 @@
module github.com/umputun/remark42/memory_store
go 1.23.0
toolchain go1.24.1
go 1.25
require (
github.com/go-pkgz/jrpc v0.3.1
+5 -3
View File
@@ -98,9 +98,6 @@ func TestMain_WithWebhook(t *testing.T) {
finished := make(chan struct{})
go func() {
main()
assert.Eventually(t, func() bool {
return atomic.LoadInt32(&webhookSent) == int32(1)
}, time.Second, 100*time.Millisecond, "webhook was not sent")
close(finished)
}()
@@ -117,6 +114,11 @@ func TestMain_WithWebhook(t *testing.T) {
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusCreated, resp.StatusCode)
// wait for webhook to be sent before shutting down
assert.Eventually(t, func() bool {
return atomic.LoadInt32(&webhookSent) == int32(1)
}, time.Second, 100*time.Millisecond, "webhook was not sent")
}
func TestGetDump(t *testing.T) {
+12 -1
View File
@@ -66,4 +66,15 @@ func (m *MockDest) GetVerify() []VerificationRequest {
return res
}
func (m *MockDest) String() string { return fmt.Sprintf("mock id=%d, closed=%v", m.id, m.closed) }
// IsClosed returns closed status safely
func (m *MockDest) IsClosed() bool {
m.lock.Lock()
defer m.lock.Unlock()
return m.closed
}
func (m *MockDest) String() string {
m.lock.Lock()
defer m.lock.Unlock()
return fmt.Sprintf("mock id=%d, closed=%v", m.id, m.closed)
}
+5 -3
View File
@@ -102,15 +102,17 @@ func TestService_Many(t *testing.T) {
time.Sleep(time.Millisecond * time.Duration(rand.Int31n(20)))
}
s.Close()
time.Sleep(time.Millisecond * 10)
// wait for destinations to close
assert.Eventually(t, func() bool { return d1.IsClosed() && d2.IsClosed() }, 100*time.Millisecond, 10*time.Millisecond)
assert.NotEqual(t, 10, len(d1.Get()), "some comments dropped from d1")
assert.NotEqual(t, 10, len(d1.GetVerify()), "some verifications dropped from d1")
assert.NotEqual(t, 10, len(d2.Get()), "some comments dropped from d2")
assert.NotEqual(t, 10, len(d2.GetVerify()), "some verifications dropped from d2")
assert.True(t, d1.closed)
assert.True(t, d2.closed)
assert.True(t, d1.IsClosed())
assert.True(t, d2.IsClosed())
assert.Equal(t, "mock id=1, closed=true", d1.String())
}
+1 -3
View File
@@ -1,8 +1,6 @@
module github.com/umputun/remark42/backend
go 1.23.0
toolchain go1.24.2
go 1.25
require (
github.com/Depado/bfchroma/v2 v2.0.0