I've got the following Makefile:
#runs the working directory unit tests
test:
@NODE_ENV=test; \
mocha --ignore-leaks $(shell find ./test -name \*test.js);
#deploys working directory
deploy:
@make test; \
make deploy-git; \
make deploy-servers;
#deploys working to git deployment branch
deploy-git:
@status=$$(git status --porcelain); \
if test "x$${status}" = x; then \
git branch -f deployment; \
git push origin deployment; \
echo "Done deploying to git deployment branch."; \
else \
git status; \
echo "Error: cannot deploy. Working directory is dirty."; \
fi
deploy-servers:
# for each server
# @DEPLOY_SERVER_IP = "127.0.0.1"; \
# make deploy-server
#deploy-server:
# connect to this server with ssh
# check if app is already running
# stop the app on the server if already running
# set working directory to app folder
# update deployment git branch
# use git to move head to deployment branch
# start app again
Note that deploy-servers
and deploy-server
are just dummies for now. This is what the deploy
command should do:
make test
), exit on failuremake deploy-git
), exit on failuremake deploy-servers
)You can see this in the Makefile as:
deploy:
@make test; \
make deploy-git; \
make deploy-servers;
The issue is that I am not sure how to prevent make deploy-git
from executing when make test
fails, and how to prevent make deploy-servers
from executing when the tests fail or when make deploy-git
fails.
Is there a clear way to do this, or should I resort to using shell files or write these tools in a normal programming language?
The exit status of a shell command list is the exit status of the last command in the list. Simply turn your command list into separate single simple commands. By default, make
stops when a command returns nonzero. So you get what you want with
deploy:
@make test
make deploy-git
make deploy-servers
Should you ever want to ignore the exit status of a simple command, you can prefix it with a dash:
target:
cmd1
-cmd2 # It is okay if this fails
cmd3
Your make
manual has all the details.
Others have given answers which are based on splitting the "recipe" into individual commands.
In situations where that is not viable, what you can do is set -e
in the shell script to make it terminate if a command fails:
target:
set -e ; \
command1 ; \
command2 ; command3 ; \
... commandN
This is the same set -e
that you would put near the top of a shell script to get it to bail when some command terminates unsuccessfully.
Suppose that we are not interested in the termination statuses of command2
and command3
. Suppose it is okay if these indicate failure, or do not reliably use termination status. Then, instead of set -e
we can code an explicit exit test:
target:
command1 ; \
command2 || exit 1 ; \
command3 ; \
true # exit 0 will do here also.
Since command3
can indicate failure, and we don't want it to fail our build, we add a successful dummy command.
make
should already do this; it executes complex commands with sh -e
, which (as long as it's not in a loop in a POSIX compatible shell) will abort execution if a command exits nonzero, and aborts the entire Makefile
on failure of a command unless you specifically tell it not to. If you're feeling paranoid, you can use &&
in place of ;
in your commands.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With