Shell Scriptの開発に使えそうなCI構成についてまとめました
次のツールを使います。
- コンポーネントテスト(ユニットテスト):https://github.com/sstephenson/bats
- 静的解析:https://github.com/koalaman/shellcheck
- CircleCI
CI設定込みのサンプルコードはこちら -> https://github.com/NA070/sh-ci-sample
bats
batsはshellスクリプトやコマンドラインツール用のテスティングフレームワークです。
インストール
https://github.com/bats-core/bats-core#installation を参照してください。
使い方
@test
テストケースは@test〜で記述を開始します。
#!/usr/bin/env bats
@test "addition using bc" {
result="$(echo 2+2 | bc)"
[ "$result" -eq 4 ]
}
ディレクトリまたはファイル名指定で実行します。
bats test/ # or bats test/sample.bats
✓ addition using bc
1 tests, 0 failures
run
Many Bats tests need to run a command and then make assertions about its exit status and output. Bats includes a
run
helper that invokes its arguments as a command, saves the exit status and output into special global variables, and then returns with a0
status code so you can continue to make assertions in your test case.
多くのBatsテストでは、コマンドを実行して、その終了ステータスと出力についてアサーションを行う必要があります。 Batsには、その引数をコマンドとして呼び出し、終了状態と出力を特別なグローバル変数に保存した後、0のステータスコードを返す実行ヘルパーが含まれているので、テストケースでアサーションを続けることができます。 ~ google翻訳 ~
runでコマンドを実行すると下記の変数に値がセットされます。
- $status : 終了ステータスコード
- $output : 標準出力・標準エラー出力をつないだもの
- $lines:出力を配列で格納。参照が容易
これらの変数を検証に利用できます。
#!/usr/bin/env bats
@test "invoking ls with a nonexistent file prints an error" {
run ls hoge
[ "$status" -eq 1 ]
[ "$output" = "ls: hoge: No such file or directory" ]
}
@test "invoking mkdir without arguments prints usage" {
run mkdir
[ "$status" -eq 64 ]
[ "${lines[0]}" = "usage: mkdir [-pv] [-m mode] directory ..." ]
}
load
環境変数やテストフィクスチャをbatsのテストコード以外のファイルから読み込みます。
SUCCESS_CODE=0
#!/usr/bin/env bats
load test_helper
@test "assert with global variable" {
run ls -la
[ "$status" -eq "$SUCCESS_CODE" ]
}
setup / teardown
各ケースの前後に行う共通処理を定義します。
#!/usr/bin/env bats
setup(){
mkdir test/hoge
touch test/hoge/fuga.txt
}
teardown(){
rm -rf test/hoge
}
shellcheck
shellcheckはShellスクリプト用のLintツールです。
インストール
https://github.com/koalaman/shellcheck#installing を参照してください。
実行方法
ls -ltra
shellcheck lib/sample.sh
In lib/sample.sh line 1:
ls -ltra
^------^ SC2148: Tips depend on target shell and yours is unknown. Add a shebang.
For more information:
https://www.shellcheck.net/wiki/SC2148 -- Tips depend on target shell and y...
悪いコード例
下記の内容に該当するとチェックNGになります。
https://github.com/koalaman/shellcheck#gallery-of-bad-code
おまけ
Editorで自動チェックするようにしておくとFBループが早くなるので効率的になると思います。
- Vim, through ALE, Neomake, or Syntastic
- Emacs, through Flycheck or Flymake
- Sublime, through SublimeLinter
- Atom, through Linter
- VSCode, through vscode-shellcheck
CI環境構築
circle ciで実行します。
それぞれdocker imageが用意されているので簡単です。
version: 2
jobs:
component-testing:
docker:
- image: bats/bats:latest
steps:
- checkout
- run: bats ./test/
lint:
docker:
- image: koalaman/shellcheck-alpine
# Dockerfileのentrypoint実行によって
# circleci上ではうまくビルドできないので空文字で上書きます
entrypoint: ''
steps:
- checkout
- run: shellcheck ./lib/*
workflows:
version: 2
component-test-and-lint:
jobs:
- component-testing
- lint
これでpushするたびに自動実行されるようになります。