tl;dr
これの続きです。
やっぱり、WordPress プラグインバージョン
当初は...
WordPress のプラグインバージョンをパースする処理を以下のように書いていました。
echo ${plugin_name} | grep -o -E "(\.[0-9]+|\.[0-9]+\.){1}[0-9]+(\.[0-9]+)?" | sed 's/.//'
これは、プラグインのバージョン番号が以下のような状態を想定した処理でした。
- plugin-name.1.2.3.zip
- plugin-name.12345678.zip
- plugin-name-7.1.2.3.zip
実際に実行すると、以下のように、意図した通りにバージョン番号 (1.2.3
とか 12345678
等) が取得出来ます。
$ echo plugin-name.1.2.3.zip | grep -o -E "(\.[0-9]+|\.[0-9]+\.){1}[0-9]+(\.[0-9]+)?" | sed 's/.//' 1.2.3 $ echo plugin-name.12345678.zip | grep -o -E "(\.[0-9]+|\.[0-9]+\.){1}[0-9]+(\.[0-9]+)?" | sed 's/.//' 12345678 $ echo plugin-name-7.1.2.3.zip | grep -o -E "(\.[0-9]+|\.[0-9]+\.){1}[0-9]+(\.[0-9]+)?" | sed 's/.//' 1.2.3
とーころが...
新手が登場しました。
- plugin-name.1.2.3.4.zip
これを従来のパース処理で処理しようとすると...
$ echo plugin-name.1.2.3.4.zip | grep -o -E "(\.[0-9]+|\.[0-9]+\.){1}[0-9]+(\.[0-9]+)?" | sed 's/.//' 1.2.3
冒頭の 3 桁のみがパースされる状態となりました...
改修、そして shellspec
正規表現の試行錯誤
正規表現検定 8 級なので、とりあえず試行錯誤。試行錯誤の結果、以下のように書くことで、なんとか意図したような結果を得ることが出来ました。
$ echo ${plugin_name} | grep -o -E "(\.[0-9]+|\.[0-9]+\.){1}[0-9]+(\.[0-9]+|\.[0-9]+\.[0-9]+)?" | sed 's/.//'
先程の 4 桁バージョン番号を処理してみます。
$ echo plugin-name.1.2.3.4.zip | grep -o -E "(\.[0-9]+|\.[0-9]+\.){1}[0-9]+(\.[0-9]+|\.[0-9]+\.[0-9]+)?" | sed 's/.//' 1.2.3.4 $ echo plugin-name-100.1.2.3.4.zip | grep -o -E "(\.[0-9]+|\.[0-9]+\.){1}[0-9]+(\.[0-9]+|\.[0-9]+\.[0-9]+)?" | sed 's/.//' 1.2.3.4
意図した通りに解析されていることを確認しました。
そして shellspec (1)
今後も同じような変異種が現れる可能性もあり、試行錯誤している間にデグレしてしまう可能性もあったので、この処理を関数化してユニットテストを書くようにしました。
そこで、テストフレームワークとして shellspec を選びました。
選んだ理由としては、特に強いこだわりがあったわけではありませんが、Rspec っぽく書けるという触れ込みだったので、お試し程度に使ってみようと思った次第です。
インストールの手順等は割愛しますが、今回は macOS に homebrew でインストールして利用しました。
$ sw_vers ProductName: Mac OS X ProductVersion: 10.15.7 BuildVersion: 19H114 $ brew tap shellspec/shellspec $ brew install shellspec
以下のように実行して、shellspec を初期化します。
$ mkdir project $ cd project $ shellspec --init
project ディレクトリ直下に .shellspec
ファイルと spec
ディレクトリ、spec
ディレクトリ以下に spec_helper.sh
ファイルが作成されます。
そして shellspec (2)
以下のようにテスト対象の関数を用意しました。
$ cd project $ vim lib/version-number-parse function version_number_parse { echo $1 | grep -o -E "(\.[0-9]+|\.[0-9]+\.){1}[0-9]+(\.[0-9]+|\.[0-9]+\.[0-9]+)?" | sed 's/.//' }
そして、テストは以下のように用意しました。
$ vim spec/version-number-parse_spec.sh Describe "Check for version-number-parse script" Include lib/version-number-parse Describe "Call version_number_parse" It "plugin-name.3.1.21.11.zip" When call version_number_parse plugin-name.3.1.21.11.zip The output should eq "3.1.21.11" End It "plugin-name.3.10.2.zip" When call version_number_parse plugin-name.3.10.2.zip The output should eq "3.10.2" End It "plugin-name.3.9.2.zip" When call version_number_parse plugin-name.3.9.2.zip The output should eq "3.9.2" End It "plugin-name.1.2.zip" When call version_number_parse plugin-name.1.2.zip The output should eq "1.2" End It "plugin-name-7.1.2.3.zip" When call version_number_parse plugin-name-7.1.2.3.zip The output should eq "1.2.3" End It "plugin-name.12345678.zip" When call version_number_parse plugin-name.12345678.zip The output should eq "12345678" End End End
後は、以下のように実行します。
$ shellspec --format document -s bash
以下のように出力されました。
$ cd project $ shellspec --format document -s bash Running: /bin/bash [bash 3.2.57(1)-release] Check for version-number-parse script Call version_number_parse plugin-name.3.1.21.11.zip plugin-name.3.10.2.zip plugin-name.3.9.2.zip plugin-name.1.2.zip plugin-name-7.1.2.3.zip plugin-name.12345678.zip Finished in 0.37 seconds (user 0.31 seconds, sys 0.07 seconds) 6 examples, 0 failures
Fail させてみると、以下のように出力されました。
$ shellspec --format document -s bash Running: /bin/bash [bash 3.2.57(1)-release] Check for version-number-parse script Call version_number_parse plugin-name.3.1.21.11.zip plugin-name.3.10.2.zip plugin-name.3.9.2.zip (FAILED - 1) plugin-name.1.2.zip plugin-name-7.1.2.3.zip plugin-name.12345678.zip Examples: 1) Check for version-number-parse script Call version_number_parse plugin-name.3.9.2.zip When call version_number_parse plugin-name.3.9.2.zip 1.1) The output should eq 3.9.1 expected: "3.9.1" got: "3.9.2" # spec/ver-check_spec.sh:16 Finished in 0.33 seconds (user 0.31 seconds, sys 0.07 seconds) 6 examples, 1 failure Failure examples / Errors: (Listed here affect your suite's status) shellspec spec/ver-check_spec.sh:14 # 1) Check for ver-check script Call get_current_version plugin-name.3.9.2.zip FAILED
いい感じ!shellspec
テスト結果の出力
以下のように --format
オプションで指定可能です。
# --format を指定しない場合 $ shellspec -s bash Running: /bin/bash [bash 3.2.57(1)-release] ...... Finished in 0.32 seconds (user 0.31 seconds, sys 0.07 seconds) 6 examples, 0 failures # junit フォーマットで取得 $ shellspec --format junit -s bash <?xml version="1.0" encoding="UTF-8"?> <testsuites tests="6" time="0.32" errors="0" failures="0" name="ver-check"> <testsuite id="0" tests="6" errors="0" failures="0" skipped="0" name="spec/version-number-parse_spec.sh" hostname="oreno-mac" timestamp="2021-01-05T15:22:57"> <testcase time="0" classname="spec/version-number-parse_spec.sh" name="Check for version-number-parse script Call version_number_parse plugin-name.3.1.21.11.zip"></testcase> <testcase time="0" classname="spec/version-number-parse_spec.sh" name="Check for version-number-parse script Call version_number_parse plugin-name.3.10.2.zip"></testcase> <testcase time="0" classname="spec/version-number-parse_spec.sh" name="Check for version-number-parse script Call version_number_parse plugin-name.3.9.2.zip"></testcase> <testcase time="0" classname="spec/version-number-parse_spec.sh" name="Check for version-number-parse script Call version_number_parse plugin-name.1.2.zip"></testcase> <testcase time="0" classname="spec/version-number-parse_spec.sh" name="Check for version-number-parse script Call version_number_parse plugin-name-7.1.2.3.zip"></testcase> <testcase time="0" classname="spec/version-number-parse_spec.sh" name="Check for version-number-parse script Call version_number_parse plugin-name.12345678.zip"></testcase> </testsuite> </testsuites>
テストを実行するシェルを指定する
デフォルトでは、/bin/sh
が使われるとのことですが、--shell
又は -s
オプションでシェルを指定することが出来ます。
$ shellspec -s bash
上記の例では、その名の通り、bash を利用することになります。
CircleCI のオフィシャル Docker イメージである、cimg/python:3.6 上で shellspec を利用しようとした際に、このイメージのデフォルトシェルは /bin/sh
で、その実体は dash となっており、function
がサポートしていないことでエラーとなりテストが実行されずに焦りました。
circleci@0c366a26ccfd:~/project$ ls -l /bin/sh lrwxrwxrwx 1 root root 4 Apr 3 2020 /bin/sh -> dash circleci@0c366a26ccfd:/project$ cat lib/version-number-parse function version_number_parse { echo $1 | grep -o -E "(\.[0-9]+|\.[0-9]+\.){1}[0-9]+(\.[0-9]+|\.[0-9]+\.[0-9]+)?" | sed 's/.//' } # dash だと function がサポートされていない circleci@0c366a26ccfd:/project$ shellspec /bin/sh: 1: lib/version-number-parse: function: not found Unexpected output to stderr occurred at line 1-2 in 'spec/version-number-parse_spec.sh' Running: /bin/sh [sh] Finished in 0.16 seconds (user 0.04 seconds, sys 0.01 seconds) 0 examples, 0 failures, aborted by an unexpected error Aborted with status code [executor: 127] [reporter: 1] [error handler: 102] Fatal error occurred, terminated with exit status 102. circleci@0c366a26ccfd:/project$ shellspec --shell bash Running: /bin/bash [bash 4.4.20(1)-release] ...... Finished in 0.27 seconds (user 0.23 seconds, sys 0.06 seconds) 6 examples, 0 failures
上記のように --shell bash
を追加して実行することで、テストが正常に実行されました。
以上
WordPress のプラグインバージョンの付け方に翻弄されてしまいましたが、シェルスクリプトでもテストを書くと良いということと、shellspec に出会うことが出来て良かったというお話でした。