generate command line options section of README
This commit is contained in:
parent
4df5df2ab7
commit
9133ef4271
@ -10,7 +10,6 @@ output:
|
||||
format: colored-line-number
|
||||
print-issued-lines: true
|
||||
print-linter-name: true
|
||||
print-welcome: true
|
||||
|
||||
linters-settings:
|
||||
errcheck:
|
||||
|
@ -19,8 +19,4 @@ linters-settings:
|
||||
linters:
|
||||
enable-all: true
|
||||
disable:
|
||||
- maligned
|
||||
|
||||
issues:
|
||||
exclude:
|
||||
- should have a package comment
|
||||
- maligned
|
1
Makefile
1
Makefile
@ -2,7 +2,6 @@ test:
|
||||
go install ./cmd/...
|
||||
golangci-lint run -v
|
||||
golangci-lint run --fast --no-config -v
|
||||
golangci-lint run --fast --no-config -v
|
||||
golangci-lint run --no-config -v
|
||||
golangci-lint run --fast --no-config -v ./test/testdata/typecheck.go
|
||||
go test -v -race ./...
|
||||
|
170
README.md
170
README.md
@ -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.
|
||||
|
||||
# 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.
|
||||
|
||||
@ -172,7 +175,7 @@ On average golangci-lint consumes 1.35 times less memory.
|
||||
|
||||
# Supported Linters
|
||||
To see a list of supported linters and which linters are enabled/disabled by default execute a command
|
||||
```bash
|
||||
```
|
||||
golangci-lint linters
|
||||
```
|
||||
|
||||
@ -204,99 +207,77 @@ golangci-lint linters
|
||||
|
||||
# Configuration
|
||||
## Command-Line Options
|
||||
Run next command to see their description and defaults.
|
||||
```bash
|
||||
```
|
||||
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
|
||||
GolangCI-Lint looks for next config paths in the current directory:
|
||||
- `.golangci.yml`
|
||||
@ -330,11 +311,6 @@ linters:
|
||||
enable-all: true
|
||||
disable:
|
||||
- maligned
|
||||
|
||||
issues:
|
||||
exclude:
|
||||
- should have a package comment
|
||||
|
||||
```
|
||||
|
||||
# False Positives
|
||||
|
@ -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.
|
||||
|
||||
# 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.
|
||||
|
||||
@ -150,7 +153,7 @@ On average golangci-lint consumes 1.35 times less memory.
|
||||
|
||||
# Supported Linters
|
||||
To see a list of supported linters and which linters are enabled/disabled by default execute a command
|
||||
```bash
|
||||
```
|
||||
golangci-lint linters
|
||||
```
|
||||
|
||||
@ -162,99 +165,11 @@ golangci-lint linters
|
||||
|
||||
# Configuration
|
||||
## Command-Line Options
|
||||
Run next command to see their description and defaults.
|
||||
```bash
|
||||
```
|
||||
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
|
||||
GolangCI-Lint looks for next config paths in the current directory:
|
||||
- `.golangci.yml`
|
||||
|
@ -56,6 +56,14 @@ func (e *Executor) persistentPreRun(cmd *cobra.Command, args []string) {
|
||||
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() {
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "golangci-lint",
|
||||
@ -69,11 +77,13 @@ func (e *Executor) initRoot() {
|
||||
PersistentPreRun: e.persistentPostRun,
|
||||
PersistentPostRun: e.persistentPreRun,
|
||||
}
|
||||
rootCmd.PersistentFlags().BoolVarP(&e.cfg.Run.IsVerbose, "verbose", "v", false, "verbose output")
|
||||
rootCmd.PersistentFlags().StringVar(&e.cfg.Run.CPUProfilePath, "cpu-profile-path", "", "Path to CPU profile output file")
|
||||
rootCmd.PersistentFlags().StringVar(&e.cfg.Run.MemProfilePath, "mem-profile-path", "", "Path to memory profile output file")
|
||||
rootCmd.PersistentFlags().IntVarP(&e.cfg.Run.Concurrency, "concurrency", "j", runtime.NumCPU(), "Concurrency (default NumCPU)")
|
||||
rootCmd.PersistentFlags().BoolVar(&e.cfg.Run.PrintVersion, "version", false, "Print version")
|
||||
rootCmd.PersistentFlags().BoolVarP(&e.cfg.Run.IsVerbose, "verbose", "v", false, wh("verbose output"))
|
||||
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", "", wh("Path to memory profile output file"))
|
||||
rootCmd.PersistentFlags().IntVarP(&e.cfg.Run.Concurrency, "concurrency", "j", getDefaultConcurrency(), wh("Concurrency (default NumCPU)"))
|
||||
if e.commit != "" {
|
||||
rootCmd.PersistentFlags().BoolVar(&e.cfg.Run.PrintVersion, "version", false, wh("Print version"))
|
||||
}
|
||||
|
||||
e.rootCmd = rootCmd
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/lintersdb"
|
||||
@ -29,92 +30,131 @@ const (
|
||||
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() {
|
||||
var runCmd = &cobra.Command{
|
||||
Use: "run",
|
||||
Short: "Run linters",
|
||||
Short: welcomeMessage,
|
||||
Run: e.executeRun,
|
||||
}
|
||||
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
|
||||
oc := &e.cfg.Output
|
||||
runCmd.Flags().StringVar(&oc.Format, "out-format",
|
||||
config.OutFormatColoredLineNumber,
|
||||
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.PrintLinterName, "print-linter-name", true, "Print linter name in issue line")
|
||||
runCmd.Flags().BoolVar(&oc.PrintWelcomeMessage, "print-welcome", false, "Print welcome message")
|
||||
wh(fmt.Sprintf("Format of output: %s", strings.Join(config.OutFormats, "|"))))
|
||||
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, wh("Print linter name in issue line"))
|
||||
runCmd.Flags().BoolVar(&oc.PrintWelcomeMessage, "print-welcome", false, wh("Print welcome message"))
|
||||
hideFlag("print-welcome") // no longer used
|
||||
|
||||
// Run config
|
||||
rc := &e.cfg.Run
|
||||
runCmd.Flags().IntVar(&rc.ExitCodeIfIssuesFound, "issues-exit-code",
|
||||
1, "Exit code when issues were found")
|
||||
runCmd.Flags().StringSliceVar(&rc.BuildTags, "build-tags", []string{}, "Build tags (not all linters support them)")
|
||||
runCmd.Flags().DurationVar(&rc.Deadline, "deadline", time.Minute, "Deadline for total work")
|
||||
runCmd.Flags().BoolVar(&rc.AnalyzeTests, "tests", false, "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().StringVarP(&rc.Config, "config", "c", "", "Read config from file path `PATH`")
|
||||
runCmd.Flags().BoolVar(&rc.NoConfig, "no-config", false, "Don't read config")
|
||||
1, wh("Exit code when issues were found"))
|
||||
runCmd.Flags().StringSliceVar(&rc.BuildTags, "build-tags", []string{}, wh("Build tags (not all linters support them)"))
|
||||
runCmd.Flags().DurationVar(&rc.Deadline, "deadline", time.Minute, wh("Deadline for total work"))
|
||||
runCmd.Flags().BoolVar(&rc.AnalyzeTests, "tests", false, wh("Analyze tests (*_test.go)"))
|
||||
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", "", wh("Read config from file path `PATH`"))
|
||||
runCmd.Flags().BoolVar(&rc.NoConfig, "no-config", false, wh("Don't read config"))
|
||||
|
||||
// Linters settings config
|
||||
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")
|
||||
hideFlag("errcheck.check-type-assertions")
|
||||
|
||||
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")
|
||||
hideFlag("govet.check-shadowing")
|
||||
|
||||
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")
|
||||
hideFlag("gofmt.simplify")
|
||||
|
||||
runCmd.Flags().IntVar(&lsc.Gocyclo.MinComplexity, "gocyclo.min-complexity",
|
||||
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")
|
||||
hideFlag("maligned.suggest-new")
|
||||
|
||||
runCmd.Flags().IntVar(&lsc.Dupl.Threshold, "dupl.threshold",
|
||||
150, "Dupl: Minimal threshold to detect copy-paste")
|
||||
hideFlag("dupl.threshold")
|
||||
|
||||
runCmd.Flags().IntVar(&lsc.Goconst.MinStringLen, "goconst.min-len",
|
||||
3, "Goconst: minimum constant string length")
|
||||
hideFlag("goconst.min-len")
|
||||
runCmd.Flags().IntVar(&lsc.Goconst.MinOccurrencesCount, "goconst.min-occurrences",
|
||||
3, "Goconst: minimum occurrences of constant string count to trigger issue")
|
||||
hideFlag("goconst.min-occurrences")
|
||||
|
||||
// (@dixonwille) These flag is only used for testing purposes.
|
||||
runCmd.Flags().StringSliceVar(&lsc.Depguard.Packages, "depguard.packages", nil,
|
||||
"Depguard: packages to add to the list")
|
||||
if err := runCmd.Flags().MarkHidden("depguard.packages"); err != nil {
|
||||
panic(err) //Considering The only time this is called is if name does not exist
|
||||
}
|
||||
hideFlag("depguard.packages")
|
||||
|
||||
runCmd.Flags().BoolVar(&lsc.Depguard.IncludeGoRoot, "depguard.include-go-root", false,
|
||||
"Depguard: check list against standard lib")
|
||||
if err := runCmd.Flags().MarkHidden("depguard.include-go-root"); err != nil {
|
||||
panic(err) //Considering The only time this is called is if name does not exist
|
||||
}
|
||||
hideFlag("depguard.include-go-root")
|
||||
|
||||
// Linters config
|
||||
lc := &e.cfg.Linters
|
||||
runCmd.Flags().StringSliceVarP(&lc.Enable, "enable", "E", []string{}, "Enable specific linter")
|
||||
runCmd.Flags().StringSliceVarP(&lc.Disable, "disable", "D", []string{}, "Disable specific linter")
|
||||
runCmd.Flags().BoolVar(&lc.EnableAll, "enable-all", false, "Enable all linters")
|
||||
runCmd.Flags().BoolVar(&lc.DisableAll, "disable-all", false, "Disable all linters")
|
||||
runCmd.Flags().StringSliceVarP(&lc.Enable, "enable", "E", []string{}, wh("Enable specific linter"))
|
||||
runCmd.Flags().StringSliceVarP(&lc.Disable, "disable", "D", []string{}, wh("Disable specific linter"))
|
||||
runCmd.Flags().BoolVar(&lc.EnableAll, "enable-all", false, wh("Enable all linters"))
|
||||
runCmd.Flags().BoolVar(&lc.DisableAll, "disable-all", false, wh("Disable all linters"))
|
||||
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(), "|")))
|
||||
runCmd.Flags().BoolVar(&lc.Fast, "fast", false, "Run only fast linters from enabled linters set")
|
||||
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, wh("Run only fast linters from enabled linters set"))
|
||||
|
||||
// Issues config
|
||||
ic := &e.cfg.Issues
|
||||
runCmd.Flags().StringSliceVarP(&ic.ExcludePatterns, "exclude", "e", []string{}, "Exclude issue by regexp")
|
||||
runCmd.Flags().BoolVar(&ic.UseDefaultExcludes, "exclude-use-default", true,
|
||||
fmt.Sprintf("Use or not use default excludes: (%s)", strings.Join(config.DefaultExcludePatterns, "|")))
|
||||
runCmd.Flags().StringSliceVarP(&ic.ExcludePatterns, "exclude", "e", []string{}, wh("Exclude issue by regexp"))
|
||||
runCmd.Flags().BoolVar(&ic.UseDefaultExcludes, "exclude-use-default", true, getDefaultExcludeHelp())
|
||||
|
||||
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.MaxSameIssues, "max-same-issues", 3, "Maximum count of issues with the same text. 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, 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().StringVar(&ic.DiffFromRevision, "new-from-rev", "", "Show only new issues created after git revision `REV`")
|
||||
runCmd.Flags().StringVar(&ic.DiffPatchFilePath, "new-from-patch", "", "Show only new issues created in git patch with file path `PATH`")
|
||||
runCmd.Flags().BoolVarP(&ic.Diff, "new", "n", false,
|
||||
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.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)
|
||||
}
|
||||
@ -134,7 +174,7 @@ func (e *Executor) runAnalysis(ctx context.Context, args []string) (<-chan resul
|
||||
|
||||
excludePatterns := e.cfg.Issues.ExcludePatterns
|
||||
if e.cfg.Issues.UseDefaultExcludes {
|
||||
excludePatterns = append(excludePatterns, config.DefaultExcludePatterns...)
|
||||
excludePatterns = append(excludePatterns, config.GetDefaultExcludePatternsStrings()...)
|
||||
}
|
||||
var excludeTotalPattern string
|
||||
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) {
|
||||
logrus.Infof("Concurrency: %d, machine cpus count: %d",
|
||||
e.cfg.Run.Concurrency, runtime.NumCPU())
|
||||
|
||||
needTrackResources := e.cfg.Run.IsVerbose || e.cfg.Run.PrintResourcesUsage
|
||||
trackResourcesEndCh := make(chan struct{})
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
logrus.Warnf("running error: %s", err)
|
||||
if e.exitCode == 0 {
|
||||
|
@ -14,29 +14,72 @@ const (
|
||||
|
||||
var OutFormats = []string{OutFormatColoredLineNumber, OutFormatLineNumber, OutFormatJSON}
|
||||
|
||||
var DefaultExcludePatterns = []string{
|
||||
// errcheck
|
||||
"Error return value of .((os\\.)?std(out|err)\\..*|.*Close|os\\.Remove(All)?|.*printf?|os\\.(Un)?Setenv). is not checked",
|
||||
type ExcludePattern struct {
|
||||
Pattern string
|
||||
Linter string
|
||||
Why string
|
||||
}
|
||||
|
||||
// golint
|
||||
"should have comment",
|
||||
"comment on exported method",
|
||||
"func name will be used as test\\.Test.* by other packages, and that stutters; consider calling this",
|
||||
var DefaultExcludePatterns = []ExcludePattern{
|
||||
{
|
||||
Pattern: "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|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",
|
||||
},
|
||||
{
|
||||
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
|
||||
"G103:", // Use of unsafe calls should be audited
|
||||
"G104:", // disable what errcheck does: it reports on Close etc
|
||||
"G204:", // Subprocess launching should be audited: too lot false positives
|
||||
"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)`
|
||||
func GetDefaultExcludePatternsStrings() []string {
|
||||
var ret []string
|
||||
for _, p := range DefaultExcludePatterns {
|
||||
ret = append(ret, p.Pattern)
|
||||
}
|
||||
|
||||
// govet
|
||||
"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
|
||||
return ret
|
||||
}
|
||||
|
||||
type Run struct {
|
||||
|
@ -59,6 +59,17 @@ func buildTemplateContext() (map[string]interface{}, error) {
|
||||
|
||||
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{}{
|
||||
"GolangciYaml": string(golangciYaml),
|
||||
"LintersCommandOutputEnabledOnly": string(lintersOutParts[0]),
|
||||
@ -66,6 +77,7 @@ func buildTemplateContext() (map[string]interface{}, error) {
|
||||
"EnabledByDefaultLinters": getLintersListMarkdown(true),
|
||||
"DisabledByDefaultLinters": getLintersListMarkdown(false),
|
||||
"ThanksList": getThanksList(),
|
||||
"RunHelpText": string(shortHelp),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ func getGometalinterCommonArgs() []string {
|
||||
"--vendor",
|
||||
"--cyclo-over=30",
|
||||
"--dupl-threshold=150",
|
||||
"--exclude", fmt.Sprintf("(%s)", strings.Join(config.DefaultExcludePatterns, "|")),
|
||||
"--exclude", fmt.Sprintf("(%s)", strings.Join(config.GetDefaultExcludePatternsStrings(), "|")),
|
||||
"--disable-all",
|
||||
"--enable=vet",
|
||||
"--enable=vetshadow",
|
||||
|
Loading…
x
Reference in New Issue
Block a user