タスク間の依存関係を出力してくれる Gradle プラグインはあるようなのですが、木じゃなくてグラフ(DAG)で見たかったり、プラグイン使わなくても済むならそれでもいいな……みたいな気分があって自前で書いてみました。
Gradle 8.9 で確認しました。
(他所で書いていたものを引っ越してきました。元の公開日は 2024-07-28 です。)
手順
(1) build.gradle に以下を追記
def generateDotSrc(tasks, idMap, edges) {
def nodePart = ""
tasks.each { task ->
def id = idMap[task]
def style = ""
if (task.getActions().size == 0) {
style = "dashed"
}
def label = task.getName()
// def label = "${task.getProject().getName()}\\n${task.getName()}"
nodePart += """ ${id} [ label = "${label}"; style = "${style}"; ];""" + "\n"
}
def edgePart = ""
edges.each { taskFrom, taskTo ->
def idFrom = idMap[taskFrom]
def idTo = idMap[taskTo]
edgePart += " ${idFrom} -> ${idTo};" + "\n"
}
"""
digraph {
graph [
rankdir = LR; // 左 → 右の向きに配置
];
node [
fontname = "monospace";
];
${nodePart}
${edgePart}
}
"""
}
gradle.taskGraph.whenReady { taskExecutionGraph ->
def tasks = taskExecutionGraph.getAllTasks()
// .findAll { task -> task.getProject().getName() == "..." } // 必要に応じて
def edges = []
tasks.each { taskFrom ->
taskExecutionGraph.getDependencies(taskFrom).each { taskTo ->
edges << [taskFrom, taskTo]
}
}
def idMap = [:] // task => node id
tasks.eachWithIndex { task, i ->
idMap[task] = "n${i}"
}
def dotSrc = generateDotSrc(tasks, idMap, edges)
// println dotSrc
file("task_graph.dot").text = dotSrc
}
(2) 実行して Graphviz 用のコードを出力
gradle {タスク名} --dry-run
# 例
gradle build --dry-run
# → task_graph.dot に出力される
- 実際にタスクを実行する必要はなくて図が欲しいだけなので
--dry-run
を付けて実行する - タスクが実行されてもよいなら
--dry-run
なしでもいい
(3) Graphviz で画像を生成
dot -Tsvg task_graph.dot > task_graph.svg
こういう図ができあがります。枠が破線になっているのはアクションを持たない集約用のタスク。
依存先が左に来るようにしたもの。Gradle のドキュメントで見かけるのはこっちのスタイルですね。
メモ
gradle.taskGraph.whenReady { taskExecutionGraph ->
taskExecutionGraph.getAllTasks()
}
でタスクの一覧が取得できるのと、
taskExecutionGraph.getDependencies(taskFrom)
で各タスクの依存先タスクを取得できるところがポイント。グラフを描くのに必要な情報はこれで揃う。
なので、たとえば build.gradle ではノード・エッジの情報を抜き出して出力するところだけ行って残りは別のプログラムに任せる作りにすれば、 build.gradle 側の責務をより小さくできる。