При рефакторинге легаси проекта перед нами встала задача внедрить в компании готовый линтер-тулз, дабы минимизировать объёмы генерируемого говнокода.
Вот что у нас получилось (полная инструкция по внедрению).
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 проверит организацию типов данных в структурах и сам всё оптимизирует.
Мой первый пост на Хабре, надеюсь, кому-то пригодится.
