support enabling and disabling of linters and linters list command
This commit is contained in:
parent
1fa57347aa
commit
30388862d2
@ -18,6 +18,7 @@ func NewExecutor() *Executor {
|
|||||||
|
|
||||||
e.initRoot()
|
e.initRoot()
|
||||||
e.initRun()
|
e.initRun()
|
||||||
|
e.initLinters()
|
||||||
|
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
43
internal/commands/linters.go
Normal file
43
internal/commands/linters.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
|
"github.com/golangci/golangci-lint/pkg/golinters"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e *Executor) initLinters() {
|
||||||
|
var lintersCmd = &cobra.Command{
|
||||||
|
Use: "linters",
|
||||||
|
Short: "List linters",
|
||||||
|
Run: e.executeLinters,
|
||||||
|
}
|
||||||
|
e.rootCmd.AddCommand(lintersCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printLinterConfigs(lcs []golinters.LinterConfig) {
|
||||||
|
for _, lc := range lcs {
|
||||||
|
fmt.Printf("%s: %s\n", color.YellowString(lc.Linter.Name()), lc.Desc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Executor) executeLinters(cmd *cobra.Command, args []string) {
|
||||||
|
var enabledLCs, disabledLCs []golinters.LinterConfig
|
||||||
|
for _, lc := range golinters.GetAllSupportedLinterConfigs() {
|
||||||
|
if lc.EnabledByDefault {
|
||||||
|
enabledLCs = append(enabledLCs, lc)
|
||||||
|
} else {
|
||||||
|
disabledLCs = append(disabledLCs, lc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
color.Green("Enabled by default linters:\n")
|
||||||
|
printLinterConfigs(enabledLCs)
|
||||||
|
color.Red("\nDisabled by default linters:\n")
|
||||||
|
printLinterConfigs(disabledLCs)
|
||||||
|
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
@ -17,7 +17,9 @@ import (
|
|||||||
"github.com/golangci/golangci-lint/pkg/golinters"
|
"github.com/golangci/golangci-lint/pkg/golinters"
|
||||||
"github.com/golangci/golangci-lint/pkg/result"
|
"github.com/golangci/golangci-lint/pkg/result"
|
||||||
"github.com/golangci/golangci-lint/pkg/result/processors"
|
"github.com/golangci/golangci-lint/pkg/result/processors"
|
||||||
|
"github.com/golangci/golangci-shared/pkg/analytics"
|
||||||
"github.com/golangci/golangci-shared/pkg/executors"
|
"github.com/golangci/golangci-shared/pkg/executors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,7 +38,7 @@ func (e *Executor) initRun() {
|
|||||||
runCmd.Flags().IntVar(&rc.ExitCodeIfIssuesFound, "issues-exit-code",
|
runCmd.Flags().IntVar(&rc.ExitCodeIfIssuesFound, "issues-exit-code",
|
||||||
1, "Exit code when issues were found")
|
1, "Exit code when issues were found")
|
||||||
|
|
||||||
runCmd.Flags().BoolVar(&rc.Errcheck.CheckClose, "errcheck.check-close", false, " Errcheck: check missed error checks on .Close() calls")
|
runCmd.Flags().BoolVar(&rc.Errcheck.CheckClose, "errcheck.check-close", false, "Errcheck: check missed error checks on .Close() calls")
|
||||||
runCmd.Flags().BoolVar(&rc.Errcheck.CheckTypeAssertions, "errcheck.check-type-assertions", false, "Errcheck: check for ignored type assertion results")
|
runCmd.Flags().BoolVar(&rc.Errcheck.CheckTypeAssertions, "errcheck.check-type-assertions", false, "Errcheck: check for ignored type assertion results")
|
||||||
runCmd.Flags().BoolVar(&rc.Errcheck.CheckAssignToBlank, "errcheck.check-blank", false, "Errcheck: check for errors assigned to blank identifier: _ = errFunc()")
|
runCmd.Flags().BoolVar(&rc.Errcheck.CheckAssignToBlank, "errcheck.check-blank", false, "Errcheck: check for errors assigned to blank identifier: _ = errFunc()")
|
||||||
|
|
||||||
@ -45,12 +47,21 @@ func (e *Executor) initRun() {
|
|||||||
runCmd.Flags().Float64Var(&rc.Golint.MinConfidence, "golint.min-confidence", 0.8, "Golint: minimum confidence of a problem to print it")
|
runCmd.Flags().Float64Var(&rc.Golint.MinConfidence, "golint.min-confidence", 0.8, "Golint: minimum confidence of a problem to print it")
|
||||||
|
|
||||||
runCmd.Flags().BoolVar(&rc.Gofmt.Simplify, "gofmt.simplify", true, "Gofmt: simplify code")
|
runCmd.Flags().BoolVar(&rc.Gofmt.Simplify, "gofmt.simplify", true, "Gofmt: simplify code")
|
||||||
|
|
||||||
|
runCmd.Flags().StringSliceVarP(&rc.EnabledLinters, "enable", "E", []string{}, "Enable specific linter")
|
||||||
|
runCmd.Flags().StringSliceVarP(&rc.DisabledLinters, "disable", "D", []string{}, "Disable specific linter")
|
||||||
|
runCmd.Flags().BoolVar(&rc.EnableAllLinters, "enable-all", false, "Enable all linters")
|
||||||
|
runCmd.Flags().BoolVar(&rc.DisableAllLinters, "disable-all", false, "Disable all linters")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Executor) executeRun(cmd *cobra.Command, args []string) {
|
func (e Executor) executeRun(cmd *cobra.Command, args []string) {
|
||||||
f := func() (error, int) {
|
f := func() (error, int) {
|
||||||
runtime.GOMAXPROCS(e.cfg.Common.Concurrency)
|
runtime.GOMAXPROCS(e.cfg.Common.Concurrency)
|
||||||
|
|
||||||
|
if e.cfg.Common.IsVerbose {
|
||||||
|
analytics.SetLogLevel(logrus.InfoLevel)
|
||||||
|
}
|
||||||
|
|
||||||
if e.cfg.Common.CPUProfilePath != "" {
|
if e.cfg.Common.CPUProfilePath != "" {
|
||||||
f, err := os.Create(e.cfg.Common.CPUProfilePath)
|
f, err := os.Create(e.cfg.Common.CPUProfilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -85,7 +96,12 @@ func (e Executor) executeRun(cmd *cobra.Command, args []string) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
issues, err := runner.Run(ctx, golinters.GetSupportedLinters(), exec, e.cfg)
|
linters, err := golinters.GetEnabledLinters(ctx, &e.cfg.Run)
|
||||||
|
if err != nil {
|
||||||
|
return err, 1
|
||||||
|
}
|
||||||
|
|
||||||
|
issues, err := runner.Run(ctx, linters, exec, e.cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err, 1
|
return err, 1
|
||||||
}
|
}
|
||||||
@ -115,7 +131,7 @@ func outputIssues(format string, issues []result.Issue) error {
|
|||||||
if format == config.OutFormatColoredLineNumber {
|
if format == config.OutFormatColoredLineNumber {
|
||||||
outStr = color.GreenString(outStr)
|
outStr = color.GreenString(outStr)
|
||||||
}
|
}
|
||||||
fmt.Fprint(os.Stdout, outStr)
|
fmt.Println(outStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, i := range issues {
|
for _, i := range issues {
|
||||||
@ -123,7 +139,7 @@ func outputIssues(format string, issues []result.Issue) error {
|
|||||||
if format == config.OutFormatColoredLineNumber {
|
if format == config.OutFormatColoredLineNumber {
|
||||||
text = color.RedString(text)
|
text = color.RedString(text)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(os.Stdout, "%s:%d: %s\n", i.File, i.LineNumber, text)
|
fmt.Printf("%s:%d: %s\n", i.File, i.LineNumber, text)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -133,7 +149,7 @@ func outputIssues(format string, issues []result.Issue) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprint(os.Stdout, string(outputJSON))
|
fmt.Print(string(outputJSON))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +39,11 @@ type Run struct {
|
|||||||
Gofmt struct {
|
Gofmt struct {
|
||||||
Simplify bool
|
Simplify bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EnabledLinters []string
|
||||||
|
DisabledLinters []string
|
||||||
|
EnableAllLinters bool
|
||||||
|
DisableAllLinters bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
160
pkg/golinters/enabled_linters.go
Normal file
160
pkg/golinters/enabled_linters.go
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
package golinters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/golangci/golangci-lint/pkg"
|
||||||
|
"github.com/golangci/golangci-lint/pkg/config"
|
||||||
|
"github.com/golangci/golangci-shared/pkg/analytics"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LinterConfig struct {
|
||||||
|
EnabledByDefault bool
|
||||||
|
Desc string
|
||||||
|
Linter pkg.Linter
|
||||||
|
}
|
||||||
|
|
||||||
|
func enabledByDefault(linter pkg.Linter, desc string) LinterConfig {
|
||||||
|
return LinterConfig{
|
||||||
|
EnabledByDefault: true,
|
||||||
|
Linter: linter,
|
||||||
|
Desc: desc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func disabledByDefault(linter pkg.Linter, desc string) LinterConfig {
|
||||||
|
return LinterConfig{
|
||||||
|
EnabledByDefault: false,
|
||||||
|
Linter: linter,
|
||||||
|
Desc: desc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAllSupportedLinterConfigs() []LinterConfig {
|
||||||
|
return []LinterConfig{
|
||||||
|
enabledByDefault(govet{}, "Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string"),
|
||||||
|
enabledByDefault(errcheck{}, "Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases"),
|
||||||
|
enabledByDefault(golint{}, "Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes."),
|
||||||
|
disabledByDefault(gofmt{}, "Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification."),
|
||||||
|
disabledByDefault(gofmt{useGoimports: true}, "Goimports does everything that gofmt does. Additionally it checks unused imports."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAllSupportedLinters() []pkg.Linter {
|
||||||
|
var ret []pkg.Linter
|
||||||
|
for _, lc := range GetAllSupportedLinterConfigs() {
|
||||||
|
ret = append(ret, lc.Linter)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAllEnabledByDefaultLinters() []pkg.Linter {
|
||||||
|
var ret []pkg.Linter
|
||||||
|
for _, lc := range GetAllSupportedLinterConfigs() {
|
||||||
|
if lc.EnabledByDefault {
|
||||||
|
ret = append(ret, lc.Linter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
var supportedLintersByName map[string]pkg.Linter
|
||||||
|
var linterByNameMapOnce sync.Once
|
||||||
|
|
||||||
|
func getLinterByName(name string) pkg.Linter {
|
||||||
|
linterByNameMapOnce.Do(func() {
|
||||||
|
supportedLintersByName = make(map[string]pkg.Linter)
|
||||||
|
for _, lc := range GetAllSupportedLinterConfigs() {
|
||||||
|
supportedLintersByName[lc.Linter.Name()] = lc.Linter
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return supportedLintersByName[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
func lintersToMap(linters []pkg.Linter) map[string]pkg.Linter {
|
||||||
|
ret := map[string]pkg.Linter{}
|
||||||
|
for _, linter := range linters {
|
||||||
|
ret[linter.Name()] = linter
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateEnabledDisabledLintersConfig(cfg *config.Run) error {
|
||||||
|
allNames := append([]string{}, cfg.EnabledLinters...)
|
||||||
|
allNames = append(allNames, cfg.DisabledLinters...)
|
||||||
|
for _, name := range allNames {
|
||||||
|
if getLinterByName(name) == nil {
|
||||||
|
return fmt.Errorf("no such linter %q", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.EnableAllLinters && cfg.DisableAllLinters {
|
||||||
|
return fmt.Errorf("--enable-all and --disable-all options must not be combined")
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.DisableAllLinters {
|
||||||
|
if len(cfg.EnabledLinters) == 0 {
|
||||||
|
return fmt.Errorf("all linters were disabled, but no one linter was enabled: must enable at least one")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cfg.DisabledLinters) != 0 {
|
||||||
|
return fmt.Errorf("can't combine options --disable-all and --disable %s", cfg.DisabledLinters[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.EnableAllLinters && len(cfg.EnabledLinters) != 0 {
|
||||||
|
return fmt.Errorf("can't combine options --enable-all and --enable %s", cfg.EnabledLinters[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
enabledLintersSet := map[string]bool{}
|
||||||
|
for _, name := range cfg.EnabledLinters {
|
||||||
|
enabledLintersSet[name] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range cfg.DisabledLinters {
|
||||||
|
if enabledLintersSet[name] {
|
||||||
|
return fmt.Errorf("linter %q can't be disabled and enabled at one moment", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetEnabledLinters(ctx context.Context, cfg *config.Run) ([]pkg.Linter, error) {
|
||||||
|
if err := validateEnabledDisabledLintersConfig(cfg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resultLintersSet := map[string]pkg.Linter{}
|
||||||
|
switch {
|
||||||
|
case cfg.EnableAllLinters:
|
||||||
|
resultLintersSet = lintersToMap(getAllSupportedLinters())
|
||||||
|
case cfg.DisableAllLinters:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
resultLintersSet = lintersToMap(getAllEnabledByDefaultLinters())
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range cfg.EnabledLinters {
|
||||||
|
resultLintersSet[name] = getLinterByName(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range cfg.DisabledLinters {
|
||||||
|
delete(resultLintersSet, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultLinters []pkg.Linter
|
||||||
|
var resultLinterNames []string
|
||||||
|
for name, linter := range resultLintersSet {
|
||||||
|
resultLinters = append(resultLinters, linter)
|
||||||
|
resultLinterNames = append(resultLinterNames, name)
|
||||||
|
}
|
||||||
|
analytics.Log(ctx).Infof("Enabled linters: %s", resultLinterNames)
|
||||||
|
|
||||||
|
return resultLinters, nil
|
||||||
|
}
|
@ -1,10 +0,0 @@
|
|||||||
package golinters
|
|
||||||
|
|
||||||
import "github.com/golangci/golangci-lint/pkg"
|
|
||||||
|
|
||||||
const pathLineColMessage = `^(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*)$`
|
|
||||||
const pathLineMessage = `^(?P<path>.*?\.go):(?P<line>\d+):\s*(?P<message>.*)$`
|
|
||||||
|
|
||||||
func GetSupportedLinters() []pkg.Linter {
|
|
||||||
return []pkg.Linter{govet{}, errcheck{}, golint{}, gofmt{}, gofmt{useGoimports: true}}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user