generate parts of README automatically
This commit is contained in:
parent
5236feb1ae
commit
034728ec94
121
README.md
121
README.md
@ -77,16 +77,17 @@ GolangCI-Lint can be used with zero configuration. By default next linters are e
|
||||
```
|
||||
$ golangci-lint linters
|
||||
Enabled by default linters:
|
||||
govet: Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
|
||||
errcheck: Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
|
||||
staticcheck: Staticcheck is go vet on steroids, applying a ton of static analysis checks
|
||||
unused: Checks Go code for unused constants, variables, functions and types
|
||||
gosimple: Linter for Go source code that specialises on simplifying code
|
||||
gas: Inspects source code for security problems
|
||||
structcheck: Finds unused struct fields
|
||||
varcheck: Finds unused global variables and constants
|
||||
ineffassign: Detects when assignments to existing variables are not used
|
||||
deadcode: Finds unused code
|
||||
govet: Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string [fast: true]
|
||||
errcheck: Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases [fast: false]
|
||||
staticcheck: Staticcheck is a go vet on steroids, applying a ton of static analysis checks [fast: false]
|
||||
unused: Checks Go code for unused constants, variables, functions and types [fast: false]
|
||||
gosimple: Linter for Go source code that specializes in simplifying a code [fast: false]
|
||||
gas: Inspects source code for security problems [fast: false]
|
||||
structcheck: Finds an unused struct fields [fast: false]
|
||||
varcheck: Finds unused global variables and constants [fast: false]
|
||||
ineffassign: Detects when assignments to existing variables are not used [fast: true]
|
||||
deadcode: Finds unused code [fast: false]
|
||||
typecheck: Like the front-end of a Go compiler, parses and type-checks Go code [fast: false]
|
||||
```
|
||||
|
||||
and next linters are disabled by default:
|
||||
@ -94,17 +95,17 @@ and next linters are disabled by default:
|
||||
$ golangci-lint linters
|
||||
...
|
||||
Disabled by default linters:
|
||||
golint: Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes
|
||||
interfacer: Linter that suggests narrower interface types
|
||||
unconvert: Remove unnecessary type conversions
|
||||
dupl: Tool for code clone detection
|
||||
goconst: Finds repeated strings that could be replaced by a constant
|
||||
gocyclo: Computes and checks the cyclomatic complexity of functions
|
||||
gofmt: Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
|
||||
goimports: Goimports does everything that gofmt does. Additionally it checks unused imports
|
||||
maligned: Tool to detect Go structs that would take less memory if their fields were sorted
|
||||
megacheck: 3 sub-linters in one: unused, gosimple and staticcheck
|
||||
depguard: Go linter that checks if package imports are in a list of acceptable packages
|
||||
golint: Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes [fast: true]
|
||||
interfacer: Linter that suggests narrower interface types [fast: false]
|
||||
unconvert: Remove unnecessary type conversions [fast: false]
|
||||
dupl: Tool for code clone detection [fast: true]
|
||||
goconst: Finds repeated strings that could be replaced by a constant [fast: true]
|
||||
gocyclo: Computes and checks the cyclomatic complexity of functions [fast: true]
|
||||
gofmt: Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification [fast: true]
|
||||
goimports: Goimports does everything that gofmt does. Additionally it checks unused imports [fast: true]
|
||||
maligned: Tool to detect Go structs that would take less memory if their fields were sorted [fast: false]
|
||||
megacheck: 3 sub-linters in one: unused, gosimple and staticcheck [fast: false]
|
||||
depguard: Go linter that checks if package imports are in a list of acceptable packages [fast: false]
|
||||
```
|
||||
|
||||
Pass `-E/--enable` to enable linter and `-D/--disable` to disable:
|
||||
@ -174,30 +175,30 @@ golangci-lint linters
|
||||
```
|
||||
|
||||
## Enabled By Default Linters
|
||||
- [go vet](https://golang.org/cmd/vet/) - Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
|
||||
- [errcheck](https://github.com/kisielk/errcheck): Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
|
||||
- [staticcheck](https://staticcheck.io/): Staticcheck is a go vet on steroids, applying a ton of static analysis checks
|
||||
- [unused](https://github.com/dominikh/go-tools/tree/master/cmd/unused): Checks Go code for unused constants, variables, functions, and types
|
||||
- [gosimple](https://github.com/dominikh/go-tools/tree/master/cmd/gosimple): Linter for Go source code that specializes in simplifying a code
|
||||
- [gas](https://github.com/GoASTScanner/gas): Inspects source code for security problems
|
||||
- [structcheck](https://github.com/opennota/check): Finds an unused struct fields
|
||||
- [varcheck](https://github.com/opennota/check): Finds unused global variables and constants
|
||||
- [ineffassign](https://github.com/gordonklaus/ineffassign): Detects when assignments to existing variables are not used
|
||||
- [deadcode](https://github.com/remyoudompheng/go-misc/tree/master/deadcode): Finds unused code
|
||||
- typecheck: Like the front-end of a Go compiler, parses and type-checks Go code. Similar to [gotype](https://godoc.org/golang.org/x/tools/cmd/gotype).
|
||||
- [govet](https://golang.org/cmd/vet/) - Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
|
||||
- [errcheck](https://github.com/kisielk/errcheck) - Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
|
||||
- [staticcheck](https://staticcheck.io/) - Staticcheck is a go vet on steroids, applying a ton of static analysis checks
|
||||
- [unused](https://github.com/dominikh/go-tools/tree/master/cmd/unused) - Checks Go code for unused constants, variables, functions and types
|
||||
- [gosimple](https://github.com/dominikh/go-tools/tree/master/cmd/gosimple) - Linter for Go source code that specializes in simplifying a code
|
||||
- [gas](https://github.com/GoASTScanner/gas) - Inspects source code for security problems
|
||||
- [structcheck](https://github.com/opennota/check) - Finds an unused struct fields
|
||||
- [varcheck](https://github.com/opennota/check) - Finds unused global variables and constants
|
||||
- [ineffassign](https://github.com/gordonklaus/ineffassign) - Detects when assignments to existing variables are not used
|
||||
- [deadcode](https://github.com/remyoudompheng/go-misc/tree/master/deadcode) - Finds unused code
|
||||
- typecheck - Like the front-end of a Go compiler, parses and type-checks Go code
|
||||
|
||||
## Disabled By Default Linters (`-E/--enable`)
|
||||
- [golint](https://github.com/golang/lint): Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes
|
||||
- [interfacer](https://github.com/mvdan/interfacer): Linter that suggests narrower interface types
|
||||
- [unconvert](https://github.com/mdempsky/unconvert): Remove unnecessary type conversions
|
||||
- [dupl](https://github.com/mibk/dupl): Tool for code clone detection
|
||||
- [goconst](https://github.com/jgautheron/goconst): Finds repeated strings that could be replaced by a constant
|
||||
- [gocyclo](https://github.com/alecthomas/gocyclo): Computes and checks the cyclomatic complexity of functions
|
||||
- [gofmt](https://golang.org/cmd/gofmt/): Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
|
||||
- [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports): Goimports does everything that gofmt does. Additionally it checks unused imports
|
||||
- [maligned](https://github.com/mdempsky/maligned): Tool to detect Go structs that would take less memory if their fields were sorted
|
||||
- [megacheck](https://github.com/dominikh/go-tools/tree/master/cmd/megacheck): 3 sub-linters in one: unused, gosimple and staticcheck
|
||||
- [depguard](https://github.com/OpenPeeDeeP/depguard): Go linter that checks if package imports are in a list of acceptable packages
|
||||
- [golint](https://github.com/golang/lint) - Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes
|
||||
- [interfacer](https://github.com/mvdan/interfacer) - Linter that suggests narrower interface types
|
||||
- [unconvert](https://github.com/mdempsky/unconvert) - Remove unnecessary type conversions
|
||||
- [dupl](https://github.com/mibk/dupl) - Tool for code clone detection
|
||||
- [goconst](https://github.com/jgautheron/goconst) - Finds repeated strings that could be replaced by a constant
|
||||
- [gocyclo](https://github.com/alecthomas/gocyclo) - Computes and checks the cyclomatic complexity of functions
|
||||
- [gofmt](https://golang.org/cmd/gofmt/) - Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
|
||||
- [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports) - Goimports does everything that gofmt does. Additionally it checks unused imports
|
||||
- [maligned](https://github.com/mdempsky/maligned) - Tool to detect Go structs that would take less memory if their fields were sorted
|
||||
- [megacheck](https://github.com/dominikh/go-tools/tree/master/cmd/megacheck) - 3 sub-linters in one: unused, gosimple and staticcheck
|
||||
- [depguard](https://github.com/OpenPeeDeeP/depguard) - Go linter that checks if package imports are in a list of acceptable packages
|
||||
|
||||
# Configuration
|
||||
## Command-Line Options
|
||||
@ -306,7 +307,6 @@ There is a [`.golangci.yml`](https://github.com/golangci/golangci-lint/blob/mast
|
||||
It's a [.golangci.yml](https://github.com/golangci/golangci-lint/blob/master/.golangci.yml) of this repo: we enable more linters than by default and make their settings more strict:
|
||||
```yaml
|
||||
run:
|
||||
deadline: 30s
|
||||
tests: true
|
||||
|
||||
linters-settings:
|
||||
@ -410,26 +410,19 @@ Thanks to [alecthomas/gometalinter](https://github.com/alecthomas/gometalinter)
|
||||
Thanks to [bradleyfalzon/revgrep](https://github.com/bradleyfalzon/revgrep) for cool diff tool.
|
||||
|
||||
Thanks to developers and authors of used linters:
|
||||
- [golang/vet](https://golang.org/cmd/vet/)
|
||||
- [kisielk/errcheck](https://github.com/kisielk/errcheck)
|
||||
- [staticcheck](https://staticcheck.io/)
|
||||
- [dominikh/go-tools/unused](https://github.com/dominikh/go-tools/tree/master/cmd/unused)
|
||||
- [dominikh/go-tools/gosimple](https://github.com/dominikh/go-tools/tree/master/cmd/gosimple)
|
||||
- [GoASTScanner/gas](https://github.com/GoASTScanner/gas)
|
||||
- [opennota/check](https://github.com/opennota/check)
|
||||
- [gordonklaus/ineffassign](https://github.com/gordonklaus/ineffassign)
|
||||
- [remyoudompheng/go-misc/deadcode](https://github.com/remyoudompheng/go-misc/tree/master/deadcode)
|
||||
- [golang/lint](https://github.com/golang/lint)
|
||||
- [mvdan/interfacer](https://github.com/mvdan/interfacer)
|
||||
- [mdempsky/unconvert](https://github.com/mdempsky/unconvert)
|
||||
- [mibk/dupl](https://github.com/mibk/dupl)
|
||||
- [jgautheron/goconst](https://github.com/jgautheron/goconst)
|
||||
- [alecthomas/gocyclo](https://github.com/alecthomas/gocyclo)
|
||||
- [golang/gofmt](https://golang.org/cmd/gofmt/)
|
||||
- [golang/x/tools/goimports](https://godoc.org/golang.org/x/tools/cmd/goimports)
|
||||
- [mdempsky/maligned](https://github.com/mdempsky/maligned)
|
||||
- [dominikh/go-tools/megacheck](https://github.com/dominikh/go-tools/tree/master/cmd/megacheck)
|
||||
- [OpenPeeDeeP/depguard](https://github.com/OpenPeeDeeP/depguard)
|
||||
- [kisielk](https://github.com/kisielk)
|
||||
- [golang](https://github.com/golang)
|
||||
- [dominikh](https://github.com/dominikh)
|
||||
- [GoASTScanner](https://github.com/GoASTScanner)
|
||||
- [opennota](https://github.com/opennota)
|
||||
- [mvdan](https://github.com/mvdan)
|
||||
- [mdempsky](https://github.com/mdempsky)
|
||||
- [gordonklaus](https://github.com/gordonklaus)
|
||||
- [mibk](https://github.com/mibk)
|
||||
- [jgautheron](https://github.com/jgautheron)
|
||||
- [remyoudompheng](https://github.com/remyoudompheng)
|
||||
- [alecthomas](https://github.com/alecthomas)
|
||||
- [OpenPeeDeeP](https://github.com/OpenPeeDeeP)
|
||||
|
||||
# Future Plans
|
||||
1. Upstream all changes of forked linters.
|
||||
|
360
README.md.tmpl
Normal file
360
README.md.tmpl
Normal file
@ -0,0 +1,360 @@
|
||||
# GolangCI-Lint
|
||||
[](https://travis-ci.com/golangci/golangci-lint)
|
||||
|
||||
GolangCI-Lint is a linters aggregator. It's fast: on average [5 times faster](#performance) than gometalinter. It's [easy to integrate and use](#issues-options), has [nice output](#quick-start) and has a minimum number of false positives.
|
||||
|
||||
GolangCI-Lint has [integrations](#ide-integrations) with VS Code, GNU Emacs, Sublime Text.
|
||||
|
||||
Sponsored by [GolangCI.com](https://golangci.com): SaaS service for running linters on Github pull requests. Free for Open Source.
|
||||
|
||||
<a href="https://golangci.com/"><img src="docs/go.png" width="250px"></a>
|
||||
|
||||
* [Install](#install)
|
||||
* [Demo](#demo)
|
||||
* [Quick Start](#quick-start)
|
||||
* [Comparison](#comparison)
|
||||
* [<code>golangci-lint</code> vs <code>gometalinter</code>](#golangci-lint-vs-gometalinter)
|
||||
* [<code>golangci-lint</code> vs Run Needed Linters Manually](#golangci-lint-vs-run-needed-linters-manually)
|
||||
* [Performance](#performance)
|
||||
* [Comparison with gometalinter](#comparison-with-gometalinter)
|
||||
* [Supported Linters](#supported-linters)
|
||||
* [Enabled By Default Linters](#enabled-by-default-linters)
|
||||
* [Disabled By Default Linters (-E/--enable)](#disabled-by-default-linters--e--enable)
|
||||
* [Configuration](#configuration)
|
||||
* [Command-Line Options](#command-line-options)
|
||||
* [Configuration File](#configuration-file)
|
||||
* [False Positives](#false-positives)
|
||||
* [IDE integrations](#ide-integrations)
|
||||
* [Internals](#internals)
|
||||
* [FAQ](#faq)
|
||||
* [Thanks](#thanks)
|
||||
* [Future Plans](#future-plans)
|
||||
* [Contact Information](#contact-information)
|
||||
|
||||
# Install
|
||||
Recommended way to install is:
|
||||
```bash
|
||||
go get -u github.com/golangci/golangci-lint/cmd/golangci-lint
|
||||
```
|
||||
|
||||
You can also install it by brew:
|
||||
```bash
|
||||
brew install golangci/tap/golangci-lint
|
||||
```
|
||||
|
||||
For CI you can use fast local installation:
|
||||
```bash
|
||||
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh
|
||||
```
|
||||
|
||||
Check the [releases page](https://github.com/golangci/golangci-lint/releases) to fix the version.
|
||||
|
||||
# Demo
|
||||
Example of output:
|
||||

|
||||
|
||||
Short 1.5 min video demo of analyzing [beego](https://github.com/astaxie/beego).
|
||||
[](https://asciinema.org/a/1a1qaEXMlOSeRyvASbnuFomah)
|
||||
|
||||
# Quick Start
|
||||
To run golangci-lint execute:
|
||||
```bash
|
||||
golangci-lint run
|
||||
```
|
||||
|
||||
It's an equivalent of executing:
|
||||
```bash
|
||||
golangci-lint run ./...
|
||||
```
|
||||
|
||||
You can choose which directories and files to analyze:
|
||||
```bash
|
||||
golangci-lint run dir1 dir2/... dir3/file1.go
|
||||
```
|
||||
Directories are analyzed NOT recursively, to analyze them recursively append `/...` to their path.
|
||||
|
||||
GolangCI-Lint can be used with zero configuration. By default next linters are enabled:
|
||||
```
|
||||
$ golangci-lint linters
|
||||
{{.LintersCommandOutputEnabledOnly}}
|
||||
```
|
||||
|
||||
and next linters are disabled by default:
|
||||
```
|
||||
$ golangci-lint linters
|
||||
...
|
||||
{{.LintersCommandOutputDisabledOnly}}
|
||||
```
|
||||
|
||||
Pass `-E/--enable` to enable linter and `-D/--disable` to disable:
|
||||
```bash
|
||||
$ golangci-lint run --disable-all -E errcheck
|
||||
```
|
||||
|
||||
# Comparison
|
||||
## `golangci-lint` vs `gometalinter`
|
||||
GolangCI-Lint was created to fix next issues with `gometalinter`:
|
||||
1. Slow work: `gometalinter` usually works for minutes in average projects. **GolangCI-Lint works [2-7x times faster](#performance)** by [reusing work](#internals).
|
||||
2. Huge memory consumption: parallel linters don't share the same program representation and can eat `n` times more memory (`n` - concurrency). GolangCI-Lint fixes it by sharing representation and **eats 1.35x less memory**.
|
||||
3. Can't set honest concurrency: if you set it to `n` it can take up to `n*n` threads because of forced threads in specific linters. `gometalinter` can't do anything about it, because it runs linters as black-boxes in forked processes. In GolangCI-Lint we run all linters in one process and fully control them. Configured concurrency will be honest.
|
||||
This issue is important because often you'd like to set concurrency to CPUs count minus one to **not freeze your PC** and be able to work on it while analyzing code.
|
||||
4. Lack of nice output. We like how compilers `gcc` and `clang` format their warnings: **using colors, printing of warned line and showing position in line**.
|
||||
5. Too many issues. GolangCI-Lint cuts a lot of issues by using default exclude list of common false-positives. Also, it has enabled by default **smart issues processing**: merge multiple issues for one line, merge issues with the same text or from the same linter. All of these smart processors can be configured by the user.
|
||||
6. Integration to large codebases. A good way to start using linters in a large project is not to fix all hundreds on existing issues, but setup CI and **fix only issues in new commits**. You can use `revgrep` for it, but it's yet another utility to install and configure. With `golangci-lint` it's much easier: `revgrep` is already built into `golangci-lint` and you can use it with one option (`-n, --new` or `--new-from-rev`).
|
||||
7. Installation. With `gometalinter`, you need to run linters installation step. It's easy to forget this step and have stale linters. It also complicates CI setup. GolangCI-Lint requires **no installation of linters**.
|
||||
8. **Yaml or toml config**. Gometalinter's JSON isn't convenient for configuration files.
|
||||
|
||||
## `golangci-lint` vs Run Needed Linters Manually
|
||||
1. It will be much slower because `golangci-lint` runs all linters in parallel and shares 50-80% of linters work.
|
||||
2. It will have less control and more false-positives: some linters can't be properly configured without hacks.
|
||||
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`).
|
||||
|
||||
We measure peak memory usage (RSS) by tracking of processes RSS every 5 ms.
|
||||
|
||||
## Comparison with gometalinter
|
||||
We compare golangci-lint and gometalinter in default mode, but explicitly specify all linters to enable because of small differences in the default configuration.
|
||||
```bash
|
||||
$ golangci-lint run --no-config --issues-exit-code=0 --deadline=30m \
|
||||
--disable-all --enable=deadcode --enable=gocyclo --enable=golint --enable=varcheck \
|
||||
--enable=structcheck --enable=maligned --enable=errcheck --enable=dupl --enable=ineffassign \
|
||||
--enable=interfacer --enable=unconvert --enable=goconst --enable=gas --enable=megacheck
|
||||
$ gometalinter --deadline=30m --vendor --cyclo-over=30 --dupl-threshold=150 \
|
||||
--exclude=<defaul golangci-lint excludes> --skip=testdata --skip=builtin \
|
||||
--disable-all --enable=deadcode --enable=gocyclo --enable=golint --enable=varcheck \
|
||||
--enable=structcheck --enable=maligned --enable=errcheck --enable=dupl --enable=ineffassign \
|
||||
--enable=interfacer --enable=unconvert --enable=goconst --enable=gas --enable=megacheck
|
||||
./...
|
||||
```
|
||||
|
||||
| Repository | GolangCI Time | GolangCI Is Faster than Gometalinter | GolangCI Memory | GolangCI eats less memory than Gometalinter |
|
||||
| ---------- | ------------- | ------------------------------------ | --------------- | ------------------------------------------- |
|
||||
| gometalinter repo, 4 kLoC | 6s | **6.4x** | 0.7GB | 1.5x |
|
||||
| self-repo, 4 kLoC | 12s | **7.5x** | 1.2GB | 1.7x |
|
||||
| beego, 50 kLoC | 10s | **4.2x** | 1.4GB | 1.1x |
|
||||
| hugo, 70 kLoC | 15s | **6.1x** | 1.6GB | 1.8x |
|
||||
| consul, 127 kLoC | 58s | **4x** | 2.7GB | 1.7x |
|
||||
| terraform, 190 kLoC | 2m13s | **1.6x** | 4.8GB | 1x |
|
||||
| go-ethereum, 250 kLoC | 33s | **5x** | 3.6GB | 1x |
|
||||
| go source, 1300 kLoC | 2m45s | **2x** | 4.7GB | 1x |
|
||||
|
||||
|
||||
**On average golangci-lint is 4.6 times faster** than gometalinter. Maximum difference is in the
|
||||
self-repo: **7.5 times faster**, minimum difference is in terraform source code repo: 1.8 times faster.
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
## Enabled By Default Linters
|
||||
{{.EnabledByDefaultLinters}}
|
||||
|
||||
## Disabled By Default Linters (`-E/--enable`)
|
||||
{{.DisabledByDefaultLinters}}
|
||||
|
||||
# Configuration
|
||||
## Command-Line Options
|
||||
Run next command to see their description and defaults.
|
||||
```bash
|
||||
golangci-lint run -h
|
||||
```
|
||||
|
||||
### 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`
|
||||
- `.golangci.toml`
|
||||
- `.golangci.json`
|
||||
|
||||
Configuration options inside the file are identical to command-line options.
|
||||
There is a [`.golangci.yml`](https://github.com/golangci/golangci-lint/blob/master/.golangci.example.yml) with all supported options.
|
||||
|
||||
It's a [.golangci.yml](https://github.com/golangci/golangci-lint/blob/master/.golangci.yml) of this repo: we enable more linters than by default and make their settings more strict:
|
||||
```yaml
|
||||
{{.GolangciYaml}}
|
||||
```
|
||||
|
||||
# False Positives
|
||||
False positives are inevitable, but we did our best to reduce their count. For example, we have an enabled by default set of [exclude patterns](#issues-options). If false positive occurred you have next choices:
|
||||
1. Exclude issue by text using command-line option `-e` or config option `issues.exclude`. It's helpful when you decided to ignore all issues of this type.
|
||||
2. Exclude this one issue by using special comment `// nolint[:linter1,linter2,...]` on issued line.
|
||||
Comment `// nolint` disables all issues reporting on this line. Comment e.g. `// nolint:govet` disables only govet issues for this line.
|
||||
|
||||
Please create [GitHub Issues here](https://github.com/golangci/golangci-lint/issues/new) about found false positives. We will add it to default exclude list if it's common or we will fix underlying linter.
|
||||
|
||||
# IDE integrations
|
||||
1. VS Code - [pull request](https://github.com/Microsoft/vscode-go/pull/1693) to vscode-go (thanks to [pdf](https://github.com/pdf)).
|
||||
2. Vim - [issue](https://github.com/fatih/vim-go/issues/1841) for vim-go.
|
||||
3. GNU Emacs - [flycheck checker](https://github.com/weijiangan/flycheck-golangci-lint) (thanks to [weijiangan](https://github.com/weijiangan)).
|
||||
4. Sublime Text - [plugin](https://github.com/alecthomas/SublimeLinter-contrib-golang-cilint) for SublimeLinter (thanks to [alecthomas](https://github.com/alecthomas)).
|
||||
|
||||
# Internals
|
||||
The key difference with gometalinter is that golangci-lint shares work between specific linters (golint, govet, ...).
|
||||
For small and medium projects 50-80% of work between linters can be reused.
|
||||
Now we share `loader.Program` and `SSA` representation building. `SSA` representation is used from
|
||||
a [fork of go-tools](https://github.com/dominikh/go-tools), not the official one. Also, we are going to
|
||||
reuse `AST` parsing and traversal.
|
||||
|
||||
We don't fork to call specific linter but use its API. We forked GitHub repos of almost all linters
|
||||
to make API. It also allows us to be more performant and control actual count of used threads.
|
||||
|
||||
All linters are vendored in `/vendor` folder: their version is fixed, they are builtin
|
||||
and you don't need to install them separately.
|
||||
|
||||
We use chains for issues and independent processors to post-process them: exclude issues by limits,
|
||||
nolint comment, diff, regexps; prettify paths etc.
|
||||
|
||||
We use `cobra` for command-line action.
|
||||
|
||||
# FAQ
|
||||
**Q: How to add custom linter?**
|
||||
|
||||
A: You can integrate it yourself, see this [wiki page](https://github.com/golangci/golangci-lint/wiki/How-to-add-a-custom-linter) with documentation. Or you can create [GitHub Issue](https://github.com/golangci/golangci-lint/issues/new) and we will integrate it soon.
|
||||
|
||||
**Q: It's cool to use `golangci-lint` when starting a project, but what about existing projects with large codebase? It will take days to fix all found issues**
|
||||
|
||||
A: We are sure that every project can easily integrate `golangci-lint`, even the large one. The idea is to not fix all existing issues. Fix only newly added issue: issues in new code. To do this setup CI (or better use [GolangCI](https://golangci.com) to run `golangci-lint` with option `--new-from-rev=origin/master`. Also, take a look at option `-n`.
|
||||
By doing this you won't create new issues in code and can smoothly fix existing issues (or not).
|
||||
|
||||
**Q: How to use `golangci-lint` in CI (Continuous Integration)?**
|
||||
|
||||
A: You have 2 choices:
|
||||
1. Use [GolangCI](https://golangci.com): this service is highly integrated with GitHub (issues are commented in the pull request) and uses a `golangci-lint` tool. For configuration use `.golangci.yml` (or toml/json).
|
||||
2. Use custom CI: just run `golangci-lint` in CI and check the exit code. If it's non-zero - fail the build. The main disadvantage is that you can't see found issues in pull request code and should view build log, then open needed source file to see a context.
|
||||
If you'd like to vendor `golangci-lint` in your repo, run:
|
||||
```bash
|
||||
go get -u github.com/golang/dep/cmd/dep
|
||||
dep init
|
||||
dep ensure -v -add github.com/golangci/golangci-lint/cmd/golangci-lint
|
||||
```
|
||||
Then add these lines to your `Gopkg.toml` file, so `dep ensure -update` won't delete the vendored `golangci-lint` code.
|
||||
```toml
|
||||
required = [
|
||||
"github.com/golangci/golangci-lint/cmd/golangci-lint",
|
||||
]
|
||||
```
|
||||
In your CI scripts, install the vendored `golangci-lint` like this:
|
||||
```bash
|
||||
go install ./vendor/github.com/golangci/golangci-lint/cmd/golangci-lint/`
|
||||
```
|
||||
Vendoring `golangci-lint` saves a network request, potentially making your CI system a little more reliable.
|
||||
|
||||
**Q: `golangci-lint` doesn't work**
|
||||
1. Update it: `go get -u github.com/golangci/golangci-lint/cmd/golangci-lint`
|
||||
2. Run it with `-v` option and check the output.
|
||||
3. If it doesn't help create [GitHub issue](https://github.com/golangci/golangci-lint/issues/new) with the output.
|
||||
|
||||
# Thanks
|
||||
Thanks to [alecthomas/gometalinter](https://github.com/alecthomas/gometalinter) for inspiration and amazing work.
|
||||
Thanks to [bradleyfalzon/revgrep](https://github.com/bradleyfalzon/revgrep) for cool diff tool.
|
||||
|
||||
Thanks to developers and authors of used linters:
|
||||
{{.ThanksList}}
|
||||
|
||||
# Future Plans
|
||||
1. Upstream all changes of forked linters.
|
||||
2. Fully integrate all used linters: make a common interface and reuse 100% of what can be reused: AST traversal, packages preparation etc.
|
||||
3. Make it easy to write own linter/checker: it should take a minimum code, have perfect documentation, debugging and testing tooling.
|
||||
4. Speedup packages loading (dig into [loader](golang.org/x/tools/go/loader)): on-disk cache and existing code profiling-optimizing.
|
||||
5. Analyze (don't only filter) only new code: analyze only changed files and dependencies, make incremental analysis, caches.
|
||||
6. Smart new issues detector: don't print existing issues on changed lines.
|
||||
7. Integration with Text Editors. On-the-fly code analysis for text editors: it should be super-fast.
|
||||
8. Minimize false-positives by fixing linters and improving testing tooling.
|
||||
9. Automatic issues fixing (code rewrite, refactoring) where it's possible.
|
||||
10. Documentation for every issue type.
|
||||
|
||||
# Contact Information
|
||||
You can contact the author of GolangCI-Lint by [denis@golangci.com](mailto:denis@golangci.com).
|
@ -6,7 +6,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/golangci/golangci-lint/pkg"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/lintersdb"
|
||||
"github.com/golangci/golangci-lint/pkg/printers"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -20,7 +21,7 @@ func (e *Executor) initLinters() {
|
||||
e.rootCmd.AddCommand(lintersCmd)
|
||||
}
|
||||
|
||||
func printLinterConfigs(lcs []pkg.LinterConfig) {
|
||||
func printLinterConfigs(lcs []linter.Config) {
|
||||
for _, lc := range lcs {
|
||||
fmt.Fprintf(printers.StdOut, "%s: %s [fast: %t]\n", color.YellowString(lc.Linter.Name()),
|
||||
lc.Linter.Desc(), !lc.DoesFullImport)
|
||||
@ -28,8 +29,8 @@ func printLinterConfigs(lcs []pkg.LinterConfig) {
|
||||
}
|
||||
|
||||
func (e Executor) executeLinters(cmd *cobra.Command, args []string) {
|
||||
var enabledLCs, disabledLCs []pkg.LinterConfig
|
||||
for _, lc := range pkg.GetAllSupportedLinterConfigs() {
|
||||
var enabledLCs, disabledLCs []linter.Config
|
||||
for _, lc := range lintersdb.GetAllSupportedLinterConfigs() {
|
||||
if lc.EnabledByDefault {
|
||||
enabledLCs = append(enabledLCs, lc)
|
||||
} else {
|
||||
@ -43,8 +44,8 @@ func (e Executor) executeLinters(cmd *cobra.Command, args []string) {
|
||||
printLinterConfigs(disabledLCs)
|
||||
|
||||
color.Green("\nLinters presets:")
|
||||
for _, p := range pkg.AllPresets() {
|
||||
linters := pkg.GetAllLinterConfigsForPreset(p)
|
||||
for _, p := range lintersdb.AllPresets() {
|
||||
linters := lintersdb.GetAllLinterConfigsForPreset(p)
|
||||
linterNames := []string{}
|
||||
for _, lc := range linters {
|
||||
linterNames = append(linterNames, lc.Linter.Name())
|
||||
|
@ -12,9 +12,9 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg"
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/lintersdb"
|
||||
"github.com/golangci/golangci-lint/pkg/printers"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
"github.com/golangci/golangci-lint/pkg/result/processors"
|
||||
@ -100,7 +100,7 @@ func (e *Executor) initRun() {
|
||||
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.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(pkg.AllPresets(), "|")))
|
||||
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")
|
||||
|
||||
// Issues config
|
||||
@ -122,16 +122,12 @@ func (e *Executor) initRun() {
|
||||
func (e *Executor) runAnalysis(ctx context.Context, args []string) (<-chan result.Issue, error) {
|
||||
e.cfg.Run.Args = args
|
||||
|
||||
linters, err := pkg.GetEnabledLinters(e.cfg)
|
||||
linters, err := lintersdb.GetEnabledLinters(e.cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctxLinters := make([]lint.LinterConfig, 0, len(linters))
|
||||
for _, lc := range linters {
|
||||
ctxLinters = append(ctxLinters, lint.LinterConfig(lc))
|
||||
}
|
||||
lintCtx, err := lint.BuildContext(ctx, ctxLinters, e.cfg)
|
||||
lintCtx, err := lint.LoadContext(ctx, linters, e.cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -162,11 +158,7 @@ func (e *Executor) runAnalysis(ctx context.Context, args []string) (<-chan resul
|
||||
},
|
||||
}
|
||||
|
||||
runLinters := make([]lint.RunnerLinterConfig, 0, len(linters))
|
||||
for _, lc := range linters {
|
||||
runLinters = append(runLinters, lint.RunnerLinterConfig(lc))
|
||||
}
|
||||
return runner.Run(ctx, runLinters, lintCtx), nil
|
||||
return runner.Run(ctx, linters, lintCtx), nil
|
||||
}
|
||||
|
||||
func setOutputToDevNull() (savedStdout, savedStderr *os.File) {
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
deadcodeAPI "github.com/golangci/go-misc/deadcode"
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
)
|
||||
|
||||
@ -19,7 +19,7 @@ func (Deadcode) Desc() string {
|
||||
return "Finds unused code"
|
||||
}
|
||||
|
||||
func (d Deadcode) Run(ctx context.Context, lintCtx *lint.Context) ([]result.Issue, error) {
|
||||
func (d Deadcode) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
issues, err := deadcodeAPI.Run(lintCtx.Program)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
depguardAPI "github.com/OpenPeeDeeP/depguard"
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
)
|
||||
|
||||
@ -20,7 +20,7 @@ func (Depguard) Desc() string {
|
||||
return "Go linter that checks if package imports are in a list of acceptable packages"
|
||||
}
|
||||
|
||||
func (d Depguard) Run(ctx context.Context, lintCtx *lint.Context) ([]result.Issue, error) {
|
||||
func (d Depguard) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
dg := &depguardAPI.Depguard{
|
||||
Packages: lintCtx.Settings().Depguard.Packages,
|
||||
IncludeGoRoot: lintCtx.Settings().Depguard.IncludeGoRoot,
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"go/token"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
duplAPI "github.com/mibk/dupl"
|
||||
)
|
||||
@ -20,7 +20,7 @@ func (Dupl) Desc() string {
|
||||
return "Tool for code clone detection"
|
||||
}
|
||||
|
||||
func (d Dupl) Run(ctx context.Context, lintCtx *lint.Context) ([]result.Issue, error) {
|
||||
func (d Dupl) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
issues, err := duplAPI.Run(lintCtx.Paths.Files, lintCtx.Settings().Dupl.Threshold)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
errcheckAPI "github.com/kisielk/errcheck/golangci"
|
||||
)
|
||||
@ -19,7 +19,7 @@ func (Errcheck) Desc() string {
|
||||
return "Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases"
|
||||
}
|
||||
|
||||
func (e Errcheck) Run(ctx context.Context, lintCtx *lint.Context) ([]result.Issue, error) {
|
||||
func (e Errcheck) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
errCfg := &lintCtx.Settings().Errcheck
|
||||
issues, err := errcheckAPI.Run(lintCtx.Program, errCfg.CheckAssignToBlank, errCfg.CheckTypeAssertions)
|
||||
if err != nil {
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
"github.com/GoASTScanner/gas/rules"
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@ -25,7 +25,7 @@ func (Gas) Desc() string {
|
||||
return "Inspects source code for security problems"
|
||||
}
|
||||
|
||||
func (lint Gas) Run(ctx context.Context, lintCtx *lint.Context) ([]result.Issue, error) {
|
||||
func (lint Gas) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
gasConfig := gas.NewConfig()
|
||||
enabledRules := rules.Generate()
|
||||
logger := log.New(ioutil.Discard, "", 0)
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
goconstAPI "github.com/golangci/goconst"
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
)
|
||||
|
||||
@ -19,7 +19,7 @@ func (Goconst) Desc() string {
|
||||
return "Finds repeated strings that could be replaced by a constant"
|
||||
}
|
||||
|
||||
func (lint Goconst) Run(ctx context.Context, lintCtx *lint.Context) ([]result.Issue, error) {
|
||||
func (lint Goconst) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
var goconstIssues []goconstAPI.Issue
|
||||
// TODO: make it cross-package: pass package names inside goconst
|
||||
for _, files := range lintCtx.Paths.FilesGrouppedByDirs() {
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"sort"
|
||||
|
||||
gocycloAPI "github.com/golangci/gocyclo/pkg/gocyclo"
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
)
|
||||
|
||||
@ -20,7 +20,7 @@ func (Gocyclo) Desc() string {
|
||||
return "Computes and checks the cyclomatic complexity of functions"
|
||||
}
|
||||
|
||||
func (g Gocyclo) Run(ctx context.Context, lintCtx *lint.Context) ([]result.Issue, error) {
|
||||
func (g Gocyclo) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
var stats []gocycloAPI.Stat
|
||||
for _, f := range lintCtx.ASTCache.GetAllValidFiles() {
|
||||
stats = gocycloAPI.BuildStats(f.F, f.Fset, stats)
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
|
||||
gofmtAPI "github.com/golangci/gofmt/gofmt"
|
||||
goimportsAPI "github.com/golangci/gofmt/goimports"
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
"github.com/sirupsen/logrus"
|
||||
"sourcegraph.com/sourcegraph/go-diff/diff"
|
||||
@ -102,7 +102,7 @@ func (g Gofmt) extractIssuesFromPatch(patch string) ([]result.Issue, error) {
|
||||
return issues, nil
|
||||
}
|
||||
|
||||
func (g Gofmt) Run(ctx context.Context, lintCtx *lint.Context) ([]result.Issue, error) {
|
||||
func (g Gofmt) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
var issues []result.Issue
|
||||
|
||||
for _, f := range lintCtx.Paths.Files {
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"io/ioutil"
|
||||
|
||||
lintAPI "github.com/golang/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@ -21,7 +21,7 @@ func (Golint) Desc() string {
|
||||
return "Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes"
|
||||
}
|
||||
|
||||
func (g Golint) Run(ctx context.Context, lintCtx *lint.Context) ([]result.Issue, error) {
|
||||
func (g Golint) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
var issues []result.Issue
|
||||
var lintErr error
|
||||
for _, pkgFiles := range lintCtx.Paths.FilesGrouppedByDirs() {
|
||||
|
@ -3,7 +3,7 @@ package golinters
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
govetAPI "github.com/golangci/govet"
|
||||
)
|
||||
@ -18,7 +18,7 @@ func (Govet) Desc() string {
|
||||
return "Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string"
|
||||
}
|
||||
|
||||
func (g Govet) Run(ctx context.Context, lintCtx *lint.Context) ([]result.Issue, error) {
|
||||
func (g Govet) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
// TODO: check .S asm files: govet can do it if pass dirs
|
||||
var govetIssues []govetAPI.Issue
|
||||
for _, files := range lintCtx.Paths.FilesGrouppedByDirs() {
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
ineffassignAPI "github.com/golangci/ineffassign"
|
||||
)
|
||||
@ -19,7 +19,7 @@ func (Ineffassign) Desc() string {
|
||||
return "Detects when assignments to existing variables are not used"
|
||||
}
|
||||
|
||||
func (lint Ineffassign) Run(ctx context.Context, lintCtx *lint.Context) ([]result.Issue, error) {
|
||||
func (lint Ineffassign) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
issues := ineffassignAPI.Run(lintCtx.Paths.Files)
|
||||
if len(issues) == 0 {
|
||||
return nil, nil
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
|
||||
"mvdan.cc/interfacer/check"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
)
|
||||
|
||||
@ -19,7 +19,7 @@ func (Interfacer) Desc() string {
|
||||
return "Linter that suggests narrower interface types"
|
||||
}
|
||||
|
||||
func (lint Interfacer) Run(ctx context.Context, lintCtx *lint.Context) ([]result.Issue, error) {
|
||||
func (lint Interfacer) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
c := new(check.Checker)
|
||||
c.Program(lintCtx.Program)
|
||||
c.ProgramSSA(lintCtx.SSAProgram)
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
malignedAPI "github.com/golangci/maligned"
|
||||
)
|
||||
@ -19,7 +19,7 @@ func (Maligned) Desc() string {
|
||||
return "Tool to detect Go structs that would take less memory if their fields were sorted"
|
||||
}
|
||||
|
||||
func (m Maligned) Run(ctx context.Context, lintCtx *lint.Context) ([]result.Issue, error) {
|
||||
func (m Maligned) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
issues := malignedAPI.Run(lintCtx.Program)
|
||||
if len(issues) == 0 {
|
||||
return nil, nil
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
megacheckAPI "github.com/golangci/go-tools/cmd/megacheck"
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
)
|
||||
|
||||
@ -42,15 +42,15 @@ func (m Megacheck) Name() string {
|
||||
func (m Megacheck) Desc() string {
|
||||
descs := map[string]string{
|
||||
"unused": "Checks Go code for unused constants, variables, functions and types",
|
||||
"gosimple": "Linter for Go source code that specialises on simplifying code",
|
||||
"staticcheck": "Staticcheck is go vet on steroids, applying a ton of static analysis checks",
|
||||
"gosimple": "Linter for Go source code that specializes in simplifying a code",
|
||||
"staticcheck": "Staticcheck is a go vet on steroids, applying a ton of static analysis checks",
|
||||
"megacheck": "3 sub-linters in one: unused, gosimple and staticcheck",
|
||||
}
|
||||
|
||||
return descs[m.Name()]
|
||||
}
|
||||
|
||||
func (m Megacheck) Run(ctx context.Context, lintCtx *lint.Context) ([]result.Issue, error) {
|
||||
func (m Megacheck) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
issues := megacheckAPI.Run(lintCtx.Program, lintCtx.LoaderConfig, lintCtx.SSAProgram,
|
||||
m.StaticcheckEnabled, m.GosimpleEnabled, m.UnusedEnabled)
|
||||
if len(issues) == 0 {
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
structcheckAPI "github.com/golangci/check/cmd/structcheck"
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
)
|
||||
|
||||
@ -16,10 +16,10 @@ func (Structcheck) Name() string {
|
||||
}
|
||||
|
||||
func (Structcheck) Desc() string {
|
||||
return "Finds unused struct fields"
|
||||
return "Finds an unused struct fields"
|
||||
}
|
||||
|
||||
func (s Structcheck) Run(ctx context.Context, lintCtx *lint.Context) ([]result.Issue, error) {
|
||||
func (s Structcheck) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
issues := structcheckAPI.Run(lintCtx.Program, lintCtx.Settings().Structcheck.CheckExportedFields)
|
||||
if len(issues) == 0 {
|
||||
return nil, nil
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
)
|
||||
|
||||
@ -62,7 +62,7 @@ func (lint TypeCheck) parseError(err error) *result.Issue {
|
||||
}
|
||||
}
|
||||
|
||||
func (lint TypeCheck) Run(ctx context.Context, lintCtx *lint.Context) ([]result.Issue, error) {
|
||||
func (lint TypeCheck) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
if lintCtx.NotCompilingPackages == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package golinters
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
unconvertAPI "github.com/golangci/unconvert"
|
||||
)
|
||||
@ -18,7 +18,7 @@ func (Unconvert) Desc() string {
|
||||
return "Remove unnecessary type conversions"
|
||||
}
|
||||
|
||||
func (lint Unconvert) Run(ctx context.Context, lintCtx *lint.Context) ([]result.Issue, error) {
|
||||
func (lint Unconvert) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
positions := unconvertAPI.Run(lintCtx.Program)
|
||||
if len(positions) == 0 {
|
||||
return nil, nil
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
varcheckAPI "github.com/golangci/check/cmd/varcheck"
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
)
|
||||
|
||||
@ -19,7 +19,7 @@ func (Varcheck) Desc() string {
|
||||
return "Finds unused global variables and constants"
|
||||
}
|
||||
|
||||
func (v Varcheck) Run(ctx context.Context, lintCtx *lint.Context) ([]result.Issue, error) {
|
||||
func (v Varcheck) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
issues := varcheckAPI.Run(lintCtx.Program, lintCtx.Settings().Varcheck.CheckExportedFields)
|
||||
if len(issues) == 0 {
|
||||
return nil, nil
|
||||
|
69
pkg/lint/linter/config.go
Normal file
69
pkg/lint/linter/config.go
Normal file
@ -0,0 +1,69 @@
|
||||
package linter
|
||||
|
||||
const (
|
||||
PresetFormatting = "format"
|
||||
PresetComplexity = "complexity"
|
||||
PresetStyle = "style"
|
||||
PresetBugs = "bugs"
|
||||
PresetUnused = "unused"
|
||||
PresetPerformance = "performance"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Linter Linter
|
||||
EnabledByDefault bool
|
||||
DoesFullImport bool
|
||||
NeedsSSARepr bool
|
||||
InPresets []string
|
||||
Speed int // more value means faster execution of linter
|
||||
|
||||
OriginalURL string // URL of original (not forked) repo, needed for autogenerated README
|
||||
}
|
||||
|
||||
func (lc Config) WithFullImport() Config {
|
||||
lc.DoesFullImport = true
|
||||
return lc
|
||||
}
|
||||
|
||||
func (lc Config) WithSSA() Config {
|
||||
lc.DoesFullImport = true
|
||||
lc.NeedsSSARepr = true
|
||||
return lc
|
||||
}
|
||||
|
||||
func (lc Config) WithPresets(presets ...string) Config {
|
||||
lc.InPresets = presets
|
||||
return lc
|
||||
}
|
||||
|
||||
func (lc Config) WithSpeed(speed int) Config {
|
||||
lc.Speed = speed
|
||||
return lc
|
||||
}
|
||||
|
||||
func (lc Config) WithURL(url string) Config {
|
||||
lc.OriginalURL = url
|
||||
return lc
|
||||
}
|
||||
|
||||
func (lc Config) NeedsProgramLoading() bool {
|
||||
return lc.DoesFullImport
|
||||
}
|
||||
|
||||
func (lc Config) NeedsSSARepresentation() bool {
|
||||
return lc.NeedsSSARepr
|
||||
}
|
||||
|
||||
func (lc Config) GetSpeed() int {
|
||||
return lc.Speed
|
||||
}
|
||||
|
||||
func (lc Config) GetLinter() Linter {
|
||||
return lc.Linter
|
||||
}
|
||||
|
||||
func NewConfig(linter Linter) *Config {
|
||||
return &Config{
|
||||
Linter: linter,
|
||||
}
|
||||
}
|
23
pkg/lint/linter/context.go
Normal file
23
pkg/lint/linter/context.go
Normal file
@ -0,0 +1,23 @@
|
||||
package linter
|
||||
|
||||
import (
|
||||
"github.com/golangci/go-tools/ssa"
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/fsutils"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/astcache"
|
||||
"golang.org/x/tools/go/loader"
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
Paths *fsutils.ProjectPaths
|
||||
Cfg *config.Config
|
||||
Program *loader.Program
|
||||
SSAProgram *ssa.Program
|
||||
LoaderConfig *loader.Config
|
||||
ASTCache *astcache.Cache
|
||||
NotCompilingPackages []*loader.PackageInfo
|
||||
}
|
||||
|
||||
func (c *Context) Settings() *config.LintersSettings {
|
||||
return &c.Cfg.LintersSettings
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package lint
|
||||
package linter
|
||||
|
||||
import (
|
||||
"context"
|
@ -1,4 +1,4 @@
|
||||
package pkg
|
||||
package lintersdb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -8,21 +8,12 @@ import (
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/golinters"
|
||||
"github.com/golangci/golangci-lint/pkg/lint"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
PresetFormatting = "format"
|
||||
PresetComplexity = "complexity"
|
||||
PresetStyle = "style"
|
||||
PresetBugs = "bugs"
|
||||
PresetUnused = "unused"
|
||||
PresetPerformance = "performance"
|
||||
)
|
||||
|
||||
func AllPresets() []string {
|
||||
return []string{PresetBugs, PresetUnused, PresetFormatting, PresetStyle, PresetComplexity, PresetPerformance}
|
||||
return []string{linter.PresetBugs, linter.PresetUnused, linter.PresetFormatting, linter.PresetStyle, linter.PresetComplexity, linter.PresetPerformance}
|
||||
}
|
||||
|
||||
func allPresetsSet() map[string]bool {
|
||||
@ -33,64 +24,12 @@ func allPresetsSet() map[string]bool {
|
||||
return ret
|
||||
}
|
||||
|
||||
type LinterConfig struct {
|
||||
Linter lint.Linter
|
||||
EnabledByDefault bool
|
||||
DoesFullImport bool
|
||||
NeedsSSARepr bool
|
||||
InPresets []string
|
||||
Speed int // more value means faster execution of linter
|
||||
}
|
||||
|
||||
func (lc LinterConfig) WithFullImport() LinterConfig {
|
||||
lc.DoesFullImport = true
|
||||
return lc
|
||||
}
|
||||
|
||||
func (lc LinterConfig) WithSSA() LinterConfig {
|
||||
lc.DoesFullImport = true
|
||||
lc.NeedsSSARepr = true
|
||||
return lc
|
||||
}
|
||||
|
||||
func (lc LinterConfig) WithPresets(presets ...string) LinterConfig {
|
||||
lc.InPresets = presets
|
||||
return lc
|
||||
}
|
||||
|
||||
func (lc LinterConfig) WithSpeed(speed int) LinterConfig {
|
||||
lc.Speed = speed
|
||||
return lc
|
||||
}
|
||||
|
||||
func (lc LinterConfig) NeedsProgramLoading() bool {
|
||||
return lc.DoesFullImport
|
||||
}
|
||||
|
||||
func (lc LinterConfig) NeedsSSARepresentation() bool {
|
||||
return lc.NeedsSSARepr
|
||||
}
|
||||
|
||||
func (lc LinterConfig) GetSpeed() int {
|
||||
return lc.Speed
|
||||
}
|
||||
|
||||
func (lc LinterConfig) GetLinter() lint.Linter {
|
||||
return lc.Linter
|
||||
}
|
||||
|
||||
func newLinterConfig(linter lint.Linter) LinterConfig {
|
||||
return LinterConfig{
|
||||
Linter: linter,
|
||||
}
|
||||
}
|
||||
|
||||
var nameToLC map[string]LinterConfig
|
||||
var nameToLC map[string]linter.Config
|
||||
var nameToLCOnce sync.Once
|
||||
|
||||
func getLinterConfig(name string) *LinterConfig {
|
||||
func getLinterConfig(name string) *linter.Config {
|
||||
nameToLCOnce.Do(func() {
|
||||
nameToLC = make(map[string]LinterConfig)
|
||||
nameToLC = make(map[string]linter.Config)
|
||||
for _, lc := range GetAllSupportedLinterConfigs() {
|
||||
nameToLC[lc.Linter.Name()] = lc
|
||||
}
|
||||
@ -104,8 +43,8 @@ func getLinterConfig(name string) *LinterConfig {
|
||||
return &lc
|
||||
}
|
||||
|
||||
func enableLinterConfigs(lcs []LinterConfig, isEnabled func(lc *LinterConfig) bool) []LinterConfig {
|
||||
var ret []LinterConfig
|
||||
func enableLinterConfigs(lcs []linter.Config, isEnabled func(lc *linter.Config) bool) []linter.Config {
|
||||
var ret []linter.Config
|
||||
for _, lc := range lcs {
|
||||
lc.EnabledByDefault = isEnabled(&lc)
|
||||
ret = append(ret, lc)
|
||||
@ -114,35 +53,113 @@ func enableLinterConfigs(lcs []LinterConfig, isEnabled func(lc *LinterConfig) bo
|
||||
return ret
|
||||
}
|
||||
|
||||
func GetAllSupportedLinterConfigs() []LinterConfig {
|
||||
lcs := []LinterConfig{
|
||||
newLinterConfig(golinters.Govet{}).WithPresets(PresetBugs).WithSpeed(4),
|
||||
newLinterConfig(golinters.Errcheck{}).WithFullImport().WithPresets(PresetBugs).WithSpeed(10),
|
||||
newLinterConfig(golinters.Golint{}).WithPresets(PresetStyle).WithSpeed(3),
|
||||
func GetAllSupportedLinterConfigs() []linter.Config {
|
||||
lcs := []linter.Config{
|
||||
linter.NewConfig(golinters.Govet{}).
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithSpeed(4).
|
||||
WithURL("https://golang.org/cmd/vet/"),
|
||||
linter.NewConfig(golinters.Errcheck{}).
|
||||
WithFullImport().
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithSpeed(10).
|
||||
WithURL("https://github.com/kisielk/errcheck"),
|
||||
linter.NewConfig(golinters.Golint{}).
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithSpeed(3).
|
||||
WithURL("https://github.com/golang/lint"),
|
||||
|
||||
newLinterConfig(golinters.Megacheck{StaticcheckEnabled: true}).WithSSA().
|
||||
WithPresets(PresetBugs).WithSpeed(2),
|
||||
newLinterConfig(golinters.Megacheck{UnusedEnabled: true}).WithSSA().WithPresets(PresetUnused).WithSpeed(5),
|
||||
newLinterConfig(golinters.Megacheck{GosimpleEnabled: true}).WithSSA().WithPresets(PresetStyle).WithSpeed(5),
|
||||
linter.NewConfig(golinters.Megacheck{StaticcheckEnabled: true}).
|
||||
WithSSA().
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithSpeed(2).
|
||||
WithURL("https://staticcheck.io/"),
|
||||
linter.NewConfig(golinters.Megacheck{UnusedEnabled: true}).
|
||||
WithSSA().
|
||||
WithPresets(linter.PresetUnused).
|
||||
WithSpeed(5).
|
||||
WithURL("https://github.com/dominikh/go-tools/tree/master/cmd/unused"),
|
||||
linter.NewConfig(golinters.Megacheck{GosimpleEnabled: true}).
|
||||
WithSSA().
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithSpeed(5).
|
||||
WithURL("https://github.com/dominikh/go-tools/tree/master/cmd/gosimple"),
|
||||
|
||||
newLinterConfig(golinters.Gas{}).WithFullImport().WithPresets(PresetBugs).WithSpeed(8),
|
||||
newLinterConfig(golinters.Structcheck{}).WithFullImport().WithPresets(PresetUnused).WithSpeed(10),
|
||||
newLinterConfig(golinters.Varcheck{}).WithFullImport().WithPresets(PresetUnused).WithSpeed(10),
|
||||
newLinterConfig(golinters.Interfacer{}).WithSSA().WithPresets(PresetStyle).WithSpeed(6),
|
||||
newLinterConfig(golinters.Unconvert{}).WithFullImport().WithPresets(PresetStyle).WithSpeed(10),
|
||||
newLinterConfig(golinters.Ineffassign{}).WithPresets(PresetUnused).WithSpeed(9),
|
||||
newLinterConfig(golinters.Dupl{}).WithPresets(PresetStyle).WithSpeed(7),
|
||||
newLinterConfig(golinters.Goconst{}).WithPresets(PresetStyle).WithSpeed(9),
|
||||
newLinterConfig(golinters.Deadcode{}).WithFullImport().WithPresets(PresetUnused).WithSpeed(10),
|
||||
newLinterConfig(golinters.Gocyclo{}).WithPresets(PresetComplexity).WithSpeed(8),
|
||||
newLinterConfig(golinters.TypeCheck{}).WithFullImport().WithPresets(PresetBugs).WithSpeed(10),
|
||||
linter.NewConfig(golinters.Gas{}).
|
||||
WithFullImport().
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithSpeed(8).
|
||||
WithURL("https://github.com/GoASTScanner/gas"),
|
||||
linter.NewConfig(golinters.Structcheck{}).
|
||||
WithFullImport().
|
||||
WithPresets(linter.PresetUnused).
|
||||
WithSpeed(10).
|
||||
WithURL("https://github.com/opennota/check"),
|
||||
linter.NewConfig(golinters.Varcheck{}).
|
||||
WithFullImport().
|
||||
WithPresets(linter.PresetUnused).
|
||||
WithSpeed(10).
|
||||
WithURL("https://github.com/opennota/check"),
|
||||
linter.NewConfig(golinters.Interfacer{}).
|
||||
WithSSA().
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithSpeed(6).
|
||||
WithURL("https://github.com/mvdan/interfacer"),
|
||||
linter.NewConfig(golinters.Unconvert{}).
|
||||
WithFullImport().
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithSpeed(10).
|
||||
WithURL("https://github.com/mdempsky/unconvert"),
|
||||
linter.NewConfig(golinters.Ineffassign{}).
|
||||
WithPresets(linter.PresetUnused).
|
||||
WithSpeed(9).
|
||||
WithURL("https://github.com/gordonklaus/ineffassign"),
|
||||
linter.NewConfig(golinters.Dupl{}).
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithSpeed(7).
|
||||
WithURL("https://github.com/mibk/dupl"),
|
||||
linter.NewConfig(golinters.Goconst{}).
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithSpeed(9).
|
||||
WithURL("https://github.com/jgautheron/goconst"),
|
||||
linter.NewConfig(golinters.Deadcode{}).
|
||||
WithFullImport().
|
||||
WithPresets(linter.PresetUnused).
|
||||
WithSpeed(10).
|
||||
WithURL("https://github.com/remyoudompheng/go-misc/tree/master/deadcode"),
|
||||
linter.NewConfig(golinters.Gocyclo{}).
|
||||
WithPresets(linter.PresetComplexity).
|
||||
WithSpeed(8).
|
||||
WithURL("https://github.com/alecthomas/gocyclo"),
|
||||
linter.NewConfig(golinters.TypeCheck{}).
|
||||
WithFullImport().
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithSpeed(10).
|
||||
WithURL(""),
|
||||
|
||||
newLinterConfig(golinters.Gofmt{}).WithPresets(PresetFormatting).WithSpeed(7),
|
||||
newLinterConfig(golinters.Gofmt{UseGoimports: true}).WithPresets(PresetFormatting).WithSpeed(5),
|
||||
newLinterConfig(golinters.Maligned{}).WithFullImport().WithPresets(PresetPerformance).WithSpeed(10),
|
||||
newLinterConfig(golinters.Megacheck{GosimpleEnabled: true, UnusedEnabled: true, StaticcheckEnabled: true}).
|
||||
WithSSA().WithPresets(PresetStyle, PresetBugs, PresetUnused).WithSpeed(1),
|
||||
newLinterConfig(golinters.Depguard{}).WithFullImport().WithPresets(PresetStyle).WithSpeed(6),
|
||||
linter.NewConfig(golinters.Gofmt{}).
|
||||
WithPresets(linter.PresetFormatting).
|
||||
WithSpeed(7).
|
||||
WithURL("https://golang.org/cmd/gofmt/"),
|
||||
linter.NewConfig(golinters.Gofmt{UseGoimports: true}).
|
||||
WithPresets(linter.PresetFormatting).
|
||||
WithSpeed(5).
|
||||
WithURL("https://godoc.org/golang.org/x/tools/cmd/goimports"),
|
||||
linter.NewConfig(golinters.Maligned{}).
|
||||
WithFullImport().
|
||||
WithPresets(linter.PresetPerformance).
|
||||
WithSpeed(10).
|
||||
WithURL("https://github.com/mdempsky/maligned"),
|
||||
linter.NewConfig(golinters.Megacheck{GosimpleEnabled: true, UnusedEnabled: true, StaticcheckEnabled: true}).
|
||||
WithSSA().
|
||||
WithPresets(linter.PresetStyle, linter.PresetBugs, linter.PresetUnused).
|
||||
WithSpeed(1).
|
||||
WithURL("https://github.com/dominikh/go-tools/tree/master/cmd/megacheck"),
|
||||
linter.NewConfig(golinters.Depguard{}).
|
||||
WithFullImport().
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithSpeed(6).
|
||||
WithURL("https://github.com/OpenPeeDeeP/depguard"),
|
||||
}
|
||||
|
||||
if os.Getenv("GOLANGCI_COM_RUN") == "1" {
|
||||
@ -152,7 +169,7 @@ func GetAllSupportedLinterConfigs() []LinterConfig {
|
||||
golinters.Maligned{}.Name(): true, // rarely usable
|
||||
golinters.TypeCheck{}.Name(): true, // annoying because of different building envs
|
||||
}
|
||||
return enableLinterConfigs(lcs, func(lc *LinterConfig) bool {
|
||||
return enableLinterConfigs(lcs, func(lc *linter.Config) bool {
|
||||
return !disabled[lc.Linter.Name()]
|
||||
})
|
||||
}
|
||||
@ -170,13 +187,13 @@ func GetAllSupportedLinterConfigs() []LinterConfig {
|
||||
golinters.Deadcode{}.Name(): true,
|
||||
golinters.TypeCheck{}.Name(): true,
|
||||
}
|
||||
return enableLinterConfigs(lcs, func(lc *LinterConfig) bool {
|
||||
return enableLinterConfigs(lcs, func(lc *linter.Config) bool {
|
||||
return enabled[lc.Linter.Name()]
|
||||
})
|
||||
}
|
||||
|
||||
func getAllEnabledByDefaultLinters() []LinterConfig {
|
||||
var ret []LinterConfig
|
||||
func getAllEnabledByDefaultLinters() []linter.Config {
|
||||
var ret []linter.Config
|
||||
for _, lc := range GetAllSupportedLinterConfigs() {
|
||||
if lc.EnabledByDefault {
|
||||
ret = append(ret, lc)
|
||||
@ -186,8 +203,8 @@ func getAllEnabledByDefaultLinters() []LinterConfig {
|
||||
return ret
|
||||
}
|
||||
|
||||
func linterConfigsToMap(lcs []LinterConfig) map[string]*LinterConfig {
|
||||
ret := map[string]*LinterConfig{}
|
||||
func linterConfigsToMap(lcs []linter.Config) map[string]*linter.Config {
|
||||
ret := map[string]*linter.Config{}
|
||||
for _, lc := range lcs {
|
||||
lc := lc // local copy
|
||||
ret[lc.Linter.Name()] = &lc
|
||||
@ -276,8 +293,8 @@ func validateEnabledDisabledLintersConfig(cfg *config.Linters) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAllLinterConfigsForPreset(p string) []LinterConfig {
|
||||
ret := []LinterConfig{}
|
||||
func GetAllLinterConfigsForPreset(p string) []linter.Config {
|
||||
ret := []linter.Config{}
|
||||
for _, lc := range GetAllSupportedLinterConfigs() {
|
||||
for _, ip := range lc.InPresets {
|
||||
if p == ip {
|
||||
@ -290,8 +307,8 @@ func GetAllLinterConfigsForPreset(p string) []LinterConfig {
|
||||
return ret
|
||||
}
|
||||
|
||||
func getEnabledLintersSet(lcfg *config.Linters, enabledByDefaultLinters []LinterConfig) map[string]*LinterConfig { // nolint:gocyclo
|
||||
resultLintersSet := map[string]*LinterConfig{}
|
||||
func getEnabledLintersSet(lcfg *config.Linters, enabledByDefaultLinters []linter.Config) map[string]*linter.Config { // nolint:gocyclo
|
||||
resultLintersSet := map[string]*linter.Config{}
|
||||
switch {
|
||||
case len(lcfg.Presets) != 0:
|
||||
break // imply --disable-all
|
||||
@ -345,7 +362,7 @@ func getAllMegacheckSubLinterNames() []string {
|
||||
return []string{unusedName, gosimpleName, staticcheckName}
|
||||
}
|
||||
|
||||
func optimizeLintersSet(linters map[string]*LinterConfig) {
|
||||
func optimizeLintersSet(linters map[string]*linter.Config) {
|
||||
unusedName := golinters.Megacheck{UnusedEnabled: true}.Name()
|
||||
gosimpleName := golinters.Megacheck{GosimpleEnabled: true}.Name()
|
||||
staticcheckName := golinters.Megacheck{StaticcheckEnabled: true}.Name()
|
||||
@ -379,14 +396,14 @@ func optimizeLintersSet(linters map[string]*LinterConfig) {
|
||||
linters[m.Name()] = &lc
|
||||
}
|
||||
|
||||
func GetEnabledLinters(cfg *config.Config) ([]LinterConfig, error) {
|
||||
func GetEnabledLinters(cfg *config.Config) ([]linter.Config, error) {
|
||||
if err := validateEnabledDisabledLintersConfig(&cfg.Linters); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resultLintersSet := getEnabledLintersSet(&cfg.Linters, getAllEnabledByDefaultLinters())
|
||||
|
||||
var resultLinters []LinterConfig
|
||||
var resultLinters []linter.Config
|
||||
for _, lc := range resultLintersSet {
|
||||
resultLinters = append(resultLinters, *lc)
|
||||
}
|
||||
@ -410,7 +427,7 @@ func uniqStrings(ss []string) []string {
|
||||
return ret
|
||||
}
|
||||
|
||||
func verbosePrintLintersStatus(cfg *config.Config, lcs []LinterConfig) {
|
||||
func verbosePrintLintersStatus(cfg *config.Config, lcs []linter.Config) {
|
||||
var linterNames []string
|
||||
for _, lc := range lcs {
|
||||
linterNames = append(linterNames, lc.Linter.Name())
|
@ -1,10 +1,11 @@
|
||||
package pkg
|
||||
package lintersdb
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@ -45,7 +46,7 @@ func TestGetEnabledLintersSet(t *testing.T) {
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
defaultLinters := []LinterConfig{}
|
||||
defaultLinters := []linter.Config{}
|
||||
for _, ln := range c.def {
|
||||
defaultLinters = append(defaultLinters, *getLinterConfig(ln))
|
||||
}
|
@ -14,6 +14,7 @@ import (
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/fsutils"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/astcache"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/tools/go/loader"
|
||||
)
|
||||
@ -32,12 +33,7 @@ func (c *Context) Settings() *config.LintersSettings {
|
||||
return &c.Cfg.LintersSettings
|
||||
}
|
||||
|
||||
type LinterConfig interface {
|
||||
NeedsProgramLoading() bool
|
||||
NeedsSSARepresentation() bool
|
||||
}
|
||||
|
||||
func isFullImportNeeded(linters []LinterConfig) bool {
|
||||
func isFullImportNeeded(linters []linter.Config) bool {
|
||||
for _, linter := range linters {
|
||||
if linter.NeedsProgramLoading() {
|
||||
return true
|
||||
@ -47,7 +43,7 @@ func isFullImportNeeded(linters []LinterConfig) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func isSSAReprNeeded(linters []LinterConfig) bool {
|
||||
func isSSAReprNeeded(linters []linter.Config) bool {
|
||||
for _, linter := range linters {
|
||||
if linter.NeedsSSARepresentation() {
|
||||
return true
|
||||
@ -57,7 +53,7 @@ func isSSAReprNeeded(linters []LinterConfig) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func loadWholeAppIfNeeded(ctx context.Context, linters []LinterConfig, cfg *config.Run, paths *fsutils.ProjectPaths) (*loader.Program, *loader.Config, error) {
|
||||
func loadWholeAppIfNeeded(ctx context.Context, linters []linter.Config, cfg *config.Run, paths *fsutils.ProjectPaths) (*loader.Program, *loader.Config, error) {
|
||||
if !isFullImportNeeded(linters) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
@ -117,7 +113,7 @@ func discoverGoRoot() (string, error) {
|
||||
// separateNotCompilingPackages moves not compiling packages into separate slices:
|
||||
// a lot of linters crash on such packages. Leave them only for those linters
|
||||
// which can work with them.
|
||||
func separateNotCompilingPackages(lintCtx *Context) {
|
||||
func separateNotCompilingPackages(lintCtx *linter.Context) {
|
||||
prog := lintCtx.Program
|
||||
|
||||
if prog.Created != nil {
|
||||
@ -142,7 +138,7 @@ func separateNotCompilingPackages(lintCtx *Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func BuildContext(ctx context.Context, linters []LinterConfig, cfg *config.Config) (*Context, error) {
|
||||
func LoadContext(ctx context.Context, linters []linter.Config, cfg *config.Config) (*linter.Context, error) {
|
||||
// Set GOROOT to have working cross-compilation: cross-compiled binaries
|
||||
// have invalid GOROOT. XXX: can't use runtime.GOROOT().
|
||||
goroot, err := discoverGoRoot()
|
||||
@ -183,7 +179,7 @@ func BuildContext(ctx context.Context, linters []LinterConfig, cfg *config.Confi
|
||||
astCache = astcache.LoadFromFiles(paths.Files)
|
||||
}
|
||||
|
||||
ret := &Context{
|
||||
ret := &linter.Context{
|
||||
Paths: paths,
|
||||
Cfg: cfg,
|
||||
Program: prog,
|
@ -7,24 +7,17 @@ import (
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/fsutils"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/astcache"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type testLinterConfig struct{}
|
||||
|
||||
func (t testLinterConfig) NeedsProgramLoading() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (t testLinterConfig) NeedsSSARepresentation() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func TestASTCacheLoading(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
linters := []LinterConfig{testLinterConfig{}}
|
||||
linters := []linter.Config{
|
||||
linter.NewConfig(nil).WithFullImport(),
|
||||
}
|
||||
|
||||
inputPaths := []string{"./...", "./", "./context.go", "context.go"}
|
||||
inputPaths := []string{"./...", "./", "./load.go", "load.go"}
|
||||
for _, inputPath := range inputPaths {
|
||||
paths, err := fsutils.GetPathsForAnalysis(ctx, []string{inputPath}, true)
|
||||
assert.NoError(t, err)
|
@ -9,6 +9,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
"github.com/golangci/golangci-lint/pkg/result/processors"
|
||||
"github.com/golangci/golangci-lint/pkg/timeutils"
|
||||
@ -20,12 +21,12 @@ type SimpleRunner struct {
|
||||
}
|
||||
|
||||
type lintRes struct {
|
||||
linter Linter
|
||||
linter linter.Config
|
||||
err error
|
||||
issues []result.Issue
|
||||
}
|
||||
|
||||
func runLinterSafe(ctx context.Context, lintCtx *Context, linter Linter) (ret []result.Issue, err error) {
|
||||
func runLinterSafe(ctx context.Context, lintCtx *linter.Context, lc linter.Config) (ret []result.Issue, err error) {
|
||||
defer func() {
|
||||
if panicData := recover(); panicData != nil {
|
||||
err = fmt.Errorf("panic occured: %s", panicData)
|
||||
@ -33,10 +34,19 @@ func runLinterSafe(ctx context.Context, lintCtx *Context, linter Linter) (ret []
|
||||
}
|
||||
}()
|
||||
|
||||
return linter.Run(ctx, lintCtx)
|
||||
issues, err := lc.Linter.Run(ctx, lintCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, i := range issues {
|
||||
i.FromLinter = lc.Linter.Name()
|
||||
}
|
||||
|
||||
return issues, nil
|
||||
}
|
||||
|
||||
func runWorker(ctx context.Context, lintCtx *Context, tasksCh <-chan Linter, lintResultsCh chan<- lintRes, name string) {
|
||||
func runWorker(ctx context.Context, lintCtx *linter.Context, tasksCh <-chan linter.Config, lintResultsCh chan<- lintRes, name string) {
|
||||
sw := timeutils.NewStopwatch(name)
|
||||
defer sw.Print()
|
||||
|
||||
@ -44,7 +54,7 @@ func runWorker(ctx context.Context, lintCtx *Context, tasksCh <-chan Linter, lin
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case linter, ok := <-tasksCh:
|
||||
case lc, ok := <-tasksCh:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@ -55,11 +65,11 @@ func runWorker(ctx context.Context, lintCtx *Context, tasksCh <-chan Linter, lin
|
||||
}
|
||||
var issues []result.Issue
|
||||
var err error
|
||||
sw.TrackStage(linter.Name(), func() {
|
||||
issues, err = runLinterSafe(ctx, lintCtx, linter)
|
||||
sw.TrackStage(lc.Linter.Name(), func() {
|
||||
issues, err = runLinterSafe(ctx, lintCtx, lc)
|
||||
})
|
||||
lintResultsCh <- lintRes{
|
||||
linter: linter,
|
||||
linter: lc,
|
||||
err: err,
|
||||
issues: issues,
|
||||
}
|
||||
@ -87,13 +97,8 @@ func logWorkersStat(workersFinishTimes []time.Time) {
|
||||
logrus.Infof("Workers idle times: %s", strings.Join(logStrings, ", "))
|
||||
}
|
||||
|
||||
type RunnerLinterConfig interface {
|
||||
GetSpeed() int
|
||||
GetLinter() Linter
|
||||
}
|
||||
|
||||
func getSortedLintersConfigs(linters []RunnerLinterConfig) []RunnerLinterConfig {
|
||||
ret := make([]RunnerLinterConfig, len(linters))
|
||||
func getSortedLintersConfigs(linters []linter.Config) []linter.Config {
|
||||
ret := make([]linter.Config, len(linters))
|
||||
copy(ret, linters)
|
||||
|
||||
sort.Slice(ret, func(i, j int) bool {
|
||||
@ -103,8 +108,8 @@ func getSortedLintersConfigs(linters []RunnerLinterConfig) []RunnerLinterConfig
|
||||
return ret
|
||||
}
|
||||
|
||||
func (r *SimpleRunner) runWorkers(ctx context.Context, lintCtx *Context, linters []RunnerLinterConfig) <-chan lintRes {
|
||||
tasksCh := make(chan Linter, len(linters))
|
||||
func (r *SimpleRunner) runWorkers(ctx context.Context, lintCtx *linter.Context, linters []linter.Config) <-chan lintRes {
|
||||
tasksCh := make(chan linter.Config, len(linters))
|
||||
lintResultsCh := make(chan lintRes, len(linters))
|
||||
var wg sync.WaitGroup
|
||||
|
||||
@ -122,7 +127,7 @@ func (r *SimpleRunner) runWorkers(ctx context.Context, lintCtx *Context, linters
|
||||
|
||||
lcs := getSortedLintersConfigs(linters)
|
||||
for _, lc := range lcs {
|
||||
tasksCh <- lc.GetLinter()
|
||||
tasksCh <- lc
|
||||
}
|
||||
close(tasksCh)
|
||||
|
||||
@ -146,7 +151,7 @@ func (r SimpleRunner) processLintResults(ctx context.Context, inCh <-chan lintRe
|
||||
|
||||
for res := range inCh {
|
||||
if res.err != nil {
|
||||
logrus.Infof("Can't run linter %s: %s", res.linter.Name(), res.err)
|
||||
logrus.Infof("Can't run linter %s: %s", res.linter.Linter.Name(), res.err)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -189,7 +194,7 @@ func collectIssues(ctx context.Context, resCh <-chan lintRes) <-chan result.Issu
|
||||
return retIssues
|
||||
}
|
||||
|
||||
func (r SimpleRunner) Run(ctx context.Context, linters []RunnerLinterConfig, lintCtx *Context) <-chan result.Issue {
|
||||
func (r SimpleRunner) Run(ctx context.Context, linters []linter.Config, lintCtx *linter.Context) <-chan result.Issue {
|
||||
lintResultsCh := r.runWorkers(ctx, lintCtx, linters)
|
||||
processedLintResultsCh := r.processLintResults(ctx, lintResultsCh)
|
||||
if ctx.Err() != nil {
|
||||
|
122
scripts/gen_readme/main.go
Normal file
122
scripts/gen_readme/main.go
Normal file
@ -0,0 +1,122 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/lintersdb"
|
||||
)
|
||||
|
||||
func main() {
|
||||
const (
|
||||
tmplPath = "README.md.tmpl"
|
||||
outPath = "README.md"
|
||||
)
|
||||
|
||||
if err := genReadme(tmplPath, outPath); err != nil {
|
||||
log.Fatalf("failed: %s", err)
|
||||
}
|
||||
log.Printf("Successfully generated %s", outPath)
|
||||
}
|
||||
|
||||
func genReadme(tmplPath, outPath string) error {
|
||||
ctx, err := buildTemplateContext()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out, err := os.Create(outPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
tmpl := template.Must(template.ParseFiles(tmplPath))
|
||||
return tmpl.Execute(out, ctx)
|
||||
}
|
||||
|
||||
func buildTemplateContext() (map[string]interface{}, error) {
|
||||
golangciYaml, err := ioutil.ReadFile(".golangci.yml")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't read .golangci.yml: %s", err)
|
||||
}
|
||||
|
||||
if err = exec.Command("go", "install", "./cmd/...").Run(); err != nil {
|
||||
return nil, fmt.Errorf("can't run go install: %s", err)
|
||||
}
|
||||
|
||||
lintersOut, err := exec.Command("golangci-lint", "linters").Output()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't run linters cmd: %s", err)
|
||||
}
|
||||
|
||||
lintersOutParts := bytes.Split(lintersOut, []byte("\n\n"))
|
||||
|
||||
return map[string]interface{}{
|
||||
"GolangciYaml": string(golangciYaml),
|
||||
"LintersCommandOutputEnabledOnly": string(lintersOutParts[0]),
|
||||
"LintersCommandOutputDisabledOnly": string(lintersOutParts[1]),
|
||||
"EnabledByDefaultLinters": getLintersListMarkdown(true),
|
||||
"DisabledByDefaultLinters": getLintersListMarkdown(false),
|
||||
"ThanksList": getThanksList(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getLintersListMarkdown(enabled bool) string {
|
||||
var neededLcs []linter.Config
|
||||
lcs := lintersdb.GetAllSupportedLinterConfigs()
|
||||
for _, lc := range lcs {
|
||||
if lc.EnabledByDefault == enabled {
|
||||
neededLcs = append(neededLcs, lc)
|
||||
}
|
||||
}
|
||||
|
||||
var lines []string
|
||||
for _, lc := range neededLcs {
|
||||
var link string
|
||||
if lc.OriginalURL != "" {
|
||||
link = fmt.Sprintf("[%s](%s)", lc.Linter.Name(), lc.OriginalURL)
|
||||
} else {
|
||||
link = lc.Linter.Name()
|
||||
}
|
||||
line := fmt.Sprintf("- %s - %s", link, lc.Linter.Desc())
|
||||
lines = append(lines, line)
|
||||
}
|
||||
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func getThanksList() string {
|
||||
var lines []string
|
||||
addedAuthors := map[string]bool{}
|
||||
for _, lc := range lintersdb.GetAllSupportedLinterConfigs() {
|
||||
if lc.OriginalURL == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
const githubPrefix = "https://github.com/"
|
||||
if !strings.HasPrefix(lc.OriginalURL, githubPrefix) {
|
||||
continue
|
||||
}
|
||||
|
||||
githubSuffix := strings.TrimPrefix(lc.OriginalURL, githubPrefix)
|
||||
githubAuthor := strings.Split(githubSuffix, "/")[0]
|
||||
if addedAuthors[githubAuthor] {
|
||||
continue
|
||||
}
|
||||
addedAuthors[githubAuthor] = true
|
||||
|
||||
line := fmt.Sprintf("- [%s](https://github.com/%s)",
|
||||
githubAuthor, githubAuthor)
|
||||
lines = append(lines, line)
|
||||
}
|
||||
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user