Skip to content

Commit ecc99ae

Browse files
authored
feat: add code linter (#44)
1 parent 3c5ae0a commit ecc99ae

File tree

7 files changed

+81
-177
lines changed

7 files changed

+81
-177
lines changed

.github/workflows/linter.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: linter
2+
3+
on:
4+
pull_request:
5+
push:
6+
7+
permissions:
8+
contents: write
9+
10+
jobs:
11+
linter:
12+
runs-on: ubuntu-latest
13+
steps:
14+
-
15+
name: Checkout
16+
uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 0
19+
- name: Install Go
20+
uses: actions/setup-go@v5
21+
with:
22+
go-version: '>=1.24'
23+
- name: Install devbox
24+
uses: jetify-com/devbox-install-action@v0.12.0
25+
with:
26+
enable-cache: true
27+
devbox-version: 0.14.0
28+
29+
- name: Install prerequisites
30+
shell: /usr/bin/bash {0}
31+
run: |
32+
devbox install
33+
devbox run linter

.golangci.yml

Lines changed: 15 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -1,160 +1,18 @@
1-
linters-settings:
2-
dupl:
3-
threshold: 100
4-
funlen:
5-
lines: -1 # the number of lines (code + empty lines) is not a right metric and leads to code without empty line or one-liner.
6-
statements: 50
7-
goconst:
8-
min-len: 2
9-
min-occurrences: 3
10-
gocritic:
11-
enabled-tags:
12-
- diagnostic
13-
- experimental
14-
- opinionated
15-
- performance
16-
- style
17-
disabled-checks:
18-
- dupImport # https://github.com/go-critic/go-critic/issues/845
19-
- ifElseChain
20-
- octalLiteral
21-
- whyNoLint
22-
gocyclo:
23-
min-complexity: 15
24-
gofmt:
25-
rewrite-rules:
26-
- pattern: 'interface{}'
27-
replacement: 'any'
28-
goimports:
29-
local-prefixes: github.com/golangci/golangci-lint
30-
gomnd:
31-
# don't include the "operation" and "assign"
32-
checks:
33-
- argument
34-
- case
35-
- condition
36-
- return
37-
ignored-numbers:
38-
- '0'
39-
- '1'
40-
- '2'
41-
- '3'
42-
ignored-functions:
43-
- strings.SplitN
44-
45-
govet:
46-
check-shadowing: true
47-
settings:
48-
printf:
49-
funcs:
50-
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
51-
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
52-
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
53-
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
54-
errorlint:
55-
asserts: false
56-
lll:
57-
line-length: 140
58-
misspell:
59-
locale: US
60-
nolintlint:
61-
allow-unused: false # report any unused nolint directives
62-
require-explanation: false # don't require an explanation for nolint directives
63-
require-specific: false # don't require nolint directives to be specific about which linter is being skipped
64-
revive:
65-
rules:
66-
- name: unexported-return
67-
disabled: true
68-
- name: unused-parameter
1+
---
2+
version: "2"
3+
# Configure which files to skip during linting
4+
run:
5+
tests: false
696

707
linters:
71-
disable-all: true
72-
enable:
73-
- bodyclose
74-
# - depguard
75-
- dogsled
76-
- dupl
77-
- errcheck
78-
- errorlint
79-
- exportloopref
80-
- funlen
81-
- gocheckcompilerdirectives
82-
- gochecknoinits
83-
- goconst
84-
- gocritic
85-
- gocyclo
86-
- gofmt
87-
- goimports
88-
- gomnd
89-
- goprintffuncname
90-
- gosec
91-
- gosimple
92-
- govet
93-
- ineffassign
94-
- lll
95-
- misspell
96-
- nakedret
97-
- noctx
98-
- nolintlint
99-
- revive
100-
- staticcheck
101-
- stylecheck
102-
- typecheck
103-
- unconvert
104-
- unparam
105-
- unused
106-
- whitespace
107-
108-
# don't enable:
109-
# - asciicheck
110-
# - scopelint
111-
# - gochecknoglobals
112-
# - gocognit
113-
# - godot
114-
# - godox
115-
# - goerr113
116-
# - interfacer
117-
# - maligned
118-
# - nestif
119-
# - prealloc
120-
# - testpackage
121-
# - wsl
122-
123-
issues:
124-
# Excluding configuration per-path, per-linter, per-text and per-source
125-
exclude-rules:
126-
- path: _test\.go
127-
linters:
128-
- gomnd
8+
default: all
1299

130-
- path: pkg/golinters/errcheck.go
131-
text: "SA1019: errCfg.Exclude is deprecated: use ExcludeFunctions instead"
132-
- path: pkg/commands/run.go
133-
text: "SA1019: lsc.Errcheck.Exclude is deprecated: use ExcludeFunctions instead"
134-
- path: pkg/commands/run.go
135-
text: "SA1019: e.cfg.Run.Deadline is deprecated: Deadline exists for historical compatibility and should not be used."
136-
137-
- path: pkg/golinters/gofumpt.go
138-
text: "SA1019: settings.LangVersion is deprecated: use the global `run.go` instead."
139-
- path: pkg/golinters/staticcheck_common.go
140-
text: "SA1019: settings.GoVersion is deprecated: use the global `run.go` instead."
141-
- path: pkg/lint/lintersdb/manager.go
142-
text: "SA1019: (.+).(GoVersion|LangVersion) is deprecated: use the global `run.go` instead."
143-
- path: pkg/golinters/unused.go
144-
text: "rangeValCopy: each iteration copies 160 bytes \\(consider pointers or indexing\\)"
145-
- path: test/(fix|linters)_test.go
146-
text: "string `gocritic.go` has 3 occurrences, make it a constant"
147-
148-
# Due to a change inside go-critic v0.10.0, some reports have been removed,
149-
# but as we run analysis with the previous version of golangci-lint this leads to a paradoxical situation.
150-
# This exclusion will be removed when the next version of golangci-lint (v1.56.0) will be released.
151-
- path: pkg/golinters/nolintlint/nolintlint.go
152-
text: "hugeParam: (i|b) is heavy \\(\\d+ bytes\\); consider passing it by pointer"
153-
154-
run:
155-
timeout: 5m
156-
skip-dirs:
157-
- test/testdata_etc # test files
158-
- internal/cache # extracted from Go code
159-
- internal/renameio # extracted from Go code
160-
- internal/robustio # extracted from Go code
10+
disable:
11+
- wsl
12+
- nlreturn
13+
- depguard
14+
- gochecknoinits
15+
- gochecknoglobals
16+
- forbidigo
17+
- varnamelen
18+
- exhaustruct

Taskfile.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ tasks:
1313
cmds:
1414
- task -a
1515

16+
linter:
17+
desc: "Run linter"
18+
cmds:
19+
- golangci-lint run --timeout 5m
20+
1621
binary:
1722
desc: "Build binary"
1823
cmds:

gitlab-backup2s3.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Package main is the entry point for gitlab-backup2s3.
12
package main
23

34
import (

pkg/app/app.go

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Package app contains the main application logic for gitlab-backup2s3.
12
package app
23

34
import (
@@ -9,13 +10,13 @@ import (
910
"github.com/sgaunet/gitlab-backup2s3/pkg/logger"
1011
)
1112

12-
// App is the main application
13+
// App is the main application.
1314
type App struct {
1415
logger logger.Logger
1516
backupCmd []string
1617
}
1718

18-
// NewApp creates a new App
19+
// NewApp creates a new App.
1920
func NewApp() *App {
2021
return &App{
2122
logger: logger.NoLogger(),
@@ -25,7 +26,7 @@ func NewApp() *App {
2526
}
2627
}
2728

28-
// SetLogger sets the logger
29+
// SetLogger sets the logger.
2930
func (a *App) SetLogger(log logger.Logger) {
3031
if log == nil {
3132
a.logger = logger.NoLogger()
@@ -34,13 +35,25 @@ func (a *App) SetLogger(log logger.Logger) {
3435
a.logger = log
3536
}
3637

37-
// SetBackupCmd sets the backup command
38-
// Use this method for testing purposes
38+
// SetBackupCmd sets the backup command.
39+
// Use this method for testing purposes.
3940
func (a *App) SetBackupCmd(backupCmd []string) {
4041
a.backupCmd = backupCmd
4142
}
4243

43-
// execCommand executes a command
44+
// Run executes the application.
45+
func (a *App) Run() error {
46+
a.logger.Info("Execute gitlab-backup")
47+
err := a.execCommand(a.backupCmd)
48+
if err != nil {
49+
a.logger.Error("Error executing gitlab-backup", slog.String("error", err.Error()))
50+
return err
51+
}
52+
return nil
53+
}
54+
55+
// execCommand executes a command.
56+
// It wraps all errors from external packages.
4457
func (a *App) execCommand(cmdToExec []string) error {
4558
cmd := exec.Command(cmdToExec[0], cmdToExec[1:]...) // #nosec G204
4659
stderr, err := cmd.StderrPipe()
@@ -71,16 +84,8 @@ func (a *App) execCommand(cmdToExec []string) error {
7184
}
7285
}()
7386
err = cmd.Wait()
74-
return err
75-
}
76-
77-
// Run executes the application
78-
func (a *App) Run() error {
79-
a.logger.Info("Execute gitlab-backup")
80-
err := a.execCommand(a.backupCmd)
8187
if err != nil {
82-
a.logger.Error("Error executing gitlab-backup", slog.String("error", err.Error()))
83-
return err
88+
return fmt.Errorf("error waiting for command: %w", err)
8489
}
8590
return nil
8691
}

pkg/app/app_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func TestSetLoggerNil(t *testing.T) {
3535
if a == nil {
3636
t.Fatalf("Expected non-nil app, got nil")
3737
}
38-
a.SetLogger(nil)
38+
a.SetLogger(nil) // now accepts *logger.Logger as nil
3939
a.SetBackupCmd([]string{"echo", "hello"})
4040
err := a.Run()
4141
if err != nil {

pkg/logger/logger.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Package logger provides logging utilities for gitlab-backup2s3.
12
package logger
23

34
import (
@@ -6,6 +7,7 @@ import (
67
"os"
78
)
89

10+
// Logger is the interface for logging in gitlab-backup2s3.
911
type Logger interface {
1012
Debug(msg string, args ...any)
1113
Info(msg string, args ...any)
@@ -16,8 +18,8 @@ type Logger interface {
1618
// NewLogger creates a new logger
1719
// logLevel is the level of logging
1820
// Possible values of logLevel are: "debug", "info", "warn", "error"
19-
// Default value is "info"
20-
func NewLogger(logLevel string) Logger {
21+
// Default value is "info".
22+
func NewLogger(logLevel string) *slog.Logger {
2123
var level slog.Level
2224
switch logLevel {
2325
case "debug":
@@ -39,8 +41,8 @@ func NewLogger(logLevel string) Logger {
3941
return logger
4042
}
4143

42-
// NoLogger creates a logger that does not log anything
43-
func NoLogger() Logger {
44+
// NoLogger creates a logger that does not log anything.
45+
func NoLogger() *slog.Logger {
4446
noLogger := slog.New(slog.NewTextHandler(io.Discard, &slog.HandlerOptions{
4547
Level: slog.LevelDebug,
4648
AddSource: false,

0 commit comments

Comments
 (0)