Here is the situation: a step in GitHub actions runs a process, in this case a Helm command, and I need to redirect the output.
The obvious way to do it is to redirect into a file
helm ... > helm.log # show logs after done cat helm.log
However, what happens is that GitHub Actions immediately skips this step. It doesn't wait for the redirected command to end! I also lose the ability to watch logs, especially if --wait
is passed to Helm.
Introducing tee
tee
is a command that redirects output and duplicates it. This way the output is both standard output and, in this case, a file.
Here is the new command:
helm ... 2>&1 | tee helm.log
Sweet, now GitHub Actions will wait for the process as we expected. We also get live logs.
However, if helm
returns with a nonzero value, the step is a success. Which we clearly don't want.
Use pipefail
to catch pipeline errors
Since |
is a pipe, it kinda swallows errors. We need to propagate them "out".
# ensure that a step failing will make the pipeline appear to fail set -o pipefail # tee to split into file helm ... 2>&1 | tee helm.log # do something with helm.log # restore the previous state set +o pipefail # Now fail if helm command returned a nonzero exit code if [ $? -ne 0 ]; then echo "Helm deployment failed" exit 1 fi
VoilĂ ! We have a functional step that will properly redirect output and fail.