Announcing Stack Lint Extra Deps
by @pbrisbin on December 17, 2021
Freckle is happy to announce a new command-line tool for linting a
Stack-based Haskell application. If you make heavy use of extra-deps
, this
tool may be useful to you.
Context & Motivation
At Freckle, we publish a custom snapshot for use across all
our Haskell applications. This brings a minor bit of supply-chain security, but
we primarily do it out of convenience. As a team, we no longer manage disparate,
app-specific resolvers or extra-deps
; we just use the canonical snapshot and
assume the same versions of all dependencies when we move from project to
project. extra-deps
require maintaining (as I’ll describe soon), so
centralizing them has been a big boost to efficiency.
There exists a priority order of extra-deps
sources:
- Using the latest Hackage release
- Using any Hackage release
- Using the latest
git
version tag - Using any
git
version tag - Using the latest
git
commit - Using any
git
commit
Whenever we release a new snapshot (roughly every two weeks), we re-evaluate
every extra dependency to see if we can now move it up on this list. We used to
do this cumbersome series of checks by hand for every dependency: referencing
the new resolver’s Stackage page, checking against Hackage, and possibly
browsing git
tags. With any reasonably-sized list of extra-deps
this takes
ages.
We built lint-extra-deps to do it for us:
Features
Checks
lint-extra-deps asks the following for each extra dependency and suggests changes depending on the answers:
If it’s a Hackage dependency,
- Is there a same-or-newer version in the resolver?
- Is there a newer version on Hackage?
If it’s a Git dependency,
- Is there a newer commit with a version-like tag that exists in Hackage?
- Is there a newer commit with a version-like tag at all?
- Are there newer commits?
The Git checks are somewhat heuristics-based. We assume the base name of the
repository is the package name on Hackage, and we take any tag that parses as a
Version
to represent a possibly-released version. This may result in
false-positives or false-negatives.
Which checks are performed can be changed through the --checks
option.
Exclude/Include
lint-extra-deps will operate on the extra-deps
or packages
key of the input
Yaml file. This means it supports stack.yaml
or snapshot.yaml
use-cases. By
default, it processes all dependencies, but you can:
- Pass multiple
--exclude PATTERN
options to not operate on the given dependencies, and/or - Pass a
PATTERN
argument to operate on only matching dependencies
PATTERN
is a glob matched against the Hackage package name or the owner/repo
portion of a git dependency.
For example,
stack lint-extra-deps --exclude 'freckle/*'
Would skip any git
dependencies from our own organization, and
stack lint-extra-deps 'hspec*'
Would check only the handful of Hspec packages we’re using right now.
Exit
By default, lint-extra-deps exits non-zero if suggestions were made, but this
can be disabled by passing --no-exit
.
Installation
We’re shipping binaries from CI and you can find instructions for installing them in the README, or head right to the Releases.
stack
will look for any executables named stack-{subcommand}
and support
calling them as, well, a sub-command. So with this installed, you can run (e.g.)
stack lint-extra-deps --help
for complete usage.
At Freckle, we rarely let an annoying and manual task go un-automated. If you
are are performing similar extra-deps
maintenance for your projects, we hope
this tool can get you back some time.
If you would enjoy working on tools like this, or the projects it enables, we’re hiring. And as always, patches welcome.