[gradle 3.5] タスクからタスク呼び出し(※executeを使用)


# はじめに

　本記事ではAbstractTask.execute()を利用してスクリプト内でタスク実行をするコードを掲載しています。
　この方法は、gradleの正式APIではないと思われるため、予めご了承ください。
　詳しくは後述の「注意事項：executeの利用について」を参照。　

　また、gradleは色んなことができるので、この方法以外にもやり方はあると思います。
　あくまで数ある中の一例としてご覧ください。

# こんなときに使う

- depensOnではなく、task内のクロージャからtaskを制御したい

- 複数のtaskを制御したい（エラー処理や、スキップ処理を自由に組み替えたい）

　筆者の場合、gradleを使ってCI的なビルドスクリプトを作成したかった。
　例えば、ソースのビルドに失敗したらエラーだけど、静的解析ツールの失敗は継続する、みたいなイメージ。

# タスクからタスクを呼ぶスクリプト

```groovy:依存先を含めてタスクを実行する関数（クロージャ）

// タスク呼び出し関数を定義
Closure callTask
callTask = {Task t ->
    t.taskDependencies.getDependencies().each { callTask it }
    if (!t.didWork) {
        println ":$t.name"
        t.execute()
    }
}

// 関数を利用する
task myTask {
    callTask タスク
}
```

```bat:コマンド実行すると、依存先を含んだ「タスク」が実行される
gradlew myTask
```

## 動作環境
> Version:      Gradle 3.5
> Build time:   2017-04-10 13:37:25 UTC
> Groovy:       2.4.10
> Ant:          Apache Ant(TM) version 1.9.6 compiled on June 29 2015
> JVM:          1.8.0_111 (Oracle Corporation 25.111-b14)
> OS:           Windows 10 10.0 x86


## 注意事項：executeの利用について

　execute()はorg.gradle.api.internal.AbstractTaskクラスに実装されているprotectedメソッドです。
　internalパッケージのprotectedメソッドということなので、推奨されている使い方ではないと思われます。
　ググってみると、非公式だし「使うべきではないよ」と語っている記事もいくつか見つけました。

　そのため、当初はexecute()を使わずにTaskの実行をしようと思っていたのですが、調査不足のためか他に方法が見つからなかったので割り切りました。
　（よりよい方法が見つかった場合、記載内容を更新したいと思います。）

　何かの実験や自作アプリなんかで使用する分には特に問題ないと思いますが、
　公式APIという位置づけでない以上、やはり都合が悪い場合があり得ます。
　ご利用の際は、以上の点に注意してください。

## サンプルコード全量
```groovy:build.gradle
//--------------------------------------
// 適当なタスクを定義しておく
//--------------------------------------

// タスク１：依存先なし
task myTask1 {
    doLast {
        println 'task1 called.'
    }
}

// タスク２：依存先 - タスク１
task myTask2(dependsOn: 'myTask1') {
    doLast {
        println 'task2 called.'
    }
}

// タスク３：依存先 - タスク２
task myTask3(dependsOn: 'myTask2') {
    doLast {
        println 'task3 called.'
    }
}

// タスク４：依存先 - タスク３、タスク２
task myTask4(dependsOn: ['myTask3', 'myTask2']) {
    doLast {
        println 'task4 called.'
    }
}

//--------------------------------------
// 本題：タスクを再帰呼び出しする関数
//--------------------------------------
Closure callTask
callTask = {Task t ->
    t.taskDependencies.getDependencies().each { callTask it }
    if (!t.didWork) {
        println ":$t.name"
        t.execute()
    }
}

//--------------------------------------
// コマンドから呼び出すタスク
//--------------------------------------
task myTask {
    doLast {
        println 'sequential execution of tasks.'
        callTask myTask4
    }
}
```

## 実行結果

### myTask4をコマンドラインから呼び出した場合
> \> gradlew myTask4
> :myTask1
> task1 called.
> :myTask2
> task2 called.
> :myTask3
> task3 called.
> :myTask4
> task4 called.
> 
> BUILD SUCCESSFUL
> 
> Total time: 1.751 secs

### myTaskをコマンドラインから呼び出した場合
> \> gradlew myTask
> :myTask
> sequential execution of tasks.
> :myTask1
> task1 called.
> :myTask2
> task2 called.
> :myTask3
> task3 called.
> :myTask4
> task4 called.
> 
> BUILD SUCCESSFUL
> 
> Total time: 1.76 secs

# おわりに

　筆者はgradleもgroovyもあまり経験がないです。
　変なところがあれば是非ご指摘ください。

# 参考文献

　[Gradle 日本語ドキュメント](http://gradle.monochromeroad.com/docs/)　
　版数が古いようですが、ここから日本語のユーザーガイドが閲覧できます。

　[Gradle API 3.5](https://docs.gradle.org/current/javadoc/)
　javadocは主に3.5を参考にしました。