golangci-lint/pkg/config/config.go

394 lines
9.6 KiB
Go
Raw Normal View History

package config
2018-05-06 19:08:34 +03:00
import (
2018-11-05 18:20:28 +03:00
"errors"
"fmt"
"regexp"
"strings"
2018-05-06 19:08:34 +03:00
"time"
2018-11-05 18:20:28 +03:00
"github.com/golangci/golangci-lint/pkg/logutils"
2018-05-06 19:08:34 +03:00
)
2018-05-06 09:41:48 +03:00
2018-05-05 09:24:37 +03:00
const (
OutFormatJSON = "json"
OutFormatLineNumber = "line-number"
OutFormatColoredLineNumber = "colored-line-number"
OutFormatTab = "tab"
OutFormatCheckstyle = "checkstyle"
2018-05-05 09:24:37 +03:00
)
var OutFormats = []string{
OutFormatColoredLineNumber,
OutFormatLineNumber,
OutFormatJSON,
OutFormatTab,
OutFormatCheckstyle,
}
2018-05-05 09:24:37 +03:00
type ExcludePattern struct {
Pattern string
Linter string
Why string
}
var DefaultExcludePatterns = []ExcludePattern{
{
2018-06-28 22:39:23 +03:00
Pattern: "Error return value of .((os\\.)?std(out|err)\\..*|.*Close" +
"|.*Flush|os\\.Remove(All)?|.*printf?|os\\.(Un)?Setenv). is not checked",
Linter: "errcheck",
Why: "Almost all programs ignore errors on these functions and in most cases it's ok",
},
{
2018-06-28 22:39:23 +03:00
Pattern: "(comment on exported (method|function|type|const)|" +
"should have( a package)? comment|comment should be of the form)",
Linter: "golint",
Why: "Annoying issue about not having a comment. The rare codebase has such comments",
},
{
Pattern: "func name will be used as test\\.Test.* by other packages, and that stutters; consider calling this",
Linter: "golint",
Why: "False positive when tests are defined in package 'test'",
},
{
Pattern: "(possible misuse of unsafe.Pointer|should have signature)",
Linter: "govet",
Why: "Common false positives",
},
{
Pattern: "ineffective break statement. Did you mean to break out of the outer loop",
Linter: "megacheck",
Why: "Developers tend to write in C-style with an explicit 'break' in a 'switch', so it's ok to ignore",
},
{
Pattern: "Use of unsafe calls should be audited",
Linter: "gosec",
Why: "Too many false-positives on 'unsafe' usage",
},
{
Pattern: "Subprocess launch(ed with variable|ing should be audited)",
Linter: "gosec",
Why: "Too many false-positives for parametrized shell calls",
},
{
Pattern: "G104",
Linter: "gosec",
Why: "Duplicated errcheck checks",
},
{
Pattern: "(Expect directory permissions to be 0750 or less|Expect file permissions to be 0600 or less)",
Linter: "gosec",
Why: "Too many issues in popular repos",
},
{
Pattern: "Potential file inclusion via variable",
Linter: "gosec",
Why: "False positive is triggered by 'src, err := ioutil.ReadFile(filename)'",
},
}
func GetDefaultExcludePatternsStrings() []string {
var ret []string
for _, p := range DefaultExcludePatterns {
ret = append(ret, p.Pattern)
}
return ret
}
2018-05-06 13:41:42 +03:00
type Run struct {
IsVerbose bool `mapstructure:"verbose"`
Silent bool
CPUProfilePath string
2018-05-19 22:09:20 +03:00
MemProfilePath string
Concurrency int
PrintResourcesUsage bool `mapstructure:"print-resources-usage"`
2018-05-05 09:24:37 +03:00
2018-05-19 22:09:20 +03:00
Config string
NoConfig bool
2018-05-06 19:08:34 +03:00
Args []string
2018-05-05 19:43:18 +03:00
2018-12-22 13:28:35 +03:00
BuildTags []string `mapstructure:"build-tags"`
ModulesDownloadMode string `mapstructure:"modules-download-mode"`
2018-05-08 11:54:30 +03:00
ExitCodeIfIssuesFound int `mapstructure:"issues-exit-code"`
AnalyzeTests bool `mapstructure:"tests"`
Deadline time.Duration
2018-05-29 11:18:47 +03:00
PrintVersion bool
SkipFiles []string `mapstructure:"skip-files"`
SkipDirs []string `mapstructure:"skip-dirs"`
}
2018-05-05 19:43:18 +03:00
type LintersSettings struct {
2018-05-05 22:22:21 +03:00
Govet struct {
CheckShadowing bool `mapstructure:"check-shadowing"`
2018-05-05 22:22:21 +03:00
}
2018-05-06 07:20:12 +03:00
Golint struct {
MinConfidence float64 `mapstructure:"min-confidence"`
2018-05-06 07:20:12 +03:00
}
2018-05-06 09:41:48 +03:00
Gofmt struct {
Simplify bool
}
Goimports struct {
LocalPrefixes string `mapstructure:"local-prefixes"`
}
2018-05-06 15:24:45 +03:00
Gocyclo struct {
MinComplexity int `mapstructure:"min-complexity"`
2018-05-06 15:24:45 +03:00
}
2018-05-06 20:28:59 +03:00
Varcheck struct {
CheckExportedFields bool `mapstructure:"exported-fields"`
2018-05-06 20:28:59 +03:00
}
Structcheck struct {
CheckExportedFields bool `mapstructure:"exported-fields"`
2018-05-06 20:28:59 +03:00
}
2018-05-06 21:08:53 +03:00
Maligned struct {
SuggestNewOrder bool `mapstructure:"suggest-new"`
2018-05-06 22:58:04 +03:00
}
2018-05-07 09:09:10 +03:00
Dupl struct {
Threshold int
}
2018-05-07 12:43:52 +03:00
Goconst struct {
MinStringLen int `mapstructure:"min-len"`
MinOccurrencesCount int `mapstructure:"min-occurrences"`
2018-05-07 12:43:52 +03:00
}
2018-05-31 01:24:46 -04:00
Depguard struct {
ListType string `mapstructure:"list-type"`
Packages []string
2018-06-03 19:24:24 -07:00
IncludeGoRoot bool `mapstructure:"include-go-root"`
2018-05-31 01:24:46 -04:00
}
2018-06-28 21:27:07 +03:00
Misspell struct {
Locale string
}
Unused struct {
CheckExported bool `mapstructure:"check-exported"`
}
2018-06-30 13:55:47 +03:00
Lll LllSettings
Unparam UnparamSettings
Nakedret NakedretSettings
2018-06-30 21:02:41 +03:00
Prealloc PreallocSettings
Errcheck ErrcheckSettings
2018-11-05 18:20:28 +03:00
Gocritic GocriticSettings
}
type ErrcheckSettings struct {
CheckTypeAssertions bool `mapstructure:"check-type-assertions"`
CheckAssignToBlank bool `mapstructure:"check-blank"`
Ignore IgnoreFlag `mapstructure:"ignore"`
Exclude string `mapstructure:"exclude"`
2018-06-28 22:39:23 +03:00
}
type LllSettings struct {
LineLength int `mapstructure:"line-length"`
2018-07-20 12:36:18 -07:00
TabWidth int `mapstructure:"tab-width"`
2018-06-28 22:39:23 +03:00
}
2018-06-30 21:02:41 +03:00
type UnparamSettings struct {
CheckExported bool `mapstructure:"check-exported"`
Algo string
}
2018-06-30 13:55:47 +03:00
type NakedretSettings struct {
MaxFuncLines int `mapstructure:"max-func-lines"`
}
2018-06-30 21:02:41 +03:00
type PreallocSettings struct {
Simple bool
RangeLoops bool `mapstructure:"range-loops"`
ForLoops bool `mapstructure:"for-loops"`
2018-06-30 13:55:47 +03:00
}
2018-11-05 18:20:28 +03:00
type GocriticCheckSettings map[string]interface{}
type GocriticSettings struct {
EnabledChecks []string `mapstructure:"enabled-checks"`
DisabledChecks []string `mapstructure:"disabled-checks"`
SettingsPerCheck map[string]GocriticCheckSettings `mapstructure:"settings"`
inferredEnabledChecks map[string]bool
}
func (s *GocriticSettings) InferEnabledChecks(log logutils.Log) {
enabledChecks := s.EnabledChecks
if len(enabledChecks) == 0 {
if len(s.DisabledChecks) != 0 {
for _, defaultCheck := range defaultGocriticEnabledChecks {
if !s.isCheckDisabled(defaultCheck) {
enabledChecks = append(enabledChecks, defaultCheck)
}
}
} else {
enabledChecks = defaultGocriticEnabledChecks
}
}
s.inferredEnabledChecks = map[string]bool{}
for _, check := range enabledChecks {
s.inferredEnabledChecks[strings.ToLower(check)] = true
}
log.Infof("Gocritic enabled checks: %s", enabledChecks)
}
func (s GocriticSettings) isCheckDisabled(name string) bool {
for _, disabledCheck := range s.DisabledChecks {
if disabledCheck == name {
return true
}
}
return false
}
func (s GocriticSettings) Validate(log logutils.Log) error {
if len(s.EnabledChecks) != 0 && len(s.DisabledChecks) != 0 {
return errors.New("both enabled and disabled check aren't allowed for gocritic")
}
for checkName := range s.SettingsPerCheck {
if !s.IsCheckEnabled(checkName) {
log.Warnf("Gocritic settings were provided for not enabled check %q", checkName)
}
}
return nil
}
func (s GocriticSettings) IsCheckEnabled(name string) bool {
return s.inferredEnabledChecks[strings.ToLower(name)]
}
var defaultGocriticEnabledChecks = []string{
"appendAssign",
"assignOp",
"caseOrder",
"dupArg",
"dupBranchBody",
"dupCase",
"flagDeref",
"ifElseChain",
"regexpMust",
"singleCaseSwitch",
"sloppyLen",
"switchTrue",
"typeSwitchVar",
"underef",
"unlambda",
"unslice",
"defaultCaseOrder",
}
2018-06-28 22:39:23 +03:00
var defaultLintersSettings = LintersSettings{
Lll: LllSettings{
LineLength: 120,
2018-07-20 12:36:18 -07:00
TabWidth: 1,
2018-06-28 22:39:23 +03:00
},
Unparam: UnparamSettings{
Algo: "cha",
},
2018-06-30 13:55:47 +03:00
Nakedret: NakedretSettings{
MaxFuncLines: 30,
},
2018-06-30 21:02:41 +03:00
Prealloc: PreallocSettings{
Simple: true,
RangeLoops: true,
ForLoops: false,
},
2018-10-04 23:27:31 +03:00
Errcheck: ErrcheckSettings{
Ignore: IgnoreFlag{},
},
2018-11-05 18:20:28 +03:00
Gocritic: GocriticSettings{
SettingsPerCheck: map[string]GocriticCheckSettings{},
},
}
type Linters struct {
Enable []string
Disable []string
EnableAll bool `mapstructure:"enable-all"`
DisableAll bool `mapstructure:"disable-all"`
2018-05-15 08:59:50 +03:00
Fast bool
2018-05-06 13:41:42 +03:00
Presets []string
}
type Issues struct {
ExcludePatterns []string `mapstructure:"exclude"`
UseDefaultExcludes bool `mapstructure:"exclude-use-default"`
2018-05-08 09:55:38 +03:00
MaxIssuesPerLinter int `mapstructure:"max-issues-per-linter"`
MaxSameIssues int `mapstructure:"max-same-issues"`
2018-05-08 12:28:36 +03:00
DiffFromRevision string `mapstructure:"new-from-rev"`
DiffPatchFilePath string `mapstructure:"new-from-patch"`
Diff bool `mapstructure:"new"`
2018-05-05 09:24:37 +03:00
}
type Config struct { //nolint:maligned
Run Run
2018-05-05 09:24:37 +03:00
Output struct {
Format string
PrintIssuedLine bool `mapstructure:"print-issued-lines"`
PrintLinterName bool `mapstructure:"print-linter-name"`
PrintWelcomeMessage bool `mapstructure:"print-welcome"`
2018-05-05 09:24:37 +03:00
}
LintersSettings LintersSettings `mapstructure:"linters-settings"`
Linters Linters
Issues Issues
InternalTest bool // Option is used only for testing golangci-lint code, don't use it
}
2018-06-28 22:39:23 +03:00
func NewDefault() *Config {
return &Config{
LintersSettings: defaultLintersSettings,
}
}
// IgnoreFlags was taken from errcheck in order to keep the API identical.
// https://github.com/kisielk/errcheck/blob/1787c4bee836470bf45018cfbc783650db3c6501/main.go#L25-L60
type IgnoreFlag map[string]*regexp.Regexp
func (f IgnoreFlag) String() string {
pairs := make([]string, 0, len(f))
for pkg, re := range f {
prefix := ""
if pkg != "" {
prefix = pkg + ":"
}
pairs = append(pairs, prefix+re.String())
}
return fmt.Sprintf("%q", strings.Join(pairs, ","))
}
func (f IgnoreFlag) Set(s string) error {
if s == "" {
return nil
}
for _, pair := range strings.Split(s, ",") {
colonIndex := strings.Index(pair, ":")
var pkg, re string
if colonIndex == -1 {
pkg = ""
re = pair
} else {
pkg = pair[:colonIndex]
re = pair[colonIndex+1:]
}
regex, err := regexp.Compile(re)
if err != nil {
return err
}
f[pkg] = regex
}
return nil
}
// Type returns the type of the flag follow the pflag format.
func (IgnoreFlag) Type() string {
return "stringToRegexp"
}