For the past 5 years or so, I’ve added a group of scripts to every project I’ve worked on. These scripts are relatively simple and automate some very common tasks.
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/deploy
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
Example:
#!/usr/bin/env bash
set -e
CYAN='\033[0;36m'
YELLOW='\033[1;33m'
NC='\033[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 that changes to the way the team runs tests are automatically shared by everyone.
Example:
#!/usr/bin/env bash
set -e
CYAN='\033[0;36m'
YELLOW='\033[1;33m'
NC='\033[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
Example:
#!/usr/bin/env bash
set -e
CYAN='\033[0;36m'
YELLOW='\033[1;33m'
NC='\033[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.
Example:
#!/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