alextanhongpin / .makefiles

Automate everything with Makefile

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

.makefiles

Automate everything with Makefile

Makefile basics

Creating a Makefile

$ touch Makefile

Hello World

In your Makefile:

greet:
	echo hello world
$ make greet
> hello world

Chaining Commands

You can chain commands in Makefile:

greet: bid
	echo hello

bid:
	echo bye

This is especially useful when you have multiple steps involved, e.g. building and deploying a container:

deploy: build tag push
	echo deploying

build:
	echo building image

tag:
	echo tagging the image

push: 
	echo pushing to dockerhub

Suppressing command output

To suppress the command being executed, add @ before the command:

greet:
	@echo hello

Using environment variables

You can pass environment variables into Makefile when running the command:

greet:
	@echo Hi, $(NAME)!

Running the greet command:

$ NAME=john make greet
> Hi, john!

This is useful if you need to use Makefile to configure builds for certain environment, e.g. ENV=prod make build.

Loading environment variables from file

Makefile can also load environment variables from .env file

include .env
export

If you want to make it optional, add the minus sign before include. Otherwise, an error will occur:

-include .env
export

The export will export all available environment variables in the Makefile.

You can include as many .env files as you want, the order matters though:

.env.development
.env # This will overwrite any values that already existed in .env.development
export

Loading enviroment variables dynamically

You can also load environment variables dynamically:

ENV ?= development    # Defaults to development.
-include .env         # Include the base environment.
-include .env.$(ENV)  # Will load based on your current environment, and overrides the values in base environment file.
export

greet:
    echo Running in $(ENV)

Run:

$ make greet ENV=development
> Running in development

$ make greet ENV=production
> Running in production

Environment guards

Say if we only want to ensure that certain command can only be run in certain environment:

ENV ?= development
-include .env
-include .env.$(ENV)
export

deploy: prod-only
	@echo deploying to production

prod-only:
ifneq ($(ENV),production)
	$(error ENV must be production)
endif

Run:

$ make deploy
> Makefile:6: *** ENV must be production.  Stop.

$ make deploy ENV=production
> deploying to production

You can make a CLI with your Makefile

.PHONY: help
help:
	@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)

.DEFAULT_GOAL := help

vendor: ## Vendor the application
	@echo vendoring...

Just run make without any commands, it will print the command and the description.

Useful variables

PROJECTNAME := $(shell basename $(PWD))
COMMIT=$(shell git rev-parse HEAD)
BRANCH=$(shell git rev-parse --abbrev-ref HEAD)
BUILD_DATE := $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
CURRENT_DIR=$(shell pwd)
VERSION := $(shell git describe --tags --abbrev=0)

COLOR="\033[32;1m"
ENDCOLOR="\033[0m"

Using dynamic variables in command

# To override just a single environment variable inline.
deploy:
	@echo ${A}

# make deploy-staging
# make deploy-production
deploy-%: .env.%
	@$(MAKE) deploy ENV=$*

Modular Makefiles

You can separate your Makefiles into smaller Makefiles. This promote reusability, while keeping your Makefile small. Say you have the following Makefiles:

In database/Makefile:

start:
	@echo starting db
  
stop:
	@echo stopping db

In docker/Makefile:

IMG := alextanhongpin/api
build:
  @docker build -t $(IMG) .
  
up:
  @docker-compose up -d
  
down:
  @docker-compose down

You can now include them in your main Makefile at the root of your project directory:

include docker/Makefile
include database/Makefile

greet:
	echo greet

And you can run all the commands that are available in docker/Makefile and database/Makefile:

$ make up
$ make down
$ make start
$ make stop

The only disadvantage is that the naming of the command cannot be the same.

Read Input

You can read input in makefiles too. The example below copies an existing folder and rename all the variables/classes for code reuse:

service: # Clones the currency folder, and replaces all the name with given name.
	@read -p "Enter folder name: " folder; \
	read -p "Enter class name: " class; \
	read -p "Enter singular name: " singular; \
	read -p "Enter pluralize name: " plural; \
	cp -r src/currency src/$$folder; \
	sed -i "" "s/Currency/$$class/g" src/$$folder/**.ts; \
	sed -i "" "s/currency/$$singular/g" src/$$folder/**.ts; \
	sed -i "" "s/currencies/$$plural/g" src/$$folder/**.ts;

Makefile alternatives

About

Automate everything with Makefile


Languages

Language:Makefile 100.0%