generate command line options section of README

This commit is contained in:
golangci 2018-06-02 15:32:40 +03:00
parent 4df5df2ab7
commit 9133ef4271
10 changed files with 245 additions and 262 deletions

View File

@ -10,7 +10,6 @@ output:
format: colored-line-number format: colored-line-number
print-issued-lines: true print-issued-lines: true
print-linter-name: true print-linter-name: true
print-welcome: true
linters-settings: linters-settings:
errcheck: errcheck:

View File

@ -20,7 +20,3 @@ linters:
enable-all: true enable-all: true
disable: disable:
- maligned - maligned
issues:
exclude:
- should have a package comment

View File

@ -2,7 +2,6 @@ test:
go install ./cmd/... go install ./cmd/...
golangci-lint run -v golangci-lint run -v
golangci-lint run --fast --no-config -v golangci-lint run --fast --no-config -v
golangci-lint run --fast --no-config -v
golangci-lint run --no-config -v golangci-lint run --no-config -v
golangci-lint run --fast --no-config -v ./test/testdata/typecheck.go golangci-lint run --fast --no-config -v ./test/testdata/typecheck.go
go test -v -race ./... go test -v -race ./...

170
README.md
View File

@ -134,7 +134,10 @@ This issue is important because often you'd like to set concurrency to CPUs coun
3. It will take more time because of different usages and need of tracking of versions of `n` linters. 3. It will take more time because of different usages and need of tracking of versions of `n` linters.
# Performance # Performance
Benchmarks were executed on MacBook Pro (Retina, 13-inch, Late 2013), 2,4 GHz Intel Core i5, 8 GB 1600 MHz DDR3. It has 4 cores and concurrency for linters was default: number of cores. Benchmark runs and measures timings automatically, it's code is [here](https://github.com/golangci/golangci-lint/blob/master/test/bench.go) (`BenchmarkWithGometalinter`). Benchmarks were executed on MacBook Pro (Retina, 13-inch, Late 2013), 2,4 GHz Intel Core i5, 8 GB 1600 MHz DDR3.
It has 4 cores and concurrency for linters was default: number of cores.
Benchmark runs and measures timings automatically, it's code is
[here](https://github.com/golangci/golangci-lint/blob/master/test/bench_test.go) (`BenchmarkWithGometalinter`).
We measure peak memory usage (RSS) by tracking of processes RSS every 5 ms. We measure peak memory usage (RSS) by tracking of processes RSS every 5 ms.
@ -172,7 +175,7 @@ On average golangci-lint consumes 1.35 times less memory.
# Supported Linters # Supported Linters
To see a list of supported linters and which linters are enabled/disabled by default execute a command To see a list of supported linters and which linters are enabled/disabled by default execute a command
```bash ```
golangci-lint linters golangci-lint linters
``` ```
@ -204,99 +207,77 @@ golangci-lint linters
# Configuration # Configuration
## Command-Line Options ## Command-Line Options
Run next command to see their description and defaults. ```
```bash
golangci-lint run -h golangci-lint run -h
Usage:
golangci-lint run [flags]
Flags:
--out-format string Format of output: colored-line-number|line-number|json (default "colored-line-number")
--print-issued-lines Print lines of code with issue (default true)
--print-linter-name Print linter name in issue line (default true)
--issues-exit-code int Exit code when issues were found (default 1)
--build-tags strings Build tags (not all linters support them)
--deadline duration Deadline for total work (default 1m0s)
--tests Analyze tests (*_test.go)
--print-resources-usage Print avg and max memory usage of golangci-lint and total time
-c, --config PATH Read config from file path PATH
--no-config Don't read config
-E, --enable strings Enable specific linter
-D, --disable strings Disable specific linter
--enable-all Enable all linters
--disable-all Disable all linters
-p, --presets strings Enable presets (bugs|unused|format|style|complexity|performance) of linters. Run 'golangci-lint linters' to see them. This option implies option --disable-all
--fast Run only fast linters from enabled linters set
-e, --exclude strings Exclude issue by regexp
--exclude-use-default Use or not use default excludes:
# errcheck: Almost all programs ignore errors on these functions and in most cases it's ok
- Error return value of .((os\.)?std(out|err)\..*|.*Close|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv). is not checked
# golint: Annoying issue about not having a comment. The rare codebase has such comments
- (should have comment|comment on exported method|should have a package comment)
# golint: False positive when tests are defined in package 'test'
- func name will be used as test\.Test.* by other packages, and that stutters; consider calling this
# gas: Too many false-positives on 'unsafe' usage
- Use of unsafe calls should be audited
# gas: Too many false-positives for parametrized shell calls
- Subprocess launch(ed with variable|ing should be audited)
# gas: Duplicated errcheck checks
- G104
# gas: Too many issues in popular repos
- (Expect directory permissions to be 0750 or less|Expect file permissions to be 0600 or less)
# gas: False positive is triggered by 'src, err := ioutil.ReadFile(filename)'
- Potential file inclusion via variable
# govet: Common false positives
- (possible misuse of unsafe.Pointer|should have signature)
# megacheck: Developers tend to write in C-style with an explicit 'break' in a 'switch', so it's ok to ignore
- ineffective break statement. Did you mean to break out of the outer loop
(default true)
--max-issues-per-linter int Maximum issues count per one linter. Set to 0 to disable (default 50)
--max-same-issues int Maximum count of issues with the same text. Set to 0 to disable (default 3)
-n, --new Show only new issues: if there are unstaged changes or untracked files, only those changes are analyzed, else only changes in HEAD~ are analyzed.
It's a super-useful option for integration of golangci-lint into existing large codebase.
It's not practical to fix all existing issues at the moment of integration: much better don't allow issues in new code
--new-from-rev REV Show only new issues created after git revision REV
--new-from-patch PATH Show only new issues created in git patch with file path PATH
-h, --help help for run
Global Flags:
-j, --concurrency int Concurrency (default NumCPU) (default 8)
--cpu-profile-path string Path to CPU profile output file
--mem-profile-path string Path to memory profile output file
-v, --verbose verbose output
``` ```
### Run Options
- `-c, --config` - path to [config file](#configuration-file) if you don't like using default config path `.golangci.(yml|toml|json)`.
- `-j, --concurrency` - the number of threads used. By default, it's a number of CPUs. Unlike `gometalinter`, it's an honest value, since we do not fork linter processes.
- `--build-tags` - build tags to take into account.
- `--issues-exit-code` - exit code if issues were found. The default is `1`.
- `--deadline` - timeout for running golangci-lint, `1m` by default.
- `--tests` - analyze `*_test.go` files. It's `false` by default.
- `-v, --verbose` - enable verbose output. Use this options to see which linters were enabled, to see timings of steps and another helpful information.
- `--print-resources-usage` - print memory usage and total time elapsed.
### Linters
- `-E, --enable` - enable specific linter. You can pass option multiple times or use a comma:
```bash
golangci-lint run --disable-all -E golint -E govet -E errcheck
golangci-lint run --disable-all --enable golint,govet,errcheck
```
- `-D, --disable` - disable specific linter. Similar to enabling option.
- `--enable-all` - enable all supported linters.
- `--disable-all` - disable all supported linters.
- `-p, --presets` - enable specific presets. To list all presets run
```bash
$ golangci-lint linters
...
Linters presets:
bugs: govet, errcheck, staticcheck, gas, megacheck
unused: unused, structcheck, varcheck, ineffassign, deadcode, megacheck
format: gofmt, goimports
style: golint, gosimple, interfacer, unconvert, dupl, goconst, megacheck, depguard
complexity: gocyclo
performance: maligned
```
Usage example:
```bash
$ golangci-lint run -v --disable-all -p bugs,style,complexity,format
INFO[0000] Active linters: [govet goconst gocyclo gofmt gas dupl goimports megacheck interfacer unconvert errcheck golint]
```
- `--fast` - run only fast linters from the enabled set of linters. To find out which linters are fast run `golangci-lint linters`.
### Linters Options
- `--errcheck.check-type-assertions` - errcheck: check for ignored type assertion results. Disabled by default.
- `--errcheck.check-blank` - errcheck: check for errors assigned to blank identifier: `_ = errFunc()`. Disabled by default
- `--govet.check-shadowing` - govet: check for shadowed variables. Disabled by default.
- `--golint.min-confidence` - golint: minimum confidence of a problem to print it. The default is `0.8`.
- `--gofmt.simplify` - gofmt: simplify code (`gofmt -s`), enabled by default.
- `--gocyclo.min-complexity` - gocyclo: a minimal complexity of function to report it. The default is `30` (it's very high limit).
- `--maligned.suggest-new` - Maligned: print suggested more optimal struct fields ordering. Disabled by default. Example:
```
crypto/tls/ticket.go:20: struct of size 64 bytes could be of size 56 bytes:
struct{
masterSecret []byte,
certificates [][]byte,
vers uint16,
cipherSuite uint16,
usedOldKey bool,
}
```
- `--dupl.threshold` - dupl: Minimal threshold to detect copy-paste, `150` by default.
- `--goconst.min-len` - goconst: minimum constant string length, `3` by default.
- `--goconst.min-occurrences` - goconst: minimum occurences of constant string count to trigger issue. Default is `3`.
### Issues Options
- `-n, --new` - show only new issues: if there are unstaged changes or untracked files, only those changes are analyzed, else only changes in HEAD~ are analyzed. It's a super-useful option for integration `golangci-lint` into existing large codebase. It's not practical to fix all existing issues at the moment of integration: much better don't allow issues in new code. Disabled by default.
- `--new-from-rev` - show only new issues created after specified git revision.
- `--new-from-patch` - show only new issues created in git patch with the specified file path.
- `-e, --exclude` - exclude issue by regexp on issue text.
- `--exclude-use-default` - use or not use default excludes. We tested our linter on large codebases and marked common false positives. By default we ignore common false positives by next regexps:
- `Error return value of .((os\.)?std(out|err)\..*|.*Close|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv). is not checked` - ercheck: almost all programs ignore errors on these functions and in most cases it's ok.
- `(should have comment|comment on exported method)` - golint: annoying issues about not having a comment. The rare codebase has such comments.
- `G103:` - gas: `Use of unsafe calls should be audited`
- `G104:` - gas: `disable what errcheck does: it reports on Close etc`
- `G204:` - gas: `Subprocess launching should be audited: too lot false - positives`
- `G301:` - gas: `Expect directory permissions to be 0750 or less`
- `G302:` - gas: `Expect file permissions to be 0600 or less`
- `G304:` - gas: ``Potential file inclusion via variable: `src, err := ioutil.ReadFile(filename)`.``
- `(possible misuse of unsafe.Pointer|should have signature)` - common false positives by govet.
- `ineffective break statement. Did you mean to break out of the outer loop` - megacheck: developers tend to write in C-style with an explicit `break` in a switch, so it's ok to ignore.
Use option `--exclude-use-default=false` to disable these default exclude regexps.
- `--max-issues-per-linter` - maximum issues count per one linter. Set to `0` to disable. The default value is `50` to not being annoying.
- `--max-same-issues` - maximum count of issues with the same text. Set to 0 to disable. The default value is `3` to not being annoying.
### Output Options
- `--out-format` - format of output: `colored-line-number|line-number|json`, default is `colored-line-number`.
- `--print-issued-lines` - print line of source code where the issue occurred. Enabled by default.
- `--print-linter-name` - print linter name in issue line. Enabled by default.
- `--print-welcome` - print welcome message. Enabled by default.
## Configuration File ## Configuration File
GolangCI-Lint looks for next config paths in the current directory: GolangCI-Lint looks for next config paths in the current directory:
- `.golangci.yml` - `.golangci.yml`
@ -330,11 +311,6 @@ linters:
enable-all: true enable-all: true
disable: disable:
- maligned - maligned
issues:
exclude:
- should have a package comment
``` ```
# False Positives # False Positives

View File

@ -112,7 +112,10 @@ This issue is important because often you'd like to set concurrency to CPUs coun
3. It will take more time because of different usages and need of tracking of versions of `n` linters. 3. It will take more time because of different usages and need of tracking of versions of `n` linters.
# Performance # Performance
Benchmarks were executed on MacBook Pro (Retina, 13-inch, Late 2013), 2,4 GHz Intel Core i5, 8 GB 1600 MHz DDR3. It has 4 cores and concurrency for linters was default: number of cores. Benchmark runs and measures timings automatically, it's code is [here](https://github.com/golangci/golangci-lint/blob/master/test/bench.go) (`BenchmarkWithGometalinter`). Benchmarks were executed on MacBook Pro (Retina, 13-inch, Late 2013), 2,4 GHz Intel Core i5, 8 GB 1600 MHz DDR3.
It has 4 cores and concurrency for linters was default: number of cores.
Benchmark runs and measures timings automatically, it's code is
[here](https://github.com/golangci/golangci-lint/blob/master/test/bench_test.go) (`BenchmarkWithGometalinter`).
We measure peak memory usage (RSS) by tracking of processes RSS every 5 ms. We measure peak memory usage (RSS) by tracking of processes RSS every 5 ms.
@ -150,7 +153,7 @@ On average golangci-lint consumes 1.35 times less memory.
# Supported Linters # Supported Linters
To see a list of supported linters and which linters are enabled/disabled by default execute a command To see a list of supported linters and which linters are enabled/disabled by default execute a command
```bash ```
golangci-lint linters golangci-lint linters
``` ```
@ -162,99 +165,11 @@ golangci-lint linters
# Configuration # Configuration
## Command-Line Options ## Command-Line Options
Run next command to see their description and defaults. ```
```bash
golangci-lint run -h golangci-lint run -h
{{.RunHelpText}}
``` ```
### Run Options
- `-c, --config` - path to [config file](#configuration-file) if you don't like using default config path `.golangci.(yml|toml|json)`.
- `-j, --concurrency` - the number of threads used. By default, it's a number of CPUs. Unlike `gometalinter`, it's an honest value, since we do not fork linter processes.
- `--build-tags` - build tags to take into account.
- `--issues-exit-code` - exit code if issues were found. The default is `1`.
- `--deadline` - timeout for running golangci-lint, `1m` by default.
- `--tests` - analyze `*_test.go` files. It's `false` by default.
- `-v, --verbose` - enable verbose output. Use this options to see which linters were enabled, to see timings of steps and another helpful information.
- `--print-resources-usage` - print memory usage and total time elapsed.
### Linters
- `-E, --enable` - enable specific linter. You can pass option multiple times or use a comma:
```bash
golangci-lint run --disable-all -E golint -E govet -E errcheck
golangci-lint run --disable-all --enable golint,govet,errcheck
```
- `-D, --disable` - disable specific linter. Similar to enabling option.
- `--enable-all` - enable all supported linters.
- `--disable-all` - disable all supported linters.
- `-p, --presets` - enable specific presets. To list all presets run
```bash
$ golangci-lint linters
...
Linters presets:
bugs: govet, errcheck, staticcheck, gas, megacheck
unused: unused, structcheck, varcheck, ineffassign, deadcode, megacheck
format: gofmt, goimports
style: golint, gosimple, interfacer, unconvert, dupl, goconst, megacheck, depguard
complexity: gocyclo
performance: maligned
```
Usage example:
```bash
$ golangci-lint run -v --disable-all -p bugs,style,complexity,format
INFO[0000] Active linters: [govet goconst gocyclo gofmt gas dupl goimports megacheck interfacer unconvert errcheck golint]
```
- `--fast` - run only fast linters from the enabled set of linters. To find out which linters are fast run `golangci-lint linters`.
### Linters Options
- `--errcheck.check-type-assertions` - errcheck: check for ignored type assertion results. Disabled by default.
- `--errcheck.check-blank` - errcheck: check for errors assigned to blank identifier: `_ = errFunc()`. Disabled by default
- `--govet.check-shadowing` - govet: check for shadowed variables. Disabled by default.
- `--golint.min-confidence` - golint: minimum confidence of a problem to print it. The default is `0.8`.
- `--gofmt.simplify` - gofmt: simplify code (`gofmt -s`), enabled by default.
- `--gocyclo.min-complexity` - gocyclo: a minimal complexity of function to report it. The default is `30` (it's very high limit).
- `--maligned.suggest-new` - Maligned: print suggested more optimal struct fields ordering. Disabled by default. Example:
```
crypto/tls/ticket.go:20: struct of size 64 bytes could be of size 56 bytes:
struct{
masterSecret []byte,
certificates [][]byte,
vers uint16,
cipherSuite uint16,
usedOldKey bool,
}
```
- `--dupl.threshold` - dupl: Minimal threshold to detect copy-paste, `150` by default.
- `--goconst.min-len` - goconst: minimum constant string length, `3` by default.
- `--goconst.min-occurrences` - goconst: minimum occurences of constant string count to trigger issue. Default is `3`.
### Issues Options
- `-n, --new` - show only new issues: if there are unstaged changes or untracked files, only those changes are analyzed, else only changes in HEAD~ are analyzed. It's a super-useful option for integration `golangci-lint` into existing large codebase. It's not practical to fix all existing issues at the moment of integration: much better don't allow issues in new code. Disabled by default.
- `--new-from-rev` - show only new issues created after specified git revision.
- `--new-from-patch` - show only new issues created in git patch with the specified file path.
- `-e, --exclude` - exclude issue by regexp on issue text.
- `--exclude-use-default` - use or not use default excludes. We tested our linter on large codebases and marked common false positives. By default we ignore common false positives by next regexps:
- `Error return value of .((os\.)?std(out|err)\..*|.*Close|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv). is not checked` - ercheck: almost all programs ignore errors on these functions and in most cases it's ok.
- `(should have comment|comment on exported method)` - golint: annoying issues about not having a comment. The rare codebase has such comments.
- `G103:` - gas: `Use of unsafe calls should be audited`
- `G104:` - gas: `disable what errcheck does: it reports on Close etc`
- `G204:` - gas: `Subprocess launching should be audited: too lot false - positives`
- `G301:` - gas: `Expect directory permissions to be 0750 or less`
- `G302:` - gas: `Expect file permissions to be 0600 or less`
- `G304:` - gas: ``Potential file inclusion via variable: `src, err := ioutil.ReadFile(filename)`.``
- `(possible misuse of unsafe.Pointer|should have signature)` - common false positives by govet.
- `ineffective break statement. Did you mean to break out of the outer loop` - megacheck: developers tend to write in C-style with an explicit `break` in a switch, so it's ok to ignore.
Use option `--exclude-use-default=false` to disable these default exclude regexps.
- `--max-issues-per-linter` - maximum issues count per one linter. Set to `0` to disable. The default value is `50` to not being annoying.
- `--max-same-issues` - maximum count of issues with the same text. Set to 0 to disable. The default value is `3` to not being annoying.
### Output Options
- `--out-format` - format of output: `colored-line-number|line-number|json`, default is `colored-line-number`.
- `--print-issued-lines` - print line of source code where the issue occurred. Enabled by default.
- `--print-linter-name` - print linter name in issue line. Enabled by default.
- `--print-welcome` - print welcome message. Enabled by default.
## Configuration File ## Configuration File
GolangCI-Lint looks for next config paths in the current directory: GolangCI-Lint looks for next config paths in the current directory:
- `.golangci.yml` - `.golangci.yml`

View File

@ -56,6 +56,14 @@ func (e *Executor) persistentPreRun(cmd *cobra.Command, args []string) {
os.Exit(e.exitCode) os.Exit(e.exitCode)
} }
func getDefaultConcurrency() int {
if os.Getenv("HELP_RUN") == "1" {
return 8 // to make stable concurrency for README help generating builds
}
return runtime.NumCPU()
}
func (e *Executor) initRoot() { func (e *Executor) initRoot() {
rootCmd := &cobra.Command{ rootCmd := &cobra.Command{
Use: "golangci-lint", Use: "golangci-lint",
@ -69,11 +77,13 @@ func (e *Executor) initRoot() {
PersistentPreRun: e.persistentPostRun, PersistentPreRun: e.persistentPostRun,
PersistentPostRun: e.persistentPreRun, PersistentPostRun: e.persistentPreRun,
} }
rootCmd.PersistentFlags().BoolVarP(&e.cfg.Run.IsVerbose, "verbose", "v", false, "verbose output") rootCmd.PersistentFlags().BoolVarP(&e.cfg.Run.IsVerbose, "verbose", "v", false, wh("verbose output"))
rootCmd.PersistentFlags().StringVar(&e.cfg.Run.CPUProfilePath, "cpu-profile-path", "", "Path to CPU profile output file") rootCmd.PersistentFlags().StringVar(&e.cfg.Run.CPUProfilePath, "cpu-profile-path", "", wh("Path to CPU profile output file"))
rootCmd.PersistentFlags().StringVar(&e.cfg.Run.MemProfilePath, "mem-profile-path", "", "Path to memory profile output file") rootCmd.PersistentFlags().StringVar(&e.cfg.Run.MemProfilePath, "mem-profile-path", "", wh("Path to memory profile output file"))
rootCmd.PersistentFlags().IntVarP(&e.cfg.Run.Concurrency, "concurrency", "j", runtime.NumCPU(), "Concurrency (default NumCPU)") rootCmd.PersistentFlags().IntVarP(&e.cfg.Run.Concurrency, "concurrency", "j", getDefaultConcurrency(), wh("Concurrency (default NumCPU)"))
rootCmd.PersistentFlags().BoolVar(&e.cfg.Run.PrintVersion, "version", false, "Print version") if e.commit != "" {
rootCmd.PersistentFlags().BoolVar(&e.cfg.Run.PrintVersion, "version", false, wh("Print version"))
}
e.rootCmd = rootCmd e.rootCmd = rootCmd
} }

View File

@ -12,6 +12,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/fatih/color"
"github.com/golangci/golangci-lint/pkg/config" "github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/lint" "github.com/golangci/golangci-lint/pkg/lint"
"github.com/golangci/golangci-lint/pkg/lint/lintersdb" "github.com/golangci/golangci-lint/pkg/lint/lintersdb"
@ -29,92 +30,131 @@ const (
exitCodeIfTimeout = 4 exitCodeIfTimeout = 4
) )
func getDefaultExcludeHelp() string {
parts := []string{"Use or not use default excludes:"}
for _, ep := range config.DefaultExcludePatterns {
parts = append(parts, fmt.Sprintf(" # %s: %s", ep.Linter, ep.Why))
parts = append(parts, fmt.Sprintf(" - %s", color.YellowString(ep.Pattern)))
parts = append(parts, "")
}
return strings.Join(parts, "\n")
}
const welcomeMessage = "Run this tool in cloud on every github pull request in https://golangci.com for free (public repos)"
func wh(text string) string {
return color.GreenString(text)
}
func (e *Executor) initRun() { func (e *Executor) initRun() {
var runCmd = &cobra.Command{ var runCmd = &cobra.Command{
Use: "run", Use: "run",
Short: "Run linters", Short: welcomeMessage,
Run: e.executeRun, Run: e.executeRun,
} }
e.rootCmd.AddCommand(runCmd) e.rootCmd.AddCommand(runCmd)
runCmd.SetOutput(printers.StdOut) // use custom output to properly color it in Windows terminals
runCmd.Flags().SortFlags = false // sort them as they are defined here
hideFlag := func(name string) {
if err := runCmd.Flags().MarkHidden(name); err != nil {
panic(err)
}
}
// Output config // Output config
oc := &e.cfg.Output oc := &e.cfg.Output
runCmd.Flags().StringVar(&oc.Format, "out-format", runCmd.Flags().StringVar(&oc.Format, "out-format",
config.OutFormatColoredLineNumber, config.OutFormatColoredLineNumber,
fmt.Sprintf("Format of output: %s", strings.Join(config.OutFormats, "|"))) wh(fmt.Sprintf("Format of output: %s", strings.Join(config.OutFormats, "|"))))
runCmd.Flags().BoolVar(&oc.PrintIssuedLine, "print-issued-lines", true, "Print lines of code with issue") runCmd.Flags().BoolVar(&oc.PrintIssuedLine, "print-issued-lines", true, wh("Print lines of code with issue"))
runCmd.Flags().BoolVar(&oc.PrintLinterName, "print-linter-name", true, "Print linter name in issue line") runCmd.Flags().BoolVar(&oc.PrintLinterName, "print-linter-name", true, wh("Print linter name in issue line"))
runCmd.Flags().BoolVar(&oc.PrintWelcomeMessage, "print-welcome", false, "Print welcome message") runCmd.Flags().BoolVar(&oc.PrintWelcomeMessage, "print-welcome", false, wh("Print welcome message"))
hideFlag("print-welcome") // no longer used
// Run config // Run config
rc := &e.cfg.Run rc := &e.cfg.Run
runCmd.Flags().IntVar(&rc.ExitCodeIfIssuesFound, "issues-exit-code", runCmd.Flags().IntVar(&rc.ExitCodeIfIssuesFound, "issues-exit-code",
1, "Exit code when issues were found") 1, wh("Exit code when issues were found"))
runCmd.Flags().StringSliceVar(&rc.BuildTags, "build-tags", []string{}, "Build tags (not all linters support them)") runCmd.Flags().StringSliceVar(&rc.BuildTags, "build-tags", []string{}, wh("Build tags (not all linters support them)"))
runCmd.Flags().DurationVar(&rc.Deadline, "deadline", time.Minute, "Deadline for total work") runCmd.Flags().DurationVar(&rc.Deadline, "deadline", time.Minute, wh("Deadline for total work"))
runCmd.Flags().BoolVar(&rc.AnalyzeTests, "tests", false, "Analyze tests (*_test.go)") runCmd.Flags().BoolVar(&rc.AnalyzeTests, "tests", false, wh("Analyze tests (*_test.go)"))
runCmd.Flags().BoolVar(&rc.PrintResourcesUsage, "print-resources-usage", false, "Print avg and max memory usage of golangci-lint and total time") runCmd.Flags().BoolVar(&rc.PrintResourcesUsage, "print-resources-usage", false, wh("Print avg and max memory usage of golangci-lint and total time"))
runCmd.Flags().StringVarP(&rc.Config, "config", "c", "", "Read config from file path `PATH`") runCmd.Flags().StringVarP(&rc.Config, "config", "c", "", wh("Read config from file path `PATH`"))
runCmd.Flags().BoolVar(&rc.NoConfig, "no-config", false, "Don't read config") runCmd.Flags().BoolVar(&rc.NoConfig, "no-config", false, wh("Don't read config"))
// Linters settings config // Linters settings config
lsc := &e.cfg.LintersSettings lsc := &e.cfg.LintersSettings
// Hide all linters settings flags: they were initially visible,
// but when number of linters started to grow it became ovious that
// we can't fill 90% of flags by linters settings: common flags became hard to find.
// New linters settings should be done only through config file.
runCmd.Flags().BoolVar(&lsc.Errcheck.CheckTypeAssertions, "errcheck.check-type-assertions", false, "Errcheck: check for ignored type assertion results") runCmd.Flags().BoolVar(&lsc.Errcheck.CheckTypeAssertions, "errcheck.check-type-assertions", false, "Errcheck: check for ignored type assertion results")
hideFlag("errcheck.check-type-assertions")
runCmd.Flags().BoolVar(&lsc.Errcheck.CheckAssignToBlank, "errcheck.check-blank", false, "Errcheck: check for errors assigned to blank identifier: _ = errFunc()") runCmd.Flags().BoolVar(&lsc.Errcheck.CheckAssignToBlank, "errcheck.check-blank", false, "Errcheck: check for errors assigned to blank identifier: _ = errFunc()")
hideFlag("errcheck.check-blank")
runCmd.Flags().BoolVar(&lsc.Govet.CheckShadowing, "govet.check-shadowing", false, "Govet: check for shadowed variables") runCmd.Flags().BoolVar(&lsc.Govet.CheckShadowing, "govet.check-shadowing", false, "Govet: check for shadowed variables")
hideFlag("govet.check-shadowing")
runCmd.Flags().Float64Var(&lsc.Golint.MinConfidence, "golint.min-confidence", 0.8, "Golint: minimum confidence of a problem to print it") runCmd.Flags().Float64Var(&lsc.Golint.MinConfidence, "golint.min-confidence", 0.8, "Golint: minimum confidence of a problem to print it")
hideFlag("golint.min-confidence")
runCmd.Flags().BoolVar(&lsc.Gofmt.Simplify, "gofmt.simplify", true, "Gofmt: simplify code") runCmd.Flags().BoolVar(&lsc.Gofmt.Simplify, "gofmt.simplify", true, "Gofmt: simplify code")
hideFlag("gofmt.simplify")
runCmd.Flags().IntVar(&lsc.Gocyclo.MinComplexity, "gocyclo.min-complexity", runCmd.Flags().IntVar(&lsc.Gocyclo.MinComplexity, "gocyclo.min-complexity",
30, "Minimal complexity of function to report it") 30, "Minimal complexity of function to report it")
hideFlag("gocyclo.min-complexity")
runCmd.Flags().BoolVar(&lsc.Maligned.SuggestNewOrder, "maligned.suggest-new", false, "Maligned: print suggested more optimal struct fields ordering") runCmd.Flags().BoolVar(&lsc.Maligned.SuggestNewOrder, "maligned.suggest-new", false, "Maligned: print suggested more optimal struct fields ordering")
hideFlag("maligned.suggest-new")
runCmd.Flags().IntVar(&lsc.Dupl.Threshold, "dupl.threshold", runCmd.Flags().IntVar(&lsc.Dupl.Threshold, "dupl.threshold",
150, "Dupl: Minimal threshold to detect copy-paste") 150, "Dupl: Minimal threshold to detect copy-paste")
hideFlag("dupl.threshold")
runCmd.Flags().IntVar(&lsc.Goconst.MinStringLen, "goconst.min-len", runCmd.Flags().IntVar(&lsc.Goconst.MinStringLen, "goconst.min-len",
3, "Goconst: minimum constant string length") 3, "Goconst: minimum constant string length")
hideFlag("goconst.min-len")
runCmd.Flags().IntVar(&lsc.Goconst.MinOccurrencesCount, "goconst.min-occurrences", runCmd.Flags().IntVar(&lsc.Goconst.MinOccurrencesCount, "goconst.min-occurrences",
3, "Goconst: minimum occurrences of constant string count to trigger issue") 3, "Goconst: minimum occurrences of constant string count to trigger issue")
hideFlag("goconst.min-occurrences")
// (@dixonwille) These flag is only used for testing purposes. // (@dixonwille) These flag is only used for testing purposes.
runCmd.Flags().StringSliceVar(&lsc.Depguard.Packages, "depguard.packages", nil, runCmd.Flags().StringSliceVar(&lsc.Depguard.Packages, "depguard.packages", nil,
"Depguard: packages to add to the list") "Depguard: packages to add to the list")
if err := runCmd.Flags().MarkHidden("depguard.packages"); err != nil { hideFlag("depguard.packages")
panic(err) //Considering The only time this is called is if name does not exist
}
runCmd.Flags().BoolVar(&lsc.Depguard.IncludeGoRoot, "depguard.include-go-root", false, runCmd.Flags().BoolVar(&lsc.Depguard.IncludeGoRoot, "depguard.include-go-root", false,
"Depguard: check list against standard lib") "Depguard: check list against standard lib")
if err := runCmd.Flags().MarkHidden("depguard.include-go-root"); err != nil { hideFlag("depguard.include-go-root")
panic(err) //Considering The only time this is called is if name does not exist
}
// Linters config // Linters config
lc := &e.cfg.Linters lc := &e.cfg.Linters
runCmd.Flags().StringSliceVarP(&lc.Enable, "enable", "E", []string{}, "Enable specific linter") runCmd.Flags().StringSliceVarP(&lc.Enable, "enable", "E", []string{}, wh("Enable specific linter"))
runCmd.Flags().StringSliceVarP(&lc.Disable, "disable", "D", []string{}, "Disable specific linter") runCmd.Flags().StringSliceVarP(&lc.Disable, "disable", "D", []string{}, wh("Disable specific linter"))
runCmd.Flags().BoolVar(&lc.EnableAll, "enable-all", false, "Enable all linters") runCmd.Flags().BoolVar(&lc.EnableAll, "enable-all", false, wh("Enable all linters"))
runCmd.Flags().BoolVar(&lc.DisableAll, "disable-all", false, "Disable all linters") runCmd.Flags().BoolVar(&lc.DisableAll, "disable-all", false, wh("Disable all linters"))
runCmd.Flags().StringSliceVarP(&lc.Presets, "presets", "p", []string{}, runCmd.Flags().StringSliceVarP(&lc.Presets, "presets", "p", []string{},
fmt.Sprintf("Enable presets (%s) of linters. Run 'golangci-lint linters' to see them. This option implies option --disable-all", strings.Join(lintersdb.AllPresets(), "|"))) wh(fmt.Sprintf("Enable presets (%s) of linters. Run 'golangci-lint linters' to see them. This option implies option --disable-all", strings.Join(lintersdb.AllPresets(), "|"))))
runCmd.Flags().BoolVar(&lc.Fast, "fast", false, "Run only fast linters from enabled linters set") runCmd.Flags().BoolVar(&lc.Fast, "fast", false, wh("Run only fast linters from enabled linters set"))
// Issues config // Issues config
ic := &e.cfg.Issues ic := &e.cfg.Issues
runCmd.Flags().StringSliceVarP(&ic.ExcludePatterns, "exclude", "e", []string{}, "Exclude issue by regexp") runCmd.Flags().StringSliceVarP(&ic.ExcludePatterns, "exclude", "e", []string{}, wh("Exclude issue by regexp"))
runCmd.Flags().BoolVar(&ic.UseDefaultExcludes, "exclude-use-default", true, runCmd.Flags().BoolVar(&ic.UseDefaultExcludes, "exclude-use-default", true, getDefaultExcludeHelp())
fmt.Sprintf("Use or not use default excludes: (%s)", strings.Join(config.DefaultExcludePatterns, "|")))
runCmd.Flags().IntVar(&ic.MaxIssuesPerLinter, "max-issues-per-linter", 50, "Maximum issues count per one linter. Set to 0 to disable") runCmd.Flags().IntVar(&ic.MaxIssuesPerLinter, "max-issues-per-linter", 50, wh("Maximum issues count per one linter. Set to 0 to disable"))
runCmd.Flags().IntVar(&ic.MaxSameIssues, "max-same-issues", 3, "Maximum count of issues with the same text. Set to 0 to disable") runCmd.Flags().IntVar(&ic.MaxSameIssues, "max-same-issues", 3, wh("Maximum count of issues with the same text. Set to 0 to disable"))
runCmd.Flags().BoolVarP(&ic.Diff, "new", "n", false, "Show only new issues: if there are unstaged changes or untracked files, only those changes are analyzed, else only changes in HEAD~ are analyzed") runCmd.Flags().BoolVarP(&ic.Diff, "new", "n", false,
runCmd.Flags().StringVar(&ic.DiffFromRevision, "new-from-rev", "", "Show only new issues created after git revision `REV`") wh("Show only new issues: if there are unstaged changes or untracked files, only those changes are analyzed, else only changes in HEAD~ are analyzed.\nIt's a super-useful option for integration of golangci-lint into existing large codebase.\nIt's not practical to fix all existing issues at the moment of integration: much better don't allow issues in new code"))
runCmd.Flags().StringVar(&ic.DiffPatchFilePath, "new-from-patch", "", "Show only new issues created in git patch with file path `PATH`") runCmd.Flags().StringVar(&ic.DiffFromRevision, "new-from-rev", "", wh("Show only new issues created after git revision `REV`"))
runCmd.Flags().StringVar(&ic.DiffPatchFilePath, "new-from-patch", "", wh("Show only new issues created in git patch with file path `PATH`"))
e.parseConfig(runCmd) e.parseConfig(runCmd)
} }
@ -134,7 +174,7 @@ func (e *Executor) runAnalysis(ctx context.Context, args []string) (<-chan resul
excludePatterns := e.cfg.Issues.ExcludePatterns excludePatterns := e.cfg.Issues.ExcludePatterns
if e.cfg.Issues.UseDefaultExcludes { if e.cfg.Issues.UseDefaultExcludes {
excludePatterns = append(excludePatterns, config.DefaultExcludePatterns...) excludePatterns = append(excludePatterns, config.GetDefaultExcludePatternsStrings()...)
} }
var excludeTotalPattern string var excludeTotalPattern string
if len(excludePatterns) != 0 { if len(excludePatterns) != 0 {
@ -207,9 +247,6 @@ func (e *Executor) runAndPrint(ctx context.Context, args []string) error {
} }
func (e *Executor) executeRun(cmd *cobra.Command, args []string) { func (e *Executor) executeRun(cmd *cobra.Command, args []string) {
logrus.Infof("Concurrency: %d, machine cpus count: %d",
e.cfg.Run.Concurrency, runtime.NumCPU())
needTrackResources := e.cfg.Run.IsVerbose || e.cfg.Run.PrintResourcesUsage needTrackResources := e.cfg.Run.IsVerbose || e.cfg.Run.PrintResourcesUsage
trackResourcesEndCh := make(chan struct{}) trackResourcesEndCh := make(chan struct{})
defer func() { // XXX: this defer must be before ctx.cancel defer defer func() { // XXX: this defer must be before ctx.cancel defer
@ -225,10 +262,6 @@ func (e *Executor) executeRun(cmd *cobra.Command, args []string) {
go watchResources(ctx, trackResourcesEndCh) go watchResources(ctx, trackResourcesEndCh)
} }
if e.cfg.Output.PrintWelcomeMessage {
fmt.Fprintln(printers.StdOut, "Run this tool in cloud on every github pull request in https://golangci.com for free (public repos)")
}
if err := e.runAndPrint(ctx, args); err != nil { if err := e.runAndPrint(ctx, args); err != nil {
logrus.Warnf("running error: %s", err) logrus.Warnf("running error: %s", err)
if e.exitCode == 0 { if e.exitCode == 0 {

View File

@ -14,29 +14,72 @@ const (
var OutFormats = []string{OutFormatColoredLineNumber, OutFormatLineNumber, OutFormatJSON} var OutFormats = []string{OutFormatColoredLineNumber, OutFormatLineNumber, OutFormatJSON}
var DefaultExcludePatterns = []string{ type ExcludePattern struct {
// errcheck Pattern string
"Error return value of .((os\\.)?std(out|err)\\..*|.*Close|os\\.Remove(All)?|.*printf?|os\\.(Un)?Setenv). is not checked", Linter string
Why string
}
// golint var DefaultExcludePatterns = []ExcludePattern{
"should have comment", {
"comment on exported method", Pattern: "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|os\\.Remove(All)?|.*printf?|os\\.(Un)?Setenv). is not checked",
"func name will be used as test\\.Test.* by other packages, and that stutters; consider calling this", Linter: "errcheck",
Why: "Almost all programs ignore errors on these functions and in most cases it's ok",
},
{
Pattern: "(should have comment|comment on exported method|should have a package comment)",
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: "Use of unsafe calls should be audited",
Linter: "gas",
Why: "Too many false-positives on 'unsafe' usage",
},
{
Pattern: "Subprocess launch(ed with variable|ing should be audited)",
Linter: "gas",
Why: "Too many false-positives for parametrized shell calls",
},
{
Pattern: "G104",
Linter: "gas",
Why: "Duplicated errcheck checks",
},
{
Pattern: "(Expect directory permissions to be 0750 or less|Expect file permissions to be 0600 or less)",
Linter: "gas",
Why: "Too many issues in popular repos",
},
{
Pattern: "Potential file inclusion via variable",
Linter: "gas",
Why: "False positive is triggered by 'src, err := ioutil.ReadFile(filename)'",
},
{
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",
},
}
// gas func GetDefaultExcludePatternsStrings() []string {
"G103:", // Use of unsafe calls should be audited var ret []string
"G104:", // disable what errcheck does: it reports on Close etc for _, p := range DefaultExcludePatterns {
"G204:", // Subprocess launching should be audited: too lot false positives ret = append(ret, p.Pattern)
"G301:", // Expect directory permissions to be 0750 or less }
"G302:", // Expect file permissions to be 0600 or less
"G304:", // Potential file inclusion via variable: `src, err := ioutil.ReadFile(filename)`
// govet return ret
"possible misuse of unsafe.Pointer",
"should have signature",
// megacheck
"ineffective break statement. Did you mean to break out of the outer loop", // developers tend to write in C-style with break in switch
} }
type Run struct { type Run struct {

View File

@ -59,6 +59,17 @@ func buildTemplateContext() (map[string]interface{}, error) {
lintersOutParts := bytes.Split(lintersOut, []byte("\n\n")) lintersOutParts := bytes.Split(lintersOut, []byte("\n\n"))
helpCmd := exec.Command("golangci-lint", "run", "-h")
helpCmd.Env = append(helpCmd.Env, os.Environ()...)
helpCmd.Env = append(helpCmd.Env, "HELP_RUN=1") // make default concurrency stable: don't depend on machine CPU number
help, err := helpCmd.Output()
if err != nil {
return nil, fmt.Errorf("can't run help cmd: %s", err)
}
helpLines := bytes.Split(help, []byte("\n"))
shortHelp := bytes.Join(helpLines[2:], []byte("\n"))
return map[string]interface{}{ return map[string]interface{}{
"GolangciYaml": string(golangciYaml), "GolangciYaml": string(golangciYaml),
"LintersCommandOutputEnabledOnly": string(lintersOutParts[0]), "LintersCommandOutputEnabledOnly": string(lintersOutParts[0]),
@ -66,6 +77,7 @@ func buildTemplateContext() (map[string]interface{}, error) {
"EnabledByDefaultLinters": getLintersListMarkdown(true), "EnabledByDefaultLinters": getLintersListMarkdown(true),
"DisabledByDefaultLinters": getLintersListMarkdown(false), "DisabledByDefaultLinters": getLintersListMarkdown(false),
"ThanksList": getThanksList(), "ThanksList": getThanksList(),
"RunHelpText": string(shortHelp),
}, nil }, nil
} }

View File

@ -74,7 +74,7 @@ func getGometalinterCommonArgs() []string {
"--vendor", "--vendor",
"--cyclo-over=30", "--cyclo-over=30",
"--dupl-threshold=150", "--dupl-threshold=150",
"--exclude", fmt.Sprintf("(%s)", strings.Join(config.DefaultExcludePatterns, "|")), "--exclude", fmt.Sprintf("(%s)", strings.Join(config.GetDefaultExcludePatternsStrings(), "|")),
"--disable-all", "--disable-all",
"--enable=vet", "--enable=vet",
"--enable=vetshadow", "--enable=vetshadow",