Gradle:publishの前に処理をはさみこみたい

2018年8月29日

Gradleでmaven-publishプラグインを使うと簡単にアーティファクトをMavenリポジトリに公開することができるのだが、ある時非常に困ったことがあった。それは、

jarファイルを生成した後に、そのjarの妥当性をチェックし、OKだったらpublishしたい。

ということである。こんなことをするのは、必ずしもコンパイラではチェックしきれないエラーが存在しうるからなのだが、詳細は面倒なので省略する。ともあれ、正常にコンパイルしてjarファイルを作成した後に、それをチェックしてOKであればpublishしたいのである。

普通のpublish

例えば、以下のように書くとする。

publishing {
  publications {
    target(MavenPublication) {
      ....
      from components.java      
    }
  }  
  repositories {
    ....
  }
}

publishタスクを起動すれば、普通はこうなる。

:generatePomFileForTargetPublication
:compileJava UP-TO-DATE
:processResources NO-SOURCE
:classes UP-TO-DATE
:jar UP-TO-DATE
<---- ここにいれたい
:publishTargetPublicationToMavenRepository
Upload http://10.8.92.1:8080/artifactory/....
....
....
:publish

この「:jar UP-TO-DATE」の後に処理をはさみこみたい。挟み込むタスクを仮にcheckJarという名前にする。

publishTargetPublicationToMavenRepositoryに依存を定義する

普通に考えれば、当然ながら、こうなる。

publishTargetPublicationToMavenRepository.dependsOn checkJar

しかし、ひどいことにこれはエラーなのである。

Could not get unknown property 'publishTargetPublicationToMavenRepository' for ...

以下でもダメだ。同じエラーになる。そんなタスクは存在しないのである。

tasks.publishTargetPublicationToMavenRepository.dependsOn checkJar

この事情はDepending on publish tasksにあるのだが、要するに、publishTargetPublicationToMavenRepositoryというタスクは実行時に「魔術的に」作成されるのだそうだ。

だから、dependsOnの時点ではタスクが存在していない。

しかし、それでいてtasksで確認すると、ちゃんと出てくるのだ。

Publishing tasks
----------------
generatePomFileForTargetPublication - Generates the Maven POM file for publication 'target'.
publish - Publishes all publications produced by this project.
publishTargetPublicationToMavenLocal - Publishes Maven publication 'target' to the local Maven repository.
publishTargetPublicationToMavenRepository - Publishes Maven publication 'target' to Maven repository 'maven'.
publishToMavenLocal - Publishes all Maven publications produced by this project to the local Maven cache.

本当にGradleにはイライラさせられる。原則というものが無いのだ。この行き当たりばったりの仕様は何とかならなかったのか?

publishに依存を定義する

ではpublishの方に依存を定義すればよいだろうか?

publish.dependsOn checkJar

すると、こうだ。

:generatePomFileForTargetPublication
:compileJava UP-TO-DATE
:processResources NO-SOURCE
:classes UP-TO-DATE
:jar UP-TO-DATE
:publishTargetPublicationToMavenRepository
Upload http://10.8.92.1:8080/artifactory/....
....
....
:checkJar <------------------- 終了した後に呼び出される
:publish

すべてが終了した後に呼び出されている。これでは全く意味が無い。

publishの依存関係を確認する

どこかで拾ってきたコードだが、以下を入れて、publishを実行する。

gradle.taskGraph.whenReady {taskGraph ->
    println "Found task graph: " + taskGraph
    println "Found " + taskGraph.allTasks.size() + " tasks."
    taskGraph.allTasks.forEach { task ->
        println task
        task.dependsOn.forEach { dep ->
            println "  - " + dep
        }
    }
}

するとタスク間の依存関係が表示される

task ':jar'
  - task 'jar' input files
task ':publishTargetPublicationToMavenRepository'
  - task 'publishTargetPublicationToMavenRepository' input files
task ':checkJar '
  - task ':jar'
  - task 'checkJar ' input files
task ':publish'
  - [checkJar ]
  - task 'publish' input files
  - publishTargetPublicationToMavenRepository

publishタスクの依存として、checkJar、publishTargetPublicationToMavenRepositoryが存在しているようなのだが、依存タスクの実行順序を変えるにはどうしたら良いのか?

いったん、publishTargetPublicationToMavenRepositoryの依存を削除し、入れ直せば良いのだろうか?

依存タスクを削除する方法は無い

しかし、これも検索してみると、元からある依存タスクを削除する方法は無いようだ。

mustRunAfter

最終的にぶち当たったのが、mustRunAfterである。この件は、以下に記述があった。

とりあえず、以下のようにしてみた。

publish.dependsOn checkJar 
publish.mustRunAfter checkJar 

どうしてそうなるのかわからないのだが、結果は所望のものになった。

:generatePomFileForTargetPublication
:compileJava UP-TO-DATE
:processResources NO-SOURCE
:classes UP-TO-DATE
:jar UP-TO-DATE
:checkJar
:publishTargetPublicationToMavenRepository
Upload http://10.8.92.1:8080/artifactory/....
....
....
:publish

結論

結局のところこういうことだ。

  • publishTargetPublicationToMavenRepositoryタスクは存在していないので、依存タスクの追加は不可
  • 既にある依存タスクを削除する方法は無い。
  • publishにやらせたい依存タスクを追加しても、そのままでは実行順序は不定。
  • mustRunAfterで実行順序を変えられるらしいが、今回の場合、どうしてそうなるのか不明。

本当にGradleは厄介だ。行き当たりばったりの上に、理由が良くわからない。わけがわからないのだ。今回は使うのをやめようかと思った位である。