GradleスクリプトからShellを実行
ビルド終了時に通知を飛ばしたい。
apkをビルドして、deploygateに挙げ終わったら、Slackなどに自動で通知をしたいと思いました。
Slackにテスト投稿がかさむので、PushBulletで試しに検証しました。
execute
//build.gradle // 指定したデバイスに通知が送られます。 task push1(type:Exec) { "curl -u [token]: https://api.pushbullet.com/v2/pushes -d device_iden=[device_iden] -d type=note -d title=title -d body=body".execute() }
通知は送れたのですが、build.gradleの同期の度に実行されて非常によろしくないです。
なので、次のように書きます。
executable
//build.gradle task push2(type: Exec) { executable "sh" args "-c", "curl -u [token]: https://api.pushbullet.com/v2/pushes -d device_iden=[device_iden] -d type=note -d title=title -d body=body" }
//build.gradle task push3 << { exec { executable "sh" args "-c", "curl -u [token]: https://api.pushbullet.com/v2/pushes -d device_iden=[device_iden] -d type=note -d title=title -d body=body" } }
executable
は実行するコマンドを入力します。
python
なども実行することも出来ます。
上の2つはほぼ同じ意味ですが、push2
はexec
の中身が、タスクの実行時ではなく設定時に適用されるという違いがあります。push1
が、同期の度に実行されてしまったのはそのためです。
push1
でも次のように書くことで、同期の度に実行されることを防げます。
//build.gradle task push1 << { "curl -u [token]: https://api.pushbullet.com/v2/pushes -d device_iden=[device_iden] -d type=note -d title=title -d body=body".execute() } //type:Execを入れると、設定時に実行可能な引数がないということになり、エラーになります。
また、次のような書き方も出来ます。
commandLine
//build.gradle task push4 (type: Exec) { commandLine 'curl', '-u', '[token]:', 'https://api.pushbullet.com/v2/pushes', '-d', 'device_iden=[device_iden]', '-d', 'type=note', '-d', 'title=title', '-d', 'body=body' }
push4
では、コマンドラインで入力する場合と同じように、引数も同様の扱いとして書きます。
たとえ一行でもこうなってくると見にくいですね。スクリプトにしましょう。
script作成
#pushBullet.sh #!/bin/sh curl -u [token]: https://api.pushbullet.com/v2/pushes -d device_iden=[device_iden] -d type=note -d title=title -d body=body
注意として、実行権限を与えないと動かない場合があります。
$ chmod 755 pushBullet.sh
完成
最終的に、こうなりました。
//build.gradle task push5(type: Exec, dependsOn: 'uploadDeployGateRelease') { workingDir '../' executable "./pushBullet.sh" args System.properties["pushBullet_token"], System.properties["pushBullet_device_iden"], "title", "body" }
#pushBullet.sh #!/bin/sh curl -u $1: https://api.pushbullet.com/v2/pushes -d device_iden=$2 -d type=note -d title=$3 -d body=$4
注意として、タスクが記述されているbuild.gradle
をカレントディレクトリとするので、スクリプトがある場所を指定してあげなければなりません。
また、tokenなどのリポジトリに含めたくない情報は、~/.gradle/gradle.properties
に記入しましょう。
次のようにタスクを実行すると、deploygateのアップロードが完了するとpush通知が届きます。
$ ./gradlew clean assembleRelease uploadDeployGateRelease push5
dependsOn
で依存関係を示したので、次のように入力しても同じです。
$ ./gradlew clean assembleRelease push5
実行するタスクを変更したくない場合は、次のようにタスクの依存関係を定義することも出来ます。
//build.gradle ... deploygate { ... } ... task push5 (...) { ... } ... uploadDeployGateRelease.finalizedBy push5
上記のように記述すると
uploadDeployGateRelease
タスクの終了時にpush5
タスクが実行されます。
便利ですが、uploadDeployGateRelease
の成功・失敗に関わらずpush5
タスクが実行されるので、使う場面を考える必要があります。
ひとまずこれで、暴投をせずに連携できるようになりました。
参考
Run shell command in gradle but NOT inside a task / stackoverflow
how to execute shell command? source or dot doesn't work with exec / Gradle Forums