Готовый набор golang линтеров (джунам и мидлам)

52d259f0594ae8807ab217a22af543ed

При рефакторинге легаси проекта перед нами встала задача внедрить в компании готовый линтер-тулз, дабы минимизировать объёмы генерируемого говнокода.

Вот что у нас получилось (полная инструкция по внедрению).

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 проверит организацию типов данных в структурах и сам всё оптимизирует.

Мой первый пост на Хабре, надеюсь, кому-то пригодится.

© Habrahabr.ru