Developer's Guide
March 11, 2026 ยท View on GitHub
This document explains how to build, test, and develop features for revive.
Installation
Clone the project:
git clone git@github.com:mgechev/revive.git
cd revive
Build
In order to build the project run:
make build
The command will produce the revive binary in the root of the project.
Logging
By default, any logging output is disabled when REVIVE_LOG_LEVEL is unset or empty.
You can enable and customize the log level using the REVIVE_LOG_LEVEL environment variable.
Supported values are:
debug: log all messages including debug-level informationinfo: log informational messages and abovewarn: log warnings and errors; also used as a fallback whenREVIVE_LOG_LEVELis set to an invalid valueerror: log errors only
Logs are output to stderr:
REVIVE_LOG_LEVEL=debug go run main.go
Coding standards
Follow the instructions which contain Go coding standards and conventions used by both humans and GitHub Copilot.
Development of rules
If you want to develop a new rule, follow as an example the already existing rules in the rule package.
When adding a new rule that does not require type information (for example, a rule that does not call file.Pkg.TypeCheck() and works purely on syntax/AST),
add its name to untyped.toml and keep that file in sync with any such rules.
Each rule needs to implement the lint.Rule interface:
type Rule interface {
Name() string
Apply(*File, Arguments) []Failure
}
All rules with a configuration must implement lint.ConfigurableRule interface:
type ConfigurableRule interface {
Configure(Arguments) error
}
The Arguments type is an alias of the type []any. The arguments of the rule are passed from the configuration file.
Example
Let's suppose we have developed a rule called BanStructNameRule which disallow us to name a structure with a given identifier.
We can set the banned identifier by using the TOML configuration file:
[rule.ban-struct-name]
arguments = ["Foo"]
With the snippet above we:
- Enable the rule with the name
ban-struct-name. TheName()method of our rule should return a string that matchesban-struct-name. - Configure the rule with the argument
Foo. The list of arguments will be passed toApply(*File, Arguments)together with the target file we're linting currently.
A sample rule implementation can be found here.
Development of formatters
If you want to develop a new formatter, follow as an example the already existing formatters in the formatter package.
All formatters should implement the following interface:
type Formatter interface {
Format(<-chan Failure, RulesConfig) (string, error)
Name() string
}
Lint
Lint Markdown files
We use markdownlint,
markdown-toc,
and mdsf to check Markdown files.
markdownlint verifies document formatting, such as line length and empty lines.
markdown-toc checks the entries in the table of contents.
mdsf is responsible for formatting code snippets.
- Install markdownlint-cli2.
- Install markdown-toc.
- Install mdsf and formatters:
- Run the following command to check formatting:
$ markdownlint-cli2 .
Finding: *.{md,markdown} *.md
Found:
CODE_OF_CONDUCT.md
CONTRIBUTING.md
DEVELOPING.md
README.md
RULES_DESCRIPTIONS.md
Linting: 5 file(s)
Summary: 0 error(s)
The markdownlint-cli2 tool automatically uses the config file .markdownlint-cli2.yaml.
4. Run the following command to check TOC:
markdown-toc --maxdepth 4 --no-first1 --bullets "-" -i README.md && git diff --exit-code README.md
markdown-toc --maxdepth 2 --no-first1 --bullets "-" -i RULES_DESCRIPTIONS.md && git diff --exit-code RULES_DESCRIPTIONS.md
5. Run the following commands to verify and format code snippets:
mdsf verify .
mdsf format .
Note: Use golang for Go code snippets that are intentionally non-compilable.
However, it is recommended to avoid this and use go whenever possible.