Project-Specific Command Line Shortcuts with direnv

Most projects that last more than a few weeks accumulate some form or another of automation. Some carefully craft jobs in a package.json file and run them with yarn automation. Some stuff their Makefiles full of .PHONY targets and run them with make my-automation-better. Still others fill up a directory with Bash scripts and run them with ./bin/my-awesome-automation.

Lately, I’ve been using a little command line tool called direnv to automate repetitive tasks for myself and my team without having to prefix automation commands. When I want to clean my project, I just run clean. When it’s time to build: build. To open a web browser straight to our continuous integration server: ci.

Here’s how you can use direnv to save a little bit of focus and a little bit of time every day.

Install direnv

This is the easy part. direnv is available from most package management systems. On macOS, just run brew install direnv. On Ubuntu, apt install direnv. You can even install it on Windows if that’s your corporate IT policy cup of tea. With the package installed, just follow the directions in the direnv Readme to add the right shell hooks for your OS.

With that basic setup out of the way, you’ll have gained the following superpower: Any time you cd (or j) into a directory that contains a .envrc file, direnv will run any commands that it finds in that file. You can use this for all sorts of things like setting up environment variables, adding things to your $PATH, or fetching new commits from a remote.

It’s super-easy to get overwhelmed by automation possibility and never actually build anything, so when setting up a new project, I recommend starting simple:

  1. Let your team know that you’re going to start using direnv. Explain to them what the new .envrc file is and why it’s awesome. Encourage them to try it out and let them know that there’s a pretty nifty security feature that makes it less scary than some other methods for shared shell hackery. If your colleagues don’t want to use direnv, they can safely ignore it while you continue to benefit from your newfound automation prowess.
  2. Make a new .envrc file for your project and check it into source control. You can add whatever you like in here. I like to keep things simple and just add my project’s local bin directory to my $PATH to start with. That looks like this:

    
    # .envrc
    PATH=./bin:$PATH
    

Automate All the Things!

Whenever you find yourself doing something on the project more than once, take a moment to write a little script in your bin directory. I like to add tiny scripts that automate everyday tasks like opening up our project repo page on GitHub:


# ./bin/repo
#!/usr/bin/env bash

open "https://github.com/atomicobject/secret-project"

or opening the web interface to our continuous integration server:


# ./bin/ci
#!/usr/bin/env bash

open "https://circleci.com/atomicobject/secret-project"

or opening our project management tool:


# ./bin/tracker
#!/usr/bin/env bash

open "https://pivotaltracker.com/atomicobject/secret-project"

Because I’m working on a mobile app right now, I occasionally need to update the marketing version number for our project. I used to do that manually for our iOS and Android builds, but a while back, I took 10 minutes and whipped up this script:


# ./bin/new-marketing-version
#!/usr/bin/env bash

# Expects one argument, the new marketing version
[ $# -ne 1 ] && echo "What new marketing version would you like?"

output=$(mktemp)
old_marketing_version=$(cd ios || exit; agvtool what-marketing-version -terse1 | perl -pe 's/\./\\./g')
cd ios || exit; agvtool new-marketing-version "${1}"
cd - || exit
cat android/app/build.gradle \
| perl -pe "s/${old_marketing_version}/${1}/g" > "${output}"
mv "${output}" android/app/build.gradle
rm "${output}"

Now, I can just run:


> new-marketing-version 1.2.3

For some reason, being able to run my own automation scripts as if they were first-class citizens of my command line has driven my motivation to automate way more tasks on my project than I used to. That’s good for my client because I’m a smidge faster and I reduce the possibility for mistakes. It’s good for my team because odds are that they can benefit from the same scripts. And it’s good for me because I get a little micro-burst of pride-in-craftsmanship every time I run repo instead of opening a web browser, tapping ⌘L, then github, then tapping down a few times to find my repo, then ⏎.

How do you power up your projects with automation?