私が雰囲気でGradleを使ってる感がよくわかる。
- Gradle 6.0.1 と 5.6.4
前置き
とあるタスクを実行するときに clean
してコンパイルしてから実行したくて、こんなこと書いてました。
myTask.dependsOn(clean, compileJava, processResources)
opengl-8080さんのQiitaに書いてあるし、たぶんGradle徹底入門にもあったかとおもうけど、dependsOn
の引数は実行順を制御しません。
Gradleで実行順を制御したかったら mustRunAfter
か shouldRunAfter
を併用するものです。
でもこれで今まで特に問題になったことなかったんですよね……。
起こした問題と原因
なんでこんなことを今更書いてるのかと言うと、以下のように書き直したら一部の環境で動かなくなりました。正確に言うとMacのターミナル上でコマンド叩いた時だけ動きました。
classes.dependsOn(clean) myTask.dependsOn(classes)
ここでGradleのThe Java Pluginの図を引用。
compileJava
と processResources
に classes
が依存してるからこれで良いかーって。
まあダメなんですけどね。clean
がいつ実行されるか運に任せ……実際は何かで決まるんだろけど詳細は追っていません。ログ眺めてると個々のタスクの依存関係みながら何度も並び替えしてるっぽくて、結果をみると環境依存でした。
でこれが、CIでコンパイルが落ちる。 ./gradlew build
を手元で叩いたら問題なくコンパイルできる。
そしてIntellJのビルド( ./gradlew classes testClasses
相当が実行される )は動かない……クラスあるのにクラスがないって怒られる。よくわからないから放置して寝た(せめて戻せ)。
で翌朝ログを眺めてたら「なんか clean
動くタイミングがおかしいな?」と気づきました。
やっぱ深夜の脳はなんかダメだし、寝起きの脳はとても役立ちますね。
CircleCIでは compileJava -> clean -> processResources -> classes -...-> compileTestJava
の順で動いてました。Appveyorはまた別の順番。
IntelliJのビルドは compileJava -> processResources -> clean -> classes -...-> compileTestJava
となっており、そりゃクラス(*.java
ファイル)あってもクラス(*.class
)がコンパイル後に消されてるんだからビルドできないよね。
なお手元の ./gradlew build
は clean
が一番最初に動いてました。そりゃ動く。
潜在してた問題
ていうか、元のもこうだったわけで。
clean
がいつ動くかは誰にもわからない。
よく動いてたな?
結局どうしたか
[compileJava, processResources]*.mustRunAfter(clean) myTask.dependsOn(clean, classes)
clean
が途中で動いて欲しいことってないし。
classes
から mustRunAfter
しても意味ないし、並べるしかない気がしたからこんな感じ。
compileJava.dependsOn(clean)
とかにしないのは、いつも clean
したいかってとそうでもないから避けました。
あと、GradleのIssueに gradle clean build
can run clean after tasks that produce output by depending on other tasks #2488 とかありました。問題になるのはmulti-projectの時だけなのかな。