-
Star
(333)
You must be signed in to star a gist -
Fork
(39)
You must be signed in to fork a gist
-
-
Save maratori/47a4d00457a92aa426dbd48a18776322 to your computer and use it in GitHub Desktop.
# This file is licensed under the terms of the MIT license https://opensource.org/license/mit | |
# Copyright (c) 2021-2025 Marat Reymers | |
## Golden config for golangci-lint v2.0.2 | |
# | |
# This is the best config for golangci-lint based on my experience and opinion. | |
# It is very strict, but not extremely strict. | |
# Feel free to adapt it to suit your needs. | |
# If this config helps you, please consider keeping a link to this file (see the next comment). | |
# Based on https://gist.github.com/maratori/47a4d00457a92aa426dbd48a18776322 | |
version: "2" | |
issues: | |
# Maximum count of issues with the same text. | |
# Set to 0 to disable. | |
# Default: 3 | |
max-same-issues: 50 | |
formatters: | |
enable: | |
- goimports # checks if the code and import statements are formatted according to the 'goimports' command | |
- golines # checks if code is formatted, and fixes long lines | |
## you may want to enable | |
#- gci # checks if code and import statements are formatted, with additional rules | |
#- gofmt # checks if the code is formatted according to 'gofmt' command | |
## disabled | |
#- gofumpt # [replaced by goimports, gofumports is not available yet] checks if code and import statements are formatted, with additional rules | |
# All settings can be found here https://github.com/golangci/golangci-lint/blob/HEAD/.golangci.reference.yml | |
settings: | |
goimports: | |
# A list of prefixes, which, if set, checks import paths | |
# with the given prefixes are grouped after 3rd-party packages. | |
# Default: [] | |
local-prefixes: | |
- github.com/my/project | |
golines: | |
# Target maximum line length. | |
# Default: 100 | |
max-len: 120 | |
linters: | |
enable: | |
- asasalint # checks for pass []any as any in variadic func(...any) | |
- asciicheck # checks that your code does not contain non-ASCII identifiers | |
- bidichk # checks for dangerous unicode character sequences | |
- bodyclose # checks whether HTTP response body is closed successfully | |
- canonicalheader # checks whether net/http.Header uses canonical header | |
- copyloopvar # detects places where loop variables are copied (Go 1.22+) | |
- cyclop # checks function and package cyclomatic complexity | |
- depguard # checks if package imports are in a list of acceptable packages | |
- dupl # tool for code clone detection | |
- durationcheck # checks for two durations multiplied together | |
- errcheck # checking for unchecked errors, these unchecked errors can be critical bugs in some cases | |
- errname # checks that sentinel errors are prefixed with the Err and error types are suffixed with the Error | |
- errorlint # finds code that will cause problems with the error wrapping scheme introduced in Go 1.13 | |
- exhaustive # checks exhaustiveness of enum switch statements | |
- exptostd # detects functions from golang.org/x/exp/ that can be replaced by std functions | |
- fatcontext # detects nested contexts in loops | |
- forbidigo # forbids identifiers | |
- funlen # tool for detection of long functions | |
- gocheckcompilerdirectives # validates go compiler directive comments (//go:) | |
- gochecknoglobals # checks that no global variables exist | |
- gochecknoinits # checks that no init functions are present in Go code | |
- gochecksumtype # checks exhaustiveness on Go "sum types" | |
- gocognit # computes and checks the cognitive complexity of functions | |
- goconst # finds repeated strings that could be replaced by a constant | |
- gocritic # provides diagnostics that check for bugs, performance and style issues | |
- gocyclo # computes and checks the cyclomatic complexity of functions | |
- godot # checks if comments end in a period | |
- gomoddirectives # manages the use of 'replace', 'retract', and 'excludes' directives in go.mod | |
- goprintffuncname # checks that printf-like functions are named with f at the end | |
- gosec # inspects source code for security problems | |
- govet # reports suspicious constructs, such as Printf calls whose arguments do not align with the format string | |
- iface # checks the incorrect use of interfaces, helping developers avoid interface pollution | |
- ineffassign # detects when assignments to existing variables are not used | |
- intrange # finds places where for loops could make use of an integer range | |
- loggercheck # checks key value pairs for common logger libraries (kitlog,klog,logr,zap) | |
- makezero # finds slice declarations with non-zero initial length | |
- mirror # reports wrong mirror patterns of bytes/strings usage | |
- mnd # detects magic numbers | |
- musttag # enforces field tags in (un)marshaled structs | |
- nakedret # finds naked returns in functions greater than a specified function length | |
- nestif # reports deeply nested if statements | |
- nilerr # finds the code that returns nil even if it checks that the error is not nil | |
- nilnesserr # reports that it checks for err != nil, but it returns a different nil value error (powered by nilness and nilerr) | |
- nilnil # checks that there is no simultaneous return of nil error and an invalid value | |
- noctx # finds sending http request without context.Context | |
- nolintlint # reports ill-formed or insufficient nolint directives | |
- nonamedreturns # reports all named returns | |
- nosprintfhostport # checks for misuse of Sprintf to construct a host with port in a URL | |
- perfsprint # checks that fmt.Sprintf can be replaced with a faster alternative | |
- predeclared # finds code that shadows one of Go's predeclared identifiers | |
- promlinter # checks Prometheus metrics naming via promlint | |
- protogetter # reports direct reads from proto message fields when getters should be used | |
- reassign # checks that package variables are not reassigned | |
- recvcheck # checks for receiver type consistency | |
- revive # fast, configurable, extensible, flexible, and beautiful linter for Go, drop-in replacement of golint | |
- rowserrcheck # checks whether Err of rows is checked successfully | |
- sloglint # ensure consistent code style when using log/slog | |
- spancheck # checks for mistakes with OpenTelemetry/Census spans | |
- sqlclosecheck # checks that sql.Rows and sql.Stmt are closed | |
- staticcheck # is a go vet on steroids, applying a ton of static analysis checks | |
- testableexamples # checks if examples are testable (have an expected output) | |
- testifylint # checks usage of github.com/stretchr/testify | |
- testpackage # makes you use a separate _test package | |
- tparallel # detects inappropriate usage of t.Parallel() method in your Go test codes | |
- unconvert # removes unnecessary type conversions | |
- unparam # reports unused function parameters | |
- unused # checks for unused constants, variables, functions and types | |
- usestdlibvars # detects the possibility to use variables/constants from the Go standard library | |
- usetesting # reports uses of functions with replacement inside the testing package | |
- wastedassign # finds wasted assignment statements | |
- whitespace # detects leading and trailing whitespace | |
## you may want to enable | |
#- decorder # checks declaration order and count of types, constants, variables and functions | |
#- exhaustruct # [highly recommend to enable] checks if all structure fields are initialized | |
#- ginkgolinter # [if you use ginkgo/gomega] enforces standards of using ginkgo and gomega | |
#- godox # detects usage of FIXME, TODO and other keywords inside comments | |
#- goheader # checks is file header matches to pattern | |
#- inamedparam # [great idea, but too strict, need to ignore a lot of cases by default] reports interfaces with unnamed method parameters | |
#- interfacebloat # checks the number of methods inside an interface | |
#- ireturn # accept interfaces, return concrete types | |
#- prealloc # [premature optimization, but can be used in some cases] finds slice declarations that could potentially be preallocated | |
#- tagalign # checks that struct tags are well aligned | |
#- varnamelen # [great idea, but too many false positives] checks that the length of a variable's name matches its scope | |
#- wrapcheck # checks that errors returned from external packages are wrapped | |
#- zerologlint # detects the wrong usage of zerolog that a user forgets to dispatch zerolog.Event | |
## disabled | |
#- containedctx # detects struct contained context.Context field | |
#- contextcheck # [too many false positives] checks the function whether use a non-inherited context | |
#- dogsled # checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) | |
#- dupword # [useless without config] checks for duplicate words in the source code | |
#- err113 # [too strict] checks the errors handling expressions | |
#- errchkjson # [don't see profit + I'm against of omitting errors like in the first example https://github.com/breml/errchkjson] checks types passed to the json encoding functions. Reports unsupported types and optionally reports occasions, where the check for the returned error can be omitted | |
#- forcetypeassert # [replaced by errcheck] finds forced type assertions | |
#- gomodguard # [use more powerful depguard] allow and block lists linter for direct Go module dependencies | |
#- gosmopolitan # reports certain i18n/l10n anti-patterns in your Go codebase | |
#- grouper # analyzes expression groups | |
#- importas # enforces consistent import aliases | |
#- lll # [replaced by golines] reports long lines | |
#- maintidx # measures the maintainability index of each function | |
#- misspell # [useless] finds commonly misspelled English words in comments | |
#- nlreturn # [too strict and mostly code is not more readable] checks for a new line before return and branch statements to increase code clarity | |
#- paralleltest # [too many false positives] detects missing usage of t.Parallel() method in your Go test | |
#- tagliatelle # checks the struct tags | |
#- thelper # detects golang test helpers without t.Helper() call and checks the consistency of test helpers | |
#- wsl # [too strict and mostly code is not more readable] whitespace linter forces you to use empty lines | |
# All settings can be found here https://github.com/golangci/golangci-lint/blob/HEAD/.golangci.reference.yml | |
settings: | |
cyclop: | |
# The maximal code complexity to report. | |
# Default: 10 | |
max-complexity: 30 | |
# The maximal average package complexity. | |
# If it's higher than 0.0 (float) the check is enabled | |
# Default: 0.0 | |
package-average: 10.0 | |
depguard: | |
# Rules to apply. | |
# | |
# Variables: | |
# - File Variables | |
# Use an exclamation mark `!` to negate a variable. | |
# Example: `!$test` matches any file that is not a go test file. | |
# | |
# `$all` - matches all go files | |
# `$test` - matches all go test files | |
# | |
# - Package Variables | |
# | |
# `$gostd` - matches all of go's standard library (Pulled from `GOROOT`) | |
# | |
# Default (applies if no custom rules are defined): Only allow $gostd in all files. | |
rules: | |
"deprecated": | |
# List of file globs that will match this list of settings to compare against. | |
# By default, if a path is relative, it is relative to the directory where the golangci-lint command is executed. | |
# The placeholder '${base-path}' is substituted with a path relative to the mode defined with `run.relative-path-mode`. | |
# Default: $all | |
files: | |
- "$all" | |
# List of packages that are not allowed. | |
# Entries can be a variable (starting with $), a string prefix, or an exact match (if ending with $). | |
# Default: [] | |
deny: | |
- pkg: github.com/golang/protobuf | |
desc: Use google.golang.org/protobuf instead, see https://developers.google.com/protocol-buffers/docs/reference/go/faq#modules | |
- pkg: github.com/satori/go.uuid | |
desc: Use github.com/google/uuid instead, satori's package is not maintained | |
- pkg: github.com/gofrs/uuid$ | |
desc: Use github.com/gofrs/uuid/v5 or later, it was not a go module before v5 | |
"non-test files": | |
files: | |
- "!$test" | |
deny: | |
- pkg: math/rand$ | |
desc: Use math/rand/v2 instead, see https://go.dev/blog/randv2 | |
"non-main files": | |
files: | |
- "!**/main.go" | |
deny: | |
- pkg: log$ | |
desc: Use log/slog instead, see https://go.dev/blog/slog | |
errcheck: | |
# Report about not checking of errors in type assertions: `a := b.(MyStruct)`. | |
# Such cases aren't reported by default. | |
# Default: false | |
check-type-assertions: true | |
exhaustive: | |
# Program elements to check for exhaustiveness. | |
# Default: [ switch ] | |
check: | |
- switch | |
- map | |
exhaustruct: | |
# List of regular expressions to exclude struct packages and their names from checks. | |
# Regular expressions must match complete canonical struct package/name/structname. | |
# Default: [] | |
exclude: | |
# std libs | |
- ^net/http.Client$ | |
- ^net/http.Cookie$ | |
- ^net/http.Request$ | |
- ^net/http.Response$ | |
- ^net/http.Server$ | |
- ^net/http.Transport$ | |
- ^net/url.URL$ | |
- ^os/exec.Cmd$ | |
- ^reflect.StructField$ | |
# public libs | |
- ^github.com/Shopify/sarama.Config$ | |
- ^github.com/Shopify/sarama.ProducerMessage$ | |
- ^github.com/mitchellh/mapstructure.DecoderConfig$ | |
- ^github.com/prometheus/client_golang/.+Opts$ | |
- ^github.com/spf13/cobra.Command$ | |
- ^github.com/spf13/cobra.CompletionOptions$ | |
- ^github.com/stretchr/testify/mock.Mock$ | |
- ^github.com/testcontainers/testcontainers-go.+Request$ | |
- ^github.com/testcontainers/testcontainers-go.FromDockerfile$ | |
- ^golang.org/x/tools/go/analysis.Analyzer$ | |
- ^google.golang.org/protobuf/.+Options$ | |
- ^gopkg.in/yaml.v3.Node$ | |
funlen: | |
# Checks the number of lines in a function. | |
# If lower than 0, disable the check. | |
# Default: 60 | |
lines: 100 | |
# Checks the number of statements in a function. | |
# If lower than 0, disable the check. | |
# Default: 40 | |
statements: 50 | |
gochecksumtype: | |
# Presence of `default` case in switch statements satisfies exhaustiveness, if all members are not listed. | |
# Default: true | |
default-signifies-exhaustive: false | |
gocognit: | |
# Minimal code complexity to report. | |
# Default: 30 (but we recommend 10-20) | |
min-complexity: 20 | |
gocritic: | |
# Settings passed to gocritic. | |
# The settings key is the name of a supported gocritic checker. | |
# The list of supported checkers can be find in https://go-critic.github.io/overview. | |
settings: | |
captLocal: | |
# Whether to restrict checker to params only. | |
# Default: true | |
paramsOnly: false | |
underef: | |
# Whether to skip (*x).method() calls where x is a pointer receiver. | |
# Default: true | |
skipRecvDeref: false | |
govet: | |
# Enable all analyzers. | |
# Default: false | |
enable-all: true | |
# Disable analyzers by name. | |
# Run `go tool vet help` to see all analyzers. | |
# Default: [] | |
disable: | |
- fieldalignment # too strict | |
# Settings per analyzer. | |
settings: | |
shadow: | |
# Whether to be strict about shadowing; can be noisy. | |
# Default: false | |
strict: true | |
inamedparam: | |
# Skips check for interface methods with only a single parameter. | |
# Default: false | |
skip-single-param: true | |
mnd: | |
# List of function patterns to exclude from analysis. | |
# Values always ignored: `time.Date`, | |
# `strconv.FormatInt`, `strconv.FormatUint`, `strconv.FormatFloat`, | |
# `strconv.ParseInt`, `strconv.ParseUint`, `strconv.ParseFloat`. | |
# Default: [] | |
ignored-functions: | |
- args.Error | |
- flag.Arg | |
- flag.Duration.* | |
- flag.Float.* | |
- flag.Int.* | |
- flag.Uint.* | |
- os.Chmod | |
- os.Mkdir.* | |
- os.OpenFile | |
- os.WriteFile | |
- prometheus.ExponentialBuckets.* | |
- prometheus.LinearBuckets | |
nakedret: | |
# Make an issue if func has more lines of code than this setting, and it has naked returns. | |
# Default: 30 | |
max-func-lines: 0 | |
nolintlint: | |
# Exclude following linters from requiring an explanation. | |
# Default: [] | |
allow-no-explanation: [ funlen, gocognit, golines ] | |
# Enable to require an explanation of nonzero length after each nolint directive. | |
# Default: false | |
require-explanation: true | |
# Enable to require nolint directives to mention the specific linter being suppressed. | |
# Default: false | |
require-specific: true | |
perfsprint: | |
# Optimizes into strings concatenation. | |
# Default: true | |
strconcat: false | |
reassign: | |
# Patterns for global variable names that are checked for reassignment. | |
# See https://github.com/curioswitch/go-reassign#usage | |
# Default: ["EOF", "Err.*"] | |
patterns: | |
- ".*" | |
rowserrcheck: | |
# database/sql is always checked | |
# Default: [] | |
packages: | |
- github.com/jmoiron/sqlx | |
sloglint: | |
# Enforce not using global loggers. | |
# Values: | |
# - "": disabled | |
# - "all": report all global loggers | |
# - "default": report only the default slog logger | |
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-global | |
# Default: "" | |
no-global: all | |
# Enforce using methods that accept a context. | |
# Values: | |
# - "": disabled | |
# - "all": report all contextless calls | |
# - "scope": report only if a context exists in the scope of the outermost function | |
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#context-only | |
# Default: "" | |
context: scope | |
staticcheck: | |
# SAxxxx checks in https://staticcheck.dev/docs/configuration/options/#checks | |
# Example (to disable some checks): [ "all", "-SA1000", "-SA1001"] | |
# Default: ["all", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022"] | |
checks: | |
- all | |
# Incorrect or missing package comment. | |
# https://staticcheck.dev/docs/checks/#ST1000 | |
- -ST1000 | |
# Use consistent method receiver names. | |
# https://staticcheck.dev/docs/checks/#ST1016 | |
- -ST1016 | |
# Omit embedded fields from selector expression. | |
# https://staticcheck.dev/docs/checks/#QF1008 | |
- -QF1008 | |
usetesting: | |
# Enable/disable `os.TempDir()` detections. | |
# Default: false | |
os-temp-dir: true | |
exclusions: | |
# Log a warning if an exclusion rule is unused. | |
# Default: false | |
warn-unused: true | |
# Predefined exclusion rules. | |
# Default: [] | |
presets: | |
- std-error-handling | |
- common-false-positives | |
# Excluding configuration per-path, per-linter, per-text and per-source. | |
rules: | |
- source: 'TODO' | |
linters: [ godot ] | |
- text: 'should have a package comment' | |
linters: [ revive ] | |
- text: 'exported \S+ \S+ should have comment( \(or a comment on this block\))? or be unexported' | |
linters: [ revive ] | |
- text: 'package comment should be of the form ".+"' | |
source: '// ?(nolint|TODO)' | |
linters: [ revive ] | |
- text: 'comment on exported \S+ \S+ should be of the form ".+"' | |
source: '// ?(nolint|TODO)' | |
linters: [ revive, staticcheck ] | |
- path: '_test\.go' | |
linters: | |
- bodyclose | |
- dupl | |
- errcheck | |
- funlen | |
- goconst | |
- gosec | |
- noctx | |
- wrapcheck |
gomodguard dont't work with standard library.
depguard work with standard library, for example
deny:
- pkg: $log
desc: "use slog or internal"
@skosovsky do you want me to enable depguard
instead of gomodguard
in this config?
@skosovsky do you want me to enable
depguard
instead ofgomodguard
in this config?
yes, depguard
also has versioning support for external packages, from docs:
A Prefix List just means that a package will match a value, if the value is a prefix of the package. Example github.com/OpenPeeDeeP/depguard package will match a value of github.com/OpenPeeDeeP but won't match github.com/OpenPeeDeeP/depguard/v2.
exportloopref
should disable since Go 1.22 because this problem no longer occurs and fixed by Go team
@chenyanchen thanks, disabled exportloopref
and copyloopvar
@maratori do you think copyloopvar
should be enabled by default? it allows us to clean the codebase where we copy the loop variables like n := n
pre-1.22
@brlala you are right. It was a mistake to disable it. Now, it's enabled.
@maratori long time to see!
Do you think it's finally time to update year in Copyright Notice? :D https://gist.github.com/maratori/47a4d00457a92aa426dbd48a18776322#file-golangci-yml-L2
Jokes aside, what do you think about providing default, maybe commented out, config for tagliatelle
? It's pretty nice linter (unless you need to make something compatible with some weird existing naming schemes). But its default parameters are not so clear to comprehend — I need to remember to change json: "snake"
every damn time. Is my chose optioned? Yes. But let's make it clear on how it can be changed.
WDYT?
Thanks a lot
Very grateful!
Thanks a lot!
it's time to update.
Thanks a lot.
@maratori thanks so much for sharing this!
Those who use https://github.com/redhat-developer/vscode-yaml/issues (or plugins for other editors)
may benefit from adding this line to the header of the file, do you mind adding it?
# yaml-language-server: $schema=https://golangci-lint.run/jsonschema/golangci.jsonschema.json
Also, maybe add a link to https://gist.github.com/maratori/47a4d00457a92aa426dbd48a18776322, so people who copy-pasted it can trace the source?
@alexbozhenko, thank you for the thoughtful suggestions! I've added a link to this file, as you recommended.
Regarding the schema, I appreciate the idea, but I don’t think it’s necessary to include it in the header. I primarily use GoLand, but I installed VS Code to test this. After installing the YAML plugin, it automatically detected and applied the correct schema without any additional configuration on my part. I'm not sure how, but it worked for the .golangci.yml
file name.
Great, thanks!
I was worried that an invalid config is silently ignored.
golangci/golangci-lint#5313
I did not realize it works out of the box without the schema line...
@kavu, sorry for the delayed reply!
Regarding tagliatelle
, I have a different perspective on linting the json
tags. I believe they’re part of the contract and should be validated through testing, rather than being linted.
@skosovsky, sorry for the delayed reply!
Thank you for bringing this up. You're absolutely right - depguard
is a more powerful linter compared to gomodguard
. I've updated the configuration accordingly. Additionally, I'm considering blocking the following packages (still evaluating):
deny:
- pkg: "log$"
desc: "Use log/slog instead, see https://go.dev/blog/slog"
- pkg: "math/rand$"
desc: "Use math/rand/v2 instead, see https://go.dev/blog/randv2"
What do you think? If you have suggestions for other packages to block, please let me know!
Thanks, Marat, for the ruleset! I've been using it successfully for quite some time.
With the recent release of version 2, would you be able to update the configuration to ensure compatibility with the new version?
That would be greatly appreciated!
Once again, thank you
Yeah, Marat’s updates version would be nice!
Meanwhile I used new migrate
command to quickly migrate and format config. Bad thing - all comments will be lost.
Hi guys. For the new GoLangCi-Lint version 2.0.0, we are receiving that kind of errors:
golangci/golangci-lint info checking GitHub for latest tag
golangci/golangci-lint info found version: 2.0.0 for v2.0.0/linux/amd64
golangci/golangci-lint info installed ./bin/golangci-lint
Error: can't load config: typecheck is not a linter, it cannot be enabled or disabled
Failed executing command with error: can't load config: typecheck is not a linter, it cannot be enabled or disabled
So, we had to:
This yml
format is deprecated in golangci-lint
version "2.0". I recommend using a previous version or running the golangci-lint migrate
command to migrate to the new yml
format. However, most configurations will need to be redefined in the new format.
I suggest reading the migration documentation to adjust whatever is necessary.
https://golangci-lint.run/product/migration-guide/#command-migrate
@rios0rios0 some linters became formatters. And some gone completely, as they are more analyzers than linters. You can try migrate you config and see how it goes
Thank you @meopedevts @kavu
In case someone is interested, I ran golangci migrate
and I got the following:
https://gist.github.com/manuelarte/76c3cedb1f819184a9a880883e6edd5f
Hi @maratori. We were working the last 3 days on this configuration file. We got the advice from @meopedevts and @kavu. Also, with the file @manuelarte sent to us here, we were able to compare the diff and put back the comments. Please see the file here and help us to understand if it could be the next file in this Gist: https://github.com/rios0rios0/pipelines/blob/main/global/scripts/golangci-lint/.golangci.yml
Kinda unrelated, but... has anybody considered to keep this file inside of a dedicated repository and tag it following the golangci-lint version it is designed for?
I think that would be great for walking back in time to older release and also for some automation pipelines.
BTW, thanks a lot for the hard work of maintaining this configuration! ❤️
Hey @beeyev @kavu @rios0rios0 @meopedevts @manuelarte and everyone else!
I've updated the configuration for version 2. Here are the key changes:
- Removed
run.timeout
(default is now no timeout). - Replaced
lll
with thegolines
formatter. - Enabled all
staticcheck
checks exceptST1000
,ST1016
, andQF1008
. - Activated exclusion presets:
std-error-handling
andcommon-false-positives
. - Explicitly included some rules from the
comments
exclusion preset. - Enclosed regex patterns in single quotes
'
to avoid escaping backslashes ("\\."
→'\.'
).
I’d like to get your feedback on this.
@flavio, thanks for your feedback and suggestion.
has anybody considered to keep this file inside of a dedicated repository and tag it following the golangci-lint version it is designed for?
I haven't considered this option before. Could you share more details about your use case, especially about automation?
walking back in time to older release
The configuration change history is available here. There aren’t many changes, so it’s quite easy to track them.
@murar8
perfsprint
introduced thestrconcat
option inv0.7.0
. The PR was merged into golangci-lint, but not released yet.