mirror of
https://github.com/scratchfoundation/golangci-lint.git
synced 2025-08-28 22:28:43 -04:00
docs: add articles about contributing
This commit is contained in:
parent
1f5e615305
commit
e3227ec340
17 changed files with 1160 additions and 81 deletions
15
docs/src/components/ResponsiveContainer.js
Normal file
15
docs/src/components/ResponsiveContainer.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
/** @jsx jsx */
|
||||
import { css, jsx } from "@emotion/core";
|
||||
|
||||
const ResponsiveContainer = ({ children }) => (
|
||||
<div
|
||||
css={css`
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
`}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
export default ResponsiveContainer;
|
|
@ -16,12 +16,10 @@
|
|||
link: "/usage/configuration/"
|
||||
- label: "False Positives"
|
||||
link: "/usage/false-positives/"
|
||||
- label: "FAQ"
|
||||
link: "/usage/faq/"
|
||||
- label: "Performance"
|
||||
link: "/usage/performance/"
|
||||
- label: "Debug"
|
||||
link: "/usage/debug/"
|
||||
- label: "FAQ"
|
||||
link: "/usage/faq/"
|
||||
- label: Product
|
||||
items:
|
||||
- label: "Roadmap"
|
||||
|
@ -32,3 +30,17 @@
|
|||
link: "/product/comparison/"
|
||||
- label: "GitHub"
|
||||
link: "https://github.com/golangci/golangci-lint"
|
||||
- label: Contributing
|
||||
items:
|
||||
- label: Workflow
|
||||
link: /contributing/workflow/
|
||||
- label: Architecture
|
||||
link: /contributing/architecture/
|
||||
- label: New Linters
|
||||
link: /contributing/new-linters/
|
||||
- label: "Debug"
|
||||
link: "/contributing/debug/"
|
||||
- label: FAQ
|
||||
link: /contributing/faq/
|
||||
- label: This Website
|
||||
link: /contributing/website/
|
||||
|
|
316
docs/src/docs/contributing/architecture.mdx
Normal file
316
docs/src/docs/contributing/architecture.mdx
Normal file
|
@ -0,0 +1,316 @@
|
|||
---
|
||||
title: Architecture
|
||||
---
|
||||
|
||||
import ResponsiveContainer from "components/ResponsiveContainer";
|
||||
|
||||
There are the following `golangci-lint` execution steps:
|
||||
|
||||
<ResponsiveContainer>
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
init[Init]
|
||||
loadPackages[Load packages]
|
||||
runLinters[Run linters]
|
||||
postprocess[Postprocess issues]
|
||||
print[Print issues]
|
||||
|
||||
init --> loadPackages --> runLinters --> postprocess --> print
|
||||
|
||||
```
|
||||
|
||||
</ResponsiveContainer>
|
||||
|
||||
## Init
|
||||
|
||||
The execution starts here:
|
||||
|
||||
```go title=cmd/golangci-lint/main.go
|
||||
func main() {
|
||||
e := commands.NewExecutor(version, commit, date)
|
||||
|
||||
if err := e.Execute(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed executing command with error %v\n", err)
|
||||
os.Exit(exitcodes.Failure)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The **executer** is our abstraction:
|
||||
|
||||
```go title=pkg/commands/executor.go
|
||||
type Executor struct {
|
||||
rootCmd *cobra.Command
|
||||
runCmd *cobra.Command
|
||||
lintersCmd *cobra.Command
|
||||
|
||||
exitCode int
|
||||
|
||||
cfg *config.Config
|
||||
log logutils.Log
|
||||
reportData report.Data
|
||||
DBManager *lintersdb.Manager
|
||||
EnabledLintersSet *lintersdb.EnabledSet
|
||||
contextLoader *lint.ContextLoader
|
||||
goenv *goutil.Env
|
||||
fileCache *fsutils.FileCache
|
||||
lineCache *fsutils.LineCache
|
||||
pkgCache *pkgcache.Cache
|
||||
debugf logutils.DebugFunc
|
||||
sw *timeutils.Stopwatch
|
||||
|
||||
loadGuard *load.Guard
|
||||
flock *flock.Flock
|
||||
}
|
||||
```
|
||||
|
||||
We use dependency injection and all root dependencies are stored in this executor.
|
||||
|
||||
In the function `NewExecutor` we do the following:
|
||||
|
||||
1. init dependencies
|
||||
2. init [cobra](https://github.com/spf13/cobra) commands
|
||||
3. parse config file using [viper](https://github.com/spf13/viper) and merge it with command line args.
|
||||
|
||||
The following execution is controlled by `cobra`. If user a user executes `golangci-lint run`
|
||||
then `cobra` executes `e.runCmd`.
|
||||
|
||||
Different `cobra` commands have different runners, e.g. a `run` command is configured in the following way:
|
||||
|
||||
```go title=pkg/commands/run.go
|
||||
func (e *Executor) initRun() {
|
||||
e.runCmd = &cobra.Command{
|
||||
Use: "run",
|
||||
Short: welcomeMessage,
|
||||
Run: e.executeRun,
|
||||
PreRun: func(_ *cobra.Command, _ []string) {
|
||||
if ok := e.acquireFileLock(); !ok {
|
||||
e.log.Fatalf("Parallel golangci-lint is running")
|
||||
}
|
||||
},
|
||||
PostRun: func(_ *cobra.Command, _ []string) {
|
||||
e.releaseFileLock()
|
||||
},
|
||||
}
|
||||
e.rootCmd.AddCommand(e.runCmd)
|
||||
e.runCmd.SetOutput(logutils.StdOut) // use custom output to properly color it in Windows terminals
|
||||
e.initRunConfiguration(e.runCmd)
|
||||
}
|
||||
```
|
||||
|
||||
The primary execution function of the `run` command is `executeRun`.
|
||||
|
||||
## Load Packages
|
||||
|
||||
Loading packages is listing all packages and their recursive dependencies for analysis.
|
||||
Also, depending from enabled linters set some parsing of a source code can be performed
|
||||
at this step.
|
||||
|
||||
Packages loading stars here:
|
||||
|
||||
```go title=pkg/lint/load.go
|
||||
func (cl *ContextLoader) Load(ctx context.Context, linters []*linter.Config) (*linter.Context, error) {
|
||||
loadMode := cl.findLoadMode(linters)
|
||||
pkgs, err := cl.loadPackages(ctx, loadMode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// ...
|
||||
ret := &linter.Context{
|
||||
// ...
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
```
|
||||
|
||||
First, we find a load mode as union of load modes for all enabled linters.
|
||||
We use [go/packages](https://godoc.org/golang.org/x/tools/go/packages) for packages loading and use it's enum `packages.Need*` for load modes.
|
||||
Load mode sets which data does a linter needs for execution.
|
||||
|
||||
A linter that works only with AST need minimum of information: only filenames and AST. There is no need for
|
||||
packages dependencies or type information. AST is built during `go/analysis` execution to reduce memory usage.
|
||||
Such AST-based linters are configured with the following code:
|
||||
|
||||
```go title=pkg/lint/linter/config.go
|
||||
func (lc *Config) WithLoadFiles() *Config {
|
||||
lc.LoadMode |= packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles
|
||||
return lc
|
||||
}
|
||||
```
|
||||
|
||||
If a linter uses `go/analysis` and needs type information, we need to extract more data by `go/packages`:
|
||||
|
||||
```go title=/pkg/lint/linter/config.go
|
||||
func (lc *Config) WithLoadForGoAnalysis() *Config {
|
||||
lc = lc.WithLoadFiles()
|
||||
lc.LoadMode |= packages.NeedImports | packages.NeedDeps | packages.NeedExportsFile | packages.NeedTypesSizes
|
||||
return lc
|
||||
}
|
||||
```
|
||||
|
||||
After finding a load mode we run `go/packages`: the library get list of dirs (or `./...` as the default value) as input
|
||||
and outputs list of packages and requested information about them: filenames, type information, AST, etc.
|
||||
|
||||
## Run Linters
|
||||
|
||||
First, we need to find all enaled linters. All linters are registered here:
|
||||
|
||||
```go title=pkg/lint/lintersdb/manager.go
|
||||
func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
||||
// ...
|
||||
lcs := []*linter.Config{
|
||||
linter.NewConfig(golinters.NewGovet(govetCfg)).
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithAlternativeNames("vet", "vetshadow").
|
||||
WithURL("https://golang.org/cmd/vet/"),
|
||||
linter.NewConfig(golinters.NewBodyclose()).
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetPerformance, linter.PresetBugs).
|
||||
WithURL("https://github.com/timakin/bodyclose"),
|
||||
// ...
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
We filter requested in config and command-line linters in `EnabledSet`:
|
||||
|
||||
```go title=pkg/lint/lintersdb/enabled_set.go
|
||||
func (es EnabledSet) GetEnabledLintersMap() (map[string]*linter.Config, error)
|
||||
```
|
||||
|
||||
We merge enabled linters into one `MetaLinter` to improve execution time if we can:
|
||||
|
||||
```go title=pkg/lint/lintersdb/enabled_set.go
|
||||
// GetOptimizedLinters returns enabled linters after optimization (merging) of multiple linters
|
||||
// into a fewer number of linters. E.g. some go/analysis linters can be optimized into
|
||||
// one metalinter for data reuse and speed up.
|
||||
func (es EnabledSet) GetOptimizedLinters() ([]*linter.Config, error) {
|
||||
// ...
|
||||
es.combineGoAnalysisLinters(resultLintersSet)
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
The `MetaLinter` just stores all merged linters inside to run them at once:
|
||||
|
||||
```go title=pkg/golinters/goanalysis/metalinter.go
|
||||
type MetaLinter struct {
|
||||
linters []*Linter
|
||||
analyzerToLinterName map[*analysis.Analyzer]string
|
||||
}
|
||||
```
|
||||
|
||||
Currently, all linters except `unused` can be merged into this meta linter.
|
||||
The `unused` isn't merged because it has high memory usage.
|
||||
|
||||
Linters execution starts in `runAnalyzers`. It's the most complex part of the `golangci-lint`.
|
||||
We use custom [go/analysis](https://godoc.org/golang.org/x/tools/go/analysis) runner there. It runs as much as it can in parallel. It lazy-loads as much as it can
|
||||
to reduce memory usage. Also, it set all heavyweight data to `nil` as becomes unneeded to save memory.
|
||||
|
||||
We don't use existing [multichecker](https://godoc.org/golang.org/x/tools/go/analysis/multichecker) because
|
||||
it doesn't use caching and doesn't have some important performance optimizations.
|
||||
|
||||
All found by linters issues are represented with `result.Issue` struct:
|
||||
|
||||
```go title=pkg/result/issue.go
|
||||
type Issue struct {
|
||||
FromLinter string
|
||||
Text string
|
||||
|
||||
// Source lines of a code with the issue to show
|
||||
SourceLines []string
|
||||
|
||||
// If we know how to fix the issue we can provide replacement lines
|
||||
Replacement *Replacement
|
||||
|
||||
// Pkg is needed for proper caching of linting results
|
||||
Pkg *packages.Package `json:"-"`
|
||||
|
||||
LineRange *Range `json:",omitempty"`
|
||||
|
||||
Pos token.Position
|
||||
|
||||
// HunkPos is used only when golangci-lint is run over a diff
|
||||
HunkPos int `json:",omitempty"`
|
||||
|
||||
// If we are expecting a nolint (because this is from nolintlint), record the expected linter
|
||||
ExpectNoLint bool
|
||||
ExpectedNoLintLinter string
|
||||
}
|
||||
```
|
||||
|
||||
## Postprocess Issues
|
||||
|
||||
We have an abstraction of `result.Processor` to postprocess found issues:
|
||||
|
||||
```bash
|
||||
$ tree -L 1 ./pkg/result/processors/
|
||||
./pkg/result/processors/
|
||||
├── autogenerated_exclude.go
|
||||
├── autogenerated_exclude_test.go
|
||||
├── cgo.go
|
||||
├── diff.go
|
||||
├── exclude.go
|
||||
├── exclude_rules.go
|
||||
├── exclude_rules_test.go
|
||||
├── exclude_test.go
|
||||
├── filename_unadjuster.go
|
||||
├── fixer.go
|
||||
├── identifier_marker.go
|
||||
├── identifier_marker_test.go
|
||||
├── max_from_linter.go
|
||||
├── max_from_linter_test.go
|
||||
├── max_per_file_from_linter.go
|
||||
├── max_per_file_from_linter_test.go
|
||||
├── max_same_issues.go
|
||||
├── max_same_issues_test.go
|
||||
├── nolint.go
|
||||
├── nolint_test.go
|
||||
├── path_prettifier.go
|
||||
├── path_shortener.go
|
||||
├── processor.go
|
||||
├── skip_dirs.go
|
||||
├── skip_files.go
|
||||
├── skip_files_test.go
|
||||
├── source_code.go
|
||||
├── testdata
|
||||
├── uniq_by_line.go
|
||||
├── uniq_by_line_test.go
|
||||
└── utils.go
|
||||
```
|
||||
|
||||
The abstraction is simple:
|
||||
|
||||
```go title=pkg/result/processors/processor.go
|
||||
type Processor interface {
|
||||
Process(issues []result.Issue) ([]result.Issue, error)
|
||||
Name() string
|
||||
Finish()
|
||||
}
|
||||
```
|
||||
|
||||
A processor can hide issues (`nolint`, `exclude`) or change issues (`path_shortener`).
|
||||
|
||||
## Print Issues
|
||||
|
||||
We have an abstraction for printint found issues.
|
||||
|
||||
```bash
|
||||
$ tree -L 1 ./pkg/printers/
|
||||
./pkg/printers/
|
||||
├── checkstyle.go
|
||||
├── codeclimate.go
|
||||
├── github.go
|
||||
├── github_test.go
|
||||
├── json.go
|
||||
├── junitxml.go
|
||||
├── printer.go
|
||||
├── tab.go
|
||||
└── text.go
|
||||
```
|
||||
|
||||
Needed printer is selected by command line option `--out-format`.
|
29
docs/src/docs/contributing/faq.mdx
Normal file
29
docs/src/docs/contributing/faq.mdx
Normal file
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
title: Contributing FAQ
|
||||
---
|
||||
|
||||
## How to write a custom linter
|
||||
|
||||
See [there](/contributing/new-linters#how-to-write-a-custom-linter).
|
||||
|
||||
## How to add a new open-source linter to `golangci-lint`
|
||||
|
||||
See [there](/contributing/new-linters#how-to-add-a-public-linter-to-golangci-lint).
|
||||
|
||||
## How to add a new private linter to `golangci-lint`
|
||||
|
||||
See [there](/contributing/new-linters#how-to-add-a-private-linter-to-golangci-lint).
|
||||
|
||||
## How to update existing linter
|
||||
|
||||
Just update it's version in `go.mod`.
|
||||
|
||||
## How to add configuration option to existing linter
|
||||
|
||||
Add a new field to a [config struct](https://github.com/golangci/golangci-lint/blob/master/pkg/config/config.go).
|
||||
Document it in [.golangci.example.yml](https://github.com/golangci/golangci-lint/blob/master/.golangci.example.yml).
|
||||
Pass it to a linter.
|
||||
|
||||
## How to see `INFO` or `DEBUG` logs
|
||||
|
||||
See [tutorial about debugging](/contributing/debug/).
|
82
docs/src/docs/contributing/new-linters.mdx
Normal file
82
docs/src/docs/contributing/new-linters.mdx
Normal file
|
@ -0,0 +1,82 @@
|
|||
---
|
||||
title: New linters
|
||||
---
|
||||
|
||||
## How to write a custom linter
|
||||
|
||||
Use `go/analysis` and take a look at [this tutorial](https://disaev.me/p/writing-useful-go-analysis-linter/): it shows how to write `go/analysis` linter
|
||||
from scratch and integrate it into `golangci-lint`.
|
||||
|
||||
## How to add a public linter to `golangci-lint`
|
||||
|
||||
You need to implement a new linter using `go/analysis` API. We don't accept not `go/analysis` linters.
|
||||
|
||||
After that:
|
||||
|
||||
1. Implement functional tests for the linter: add one file into directory [`test/testdata`](https://github.com/golangci/golangci-lint/tree/master/test/testdata).
|
||||
Run `T=yourlintername.go make test_linters` to ensure that test fails.
|
||||
2. Add a new file `pkg/golinters/{yourlintername}.go`. Look at other linters in this directory. Implement linter integration and check that test passes.
|
||||
3. Add the new struct for the linter (which you've implemented in `pkg/golinters/{yourlintername}.go`) to the
|
||||
list of all supported linters in [`pkg/lint/lintersdb/lintersdb.go`](https://github.com/golangci/golangci-lint/blob/master/pkg/lint/lintersdb/lintersdb.go)
|
||||
to the function `GetAllSupportedLinterConfigs`. Enable it by default only if you are sure.
|
||||
4. Find out what options do you need to configure for the linter. For example, `govet` has
|
||||
only 1 option: [`check-shadowing`](https://github.com/golangci/golangci-lint/blob/master/.golangci.example.yml#L20).
|
||||
Choose default values to not being annoying for users of golangci-lint. Add configuration options to:
|
||||
|
||||
- [.golangci.example.yml](https://github.com/golangci/golangci-lint/blob/master/.golangci.example.yml) - the example of a configuration file. You can also add
|
||||
them to [.golangci.yml](https://github.com/golangci/golangci-lint/blob/master/.golangci.yml) if you think
|
||||
that this project needs not default values.
|
||||
- [config struct](https://github.com/golangci/golangci-lint/blob/master/pkg/config/config.go#L61) - don't forget
|
||||
about `mapstructure` tag for proper configuration files parsing by [pflag](https://github.com/spf13/pflag).
|
||||
|
||||
5. Take a look at the example of [Pull Request with new linter support](https://github.com/golangci/golangci-lint/pull/850).
|
||||
|
||||
## How to add a private linter to `golangci-lint`
|
||||
|
||||
Some people and organizations may choose to have custom made linters run as a part of `golangci-lint`.
|
||||
Typically, these linters can't be open-sourced or too specific.
|
||||
Such linters can be added through Go's plugin library.
|
||||
|
||||
### Configure a Plugin
|
||||
|
||||
If you already have a linter plugin available, you can follow these steps to define it's usage in a projects
|
||||
`.golangci.yml` file. An example linter can be found at [here](https://github.com/golangci/example-plugin-linter). If you're looking for
|
||||
instructions on how to configure your own custom linter, they can be found further down.
|
||||
|
||||
1. If the project you want to lint does not have one already, copy the [.golangci.yml](https://github.com/golangci/golangci-lint/blob/master/.golangci.yml) to the root directory.
|
||||
2. Adjust the yaml to appropriate `linters-settings:custom` entries as so:
|
||||
|
||||
```yaml
|
||||
linters-settings:
|
||||
custom:
|
||||
example:
|
||||
path: /example.so
|
||||
description: The description of the linter
|
||||
original-url: github.com/golangci/example-linter
|
||||
```
|
||||
|
||||
That is all the configuration that is required to run a custom linter in your project. Custom linters are enabled by default,
|
||||
but abide by the same rules as other linters. If the disable all option is specified either on command line or in
|
||||
`.golangci.yml` files `linters:disable-all: true`, custom linters will be disabled; they can be re-enabled by adding them
|
||||
to the `linters:enable` list, or providing the enabled option on the command line, `golangci-lint run -Eexample`.
|
||||
|
||||
### Create a Plugin
|
||||
|
||||
Your linter must implement one or more `golang.org/x/tools/go/analysis.Analyzer` structs.
|
||||
Your project should also use `go.mod`. All versions of libraries that overlap `golangci-lint` (including replaced
|
||||
libraries) MUST be set to the same version as `golangci-lint`. You can see the versions by running `go version -m golangci-lint`.
|
||||
|
||||
You'll also need to create a go file like `plugin/example.go`. This MUST be in the package `main`, and define a
|
||||
variable of name `AnalyzerPlugin`. The `AnalyzerPlugin` instance MUST implement the following interface:
|
||||
|
||||
```go
|
||||
type AnalyzerPlugin interface {
|
||||
GetAnalyzers() []*analysis.Analyzer
|
||||
}
|
||||
```
|
||||
|
||||
The type of `AnalyzerPlugin` is not important, but is by convention `type analyzerPlugin struct {}`. See
|
||||
[plugin/example.go](https://github.com/golangci/example-plugin-linter/plugin/example.go) for more info.
|
||||
|
||||
To build the plugin, from the root project directory, run `go build -buildmode=plugin plugin/example.go`. This will create a plugin `*.so`
|
||||
file that can be copied into your project or another well known location for usage in golangci-lint.
|
76
docs/src/docs/contributing/website.mdx
Normal file
76
docs/src/docs/contributing/website.mdx
Normal file
|
@ -0,0 +1,76 @@
|
|||
---
|
||||
title: Website architecture
|
||||
---
|
||||
|
||||
## Technology
|
||||
|
||||
We use [Gatsby](https://www.gatsbyjs.org/) for static site generation because sites built with it
|
||||
are very fast.
|
||||
|
||||
This framework uses React and JavaScript/TypeScript.
|
||||
|
||||
## Source Code
|
||||
|
||||
The website lives in `docs/` directory of [golangci-lint repository](https://github.com/golangci/golangci-lint).
|
||||
|
||||
## Theme
|
||||
|
||||
Initially the site is based on [@rocketseat](https://rocketdocs.netlify.app/) theme.
|
||||
Later we've merged it's code into `src/@rocketseat` because we needed too much changes
|
||||
and [gatsby shadowing](https://www.gatsbyjs.org/docs/themes/shadowing/) doesn't
|
||||
allow shadowing `gatsby-node.js` or `gatsby-config.js`.
|
||||
|
||||
## Navigation
|
||||
|
||||
Left menu is configured in `src/config/sidebar.yml`.
|
||||
|
||||
## Articles
|
||||
|
||||
Articles are located in `src/docs/` in `*.mdx` files. [MDX](https://mdxjs.com/getting-started/gatsby) is markdown
|
||||
allowing to use `React` components.
|
||||
|
||||
## Templating
|
||||
|
||||
We use templates like `{.SomeField}` inside our `mdx` files. There templates are expanded
|
||||
by running `make expand_website_templates` in the root of the repository.
|
||||
It runs script `scripts/expand_website_templates/main.go` that rewrites `mdx` files with replaced templates.
|
||||
|
||||
## CDN and DNS
|
||||
|
||||
We use [CloudFlare](https://www.cloudflare.com/) for CDN, proxying and DNS management.
|
||||
|
||||
## Hosting
|
||||
|
||||
We use [Netlify](https://www.netlify.com/) as static website hosting and CD.
|
||||
It's integrated into our pull requests: if `docs/` directory has changes Netlify
|
||||
will trigger website rebuild and deploy it's preview for a branch. You can view
|
||||
it to ensure that everything ok.
|
||||
|
||||
Netlify deploys the website to production after merging anything to a `master` branch.
|
||||
|
||||
## Local Testing
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run start
|
||||
```
|
||||
|
||||
And navigate to `http://localhost:8000` after successfull Gatsby build.
|
||||
There is no need to restart Gatsby server almost for all changes: it supports hot reload.
|
||||
Also, there is no need to refresh a webpage: hot reload updates changed content on the open page.
|
||||
|
||||
## Trigger Website Rebuild
|
||||
|
||||
Currently, Netlify triggers rebuild only if anything has changes in `docs/` directory.
|
||||
But we can add a new linter and need to change a documentation to list the linter.
|
||||
|
||||
To do it run
|
||||
|
||||
```bash
|
||||
go run ./scripts/expand_website_templates/main.go -only-state
|
||||
```
|
||||
|
||||
It saves a hash of template replacements (that include all linters, configs, etc)
|
||||
into `docs/template_data.state`.
|
58
docs/src/docs/contributing/workflow.mdx
Normal file
58
docs/src/docs/contributing/workflow.mdx
Normal file
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
title: Contributing Workflow
|
||||
---
|
||||
|
||||
# Contributing
|
||||
|
||||
By participating to this project, you agree to abide our [code of
|
||||
conduct](https://github.com/golangci/golangci-lint/blob/master/CODE_OF_CONDUCT.md).
|
||||
|
||||
## Setup your machine
|
||||
|
||||
`golangci-lint` is written in [Go](https://golang.org/).
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- `make`
|
||||
- [Go 1.13+](https://golang.org/doc/install)
|
||||
|
||||
Fork and clone [golangci-lint](https://github.com/golangci/golangci-lint) repository.
|
||||
|
||||
A good way of making sure everything is all right is running the following:
|
||||
|
||||
```bash
|
||||
make build
|
||||
./golangci-lint run -v
|
||||
```
|
||||
|
||||
## Test your change
|
||||
|
||||
When you are satisfied with the changes, we suggest you run:
|
||||
|
||||
```bash
|
||||
$ make test
|
||||
```
|
||||
|
||||
Which runs all the linters and tests.
|
||||
|
||||
## Submit a pull request
|
||||
|
||||
Push your branch to your `golangci-lint` fork and open a pull request against the
|
||||
`master` branch.
|
||||
|
||||
## Pull request checks
|
||||
|
||||
First, please, accept [CLA](https://gist.github.com/jirfag/26a39fd375da84b2d5ad4296fecb0668) - [cla assistant](https://cla-assistant.io/) will
|
||||
make a comment on the pull request about it.
|
||||
|
||||
Also, we run a few checks in CI by using GitHub actions, you can see them [here](https://github.com/golangci/golangci-lint/blob/master/.github/workflows/pr.yml).
|
||||
|
||||
## Credits
|
||||
|
||||
### Contributors
|
||||
|
||||
Thank you to all the people who have already contributed to `golangci-lint`!
|
||||
|
||||
[](https://github.com/golangci/golangci-lint/graphs/contributors)
|
||||
|
||||
<!-- TODO: use `allcontributors` -->
|
|
@ -44,7 +44,7 @@ Short 1.5 min video demo of analyzing [beego](https://github.com/astaxie/beego).
|
|||
|
||||
## Contributors
|
||||
|
||||
This project exists thanks to all the people who contribute.
|
||||
This project exists thanks to all the people who contribute. [How to contribute](/contributing/workflow/).
|
||||
|
||||
[](https://github.com/golangci/golangci-lint/graphs/contributors)
|
||||
|
||||
|
|
|
@ -25,3 +25,4 @@ The following companies/products use `golangci-lint`:
|
|||
- [Yahoo](https://github.com/yahoo/yfuzz)
|
||||
|
||||
And thousands of other great companies use `golangci-lint` too.
|
||||
You can find them by [this GitHub search query](https://github.com/search?q=golangci-lint&type=Code).
|
||||
|
|
|
@ -7,20 +7,16 @@ title: FAQ
|
|||
You can integrate it yourself, see this [manual](/usage/linters#how-to-add-a-linter-to-golangci-lint-).
|
||||
Or you can create a [GitHub Issue](https://github.com/golangci/golangci-lint/issues/new) and we will integrate when time permits.
|
||||
|
||||
## 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
|
||||
## How to integrate `golangci-lint` into large project with thousands of issues
|
||||
|
||||
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=HEAD~1`. Also, take a look at option `--new`, but consider that CI scripts that generate unstaged files will make `--new` only point out issues in those files and not in the last commit. In that regard `--new-from-rev=HEAD~1` is safer.
|
||||
By doing this you won't create new issues in your code and can choose fix existing issues (or not).
|
||||
|
||||
## How to use `golangci-lint` in CI (Continuous Integration)?
|
||||
## How to use `golangci-lint` in CI
|
||||
|
||||
Run `golangci-lint` in CI and check the exit code. If it's non-zero - fail the build.
|
||||
|
||||
We don't recommend vendoring `golangci-lint` in your repo: you will get troubles updating `golangci-lint`. Please, use recommended way to install with the shell script: it's very fast.
|
||||
|
||||
## Do I need to run `go install`?
|
||||
|
||||
No, you don't need to do it anymore.
|
||||
See [how to properly install `golangci-lint` in CI](/usage/install#ci-installation)
|
||||
|
||||
## Which go versions are supported
|
||||
|
||||
|
@ -40,7 +36,7 @@ Long answer:
|
|||
2. Run it with `-v` option and check the output.
|
||||
3. If it doesn't help create a [GitHub issue](https://github.com/golangci/golangci-lint/issues/new) with the output from the error and #2 above.
|
||||
|
||||
## Why running with `--fast` is slow on the first run?
|
||||
## Why running with `--fast` is slow on the first run
|
||||
|
||||
Because the first run caches type information. All subsequent runs will be fast.
|
||||
Usually this options is used during development on local machine and compilation was already performed.
|
||||
|
|
|
@ -15,67 +15,3 @@ golangci-lint help linters
|
|||
## Disabled By Default Linters (`-E/--enable`)
|
||||
|
||||
{.DisabledByDefaultLinters}
|
||||
|
||||
## How to add a linter to `golangci-lint`
|
||||
|
||||
You need to implement a new linter using `go/analysis` API. After that:
|
||||
|
||||
1. Implement functional tests for the linter: add one file into directory [`test/testdata`](https://github.com/golangci/golangci-lint/tree/master/test/testdata). Run `T=yourlintername.go make test_linters` to ensure that test fails.
|
||||
2. Add a new file `pkg/golinters/{yourlintername}.go`. Look at other linters in this directory. Implement linter integration and check that test passes.
|
||||
3. Add the new struct for the linter (which you've implemented in `pkg/golinters/{yourlintername}.go`) to the list of all supported linters in [`pkg/lint/lintersdb/lintersdb.go`](https://github.com/golangci/golangci-lint/blob/master/pkg/lint/lintersdb/lintersdb.go) to the function `GetAllSupportedLinterConfigs`. Enable it by default only if you are sure.
|
||||
4. Find out what options do you need to configure for the linter. For example, `govet` has only 1 option: [`check-shadowing`](https://github.com/golangci/golangci-lint/blob/master/.golangci.example.yml#L20). Choose default values to not being annoying for users of golangci-lint. Add configuration options to:
|
||||
|
||||
- [.golangci.example.yml](.golangci.example.yml) - the example of a configuration file. You can also add them to [.golangci.yml](https://github.com/golangci/golangci-lint/blob/master/.golangci.yml) if you think that this project needs not default values.
|
||||
- [config struct](https://github.com/golangci/golangci-lint/blob/master/pkg/config/config.go#L61) - don't forget about `mapstructure` tag for proper configuration files parsing by [pflag](https://github.com/spf13/pflag).
|
||||
|
||||
5. Take a look at the example of [Pull Request with new linter support](https://github.com/golangci/golangci-lint/pull/135).
|
||||
|
||||
## How to add a private linter
|
||||
|
||||
Some people and organizations may choose to have custom made linters run as a part of `golangci-lint`.
|
||||
Typically, these linters can't be open-sourced or too specific.
|
||||
Such linters can be added through Go's plugin library.
|
||||
|
||||
### Configure a Plugin
|
||||
|
||||
If you already have a linter plugin available, you can follow these steps to define it's usage in a projects
|
||||
`.golangci.yml` file. An example linter can be found at [here](https://github.com/golangci/example-plugin-linter). If you're looking for
|
||||
instructions on how to configure your own custom linter, they can be found further down.
|
||||
|
||||
1. If the project you want to lint does not have one already, copy the [.golangci.yml](https://github.com/golangci/golangci-lint/blob/master/.golangci.yml) to the root directory.
|
||||
2. Adjust the yaml to appropriate `linters-settings:custom` entries as so:
|
||||
|
||||
```yaml
|
||||
linters-settings:
|
||||
custom:
|
||||
example:
|
||||
path: /example.so
|
||||
description: The description of the linter
|
||||
original-url: github.com/golangci/example-linter
|
||||
```
|
||||
|
||||
That is all the configuration that is required to run a custom linter in your project. Custom linters are enabled by default,
|
||||
but abide by the same rules as other linters. If the disable all option is specified either on command line or in
|
||||
`.golangci.yml` files `linters:disable-all: true`, custom linters will be disabled; they can be re-enabled by adding them
|
||||
to the `linters:enable` list, or providing the enabled option on the command line, `golangci-lint run -Eexample`.
|
||||
|
||||
### Create a Plugin
|
||||
|
||||
Your linter must implement one or more `golang.org/x/tools/go/analysis.Analyzer` structs.
|
||||
Your project should also use `go.mod`. All versions of libraries that overlap `golangci-lint` (including replaced
|
||||
libraries) MUST be set to the same version as `golangci-lint`. You can see the versions by running `go version -m golangci-lint`.
|
||||
|
||||
You'll also need to create a go file like `plugin/example.go`. This MUST be in the package `main`, and define a
|
||||
variable of name `AnalyzerPlugin`. The `AnalyzerPlugin` instance MUST implement the following interface:
|
||||
|
||||
```go
|
||||
type AnalyzerPlugin interface {
|
||||
GetAnalyzers() []*analysis.Analyzer
|
||||
}
|
||||
```
|
||||
|
||||
The type of `AnalyzerPlugin` is not important, but is by convention `type analyzerPlugin struct {}`. See
|
||||
[plugin/example.go](https://github.com/golangci/example-plugin-linter/plugin/example.go) for more info.
|
||||
|
||||
To build the plugin, from the root project directory, run `go build -buildmode=plugin plugin/example.go`. This will create a plugin `*.so`
|
||||
file that can be copied into your project or another well known location for usage in golangci-lint.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue