Imagine you're at a company with a code base that's been growing for a few years.
Now imagine you didn't start with -Werror enabled, (or the equivalent for your tool chain or linter) and now you've got a couple of warnings. Too many to fix in one go. For every warning that's fixed, someone (and sometimes you?) adds a new one. Eventually.
I'm very happy to announce Warning Counter (Wcnt), the tool that makes it so "Warnings as errors" doesn't have to be an all or nothing kind of deal. It's a tool that counts the warnings you've got, and compares that to per-directory specified limits you supply. If you use this in your CI loop, you can ensure that the number or warnings decrease over time. As long as you can match it with a regular expression, Wcnt can keep track of it for you.
The Wcnt tool is configured using toml
. For more information on the toml
markup language, see this github page. Here's an example of one Wcnt.toml
configured for gcc-style warnings and flake8, a popular linter for python.
[gcc] regex = "^(?P<file>[^:]+):(?P<line>\\d+):(?P<column>\\d+): warning: (?P<description>.+) \\[(?P<category>.+)\\]" files = ["**/build.log"] [flake8] regex = "^(?P<file>[^:]+):(?P<line>\\d+):(?P<column>\\d+): (?P<category>[^\\s]+) (?P<description>.+)$" files = ["**/lint.log"]
This will instruct the tool to look through all the build.log
files for gcc warnings, and all lint.log
files for flake8 warnings using the supplied regular expressions. I recommend this excellent webpage to try out your expressions. Just don't forget to escape your backslashes. Note: there is another cool site, which uses Rust, bt doesn't use the same settings as I do, so it's not useable for this project, but cool nonetheless.
Any warnings found, will be categorized - if applicable, indicated by the existence of a category
match group - and counted towards limits defined in a Limits.toml
file. Here's an example of that:
flake8 = 100 [gcc] -Wcomment = inf _ = 0
This file defines an upper bound for all kinds of flake8
warnings to be 100. If it finds any more than that, it will exit with a non-zero exit code. Which your CI loop can detect as a failed verification. For gcc
, we define some limits per category. inf
means that we allow an unlimited number of warnings. So we can have any number of -Wcomment
warnings and the tool won't complain about them. A very useful thing for code you have little control over, like third party headers. The _
category is the wildcard category. It matches anything else not already mentioned. In tis example it means that -Wmaybe-uninitialized
, -Wtrigraphs
and all the other have a limit of 0. Total.
You can have as many Limits.toml
files as you like. One per subsystem, one per component, per unit, or whatever you like to call things. You could also have one for your production code, and one for your testing code. This way, you can still build them with the same settings. Wcnt aims to be flexible, in case your build system isn't.
Since Wcnt knows exactly how many warnings you've got, it can also set your current limits to match those values. Run the tool with the flag --update-limits
and it will update all your Limits.toml
files. I recommend you set up a nightly job which does this, and then pushes a commit with the new result. This way, your warnings are ensured to decrease over time.
An extra feature you get from having the limits files checked in with the code, is that if you're ever in a pinch, you can raise the limits. This lets you check in those.. let's call them "late additions to the scope". Having the limits there makes it into a much more conscious decision when you side-step your quality guidelines.
Wcnt works best set up as a pre-merge verification step, with nightly jobs set up to lower the limits as you gradually improve your codebase.
I've wished for this tool to exist whenever I've seen a situation where a linter is set up, but isn't used continuously. Or the warnings in the console just keep flashing by the developers' eyes. Now I've made this tool, and I make it available to all of you as well. I hope it works as well for you as it has done for me.
Known and/or Open issues:
- Windows style paths doesn't work well. Especially if your tool output warnings using
\\?\
paths. This is because of how the rust standard library normalizes paths. - Also because of how rust stdlib normalizes paths: Wcnt needs the source code to be available when reading logs, this is because rust tries to resolve symbolic links. The tool does not read your code.
- I have not decided on how the tool should handle warnings originating from files outside of the source tree. Right now it will simply not allow them. For GCC you can use
-isystem
to prevent receiving warnings from external header files. - I'd like to add a feature to allow remapping of warnings, in case you compile on one system but check for warnings on another. Which is common when cross compiling.
- The tool will use all your available cores when parsing files. This might be a problem if you have very many cores but very little RAM.
Installation
Wcnt is written in rust published on crates.io and is thus installable using cargo by running cargo install wcnt
.
If you want to, you can also check it out on github.com/silven/wcnt and build it by running cargo build --release
.