Git Hooks Made Easy: How Whisky Helps Developers with Len Woodward
So today, welcome back to the Laravel
News Creator Series.
In this episode, I have with me Len
Woodward, who is the
creator of quite a few projects,
but today I wanted to
talk to him about whiskey.
So Len, as far as introduction,
anything, any other
projects you want to mention are
off the top of your head that you're
doing a lot of work
with that is not whiskey?
Yeah, I got a couple.
So one that got a little bit of traction
on Twitter a couple of
weeks ago was Conductor,
which is basically NPX, but for PHP.
So it allows you to run composer packages
in an ephemeral way.
So if you've got stuff like just one
rector or a shift from
the Laravel shift that
you want to run, you can do that on the
CLI and it doesn't
necessarily need to be installed.
I'm putting a lot of work into community
prompts, which is an extension of
Laravel prompts,
which allows you to do
some interesting things.
I've worked on an async prompt that lets
you unblock rendering to the terminal and
reading from the file system and
everything so that you can trigger
renders at any point
in time.
And then it's open to community
suggestions as well.
So if you had a prompt that you wanted to
submit to Laravel
prompts and it got closed
because he doesn't want the maintenance
burden, we're open to taking that on.
Other projects, I've got some stuff for
FFmpeg, managing on demand disks.
Yeah.
I think that's a few.
I think that's probably enough packages.
I got enough on my plate.
Yes.
I know because I think, I mean, this is
going back maybe one of
the first times we spoke
was on the FF, is it FFmpeg?
Yeah, FFmpeg.
MPEG.
Yeah.
Because you were doing
some cool stuff with that.
But today let's talk about Whiskey.
So Whiskey is a project you created, I
think it's been out about a year now.
Is that sound about right?
Yeah.
I started it out as a package just called
Laravel Git hooks.
And that would register a couple of
commands that you
would bring into a package.
And then I went to
Chicago for PHP tech last year.
And Nuno suggested to me that I write it
as a standalone CLI
using Laravel zero.
And by the end of the conference, I had a
working proof of concept.
And then I just kind of
kept improving it over time.
I still haven't hit 1.0 yet.
There's one more little
thing that I want to squash.
But yeah, I mean, it's useful.
It's being used out in
the wild in projects.
It's been great for my own projects.
And I love not having to rely on Husky in
my node dependencies.
That's nice.
So as someone that's never used it, don't
know anything, say that
they're just listening
in.
What is the, basically what is Whiskey
and what is the selling
point on why you would
want to use it?
Yeah.
So we, at a client I was working at, we
had a need to manage all
of our Git hooks across
the entire team.
Previously I've used Husky and like it
worked fine, but it's a
little bit higher friction
to install than I was hoping for.
And so my goal was to just build
something that's only PHP
that only depends on the PHP
version and no other dependencies and
something that would be
the lowest friction barrier
to entry possible.
So the name Whiskey is
kind of an homage to Husky.
But yeah, I went through this, tried to
make it as easy as possible.
It's easy to disable.
It's easy to update.
Well, I was going to say, so let's say
you're a developer and
you've not really used Git
hooks before.
What's the selling point
to even start using those?
Like what are some common scenarios where
you'd want to use Git hooks there?
Yeah.
So Git hooks are kind
of a controversial thing.
It's a really useful tool in certain
scenarios, but it's
really easy to go overboard.
So when you're doing your commands and
push and pull and merge
and all that sort of stuff,
each time that's called, Git
is going to trigger a hook.
And if you've got something registered in
that hook, it's going to run it.
If you don't have anything registered,
it's just a no op and
it's going to keep going.
So for myself, every time that I make a
commit, I want to run the linter.
And so I've registered that I've got my
composer lint command.
And in my Git hook, it just calls
composer lint on push.
It's going to run composer lint, composer
types, composer stan, composer test.
If that's too slow and it's slowing you
down, you can always
just tack on the dash dash
no verify flag and it'll skip it.
But that's what it is.
So it can slow you down.
You don't always have to use it.
It is easy to go overboard.
So I would warn people against going with
a Git hook that ends up
being like two minutes.
Try to keep it fast.
Yeah.
I was thinking like so, like in a team
environment, if you have a
ton of like, say you have a
two minute Git hook and does it, is it
blocking for the other person?
Like if you push and it's running and
then I push, that's not,
it's still going to push,
right?
It's just going to,
it's just going to rerun.
On the client.
So this has nothing
to do with Git at all.
So this will, if any of your Git hooks
return a non-zero exit
code, it's going to stop the
process of going to GitHub.
So this is a way to save minutes on CI
and stuff like that,
because you know that when
you're pushing, it's already going to
pass the lint check.
So you're not having to push your code up
there and it's like,
oh, I missed, I missed
my spacing on this.
I had all my stuff on one line when it
should have been split
up and it, and it doesn't
pass.
So then you need to have
another commit going in after it.
That's just tagged linting.
And then you have it run and sometimes
you've got multiple,
multiple checks on GitHub.
So you're pushing these things up.
You're still running your test suite and
then you've got
multiple things running at the
same time.
It's just, it's a bit of a pain.
And then for an organization, you've got
a limited number of
minutes in your, your GitHub
actions as well.
And so if you've got a lot of stuff going
on, you kind of want to
minimize that by offloading
that burden to the client first.
Gotcha.
Gotcha.
And, and then now as far as like whiskey,
it's, it's all, you
know, the way you build,
I guess, build, create the way you
implement everything.
It's just straight normal things, right?
Like I know you were comparing it to one
called Husky, but this
one's designed just to be
simple so that way you can define
everything you wanted to do
sort of in a normal fashion,
I guess is the right word.
Yeah.
So the, the big issue with git hooks is
that in your dot get
slash hooks directory that,
that doesn't get
committed to your get tree.
So you can't really
track things that way.
What whiskey does is it registers its own
git hooks directory
and then that's committed
to, to the repo.
And so that's what your, your native get
hooks are going to be calling.
That's a little bit more complicated to
set up than, than whiskey.
I mean, it's not, it's not a huge
difference anyways, but I
was just curious about what
it would look like to build this tool.
So I built it and then I just kind of
kept going and it was
like, Hey, this is cool.
So I was going to release it.
So my goal was to just have it be you
require the package and
then you just run whiskey
install and it does
the whole thing for you.
I've structured it in a way so that if
you've upgraded whiskey
and you're trying to install
it again, it's going to look for all the
legacy ways that I've
ever installed it and
it's going to replace those as well.
So you're usually not going to have to go
in and modify these things manually.
So it's a, I'm trying to have it just be
really, really smooth,
really smooth, straight forward.
Is this something you run on all your
projects, even for like
your personal stuff or do you
kind of think of more of like these get
hooks and, and whiskey
being more in like a team
environment?
I run it on most of my projects.
Yeah.
And I didn't know this until recently,
but apparently, uh,
verbs from, uh, from thunk,
they have it installed in there too.
So that's kind of cool.
And yeah, they told me that they like it
because it just works.
It's one of those things where you just
kind of set it up once
and you can forget about
it.
And you don't need to, it's not one of
those things that's
constantly blocking you from,
from getting your stuff done.
So it's nice to know that
at least it's tolerable.
Yeah, that's true.
That's funny.
Um, so, so what is like, um, this was
sort of off the wall, but
what is sort of the most
advanced thing you've
ever done with the package?
Like are you doing anything crazy in any,
in any of your other
projects that, uh, so
I don't do a whole lot of crazy stuff
with, with whiskey
because normally, normally I
just register all my
scripts as composer scripts.
So I just do like composer, Len,
composer types, composer
coverage, composer, all of
this.
And then in my whiskey dot Jason, Oh
yeah, that was the other change.
I don't register a get hooks directory.
I just have a single composer dot Jason
in your directory route.
So that's where you do it.
And every time you make an update in
there, as long as you're
not adding a new hook, you
don't have to update whiskey.
Um, so that's usually the
only stuff that I'm doing.
I'm not doing crazy stuff.
Like a lot of people will add in like a
scripts directory where
they can have lint staged.
So it'll only lent
anything that's been staged.
I usually try to avoid that.
My biggest suggestion with whiskey and
get hooks in general,
do not let your get hooks
modify the, um, the, the files, just have
it do checks because
if it's modifying files,
especially if you're doing patch commits,
then it's going to
overwrite the, it's going
to recommit the whole file instead of
just that patch section.
So I try my best not to do anything
ambitious and a get hook.
I try to just keep it simple and fast.
Do you, um, I, since you want it simple
and fast, do you run
tests through there too,
or do you kind of keep those for only
like sort of the sea outside?
Uh, I mean, of course running them
locally, but do you also
do that as part of this or,
or how do you usually run
the tests before pushing?
So my, my pre-commit hook is usually just
a linter and then my
pre-push hook is usually
like the, the linter again, um, static
analysis and the test suite
and sometimes type coverage.
Nice, nice.
Um, and then of course, you know, like if
anybody's listening or
watching and they want
to, um, just sort of see what you do, I
assume you, you have a
sample set up there, um, with
the package to kind of get them started
or is it best to look
at, like, look at one of
your other projects just to, just to see
how you're doing things?
Um, yeah, I mean, there's, there's not
really a whole lot to it to demonstrate.
The read me I spent a lot of time on, so
it's pretty descriptive of it.
So it goes through a couple of scenarios
where, where you might
want to skip using whiskey
and stuff like that.
Um, yeah, I don't think there would be a
whole lot of benefit in
showing how it's used in
a project just because it's such a small
narrowly targeted tool.
Um, one thing that I did want to include
in there though, was
there's certain actions
in get that aren't
compatible with the no verify flag.
So if you're doing something where
someone used the no
verify flag to push something
that wasn't passing the linter and then
they skipped the CI step
and they merged anyways.
So you've got changes in your main branch
that don't pass the linter.
You're going to bring that down into your
local branch and then
you're going to merge
from main and then as you're merging,
it's going to fail
because it doesn't pass the
lint stage because we're not, we're
running the pre-commit hook.
So if you try to run get merge dash dash
continue dash dash no
verify so that you're skipping
the hooks, it's not going to work because
that function doesn't
work with the no verify.
So I added into whiskey, uh, just a
whiskey skip once command.
And so if you do that, it'll skip it.
You can merge from main,
uh, or rebase from main.
And then at that point you run the linter
on a separate commit
and then you can keep
on going with your work.
So there's some, there's some edge cases
and everything, but I try
to, I try to demonstrate
those in the read me.
Yeah.
It's funny.
Like, yeah, I was going to say, like get,
get in general, like,
um, you know, I'm sort
of this old man developer now.
You know, we started off with no version
control and then it
was a, what CVS or CSV
and then Mercurial and
then, uh, SVN at one point.
Uh, but I love that like sort of get
seems to have won the
space of, uh, of, uh, version
control.
It just seems so much easier now.
Um, then, you know, way back in the day
when it was sort of the,
you know, the merges and
stuff were just terrible and all that.
But, uh, um, I was sort of a random
tangent, but, uh, so going
back to the name, you said
the name came from sort of,
uh, uh, a call out to Husky.
Yeah.
And the name was like a hundred percent
credit to Nuno on the name.
I don't know how he just like pulled it
out of thin air
because, uh, he suggested, why
don't you make it a, into a CLI instead.
And like, yeah, geez, I
wonder what I would name that.
He was like, why not whiskey?
It's like, it was perfect because it's
pretty similar to Husky
and that's definitely how
it was inspired.
I don't know where he got
that name from, but props to him.
Well, so Husky, I'm, I keep thinking of a
dog, like a Husky dog.
Um, and then I assumed you were drinking
whiskey the night you
created this and that's where
the name came from.
No, I haven't developed
my palette for whiskey yet.
I've still got a very unrefined palette.
But uh, but you do have the logo there
with a little whiskey
glass, um, with a little
ice cube.
So that's pretty sweet.
Yeah.
And then I just, I just spell whiskey the
correct way, much too much to the chagrin
of J Mac.
He thinks I should be spelling whiskey
the other way, but it's,
it's just not the right
way.
I will die on this hill.
What's funny though, is if you Google
like Len Woodward
whiskey, like there's actually
like whiskey that comes
up, not the, not the project.
And you keep, you would think that like,
you know, that would be
sort of random, but it
was like, cause cause when I was doing
research, I was like, Hey.
And then it was like all these, I guess
Woodward and then Woodford
and you have all these other
different whiskey actual brands, um,
which is kind of funny.
Uh, but, uh, but who
did, who did your logo?
Did you design that one yourself or?
Yeah, I just, I just went in Figma and
tried to do something
a little bit stylized.
It was just a really
quick and dirty thing.
I think I was, it was me anyways.
Did I steal it?
I don't think I stole it.
I'm pretty sure I did it myself.
I'm not even sure anymore.
I don't know what I
have and haven't done.
If I stole your artwork, let me know.
I will give you money.
I was going to say it all, it all runs
together in the end on it.
But how's the, um, you know, as far as
the usage and stuff is,
is the community picking
up and using it or, um, yeah, I mean,
it's been a slow and steady grind.
Um, I think I'm up to like 38,000
installs or something like that.
And I'm up to like 160 stars on GitHub.
So it's not like a super smash hit, but I
think get hooks are
kind of a niche thing.
So not everyone is looking for it, but
every once in a while open Twitter and
someone's like, Oh, I
found this cool tool.
And I'm like, Oh shit, that's awesome.
I wasn't expecting that.
It was just a nice little surprise.
That is also, I've actually, I don't, I'm
trying to remember if I use get hooks
that often and I don't, I'm trying to, I
don't, I'm not pulling up anything out
of my mind that where
I've been using them lately.
Um, so may I need to actually research
more on, you know, setting those up and
give them a try cause I
get, just seems so useful.
Um, especially like the running tests,
like, well, you said
that was a pre-commit
hook, but, um, just even
the linter and all that stuff.
I mean, it seems super useful to have all
that just set up once.
And then everybody just, you know, has
the same stuff all the time.
Yeah.
It's funny every once in a while, I got
this little uptick and installs too.
Cause, uh, I think like every six months
or so, um, Roman Pronsky ends up writing
like a little tiny blurb about it in the
PHP foundation newsletter.
Like people are talking about this again.
I wonder what happened
and it's always Roman.
That's great.
That's great.
Um, so they, they do, well, I guess they
pick up that's on like the official PHP
news there, is that
what Roman writes that?
Or is that on the, um, I can't remember
if he does it through
the foundation or if
he does it through the jet brains.
I think it's jet brains, but yeah, every
once in a while
there's something on there.
And then, uh, and then yeah, every once
in a while there's another project too,
like FFmpeg stuff or a conductor was on
that people are really excited about.
But I still got some heavy work to do on
that before it's, before it's ready to
properly announce and release, I've got
my proof of concept in there, but it's,
it's gross.
Well, so I think you alluded to it
earlier, whiskey, you,
you think it's pretty much
feature complete or you got one, one or
more, one or two more things you want to
do to it before jumping over.
So there's one bug that's still, that's
still annoying me and
some GitHub, uh, some
git hooks will accept parameters and I'm
not set up to handle that.
And I just haven't been able to sit down
and properly crack this, this problem.
So where that becomes an issue is if
you're using an extension or a plugin,
like, um, Oh, what's it called?
It's like lint commit message.
So if you have a certain style that you
want your commit
messages to abide by, um,
it'll, it'll look at the actual message
and we'll do that, but I'm not sure how
to handle that yet.
The other thing that, um, that I had
fought with for a while was just an
architectural thing where it was really
gross the way I had to register
everything.
So I had a, like a shell script in my, in
my vendor folder that the
get hook would call that shell script
would then ask the Laravel CLI from
Laravel zero for a list of
the, the commands to write.
Then it would bring that back.
And if you're supposed to skip it, that
list will just come back empty.
But the reason I had to do that, that was
so that I was getting the
output as it came out.
Um, I ended up discovering the process
for sad has this TTY mode.
So it basically attaches the input and
output to the, to the actual
currently running terminal.
So it had a benefit of
being able to be interactive.
So if something stops and asks for user
input, you can do that, but it also
maintains the colors in the terminal.
And that was like a really
unexpected, nice side effect.
So you still get all like the, the green
checks and the red X's.
So that brought me like way
closer to feature complete.
I've just got that one
last little thing to do.
I'm pretty sure we're
even windows compatible.
It's been a while since I've tested that
out, but I'm pretty sure it works.
Well, I guess kind of eluding into that,
are you looking for sort of community
help on any of these things?
Or you think you're just going to knock
them out one day when you get some time?
Yeah, there's been, there's been like
three other people that just pop up
every now and then with a PR and like
most of the time they're, they're great.
Like they're just this really narrowly
targeted banger of a PR and like they
list the, the issue, they list why it's
an issue, how to fix it.
They got the fix in there.
And then every time I tag a new release,
I try to tag them so that I can show them
out and thank them and yeah, it's been,
it's been fun having a project that
other people care about, even if it's
just like this tiny little bit.
Yeah.
And, and to have people that commit and
do what you just said is,
is pretty impressive now.
You know, it's always great when somebody
does all that and it's really isolated
to the one thing that they're having the
issue with, you know, so, you know, that
was where I was going to, like, if, you
know, if you're listening or watching
and you know, you've not made commits or
pull requests to any projects, keep it
small, keep it contained and focused on
one thing, and then it's your likelihood
of getting it merged is way greater than,
you know, if you're
trying to tackle 50,000
files or anything else like that.
Yeah.
And if you are trying to develop a thing
and you're not really sure why, why
certain things aren't working, I do have
some hidden commands in there as well,
which you can usually find in the not in
the read me, but in the source.
So I've got like a whiskey audit command,
and that'll just give you a table that
prints out a whole bunch of the variables
that I'm using within all these different
classes, like where the composer home
directory is, where the project directory
is, where vendor things are being kept,
like, and then ways to determine the
platform and all that type of stuff, ways
to determine if whiskey is being run
globally or locally.
So if you're trying to add in a little
feature or a bug fix and things aren't
working, you got some
tools like that built in.
That's awesome.
That's awesome.
Well, I guess we'll kind of any other
sort of highlights or anything else,
you know, that we didn't, uh, why I
didn't ask you about
as far as whiskey goes.
Not that I can think of no.
And it's a pretty small tool.
So it's not really,
those are the perfect ones.
Yeah.
Yeah.
It's, uh, um, I forgot what I was trying
to say there, but yeah, the, uh, I like
the little small, well-defined tools, you
know, and you just pull them in and they
work and you don't really have to think
about them too much.
It just seems to,
seems to make life easy.
Yeah.
That's kind of the theme that my buddy Ed
and I are trying to take where we're
building a suite of
tools called scalpels.
And so there's meant to be just very
narrowly targeted sharp tools.
So each one just does
one thing and does it well.
And we're just going to try to have a,
like a suite of these ready to go for
a Laracon and see if
people are interested.
It's not going to be like this giant
revenue generator, but if we can pay our
AWS bill, I think that'll be fun.
Hopefully you don't get the dust.
But yeah, I like those
kinds of tools, just very small.
Um, there's, you're not having things
interacting with all
sorts of other stuff.
Limited complexity.
Yeah.
It's a good way to do it.
That's awesome.
So this scalpel tool you're planning
launching sort of right around
Laracon or sort of before or after.
We're not quite sure yet.
We don't even know if we'll have enough
tools finished yet, but, uh,
putting you on the spot there.
We got about four or five tools that
we're trying to get done in time.
I don't know if we'll be able to.
Um, so we'll see what happens.
Yeah.
That's great.
Well, um, or any, any other thing, you
know, maybe anything I miss,
anything else you want to say before we
close out this, um, this
creator series spotlight.
Um, yeah, go to get hub and
give me a star on whiskey.
It makes me feel good.
And then follow me on Twitter.
Um, follow me on YouTube as well.
I started making a couple of videos.
So if you just go to YouTube slash
artisan build, that's, um, that's
where I'm putting those videos out.
And yeah, just seeing those numbers go
up, it gives me the warm and fuzzies.
Yeah.
So those are wonderful.
And we'll be sure we'll have all those in
the show notes as well with links to
the repos, his Twitter, his YouTube and
sort of everything else.
Um, I think this is going to conclude
this, uh, episode and we want to thank
everybody for tuning in and watching.
And, uh, we will see you next time.
Thanks.
Thanks, Len.
Yeah.
Cheers.