はじめに
GitHub Actionのワークフローの改修をしたのですが、全てのテストを通るようになってしまっていました。ちなみに、幸いすぐ気付いたので影響はなかったですが、今後気をつけるように残しておきます。
問題のワークフロー
ワークフローは以下のようになってます。
-
make test
でPyhonのテストを動かす - PRにカバレッジのコメントをつける (参考 :MishaKav/pytest-coverage-comment
- name: Run tests
run: make test
- name: Create coverage report
uses: MishaKav/pytest-coverage-comment@main
with:
pytest-coverage-path: ./pytest-coverage.txt
junitxml-path: ./pytest.xml
badge-title: Coverage
Makefileでは、pytestを動かして、カバレッジレポートを作成するのに必要なため、pipeを使用して、pytest-coverage.txt
を作成しております。
.PHONY: test
test:
pytest --cov=./ --junitxml=pytest.xml --cov-config=.coveragerc --cov-report=term-missing | tee pytest-coverage.txt
Pipeの罠
上記のmakefileでpipeを使ってしまっているので、前半のpytest --cov=./ --junitxml=pytest.xml --cov-config=.coveragerc --cov-report=term-missing
の部分が落ちても、pipeで渡しているので、正常終了してしまいます。
試しに、以下のコードをローカルで実行してみます。
$ exit 1 | exit 0
$ echo $?
0
$?
が 0 となっているので、正常終了していることがわかります。
$ set -o pipefail
$ exit 1 | exit 0
$ echo $?
1
$?
が1となっているので、異常終了します。
また、オプション-e
をつけることで、失敗した時点で異常終了させることが可能なので、set -eo pipefail
のようにします。
makefileの罠
set -eo pipefail
をつけることで、解決できたと思ったのですが、これだけだとGitHub Actionでのtestは期待通りに動作しませんでした。
例として、以下のmakefileを作ってみます。
SHELL=/bin/bash
.PHONY: foo
foo:
set -eo pipefail
exit 1 | exit 0
これを実行してみます。
$ make foo
$ echo $?
0
set -eo pipefail
をしたのにも関わらず、makeコマンドだと正常終了してしまうことがわかります。
この問題の解決策は2通りあるのですが、まず1つ目は以下のように一行に書いてみると改善されます。
SHELL=/bin/bash
.PHONY: foo
foo:
set -eo pipefail; exit 1 | exit 0
$ make foo
$ echo $?
2
2つ目は.SHELLFLAGS
を設定することで解決できます。
SHELL=/bin/bash
.SHELLFLAGS := -eu -o pipefail -c
.PHONY: foo
foo:
exit 1 | exit 0
.SHELLFLAGS := -eu -o pipefail -c
のように設定しています。
- -e : bashで実行したコマンドが失敗した場合に終了させる
- -o pipefail : パイプの最初や途中で処理が失敗した場合、全体を失敗させる
- -u : bashで変数未定義の場合にエラーで止める
- -c : オプションを設定する時には必須のオプション(
bash -c "echo 'Hello'"
として動かす)
これを実行すると、無事エラーとなってくれました。
$ make foo
exit 1 | exit 0
make: *** [makefile:6: foo] Error 1