golangci-lint/internal/commands/run.go

146 lines
4.4 KiB
Go
Raw Normal View History

2018-05-05 09:24:37 +03:00
package commands
import (
"context"
"encoding/json"
"fmt"
"log"
"strings"
2018-05-06 19:08:34 +03:00
"time"
2018-05-05 09:24:37 +03:00
"github.com/fatih/color"
2018-05-05 19:43:18 +03:00
"github.com/golangci/golangci-lint/pkg"
2018-05-05 09:24:37 +03:00
"github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/result"
2018-05-05 19:43:18 +03:00
"github.com/golangci/golangci-lint/pkg/result/processors"
2018-05-05 09:24:37 +03:00
"github.com/spf13/cobra"
)
2018-05-06 19:08:34 +03:00
const exitCodeIfFailure = 3
2018-05-05 09:24:37 +03:00
func (e *Executor) initRun() {
var runCmd = &cobra.Command{
Use: "run",
Short: "Run linters",
Run: e.executeRun,
}
e.rootCmd.AddCommand(runCmd)
2018-05-05 19:43:18 +03:00
rc := &e.cfg.Run
runCmd.Flags().StringVar(&rc.OutFormat, "out-format",
2018-05-05 09:24:37 +03:00
config.OutFormatColoredLineNumber,
fmt.Sprintf("Format of output: %s", strings.Join(config.OutFormats, "|")))
2018-05-05 19:43:18 +03:00
runCmd.Flags().IntVar(&rc.ExitCodeIfIssuesFound, "issues-exit-code",
2018-05-05 11:08:14 +03:00
1, "Exit code when issues were found")
2018-05-06 13:28:00 +03:00
runCmd.Flags().StringSliceVar(&rc.BuildTags, "build-tags", []string{}, "Build tags (not all linters support them)")
2018-05-05 19:43:18 +03:00
runCmd.Flags().BoolVar(&rc.Errcheck.CheckClose, "errcheck.check-close", false, "Errcheck: check missed error checks on .Close() calls")
2018-05-06 07:20:12 +03:00
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()")
2018-05-05 22:22:21 +03:00
2018-05-06 07:20:12 +03:00
runCmd.Flags().BoolVar(&rc.Govet.CheckShadowing, "govet.check-shadowing", true, "Govet: check for shadowed variables")
runCmd.Flags().Float64Var(&rc.Golint.MinConfidence, "golint.min-confidence", 0.8, "Golint: minimum confidence of a problem to print it")
2018-05-06 09:41:48 +03:00
runCmd.Flags().BoolVar(&rc.Gofmt.Simplify, "gofmt.simplify", true, "Gofmt: simplify code")
2018-05-06 15:24:45 +03:00
runCmd.Flags().IntVar(&rc.Gocyclo.MinComplexity, "gocyclo.min-complexity",
20, "Minimal complexity of function to report it")
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")
2018-05-06 13:41:42 +03:00
2018-05-06 19:08:34 +03:00
runCmd.Flags().DurationVar(&rc.Deadline, "deadline", time.Second*30, "Deadline for total work")
2018-05-06 13:41:42 +03:00
runCmd.Flags().StringSliceVarP(&rc.ExcludePatterns, "exclude", "e", config.DefaultExcludePatterns, "Exclude issue by regexp")
2018-05-05 09:24:37 +03:00
}
2018-05-06 19:08:34 +03:00
func (e *Executor) runAnalysis(ctx context.Context, args []string) ([]result.Issue, error) {
e.cfg.Run.Args = args
2018-05-06 19:08:34 +03:00
runner := pkg.SimpleRunner{
Processors: []processors.Processor{
processors.MaxLinterIssuesPerFile{},
processors.NewExcludeProcessor(fmt.Sprintf("(%s)", strings.Join(e.cfg.Run.ExcludePatterns, "|"))),
processors.UniqByLineProcessor{},
processors.NewPathPrettifier(),
},
}
2018-05-05 19:43:18 +03:00
2018-05-06 19:08:34 +03:00
linters, err := pkg.GetEnabledLinters(ctx, &e.cfg.Run)
if err != nil {
return nil, err
}
2018-05-05 11:08:14 +03:00
2018-05-06 19:08:34 +03:00
issues, err := runner.Run(ctx, linters, e.cfg)
if err != nil {
return nil, err
}
2018-05-05 09:24:37 +03:00
2018-05-06 19:08:34 +03:00
return issues, nil
}
2018-05-05 19:43:18 +03:00
2018-05-06 19:08:34 +03:00
func (e *Executor) executeRun(cmd *cobra.Command, args []string) {
f := func() error {
ctx, cancel := context.WithTimeout(context.Background(), e.cfg.Run.Deadline)
defer cancel()
2018-05-06 19:08:34 +03:00
issues, err := e.runAnalysis(ctx, args)
2018-05-05 19:43:18 +03:00
if err != nil {
2018-05-06 19:08:34 +03:00
return err
2018-05-05 09:24:37 +03:00
}
2018-05-05 19:43:18 +03:00
if err := outputIssues(e.cfg.Run.OutFormat, issues); err != nil {
2018-05-06 19:08:34 +03:00
return fmt.Errorf("can't output %d issues: %s", len(issues), err)
2018-05-05 09:24:37 +03:00
}
2018-05-05 11:08:14 +03:00
if len(issues) != 0 {
2018-05-06 19:08:34 +03:00
e.exitCode = e.cfg.Run.ExitCodeIfIssuesFound
return nil
2018-05-05 11:08:14 +03:00
}
2018-05-06 19:08:34 +03:00
return nil
2018-05-05 09:24:37 +03:00
}
2018-05-06 19:08:34 +03:00
if err := f(); err != nil {
2018-05-05 19:43:18 +03:00
log.Print(err)
2018-05-06 19:08:34 +03:00
if e.exitCode == 0 {
e.exitCode = exitCodeIfFailure
}
2018-05-05 09:24:37 +03:00
}
}
func outputIssues(format string, issues []result.Issue) error {
if format == config.OutFormatLineNumber || format == config.OutFormatColoredLineNumber {
if len(issues) == 0 {
outStr := "Congrats! No issues were found."
if format == config.OutFormatColoredLineNumber {
outStr = color.GreenString(outStr)
}
fmt.Println(outStr)
2018-05-05 09:24:37 +03:00
}
for _, i := range issues {
2018-05-05 19:43:18 +03:00
text := i.Text
if format == config.OutFormatColoredLineNumber {
text = color.RedString(text)
}
fmt.Printf("%s:%d: %s\n", i.File, i.LineNumber, text)
2018-05-05 09:24:37 +03:00
}
return nil
}
if format == config.OutFormatJSON {
outputJSON, err := json.Marshal(issues)
if err != nil {
return err
}
fmt.Print(string(outputJSON))
2018-05-05 09:24:37 +03:00
return nil
}
return fmt.Errorf("unknown output format %q", format)
}