Skip to content

Instantly share code, notes, and snippets.

@josephbolus
Last active September 11, 2023 19:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save josephbolus/e74214933b0525f175ad010d4e3dc69d to your computer and use it in GitHub Desktop.
Save josephbolus/e74214933b0525f175ad010d4e3dc69d to your computer and use it in GitHub Desktop.
Self-Documented Makefile

All our projects contain a lengthy Makefile, to automate installation, build, test, and deployment. Most of the target names are standardized (make install, make deploy), but some deserve explanation (make run-dev, make restart-api). The more we add fine-grained make targets, the more we need to describe what they do in text form.

But when using the CLI, we prefer self-documenting tools. Wouldn't it better if we could just type make, and get a list of available commands, together with their desciption?

$ make
usage : make <commands>

the following commands are available :

help                           Display this help
install-dev                    Install dependencies and prepared development configuration
install                        Install npm dependencies for the api, admin, and frontend apps
restart-frontend               Restart the frontend and admin apps in dev
run-frontend-dev               Run the frontend and admin apps in dev (using webpack-dev-server)
stop-frontend-dev              Stop the frontend and admin apps in dev

It turns out it's quite easy to do. First, document each target using a comment placed after the target name, and starting with ##, as follows:

install: ## Install npm dependencies for the api, admin, and frontend apps
	@echo "Installing Node dependencies"
	@npm install

install-dev: install ## Install dependencies and prepared development configuration
	@./node_modules/.bin/selenium-standalone install
	@cp -n ./config/development.js-dist ./config/development.js | true

run-frontend-dev: webpack.PID ## Run the frontend and admin apps in dev (using webpack-dev-server)

webpack.PID:
	@./node_modules/.bin/babel-node ./node_modules/.bin/webpack-dev-server \
		--content-base=build \
		--devtool=cheap-module-inline-source-map \
		--hot \
		--inline \
		--progress \
		& echo "$$!" > webpack.PID

stop-frontend-dev: webpack.PID ## Stop the frontend and admin apps in dev
	@kill `cat $<` && rm $<
	@echo "Webpack server stopped"

restart-frontend: ## Restart the frontend and admin apps in dev
		@make stop-frontend-dev && make run-frontend-dev
		@echo "Frontend app restarted"

Internal targets (like the webpack.PID in our example) don't need description, and therefore don't appear in the self-documentation. Next, add a help target in your makefile, doing some shell scripting voodoo:

.PHONY: help

help:   ## ## Display this help
        @printf "\nusage : make <commands> \n\nthe following commands are available : \n\n"
        @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
.PHONY: help
help: ## ## Display this help
@printf "\nusage : make <commands> \n\nthe following commands are available : \n\n"
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
install: ## Install npm dependencies for the api, admin, and frontend apps
@echo "Installing Node dependencies"
@npm install
install-dev: install ## Install dependencies and prepared development configuration
@./node_modules/.bin/selenium-standalone install
@cp -n ./config/development.js-dist ./config/development.js | true
run-frontend-dev: webpack.PID ## Run the frontend and admin apps in dev (using webpack-dev-server)
webpack.PID:
@./node_modules/.bin/babel-node ./node_modules/.bin/webpack-dev-server \
--content-base=build \
--devtool=cheap-module-inline-source-map \
--hot \
--inline \
--progress \
& echo "$$!" > webpack.PID
stop-frontend-dev: webpack.PID ## Stop the frontend and admin apps in dev
@kill `cat $<` && rm $<
@echo "Webpack server stopped"
restart-frontend: ## Restart the frontend and admin apps in dev
@make stop-frontend-dev && make run-frontend-dev
@echo "Frontend app restarted"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment