Готовый набор golang линтеров (джунам и мидлам)
При рефакторинге легаси проекта перед нами встала задача внедрить в компании готовый линтер-тулз, дабы минимизировать объёмы генерируемого говнокода.
Вот что у нас получилось (полная инструкция по внедрению).
1. Сам ямл, со всем конфигом
Ямл закидывается в корень проекта под названием .golangci.yml
linters-settings:
varnamelen:
min-name-length: 2
max-distance: 20
nlreturn:
# Size of the block (including return statement that is still "OK")
# so no return split required.
# Default: 1
block-size: 2
# errcheck:
# check-type-assertions: true
# goconst:
# min-len: 2
# min-occurrences: 3
# gocritic:
# enabled-tags:
# - diagnostic
# - experimental
# - opinionated
# - performance
# - style
# govet:
# check-shadowing: true
# enable:
# - fieldalignment
wsl:
force-err-cuddling: true
nolintlint:
require-explanation: true
require-specific: true
linters:
enable-all: true
disable:
- goimports #2
- gofmt #1
- ireturn
- musttag
- exhaustruct
- gomnd
- varnamelen #Длина имён переменных
- gochecknoglobals
- paralleltest #todo пока только мешает, разобраться.
- godox
- gci
- wrapcheck #todo включить отдельно!
- gofumpt
- exhaustivestruct
- varcheck
- golint
- ifshort
- interfacer
- nosnakecase
- scopelint
- structcheck
- maligned
- deadcode
- structcheck
run:
issues-exit-code: 1
goimports внесён в список исключений, так как в случае с большим проектом мешает запустить скрипт. Многие новички даже не пытаются организовать импорты, ИДЕ же само всё добавит… Но, этот подход не правильный.
Совет по оптимизации импортов:
import (
// Стандартные пакеты
"database/sql"
"errors"
// Внутренние пакеты
"mail/internal/pkg/model"
// Внешние
"github.com/denisenkom/go-mssqldb"
"github.com/sirupsen/logrus"
)
gofmt может не дать запуститься при кривом комменте, который в потоке сознания на 2+тыс строк просто сложно найти
2. Конфиг для запуска линтеров:
package main
import (
"log"
"os"
"os/exec"
)
func main() {
if _, err := exec.LookPath("fieldalignment"); err != nil {
log.Println("fieldalignment не найден. Устанавливаем...")
if err := installFieldalignment(); err != nil {
log.Fatal(err)
}
}
if _, err := exec.LookPath("golangci-lint"); err != nil {
log.Println("golangci-lint не найден. Устанавливаем...")
if err := installGolangciLint(); err != nil {
log.Fatal(err)
}
}
if err := os.Chdir("./.."); err != nil {
log.Fatalf("Не удалось перейти в директорию: %v", err)
}
if err := runGolangciLint(); err != nil {
log.Fatalf("Ошибка запуска golangci-lint: %v", err)
}
log.Println("Проверка golangci-lint завершена успешно!")
if err := runFieldalignment(); err != nil {
log.Printf("%v Fieldalignment сейчас всё сам исправит.", err)
}
log.Println("Проверка fieldalignment завершена успешно!")
}
func installGolangciLint() error {
cmd := exec.Command("go", "install", "github.com/golangci/golangci-lint/cmd/golangci-lint@latest")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
func runGolangciLint() error {
cmd := exec.Command("golangci-lint", "run")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
func installFieldalignment() error {
cmd := exec.Command("go", "install", "golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@latest")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
func runFieldalignment() error {
cmd := exec.Command("fieldalignment", "-fix", "./")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
Опишу максимально примитивно. В необходимой для проверки директории создаём папку, в ней файл.go с таким содержанием. Запускаем командой go run файл.go
Не обессудьте, пишу так и для стажёров, буду им кидать ссылку на статью.
В общем-то по коду всё понятно, файл установит линтеры и запустит проверку.
fieldalignment проверит организацию типов данных в структурах и сам всё оптимизирует.
Мой первый пост на Хабре, надеюсь, кому-то пригодится.