golangci-lint/pkg/config/config.go

551 lines
14 KiB
Go
Raw Normal View History

package config
2018-05-06 19:08:34 +03:00
import (
"errors"
"fmt"
"regexp"
2018-05-06 19:08:34 +03:00
"time"
)
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"
OutFormatCodeClimate = "code-climate"
2019-05-20 10:02:20 +10:00
OutFormatJunitXML = "junit-xml"
2020-04-10 23:46:19 +03:00
OutFormatGithubActions = "github-actions"
2018-05-05 09:24:37 +03:00
)
var OutFormats = []string{
OutFormatColoredLineNumber,
OutFormatLineNumber,
OutFormatJSON,
OutFormatTab,
OutFormatCheckstyle,
OutFormatCodeClimate,
2019-05-20 10:02:20 +10:00
OutFormatJunitXML,
2020-04-10 23:46:19 +03:00
OutFormatGithubActions,
}
2018-05-05 09:24:37 +03:00
type ExcludePattern struct {
2020-04-25 13:49:11 -05:00
ID string
Pattern string
Linter string
Why string
}
var DefaultExcludePatterns = []ExcludePattern{
{
2020-04-25 13:49:11 -05:00
ID: "EXC0001",
2018-06-28 22:39:23 +03:00
Pattern: "Error return value of .((os\\.)?std(out|err)\\..*|.*Close" +
"|.*Flush|os\\.Remove(All)?|.*print(f|ln)?|os\\.(Un)?Setenv). is not checked",
2018-06-28 22:39:23 +03:00
Linter: "errcheck",
Why: "Almost all programs ignore errors on these functions and in most cases it's ok",
},
{
2020-04-25 13:49:11 -05:00
ID: "EXC0002",
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",
},
{
2020-04-25 13:49:11 -05:00
ID: "EXC0003",
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'",
},
{
2020-04-25 13:49:11 -05:00
ID: "EXC0004",
Pattern: "(possible misuse of unsafe.Pointer|should have signature)",
Linter: "govet",
Why: "Common false positives",
},
{
2020-04-25 13:49:11 -05:00
ID: "EXC0005",
Pattern: "ineffective break statement. Did you mean to break out of the outer loop",
Linter: "staticcheck",
Why: "Developers tend to write in C-style with an explicit 'break' in a 'switch', so it's ok to ignore",
},
{
2020-04-25 13:49:11 -05:00
ID: "EXC0006",
Pattern: "Use of unsafe calls should be audited",
Linter: "gosec",
Why: "Too many false-positives on 'unsafe' usage",
},
{
2020-04-25 13:49:11 -05:00
ID: "EXC0007",
Pattern: "Subprocess launch(ed with variable|ing should be audited)",
Linter: "gosec",
Why: "Too many false-positives for parametrized shell calls",
},
{
2020-04-25 13:49:11 -05:00
ID: "EXC0008",
2020-03-22 06:21:46 +09:00
Pattern: "(G104|G307)",
Linter: "gosec",
Why: "Duplicated errcheck checks",
},
{
2020-04-25 13:49:11 -05:00
ID: "EXC0009",
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",
},
{
2020-04-25 13:49:11 -05:00
ID: "EXC0010",
Pattern: "Potential file inclusion via variable",
Linter: "gosec",
Why: "False positive is triggered by 'src, err := ioutil.ReadFile(filename)'",
},
}
2020-04-25 14:14:42 -05:00
func GetDefaultExcludePatternsStrings() []string {
return GetExcludePatternsStrings(nil)
}
func GetExcludePatternsStrings(include []string) []string {
2020-04-25 13:49:11 -05:00
includeMap := make(map[string]bool, len(include))
for _, inc := range include {
includeMap[inc] = true
}
var ret []string
for _, p := range DefaultExcludePatterns {
2020-04-25 13:49:11 -05:00
if !includeMap[p.ID] {
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
2019-09-21 13:50:23 +03:00
TracePath 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"`
// Deprecated: Deadline exists for historical compatibility
// and should not be used. To set run timeout use Timeout instead.
Deadline time.Duration
Timeout time.Duration
PrintVersion bool
SkipFiles []string `mapstructure:"skip-files"`
SkipDirs []string `mapstructure:"skip-dirs"`
UseDefaultSkipDirs bool `mapstructure:"skip-dirs-use-default"`
AllowParallelRunners bool `mapstructure:"allow-parallel-runners"`
}
2018-05-05 19:43:18 +03:00
type LintersSettings struct {
Gci struct {
LocalPrefixes string `mapstructure:"local-prefixes"`
}
Govet GovetSettings
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
}
Gomnd struct {
Settings map[string]map[string]interface{}
}
2018-05-31 01:24:46 -04:00
Depguard struct {
ListType string `mapstructure:"list-type"`
Packages []string
IncludeGoRoot bool `mapstructure:"include-go-root"`
PackagesWithErrorMessage map[string]string `mapstructure:"packages-with-error-message"`
2018-05-31 01:24:46 -04:00
}
2018-06-28 21:27:07 +03:00
Misspell struct {
Locale string
IgnoreWords []string `mapstructure:"ignore-words"`
2018-06-28 21:27:07 +03:00
}
Unused struct {
CheckExported bool `mapstructure:"check-exported"`
}
2019-09-09 15:56:30 +02:00
Funlen struct {
Lines int
Statements int
}
2019-09-23 12:08:43 +02:00
Whitespace struct {
2019-10-04 14:12:07 +02:00
MultiIf bool `mapstructure:"multi-if"`
MultiFunc bool `mapstructure:"multi-func"`
2019-09-23 12:08:43 +02:00
}
RowsErrCheck struct {
Packages []string
}
Gomodguard struct {
Allowed struct {
Modules []string `mapstructure:"modules"`
Domains []string `mapstructure:"domains"`
} `mapstructure:"allowed"`
Blocked struct {
Modules []map[string]struct {
Recommendations []string `mapstructure:"recommendations"`
Reason string `mapstructure:"reason"`
} `mapstructure:"modules"`
Versions []map[string]struct {
Version string `mapstructure:"version"`
Reason string `mapstructure:"reason"`
} `mapstructure:"versions"`
} `mapstructure:"blocked"`
}
2019-11-10 01:05:27 +03:00
WSL WSLSettings
Lll LllSettings
Unparam UnparamSettings
Nakedret NakedretSettings
Prealloc PreallocSettings
Errcheck ErrcheckSettings
Gocritic GocriticSettings
Godox GodoxSettings
Dogsled DogsledSettings
Gocognit GocognitSettings
Godot GodotSettings
Goheader GoHeaderSettings
2019-11-10 01:05:27 +03:00
Testpackage TestpackageSettings
Nestif NestifSettings
NoLintLint NoLintLintSettings
Exhaustive ExhaustiveSettings
Gofumpt GofumptSettings
Custom map[string]CustomLinterSettings
}
type GoHeaderSettings struct {
Values map[string]map[string]string `mapstructure:"values"`
Template string `mapstructure:"template"`
TemplatePath string `mapstructure:"template-path"`
}
type GovetSettings struct {
CheckShadowing bool `mapstructure:"check-shadowing"`
Settings map[string]map[string]interface{}
Enable []string
Disable []string
EnableAll bool `mapstructure:"enable-all"`
DisableAll bool `mapstructure:"disable-all"`
}
func (cfg GovetSettings) Validate() error {
if cfg.EnableAll && cfg.DisableAll {
return errors.New("enable-all and disable-all can't be combined")
}
if cfg.EnableAll && len(cfg.Enable) != 0 {
return errors.New("enable-all and enable can't be combined")
}
if cfg.DisableAll && len(cfg.Disable) != 0 {
return errors.New("disable-all and disable can't be combined")
}
return nil
}
type ErrcheckSettings struct {
CheckTypeAssertions bool `mapstructure:"check-type-assertions"`
CheckAssignToBlank bool `mapstructure:"check-blank"`
Ignore string `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
}
type GodoxSettings struct {
Keywords []string
}
2019-09-17 01:44:53 -04:00
type DogsledSettings struct {
MaxBlankIdentifiers int `mapstructure:"max-blank-identifiers"`
}
type GocognitSettings struct {
MinComplexity int `mapstructure:"min-complexity"`
}
type WSLSettings struct {
2019-11-14 12:12:32 +01:00
StrictAppend bool `mapstructure:"strict-append"`
AllowAssignAndCallCuddle bool `mapstructure:"allow-assign-and-call"`
AllowMultiLineAssignCuddle bool `mapstructure:"allow-multiline-assign"`
AllowCuddleDeclaration bool `mapstructure:"allow-cuddle-declarations"`
AllowTrailingComment bool `mapstructure:"allow-trailing-comment"`
AllowSeparatedLeadingComment bool `mapstructure:"allow-separated-leading-comment"`
ForceCuddleErrCheckAndAssign bool `mapstructure:"force-err-cuddling"`
ForceCaseTrailingWhitespaceLimit int `mapstructure:"force-case-trailing-whitespace"`
}
2020-03-16 09:03:59 +03:00
type GodotSettings struct {
CheckAll bool `mapstructure:"check-all"`
}
type NoLintLintSettings struct {
RequireExplanation bool `mapstructure:"require-explanation"`
AllowLeadingSpace bool `mapstructure:"allow-leading-space"`
RequireSpecific bool `mapstructure:"require-specific"`
AllowNoExplanation []string `mapstructure:"allow-no-explanation"`
AllowUnused bool `mapstructure:"allow-unused"`
}
2019-11-10 01:05:27 +03:00
type TestpackageSettings struct {
SkipRegexp string `mapstructure:"skip-regexp"`
}
2020-02-02 14:58:38 +09:00
type NestifSettings struct {
MinComplexity int `mapstructure:"min-complexity"`
}
type ExhaustiveSettings struct {
DefaultSignifiesExhaustive bool `mapstructure:"default-signifies-exhaustive"`
}
type GofumptSettings struct {
ExtraRules bool `mapstructure:"extra-rules"`
}
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-11-05 18:20:28 +03:00
Gocritic: GocriticSettings{
SettingsPerCheck: map[string]GocriticCheckSettings{},
},
Godox: GodoxSettings{
Keywords: []string{},
},
2019-09-17 01:44:53 -04:00
Dogsled: DogsledSettings{
MaxBlankIdentifiers: 2,
},
Gocognit: GocognitSettings{
MinComplexity: 30,
},
WSL: WSLSettings{
2019-11-14 12:12:32 +01:00
StrictAppend: true,
AllowAssignAndCallCuddle: true,
AllowMultiLineAssignCuddle: true,
AllowCuddleDeclaration: false,
AllowTrailingComment: false,
AllowSeparatedLeadingComment: false,
ForceCuddleErrCheckAndAssign: false,
ForceCaseTrailingWhitespaceLimit: 0,
},
NoLintLint: NoLintLintSettings{
RequireExplanation: false,
AllowLeadingSpace: true,
RequireSpecific: false,
AllowUnused: false,
},
2019-11-10 01:05:27 +03:00
Testpackage: TestpackageSettings{
SkipRegexp: `(export|internal)_test\.go`,
},
2020-02-02 14:58:38 +09:00
Nestif: NestifSettings{
MinComplexity: 5,
},
Exhaustive: ExhaustiveSettings{
DefaultSignifiesExhaustive: false,
},
Gofumpt: GofumptSettings{
ExtraRules: false,
},
}
type CustomLinterSettings struct {
Path string
Description string
OriginalURL string `mapstructure:"original-url"`
}
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 BaseRule struct {
2019-02-09 03:24:30 +03:00
Linters []string
Path string
Text string
Source string
2019-02-09 03:24:30 +03:00
}
func (b BaseRule) Validate(minConditionsCount int) error {
if err := validateOptionalRegex(b.Path); err != nil {
return fmt.Errorf("invalid path regex: %v", err)
}
if err := validateOptionalRegex(b.Text); err != nil {
return fmt.Errorf("invalid text regex: %v", err)
}
if err := validateOptionalRegex(b.Source); err != nil {
return fmt.Errorf("invalid source regex: %v", err)
}
nonBlank := 0
if len(b.Linters) > 0 {
nonBlank++
}
if b.Path != "" {
nonBlank++
}
if b.Text != "" {
nonBlank++
}
if b.Source != "" {
nonBlank++
}
if nonBlank < minConditionsCount {
return fmt.Errorf("at least %d of (text, source, path, linters) should be set", minConditionsCount)
}
return nil
}
const excludeRuleMinConditionsCount = 2
type ExcludeRule struct {
BaseRule `mapstructure:",squash"`
}
func validateOptionalRegex(value string) error {
if value == "" {
return nil
}
_, err := regexp.Compile(value)
return err
}
func (e ExcludeRule) Validate() error {
return e.BaseRule.Validate(excludeRuleMinConditionsCount)
}
const severityRuleMinConditionsCount = 1
type SeverityRule struct {
BaseRule `mapstructure:",squash"`
Severity string
}
func (s *SeverityRule) Validate() error {
return s.BaseRule.Validate(severityRuleMinConditionsCount)
}
type Issues struct {
2020-04-25 13:49:11 -05:00
IncludeDefaultExcludes []string `mapstructure:"include"`
ExcludeCaseSensitive bool `mapstructure:"exclude-case-sensitive"`
ExcludePatterns []string `mapstructure:"exclude"`
ExcludeRules []ExcludeRule `mapstructure:"exclude-rules"`
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"`
NeedFix bool `mapstructure:"fix"`
2018-05-05 09:24:37 +03:00
}
type Severity struct {
Default string `mapstructure:"default-severity"`
CaseSensitive bool `mapstructure:"case-sensitive"`
Rules []SeverityRule `mapstructure:"rules"`
}
2019-10-03 12:34:19 -04:00
type Config struct {
Run Run
2018-05-05 09:24:37 +03:00
Output struct {
Format string
Color string
PrintIssuedLine bool `mapstructure:"print-issued-lines"`
PrintLinterName bool `mapstructure:"print-linter-name"`
UniqByLine bool `mapstructure:"uniq-by-line"`
SortResults bool `mapstructure:"sort-results"`
PrintWelcomeMessage bool `mapstructure:"print-welcome"`
PathPrefix string `mapstructure:"path-prefix"`
2018-05-05 09:24:37 +03:00
}
LintersSettings LintersSettings `mapstructure:"linters-settings"`
Linters Linters
Issues Issues
Severity Severity
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,
}
}