Fail a CI step on any error
Make a CI shell step fail on an error, an unset variable or a failed pipe stage with set -euo pipefail. GitHub Actions only adds pipefail with shell: bash.
A CI step passes while a command inside it failed, because the failure was in the middle of a pipe.
bash -c 'false | cat; echo "default: kept going, status $?"'
bash -c 'set -e; false | cat; echo "-e alone: kept going, status $?"'
bash -c 'set -euo pipefail; false | cat; echo "never printed"'; echo "pipefail: step failed with $?"
bash -c 'set -u; echo "value: $UNDEFINED_VAR"'; echo "set -u: status $?"default: kept going, status 0
-e alone: kept going, status 0
pipefail: step failed with 1
bash: line 1: UNDEFINED_VAR: unbound variable
set -u: status 127By default the status of a pipeline is that of its last command, so false | cat succeeds. set -o pipefail makes it the status of the last command that failed, -e exits on a non-zero status and -u treats an unset variable as an error. All three are in the set builtin documentation. The third line stops at the pipe, and the last line shows the unset variable error.
A run: step in GitHub Actions without a shell: key uses bash -e, with no pipefail, while shell: bash uses bash --noprofile --norc -eo pipefail, according to the workflow syntax reference. The flags also have exceptions inside if tests and && lists. They catch errors, but do not replace checking a command that is allowed to fail.