Skip to content

Instantly share code, notes, and snippets.

@madroidmaq
Created March 12, 2023 08:09
Show Gist options
  • Save madroidmaq/c1243312745f5d56f546b62968f41f44 to your computer and use it in GitHub Desktop.
Save madroidmaq/c1243312745f5d56f546b62968f41f44 to your computer and use it in GitHub Desktop.
Create a dependency diagram for the current project using the syntax of plantUML, with a result that looks like the following.
task projectDependencyGraph {
doLast {
def plantuml = new File(rootProject.buildDir, 'reports/dependency-graph/project.puml')
plantuml.parentFile.mkdirs()
plantuml.delete()
plantuml << '@startuml\n'
plantuml << "!define blue #00E489\n"
plantuml << "!define origin #FF8A65\n"
plantuml << "!define green #1A73E8\n"
plantuml << "!define dark #073042\n"
plantuml << "\npackage ${rootProject.name} {\n"
def rootProjects = []
def queue = [rootProject]
while (!queue.isEmpty()) {
def project = queue.remove(0)
rootProjects.add(project)
queue.addAll(project.childProjects.values())
}
def projects = new LinkedHashSet<Project>()
def dependencies = new LinkedHashMap<Tuple2<Project, Project>, List<String>>()
queue = [rootProject]
while (!queue.isEmpty()) {
def project = queue.remove(0)
queue.addAll(project.childProjects.values())
project.configurations.all { config ->
if (!config.name.endsWith('implementation')) {
return
}
config.dependencies
.withType(ProjectDependency)
.collect { it.dependencyProject }
.each { dependency ->
projects.add(project)
projects.add(dependency)
rootProjects.remove(dependency)
def graphKey = new Tuple2<Project, Project>(project, dependency)
dependencies.computeIfAbsent(graphKey) { new ArrayList<String>() }
}
}
}
projects = projects.sort { it.path }
plantuml << '\n'
LinkedHashMap<String, LinkedHashSet<Project>> map = new LinkedHashMap<String, LinkedHashSet<Project>>()
projects.forEach {
def tempList = it.path.split(":")
if (tempList.length > 2) {
def groupName = tempList[1]
if (map[groupName] == null) {
map[groupName] = new LinkedHashSet<Project>()
}
map[groupName].add(it)
} else {
if (map[""] == null) {
map[""] = new LinkedHashSet<Project>()
}
map[""].add(it)
}
}
def colors = ["blue", "origin", "green", "dark"]
def colorIndex = 0
map.forEach { key, values ->
if (key == "") {
values.forEach {
plantuml << " [${it.path}]\n"
}
} else {
def color = colors[colorIndex % colors.size()]
plantuml << " frame ${key} $color {\n"
values.forEach {
plantuml << " [${it.path}]\n"
}
plantuml << " }\n"
colorIndex++
}
}
plantuml << "}\n"
plantuml << '\n'
dependencies.findAll { key, traits ->
return key.first.path != key.second.path
}.forEach { key, traits ->
plantuml << "[${key.first.path}] --> [${key.second.path}]"
plantuml << '\n'
}
plantuml << '@enduml\n'
}
}
@madroidmaq
Copy link
Author

以 Now in Android 项目为例,效果图如下:
project

对应的 puml 文件内容如下:

@startuml
!define blue #00E489
!define origin #FF8A65
!define green #1A73E8
!define dark #073042

package nowinandroid {

  [:app]
  [:app-nia-catalog]
  frame core blue {
    [:core:common]
    [:core:data]
    [:core:data-test]
    [:core:database]
    [:core:datastore]
    [:core:datastore-test]
    [:core:designsystem]
    [:core:domain]
    [:core:model]
    [:core:network]
    [:core:testing]
    [:core:ui]
  }
  frame feature origin {
    [:feature:bookmarks]
    [:feature:foryou]
    [:feature:interests]
    [:feature:settings]
    [:feature:topic]
  }
  frame sync green {
    [:sync:sync-test]
    [:sync:work]
  }
}

[:app] --> [:feature:interests]
[:app] --> [:feature:foryou]
[:app] --> [:feature:bookmarks]
[:app] --> [:feature:topic]
[:app] --> [:feature:settings]
[:app] --> [:core:common]
[:app] --> [:core:ui]
[:app] --> [:core:designsystem]
[:app] --> [:core:data]
[:app] --> [:core:model]
[:app] --> [:sync:work]
[:app-nia-catalog] --> [:core:ui]
[:app-nia-catalog] --> [:core:designsystem]
[:core:data] --> [:core:common]
[:core:data] --> [:core:model]
[:core:data] --> [:core:database]
[:core:data] --> [:core:datastore]
[:core:data] --> [:core:network]
[:core:data-test] --> [:core:testing]
[:core:database] --> [:core:model]
[:core:datastore] --> [:core:common]
[:core:datastore] --> [:core:model]
[:core:datastore-test] --> [:core:testing]
[:core:domain] --> [:core:data]
[:core:domain] --> [:core:model]
[:core:network] --> [:core:common]
[:core:network] --> [:core:model]
[:core:testing] --> [:core:common]
[:core:testing] --> [:core:data]
[:core:testing] --> [:core:model]
[:core:ui] --> [:core:designsystem]
[:core:ui] --> [:core:model]
[:core:ui] --> [:core:domain]
[:feature:bookmarks] --> [:core:model]
[:feature:bookmarks] --> [:core:ui]
[:feature:bookmarks] --> [:core:designsystem]
[:feature:bookmarks] --> [:core:data]
[:feature:bookmarks] --> [:core:common]
[:feature:bookmarks] --> [:core:domain]
[:feature:foryou] --> [:core:model]
[:feature:foryou] --> [:core:ui]
[:feature:foryou] --> [:core:designsystem]
[:feature:foryou] --> [:core:data]
[:feature:foryou] --> [:core:common]
[:feature:foryou] --> [:core:domain]
[:feature:interests] --> [:core:model]
[:feature:interests] --> [:core:ui]
[:feature:interests] --> [:core:designsystem]
[:feature:interests] --> [:core:data]
[:feature:interests] --> [:core:common]
[:feature:interests] --> [:core:domain]
[:feature:settings] --> [:core:model]
[:feature:settings] --> [:core:ui]
[:feature:settings] --> [:core:designsystem]
[:feature:settings] --> [:core:data]
[:feature:settings] --> [:core:common]
[:feature:settings] --> [:core:domain]
[:feature:topic] --> [:core:model]
[:feature:topic] --> [:core:ui]
[:feature:topic] --> [:core:designsystem]
[:feature:topic] --> [:core:data]
[:feature:topic] --> [:core:common]
[:feature:topic] --> [:core:domain]
[:sync:sync-test] --> [:core:data]
[:sync:sync-test] --> [:core:testing]
[:sync:work] --> [:core:common]
[:sync:work] --> [:core:model]
[:sync:work] --> [:core:data]
[:sync:work] --> [:core:datastore]
@enduml

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment