Computer Things

Using Scripts To Encode Your Development Process

See other articles in the “Software Development” topic.

For the past decade or so, I’ve added a group of scripts to every project I’ve worked on. These scripts started out relatively simple and automate some very common tasks. Scroll to the end for some updates.

Why Automate?

Automation encodes the team’s decisions in committed code, reducing questions (such as “do we like to do git pull --rebase or just git pull?”) and reducing problems caused when people forget to perform a step (such as running tests before pushing code).

How To Automate

Because Bash is ubiquitous, I typically write the scripts in Bash. Sometimes I write them in a more powerful language if they are complex. I personally put them in the bin/dev directory (I’ll often have a bin/prod directory for performing production actions, like bin/prod/ or bin/prod/logs).

Update

The update script is run when the developer wants to get the latest code onto their computer. It typically:

  • pulls code from the git remote
  • updates dependencies
  • runs migrations
  • runs doctor

Bash
#!/usr/bin/env bash

set -e

CYAN='33[0;36m'
YELLOW='33[1;33m'
NC='33[0m' # No Color

step() {
  description=$1
  command=$2

  echo -e "\n${CYAN}${description}: ${YELLOW}${command}${NC}"
  eval "${command}"
}

step "Pulling" "git pull --rebase"
step "Updating deps" "MIX_QUIET=true mix deps.get"
step "Migrating" "mix ecto.migrate ecto.dump"

bin/dev/doctor

Test

The test script runs all the tests. A script is useful for this so that everyone runs tests the same way, and so changes to the way the team runs tests are automatically shared by everyone.

Bash
#!/usr/bin/env bash

set -e

CYAN='33[0;36m'
YELLOW='33[1;33m'
NC='33[0m' # No Color

step() {
  description=$1
  command=$2

  echo -e "\n${CYAN}${description}: ${YELLOW}${command}${NC}"
  eval "${command}"
}

step "Running JS tests" "(cd assets && yarn run mocha)"
step "Running Elixir tests" "mix test --color"

Shipit

The shipit script is run when the developer wants to push code to the git remote. It typically:

  • runs the update script
  • re-compiles, ideally treating warnings as errors
  • runs tests
  • pushes to the git remote

Bash
#!/usr/bin/env bash

set -e

CYAN='33[0;36m'
YELLOW='33[1;33m'
NC='33[0m' # No Color

step() {
  description=$1
  command=$2

  echo -e "\n${CYAN}${description}: ${YELLOW}${command}${NC}"
  eval "${command}"
}

bin/dev/update
step "Recompiling" "mix compile --force --warnings-as-errors || (mix clean && false)"
bin/dev/test
step "Pushing to git" "git push"

Start

The start script starts the server or app. It’s usually not a complicated script but it makes it really easy to remember how to run the project.

Bash
#!/usr/bin/env bash
iex -S mix phx.server

Other Scripts

Besides the above scripts which I have in nearly every project, I also have other scripts that show up in some of my projects:

bin/
  dev/
    doctor    # ensures the development environment is set up correctly
    format    # formats code for consistent style
    outdated  # checks which dependencies are outdated
    psql      # opens psql with the right database
    shipit    # updates, runs tests, and pushes
    start     # starts the server or app
    test      # runs tests
    update    # updates from git remote, updates dependencies, runs migrations
  prod/
    deploy    # deploys to production, or prints instructions for how to do it
    log       # shows production logs
    restart   # restarts servers
    scale     # adds or removes servers
    shutdown  # stops servers
    ssh       # logs into servers

Related Reading

Scripts to Rule Them All
from the GitHub blog
A Doctor To Check Your Development Environment
A flexible tool for sharing project configuration and practices among members of a dev team.