Supercharge Your Makefile

A Makefile provides a simple entry point for any project for scripts and utilities, regardless of the language or platform. And there are a few tips I can offer to make yours more useful. In short, for a Javascript project or Java project, make can easily run npm or mvn or gradle, as well as assist in routine operations. And while I’ll still find myself running mvn package or npm t, here are some invaluable use cases:

  • Building artifacts
  • Running tests with profiles
  • Running specific tests by classname
  • Building docker images
  • Helm deployment to Kubernetes or VMs

New to Make?

If you haven’t used make before, its very easy to get started. There are just a few things to know, and you’ll be off to the races:

  • make is generally available in every operating system, so you needn’t install anything.
  • Comments start with #
  • Makefiles are structured as follows, defining the target and the commands with whitespace:
my-target:
    @echo "This prints text, but doesn't show the command because of the @ symbol"
    echo "This prints text, and shows the command that executed."
    npm run build
  • You can also set other commands as prerequisites by including them, in order, after the colon:
deploy: clean build
    ENV=production HOST=bravo.clearthehaze.com npm run deploy-to-box

Let’s Get Awesome

Now, if you want to make your Makefile really spectacular,

Use Colors!

Since terminals support color, spruce up your output with some color, using these variables in your Makefile, and run with make color-demo:

color-demo:
    @echo "$(BLACK)Black$(BLUE)"
    @echo "$(GREEN)Green$(BLUE)"
    @echo "$(RED)Red$(BLUE)"
    @echo "$(YELLOW)Yellow$(BLUE)"
    @echo "$(BLUE)Blue$(BLUE)"
    @echo "$(MAGENTA)Magenta$(BLUE)"
    @echo "$(CYAN)Cyan$(BLUE)"
    @echo "$(WHITE)White$(BLUE)"


###################################
## Variables for Makefile
###################################
# Colors
BLUE=\x1b[0m
BLACK=\x1b[30;01m
RED=\x1b[31;01m
GREEN=\x1b[32;01m
YELLOW=\x1b[33;01m
BLUE=\x1b[34;01m
MAGENTA=\x1b[35;01m
CYAN=\x1b[36;01m
WHITE=\x1b[37;01m

Just remember to reset the color, else all of your output will change.

Include A Help Section

I always add this target to give explicit guidance and documentation on how to use a Makefile, as the maturity of products vary over time and I may not the implementation of new patterns. And if it is your first target, then it will be printed automatically when make is run.

I like to divide up commands to help local development from production operations, and color code them accordingly.

help:
    @echo "You have the following options when using this Makefile:"
    @echo
    @echo "$(YELLOW)Development related:"
    @echo "$(YELLOW) package $(BLUE)- builds the artifacts $(BLUE)make package"
    @echo "$(YELLOW) test-class $(BLUE)- runs a single test, identified by setting CLASS, eg. $(BLUE)make test-class CLASS=StringUtils"
    @echo "$(YELLOW) docker $(BLUE)- builds the docker image, including tag $(CODE_COLOR)make docker TAG=0.0.11"
    @echo "$(YELLOW) run-container $(BLUE)- runs the built docker container, eg. $(CODE_COLOR)make run-container TAG=0.0.11"
    @echo "$(YELLOW) stop-container $(BLUE)- stops the running docker container, eg. $(CODE_COLOR)make stop-container"
    @echo
    @echo "$(GREEN)Production related:"
    @echo "$(GREEN) deploy-production $(BLUE)- deploys to production $(CODE_COLOR)make deploy-production IMAGE=<url>"
    @echo "$(GREEN) restart-production $(BLUE)- restarts the production service $(CODE_COLOR)make restart-production"
    @echo "$(GREEN) canary $(BLUE)- runs the canary health check on production $(BLUE)make rolling-restart-prod-phx"
    @echo "$(BLUE)"
Use Default Variables

Scripts are intended to simplify the routine operations for a service. That implies consistent values used in commands, such as the service name or a data center for hosting. Variables allow you to set a project specific value for an otherwise common command you’d use in any project. These variables, and your standard environment variables, can be used as ${MY_VAR} in commands, or $(MY_VAR) in echo statements.

###################################
## Default values for all variables
###################################
ENV ?= test
# Kubernetes deployment variables
CLUSTER ?= us-east-1
NAMESPACE ?= cth-test
DOCKER_REGISTRY ?= https://hub.docker.io/clearthehaze/
SERVICE_NAME ?= clearthehaze-site
TAG ?= latest


And with those variables ready…

Simplify Deployments

Ideally, all deployments are going through CI/CD. But it is handy to know how to manage your service and handle deployments for feature testing, production support, etc. Deployment commands tend to be routine with little variance between versions, and a Makefile is a handy way to document those commands.

Here is an example with Helm, including variables set above:

# This command will deploy to Kubernetes. If TAG is not provided, will deploy latest# make deploy TAG=cc2c8f3ad3087e9793c49e4e2361d686b49fab20
deploy:
    @echo"$(GREEN)Deploying $(SERVICE_NAME) to $(ENV)$(NO_COLOR)"
    @echo"Helm output..."
    helm template kubernetes -f kubernetes/${ENV}.yaml --set image=${DOCKER_REGISTRY}${SERVICE_NAME}:${TAG}
    @echo"Running helm again and sending to kubernetes"
    helm template kubernetes -f kubernetes/${ENV}.yaml --set image=${DOCKER_REGISTRY}${SERVICE_NAME}:${TAG} | kubectl --cluster ${CLUSTER} -n ${NAMESPACE} apply -f -
    kubectl --cluster ${CLUSTER} -n ${NAMESPACE} rollout status deployment/${SERVICE_NAME}

1 thought on “Supercharge Your Makefile

  1. Kirk Grossett

    Hello. This post couldn’t be written any better! Reading this post reminds me of my previous room mate. He always kept chatting about this. I will forward this page to him. Fairly certain he will have a good read. Thank you for sharing.

Comments are closed.