GNU Make 4.1 Built for x86_64-pc-linux-gnu
Below is the Makefile
:
# Project variables
PROJECT_NAME ?= todobackend
ORG_NAME ?= shamdockerhub
REPO_NAME ?= todobackend
# File names
DEV_COMPOSE_FILE := docker/dev/docker-compose.yml
REL_COMPOSE_FILE := docker/release/docker-compose.yml
# Docker compose project names
REL_PROJECT := $(PROJECT_NAME)$(BUILD_ID)
DEV_PROJECT := $(REL_PROJECT)dev
# Check and inspect logic
INSPECT := $$(docker-compose -p $$1 -f $$2 ps -q $$3 | xargs -I ARGS docker inspect -f "{{ .State.ExitCode }}" ARGS)
CHECK := @bash -c '\
if [[ $(INSPECT) -ne 0 ]]; \
then exit $(INSPECT); fi' VALUE
# Use these settings to specify a custom Docker registry
DOCKER_REGISTRY ?= docker.io
APP_SERVICE_NAME := app
.PHONY: test build release clean tag
test: # Run unit & integration test cases
${INFO} "Pulling latest images..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) pull
${INFO} "Building images..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) build cache
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) build --pull test
${INFO} "Ensuring database is ready..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) run --rm agent
${INFO} "Running tests..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) up test
@ docker cp $$(docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) ps -q test):/reports/. reports
${CHECK} ${DEV_PROJECT} ${DEV_COMPOSE_FILE} test
${INFO} "Testing complete"
build: # Create deployable artifact and copy to ../target folder
${INFO} "Creating builder image..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) build builder
${INFO} "Building application artifacts..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) up builder
${CHECK} ${DEV_PROJECT} ${DEV_COMPOSE_FILE} builder
${INFO} "Copying artifacts to target folder..."
@ docker cp $$(docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) ps -q builder):/wheelhouse/. target
${INFO} "Build complete"
release: # Creates release environment, bootstrap the environment
${INFO} "Building images..."
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) build webroot
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) build app
${INFO} "Ensuring database is ready..."
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) run --rm agent
${INFO} "Collecting static files..."
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) run --rm app manage.py collectstatic --noinput
${INFO} "Running database migrations..."
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) run --rm app manage.py migrate --noinput
${INFO} "Pull external image and build..."
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) build --pull nginx
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) pull test
${INFO} "Running acceptance tests..."
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) up test
${CHECK} $(REL_PROJECT) $(REL_COMPOSE_FILE) test
@ docker cp $$(docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) ps -q test):/reports/. reports
${INFO} "Acceptance testing complete"
clean:
${INFO} "Destroying development environment..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) kill
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) rm -f -v
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) kill
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) rm -f -v
@ docker images -q -f dangling=true -f label=application=$(REPO_NAME) | xargs -I ARGS docker rmi -f ARGS
${INFO} "Clean complete"
tag:
$(INFO) "Tagging release image with tags $(TAG_ARGS)"
@ $(foreach tag, $(TAG_ARGS), docker tag $(IMAGE_ID) $(DOCKER_REGISTRY)/$(ORG_NAME)/$(REPO_NAME):$(tag);)
${INFO} "Tagging complete"
# Cosmetics
YELLOW := "\e[1;33m"
NC := "\e[0m"
# Shell functions
INFO := @bash -c '\
printf $(YELLOW); \
echo "=> $$1"; \
printf $(NC)' VALUE
# Get container id of application service container
APP_CONTAINER_ID := $$(docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) ps -q $(APP_SERVICE_NAME))
# Get image id of application service
IMAGE_ID := $$(docker inspect -f '{{ .Image }}' $(APP_CONTAINER_ID))
# Extract tag arguments
ifeq (tag, $(firstword $(MAKECMDGOALS)))
TAG_ARGS := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
ifeq ($(TAG_ARGS),)
$(error You must specify a tag)
endif
$(eval $(TAG_ARGS):;@:) # line 108 Do not interpret "0.1 latest whatever" as make target files
endif
Below is the error on running make command:
$ make tag 0.1 latest $(git rev-parse --short HEAD)
Makefile:108: *** recipe commences before first target. Stop.
Line 108, purpose of $(eval $(TAG_ARGS):;@:)
to convey that 0.1 latest $(git rev-parse --short HEAD)
are not make
targets.
Why $(eval $(TAG_ARGS):;@:)
gives error?
That particular error happens because your $(eval ...)
line is indented by a TAB (something that it's hidden by this horribly broken web interface).
Example:
$ make -f <(printf '\t$(eval foo:;echo yup)')
/dev/fd/63:1: *** recipe commences before first target. Stop.
# now with spaces instead of TAB
$ make -f <(printf ' $(eval foo:;echo yup)')
echo yup
yup
The error is documented in the make
manual:
recipe commences before first target. Stop.
This means the first thing in the makefile seems to be part of a recipe: it begins with a recipe prefix character and doesn't appear to be a legal
make
directive (such as a variable assignment). Recipes must always be associated with a target.
The "recipe prefix character" is TAB by default.
$ make -f <(printf '\tfoo')
/dev/fd/63:1: *** recipe commences before first target. Stop.
It doesn't have to be the "first thing in the makefile", though: the same error will trigger after a number of rules, if preceded by a directive like a macro assignment or such:
$ make -f <(printf 'all:;\nkey=val\n\tfoo')
/dev/fd/63:3: *** recipe commences before first target. Stop.
And even if a macro expands to an empty string, GNU make will not consider empty a line containing just macros expanding to empty strings:
$ make -f <(printf '\t\nfoo:;@:')
$ make -f <(printf '\t$(info foo)\nfoo:;@:')
/dev/fd/63:1: *** recipe commences before first target. Stop.
$ make -f <(printf ' $(info foo)\nfoo:;@:')
foo