reviewdog — A code review dog who keeps your codebase healthy

haya14busa
4 min readOct 23, 2016

I’d like to introduce reviewdog! An automated code review tool working with any lint tools and supports local run as well.

“reviewdog” provides a way to post review comments to code hosting service, such as GitHub, automatically by integrating with any linter tools with ease. It uses any output of lint tools, with translation if required, and post them as a comment if the file and line are in diff of patches to review. reviewdog also supports run in local environment to filter output of lint tools by diff.

sample PR
Run reviewdog locally

Background

We won’t take our time for review to find a bug or style problems which can be detected automatically. We want to focus on our core logic.

We can use various linters and static code analysis tools to detect such problems in local machine, editors, CI services. However, here is the problem. Static analysis tools may report false positive results. Reporting false positive results itself is ok, but due to the false positive results we cannot make build failed and it becomes difficult for us to find true positive results from messed up analysis results. Some linter supports suppressing result by code comments, but we won’t messed up code for analysis tools.

The one solution is reporting analysis result only for changed lines as a review comment. We can catch true positive results and can just ignore false positive comments. There is a couple of services to provide this feature, but supported analysis tools are limited. (e.g. Hound, Side CI)

So, here comes “reviewdog”! It provides a general way to parse any linter results, filter them by diff output, and can report them as a review comment.

Installation

go get -u github.com/haya14busa/reviewdog/cmd/reviewdog

Usage

Run locally to filter results by diff

# check golint results with `git diff master`
$ golint ./... | reviewdog -f=golint -diff="git diff master"
# sample -efm (errorformat)
$ golint ./... | reviewdog -efm="%f:%l:%c: %m" -diff="git diff"

Run in CI service (Circle CI) to post review comments

Store GitHub API token inREVIEWDOG_GITHUB_API_TOKEN Environment variables — CircleCI

test:
pre:
- go get github.com/haya14busa/reviewdog/cmd/reviewdog
override:
- >-
go tool vet -all -shadowstrict . 2>&1 | reviewdog -f=govet -ci="circle-ci"

(see detail and more example in README)

‘errorformat’ —scanf-like string to parse lint result

To support any compiler, linter, or whatever tools, reviewdog uses Vim’s ‘errorformat’ feature (ported in Go). For example, if the result format is {file}:{line number}:{column number}: {message}, errorformat should be%f:%l:%c: %m

It’s pretty easy, right?

‘errorformat’ also handles more complex multi-line messages.

$ cat testdata/sbt.in
[warn] /path/to/F1.scala:203: local val in method f is never used: (warning smaple 3)
[warn] val x = 1
[warn] ^
[warn] /path/to/F1.scala:204: local val in method f is never used: (warning smaple 2)
[warn] val x = 2
[warn] ^
[error] /path/to/F2.scala:1093: error: value ++ is not a member of Int
[error] val x = 1 ++ 2
[error] ^
[warn] /path/to/dir/F3.scala:83: local val in method f is never used
[warn] val x = 4
[warn] ^
[error] /path/to/dir/F3.scala:84: error: value ++ is not a member of Int
[error] val x = 5 ++ 2
[error] ^
[warn] /path/to/dir/F3.scala:86: local val in method f is never used
[warn] val x = 6
[warn] ^
$ errorformat "%E[%t%.%+] %f:%l: error: %m" "%A[%t%.%+] %f:%l: %m" "%Z[%.%+] %p^" "%C[%.%+] %.%#" "%-G%.%#" < testdata/sbt.in
/path/to/F1.scala|203 col 13 warning| local val in method f is never used: (warning smaple 3)
/path/to/F1.scala|204 col 7 warning| local val in method f is never used: (warning smaple 2)
/path/to/F2.scala|1093 col 15 error| value &#43;&#43; is not a member of Int
/path/to/dir/F3.scala|83 col 13 warning| local val in method f is never used
/path/to/dir/F3.scala|84 col 19 error| value &#43;&#43; is not a member of Int
/path/to/dir/F3.scala|86 col 13 warning| local val in method f is never used

It’s somewhat difficult to understand whole ‘errorformat’ feature, but it’s really good to provide rich support for lots of tools and for most cases, all you have to know is basic easy items (%f: file, %l: line number, %c: column number, %m: message).

On top that, reviewdog ( haya14busa/errorformat ) provides pre-defined errorformat for major tools, so you don’t need to write errorformat in most cases. You can see pre-defined errorformat here or reviewdog -list . You can use them with -f={name}.

$ golint ./... | reviewdog -f=golint -diff="git diff master"

If you want to add supported tools, please contribute to haya14busa/errorformat . Bonus: you can also refer errorformats defined in some Vim plugins, like scrooloose/syntastic, neomake/neomake, and osyo-manga/vim-watchdogs .

Have a reviewdog and keep your codebase healthy!

reviewdog automatically review your code with any tools and you can run it in locally as well for faster development. reviewdog helps you to introduce strict lint tools (or tools which often report false positive results) because it runs only for diff like Pull-Request, not whole code base. You can also just ignore it if the report is not valid. Of course, you can stop keeping a reviewdog easily, so please give it a shot! I hope you like it.

--

--