Point out HN: Trunk detects and handles preexisting linter factors

Crank your code analysis to 11 without bringing your engineering to a standstillBuilding a universal linter means not only managing the discovery, installation, caching, and execution of the right tool for every file in your codebase, but freeing your organization to enable new rules and checks without bringing engineering to a standstill.Picture this scenario:Being a…

Point out HN: Trunk detects and handles preexisting linter factors

That is the improbable skedaddle-in ever!

Crank your code diagnosis to 11 with out bringing your engineering to a standstill

Spiky at the moat

Constructing a universal linter device no longer handiest managing the invention, installation, caching, and execution of the coolest software for every file to your codebase, nonetheless freeing your group to enable contemporary principles and tests with out bringing engineering to a standstill.

Record this pain:

  • Being a appropriate citizen of your codebase, you decide to at final rename your Foo class to something much less generic; a fleet win-and-replace would possibly possibly well perhaps restful create the trick. You commit, push, send it for code review, and pat yourself on the wait on.
  • You check the CI flee to your exchange and gaze that your team’s linters, static analyzers, and formatters are complaining about all varieties of pre-present factors within the details that your innocent exchange touched.
  • You flee the pre-present factors and realize you have two concepts: (1) stop on the exchange, or (2) fix the total pre-present factors, which would suggest increasing the scope of your exchange, happening a bunch of rabbit holes, and presumably breaking something.

Which different create you boom most engineers invent?

Which different create you boom most engineers would possibly possibly well perhaps restful invent?

Masses of engineering teams flee into this accurate affirm: they boom they are seeking to stage up their code quality or consistency so that they open operating contemporary checking tools on modified details or switch on contemporary principles in present tools, handiest gaze that there are hundreds pre-present factors and with out a capacity to push aside these factors, they’ll’t have the funds for to adjust on a brand contemporary software or enable a brand contemporary rule.

Enter trunk check’s maintain-the-line characteristic: with maintain-the-line we determine which factors already exist to your codebase. Ought to you flee these tools the usage of trunk check, we complain if and handiest if your exchange contains contemporary factors.

The Devil is within the Details

The answer that loads of tools reach for¹ is to flee a linter on the enviornment of modified files², after which filter the output to handiest the modified lines³. Certainly, rather loads of tools budge along with this manner:

  • clang-orderly supports a –-line-filter flag,
  • lint-diff wrapseslint with a modified line filter, and
  • darker wraps mypy, pylint, and flake8 with a modified line filter.

Sadly, this manner relies on the unsuitable assumption that contemporary lint factors can handiest seem on the modified lines. Pick into consideration this Python code:

def foo(): 

And let’s recount we boom we don’t are seeking to print this anymore, so we make a selection it away:

def foo(): 

At the same time as you look at the flake8findings from sooner than and after the exchange, you’ll explore that even supposing we didn’t exchange line 2, flake8 is sorrowful with line 2 within the second model!

foo.py:2:5: F841 local variable 's' is assigned to nonetheless never veteran

It’s easy to explore how this will happen in a staunch pain: you delete some code otherwise you toddle some stuff spherical, and you recede out something within the job. And naturally, this isn’t the handiest manner you would possibly possibly pause up with contemporary lint factors on unmodified lines: there are loads of totally different eventualities.

OK, so filtering for modified lines isn’t appropriate adequate — nonetheless what is the coolest manner to do that?

Rinse / Wash / Repeat

The answer we’ve arrive up with is to flee linters twice for every modified file — once on the upstream and once on the model to your contemporary working tree — after which diff the outcomes to identify which lint factors already existed to your mainline and that are contemporary.

Sounds easy adequate, obliging?

Well yes, but actually no

Useless to claim, no solution is ever total with out introducing contemporary concerns of its bear:

  • How create you reliably lint the upstream?
  • What if we can’t lint the upstream?
  • What in case you alter the configuration for a linter?

To lint the upstream, we prepare what we call a “shadow” tree, which we populate with your upstream git branch; we also cache these lint results, on tale of there’s no point in re-operating linters on already committed code.

But what if operating a linter to your upstream fails? This isn’t upright a hypothetical: we’ve chanced on that there are rather loads of programs it will happen: recount, as an illustration, malformed code in a device bought committed into your repo (possibly automation went haywire).

(That is the form of error facing that we make a selection indulge in doing well; belief to be a number of the many qualities which distinguish tall tools from appropriate tools, at the least, is acceptable error facing.)

In these eventualities, you proceed to are seeking to explore the lint results to your contemporary, nonetheless you proceed to also are seeking to lend a hand some distance from getting spammed by present lint factors. To tackle this, we tumble wait on to treating the modified lines as a lint field filter: even supposing each person knows there are shortcomings to this manner, it’s higher than nothing, and edifying would possibly possibly well perhaps restful no longer be the enemy of appropriate.

The final question, facing modified linter configuration, is the trickiest nonetheless also the one: we in fact flee every the upstream and contemporary lint actions the usage of your contemporary linter config, and discard the upstream’s linter config.

This sounds frightful, nonetheless we promise that there’s a appropriate enviornment off of this!

Let’s recount that you’ve ended up with a combination of naming conventions to your constants — some employ CamelCase, others employ UPPER_SNAKE_CASE — and you remember the truth that your linter wants you to reveal it which one to enforce, so that you replace your linter config to enforce UPPER_SNAKE_CASE.

That doesn’t in fact suggest you ought to head and fix every single CamelCase fixed to your codebase obliging now; all you in fact need is to require that contemporary code, beginning as of late, follows your contemporary rule. The present factors to your codebase would possibly possibly well perhaps be handled over time.

Useless to claim, that device you furthermore mght need some system to truly address them over time. That’s belief to be a number of the reasons we’re quickly launching a trunk check internet service, to ticket you how to look at the present lint factors to your repository and boom the vogue you ought to burn these down.

We also have work planned to coach maintain-the-line to detect in case you’ve moved code, so that you would be in a position to perhaps refactor your code with out having your linters nag you. Preserve tuned for updates!

Attracted to constructing the next technology of developer tooling with us? We’re hiring!

What bothers you essentially the most about your developer skills? Join the Trunk Neighborhood Slack and allow us to grasp.

¹ Every other suboptimal solution we’ve considered is selectively disabling your linter (c.f. Rubocop), either by other than explicit details or disabling explicit principles.

² Running linters on the enviornment of modified details — technically talking, the enviornment of modified targets — is in fact no longer a straightforward affirm: even supposing many linters characteristic on a per-file basis, there are rather loads of linters which don’t. clang-orderly, as an illustration, operates on translation units (even supposing the CLI pretends to characteristic on details), golangci-lint can’t resolve kinds when flee on a per-file basis, and terraform validate runs on directories, no longer single details.

³ Running a linter on handiest the modified lines sounds indulge in one other different right here, nonetheless this is rarely any longer if ever imaginable. Most linters characteristic on ASTs, and with handiest the modified lines you don’t have knowledge to invent one.

Read More
Allotment this on knowasiak.com to consult with of us on this topicRegister on Knowasiak.com now in case you would possibly possibly very well be no longer registered yet.

Charlie Layers

Charlie Layers

Fill your life with experiences so you always have a great story to tellBio: About: