Slide 1

Slide 1 text

Makefile Automating daily tasks & simplifying getting started Gustavo Pantuza

Slide 2

Slide 2 text

@gpantuza @pantuza https://blog.pantuza.com

Slide 3

Slide 3 text

Desconto de 50% na compra de SSL Utilize o código DEVBR50OFF

Slide 4

Slide 4 text

Agenda Introduction Properties Advanced ● Motivation ● How it works ● File Format ● Demo ● Variables ● Conditionals ● Builtin functions ● Includes ● Defining Functions ● Automatic Variables ● Caveats ● Other directory ● Use cases

Slide 5

Slide 5 text

Introduction

Slide 6

Slide 6 text

● Automation ● Simplicity ● Learning curve ● Getting Started ● Almost no dependencies Motivation

Slide 7

Slide 7 text

● Program make zypper install make apk add make apt-get install make ● A Makefile The file which make reads in order to execute rules How it work $> make build

Slide 8

Slide 8 text

By the original definition make is: “The make utility automatically determines which pieces of a large program need to be recompiled, and issues commands to recompile them.” How it work $> make what Overview

Slide 9

Slide 9 text

$> make build Building docker image Sending build context to Docker daemon 73.73kB Step 1/4 : FROM golang:1.14-alpine ---> 30df784d6206 Step 2/4 : COPY src /app ---> 5fa423e5e748 Step 3/4 : WORKDIR /app ---> Running in 3a969fe98be8 Removing intermediate container 3a969fe98be8 ---> 3a59a136b09c Step 4/4 : CMD go run main.go ---> Running in 49907a2f877a Removing intermediate container 49907a2f877a ---> 14ec4f19142c Successfully built 14ec4f19142c Successfully tagged makefile:latest How it work $> make build Overview

Slide 10

Slide 10 text

make rules File format Rule Shape

Slide 11

Slide 11 text

target: dependency command File format Rule Shape

Slide 12

Slide 12 text

● target Action to be executed by the rule ● dependencies Needed to exist to satisfy the target ● commands Sequence of commands to be executed File format

Slide 13

Slide 13 text

target..: dependency.. command.. .. File format Rule Shape

Slide 14

Slide 14 text

target..: dependency.. command.. .. File format Rule Shape

Slide 15

Slide 15 text

Hands On

Slide 16

Slide 16 text

Properties

Slide 17

Slide 17 text

# Branch that triggers production deployment PROD_BRANCH := production # Push current branch changes to production branch push: $(info Pushing changes to $(PROD_BRANCH)) @git push origin $(PROD_BRANCH) Variables $> make push Pushing changes to production Everything up-to-date

Slide 18

Slide 18 text

# Docker image version IMG_VERSION ?= latest # Builds the docker image based on the Dockerfile build: Dockerfile $(info Building docker image) @docker build --tag makefile:$(IMG_VERSION) . Variables $> make build ... Successfully tagged makefile:latest $> make build IMG_VERSION=0.2 ... Successfully tagged makefile:0.2 $> make build IMG_VERSION=beta ... Successfully tagged makefile:beta

Slide 19

Slide 19 text

# Source code directory SRC := src GO_FILES := $(SRC)/main.go $(SRC)/main_test.go # Runs code format on Golang files fmt: $(GO_FILES) $(info Running Go fmt on $(GO_FILES)) @go fmt $^ Variables $> make fmt Running Go fmt on src/main.go src/main_test.go

Slide 20

Slide 20 text

# Expanded once VERSION := 0.12 # Expanded on call NOW = $(shell date +%s) # Conditional assignment IMG_TAG ?= latest # Appending values CFLAGS += -O3 Variables

Slide 21

Slide 21 text

# Rolls back application to specific version rollback: ifndef ROLLBACK_VERSION $(error Missing ROLLBACK_VERSION variable) endif @kubectl rollout undo deployment app --to-revision=$(ROLLBACK_VERSION) Conditionals $> make rollback Makefile:36: *** Missing ROLLBACK_VERSION variable. Stop. $> make rollback ROLLBACK_VERSION=15 ...

Slide 22

Slide 22 text

# Operating system name OS := $(shell uname) # Install project dependencies on the Operating System deps: $(info Installing project dependencies locally) ifeq ($(OS),Linux) @zypper install --no-confirm nginx else ifeq ($(OS), Darwin) @brew install nginx else $(warning Unsupported Operating System) endif Conditionals $> make deps # Else example Makefile:36: Unsupported Operating System $> make deps # Linux example Installing project dependencies locally ... Conditionals

Slide 23

Slide 23 text

# List of files to be modified FILES := src/a src/b bin/a bin/b # String functions examples functions: @echo "Input: $(FILES)" @echo "subst -> " $(subst src, tmp, $(FILES)) @echo "filter -> " $(filter bin%, $(FILES)) @echo "findstring -> " $(findstring a, $(FILES)) @echo "sort -> " $(sort $(FILES)) @echo "word -> " $(word 2, $(FILES)) @echo "lastword -> " $(lastword, $(FILES)) Builtin functions $> make functions Input: src/a src/b bin/a bin/b subst -> tmp/a tmp/b bin/a bin/b filter -> bin/a bin/b findstring -> a sort -> bin/a bin/b src/a src/b word -> src/b lastword -> bin/b Text Functions

Slide 24

Slide 24 text

# List of files to be modified FILES := src/a src/b bin/a bin/b # Files functions examples functions: @echo "Input: $(FILES)" @echo "dir -> " $(dir $(FILES)) @echo "notdir -> " $(notdir $(FILES)) @echo "basename -> " $(basename $(FILES)) @echo "addsuffix -> " $(addsuffix .go, $(FILES)) @echo "addprefix -> " $(addprefix /tmp/, $(FILES)) @echo "abspath -> " $(abspath $(FILES)) Builtin functions $> make functions Input: src/a src/b bin/a bin/b dir -> src/ src/ bin/ bin/ notdir -> a b a b basename -> src/a src/b bin/a bin/b addsuffix -> src/a.go src/b.go bin/a.go bin/b.go addprefix -> /tmp/src/a /tmp/src/b /tmp/bin/a /tmp/bin/b abspath -> /makefile/src/a /makefile/src/b /makefile/bin/a /makefile/bin/b Files Functions

Slide 25

Slide 25 text

# List of directories DIRS := src bin logs # Directories with suffix SUF_DIRS := $(foreach dir, $(DIRS), $(addsuffix -dir, $(dir))) # Runtime functions examples runtime: @echo "$(shell hostname)" @echo $(SUF_DIRS) @echo $(wildcard src/*_test.go) $(eval AWS_ACCOUNT = $(shell aws sts get-caller-identity --query "Account")) @echo $(AWS_ACCOUNT) Builtin functions $> make runtime opensuse-machine src-dir bin-dir logs-dir src/main_test.go 151666326780

Slide 26

Slide 26 text

# Builtin functions to print messages messages: $(info Informative function) $(warning Warning function) $(error Error function) Builtin functions $> make messages Informative function Makefile:40: Warning function Makefile:41: *** Error function. Stop. Text Functions

Slide 27

Slide 27 text

# Includes an external Makefile include Makefile.conf # Gets project version read # included Makefile.conf version: @echo $(VERSION) @echo $(PROJECT_NAME) @echo $(DOCS) @echo $(PKG_MGR) Includes $> make version 0.42 makefile docs /usr/bin/zypper # =====* Makefile.conf *===== # Shell program SHELL := $(shell which bash) # Gets from shell the operating system OS := $(shell uname -s) PKG_MGR := $(shell which zypper) ifeq ($(OS), Darwin) PKG_MGR = $(shell which brew) endif # Project name PROJECT_NAME := makefile # Get the version from file VERSION := 0.42 # Documentation directory DOCS := docs

Slide 28

Slide 28 text

Advanced

Slide 29

Slide 29 text

# # Returns current timestamp (no parameters) # NOW = $(shell date +%s) # # Function to subtract the first number from the second # (with parameters) SUBTRACT = $(shell expr $(1) - $(2) ) time: @echo "Now: $(call NOW)" @echo "Subtract 20 from 30: $(call SUBTRACT, 30, 20)" Functions $> make time Now: 1595898056 Subtract 20 from 30: 10

Slide 30

Slide 30 text

# # Function that takes a template and a variable as input. # It returns template text interpolated with the variable. # define parse_template @echo $(1) | sed 's/{NAME}/$(2)/' endef # Builds templates dynamically template: $(call parse_template,"Learning {NAME} rocks!",Makefile) $(call parse_template,"Learning {NAME} rocks!",Computer Science) $(call parse_template,"Learning {NAME} rocks!",DevOps) Functions $> make template Learning Makefile rocks! Learning Computer Science rocks! Learning DevOps rocks!

Slide 31

Slide 31 text

# Magic variables example magic: Dockerfile README.md LICENSE @echo $< @echo $^ @echo $@ Automatic variables $> make magic Dockerfile Dockerfile README.md LICENSE magic Automatic Variables

Slide 32

Slide 32 text

# Resolve git command path GIT := $(shell which git) push: @$(GIT) push origin master Caveats $> make push Enumerating objects: 5, done. Counting objects: 100% (5/5), done. Delta compression using up to 8 threads Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 1014 bytes | 1014.00 KiB/s, done. Total 3 (delta 2), reused 0 (delta 0) remote: Resolving deltas: 100% (2/2), completed with 2 local objects. To github.com:pantuza/makefile.git d865102..493d7cd master -> master

Slide 33

Slide 33 text

# @ before command avoid printing the command hide: @echo "No command shown, only result" show: echo "Command shown and also the result" Caveats $> make hide No command shown, only result $> make show echo "Command shown and also the result" Command shown and also the result

Slide 34

Slide 34 text

# .PHONY make sure to not fail if the target is # equal to a file or directory .PHONY: src src: @echo "Hi PHONY target" Caveats $> ls Dockerfile LICENSE Makefile README.md src $> make src # Whitout .PHONY make: 'src' is up to date. $> make src # Using .PHONY Hi PHONY target

Slide 35

Slide 35 text

# Using Wildcards # Validates all OpenAPI spec files check_spec: $(SRC)/%.yaml @openapi-spec-validator $^ Caveats $> make check_spec OK

Slide 36

Slide 36 text

Caveats # Chaining rules $> make start logs Running application container 6de3d88c680d57da5658a5007b988cdaed909e8cb588af20b1bc9100ca2bad07 [Http] Status=Listening, Port=8080

Slide 37

Slide 37 text

Caveats # Debugging with -n option $> make build start logs -n Building docker image docker build --tag makefile:latest . Running application container docker run -it --rm -p 8080:8080 --name makefile -d makefile:latest docker logs --tail 50 --follow makefile

Slide 38

Slide 38 text

# Makefile on an inner directory # For example /lib/Makefile binary: main.go @go build -o $@ Other directories $> make -C lib/ binary make: Entering directory '/makefile/lib' make: Leaving directory '/makefile/lib'

Slide 39

Slide 39 text

Use cases # Jenkinsfile ... stage('Unit Tests') { steps { echo 'Running Unit Tests..' sh 'make unit_test' } } stage('Integration Tests') { steps { echo 'Running Integration Tests..' sh 'make integration_test' } } ...

Slide 40

Slide 40 text

Use cases # .travis.yml sudo: required language: cpp services: - docker before_install: - make start script: - make test

Slide 41

Slide 41 text

Use cases # DRY - Don’t Repeat Yourself # CI/CD Pipeline execution chain pipeline: pep8 check_openapi check_k8s unit_test integration_test acceptance_test # Deploy application to production deploy: cloud_auth build_img push_img migrate_db patch @kubectl rollout status deployment $(DEPLOYMENT_NAME) @kubectl apply -f $(K8S_DIR)/deployment.yaml

Slide 42

Slide 42 text

Use cases # Getting started In order to have the project running locally you can just run as follows: ```bash $> make setup ``` > It will install all project dependencies and > and run application using containers You can check if everything is OK by running the tests: ```bash $> make test ``` If everything went well, please refer to the CONTRIBUTING.md and start contributing to the Project!

Slide 43

Slide 43 text

Use cases Kubernetes Python language NodeJS BusyBox Docker CLI Prometheus Traefik Terraform

Slide 44

Slide 44 text

Automating & simplifying

Slide 45

Slide 45 text

https://github.com/pantuza/makefile https://www.gnu.org/software/make/manual/make.html

Slide 46

Slide 46 text

Desconto de 50% na compra de SSL Utilize o código DEVBR50OFF

Slide 47

Slide 47 text

https://blog.pantuza.com https://github.com/pantuza https://twitter.com/gpantuza Dúvidas?