Skip to content

Commit

Permalink
Add module alias to Graphviz export (#159)
Browse files Browse the repository at this point in the history
  • Loading branch information
jraska authored Jan 18, 2022
1 parent 2c133c2 commit 39773de
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 61 deletions.
11 changes: 7 additions & 4 deletions plugin/src/main/kotlin/com/jraska/module/graph/GraphvizWriter.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.jraska.module.graph

import com.jraska.module.graph.assertion.mapAlias

object GraphvizWriter {
fun toGraphviz(dependencyGraph: DependencyGraph): String {
fun toGraphviz(dependencyGraph: DependencyGraph, aliases: Map<String, String> = emptyMap()): String {

val longestPathConnections = dependencyGraph.longestPath()
.nodeNames.zipWithNext()
Expand All @@ -18,12 +20,13 @@ object GraphvizWriter {
}

dependencyPairs
.map { aliases.mapAlias(it) }
.forEach { connection ->
stringBuilder.append("\"${connection.first}\"")
stringBuilder.append("\"${connection.fromDocText()}\"")
.append(" -> ")
.append("\"${connection.second}\"")
.append("\"${connection.toDocText()}\"")

if (longestPathConnections.contains(connection)) {
if (longestPathConnections.contains(connection.dependencyPair)) {
stringBuilder.append(" [color=red style=bold]")
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.jraska.module.graph.assertion

class ModuleDependency(
val dependencyPair: Pair<String, String>,
private val fromAlias: String?,
private val toAlias: String?
) {
private val from get() = dependencyPair.first
private val to get() = dependencyPair.second

fun pairToAssert(): Pair<String, String> {
if (fromAlias != null || toAlias != null) {
return (fromAlias ?: from) to (toAlias ?: to)
} else {
return dependencyPair
}
}

fun assertDisplayText(): String {
val stringBuilder = StringBuilder()

if (fromAlias != null) {
stringBuilder.append("\"$fromAlias\"")
stringBuilder.append("('${from}')")
} else {
stringBuilder.append("'${from}'")
}

stringBuilder.append(" -> ")

if (toAlias != null) {
stringBuilder.append("\"$toAlias\"")
stringBuilder.append("('${to}')")
} else {
stringBuilder.append("'${to}'")
}

return stringBuilder.toString()
}

fun fromDocText(): String {
return if (fromAlias != null) {
"$from('$fromAlias')"
} else {
from
}
}

fun toDocText() : String {
return if (toAlias != null) {
"$to('$toAlias')"
} else {
to
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class ModuleGraphAssertionsPlugin : Plugin<Project> {
private fun Project.addModuleGraphGeneration(graphRules: GraphRulesExtension) {
tasks.register(Tasks.GENERATE_GRAPHVIZ, GenerateModulesGraphTask::class.java) {
it.configurationsToLook = graphRules.configurations
it.aliases = aliases
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class OnlyAllowedAssert(
val disallowedDependencies = dependencyGraph.dependencyPairs()
.map { aliasMap.mapAlias(it) }
.filterNot { dependency -> matchers.any { it.matches(dependency.pairToAssert()) } }
.map { it.displayText() }
.map { it.assertDisplayText() }

if (disallowedDependencies.isNotEmpty()) {
val allowedRules = allowedDependencies.joinToString(", ") { "'$it'" }
Expand All @@ -23,9 +23,9 @@ class OnlyAllowedAssert(
}
}

fun Map<String, String>.mapAlias(dependencyPair: Pair<String, String>): DependencyToAssert {
fun Map<String, String>.mapAlias(dependencyPair: Pair<String, String>): ModuleDependency {
val fromAlias = this[dependencyPair.first]
val toAlias = this[dependencyPair.second]

return DependencyToAssert(dependencyPair, fromAlias, toAlias)
return ModuleDependency(dependencyPair, fromAlias, toAlias)
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ class RestrictedDependenciesAssert(
}
}

private fun buildErrorMessage(failedDependencies: List<Pair<DependencyToAssert, List<DependencyMatcher>>>): String {
private fun buildErrorMessage(failedDependencies: List<Pair<ModuleDependency, List<DependencyMatcher>>>): String {
return failedDependencies.map {
val violatedRules = it.second.map { "'$it'" }.joinToString(", ")
"Dependency '${it.first.displayText()} violates: $violatedRules"
"Dependency '${it.first.assertDisplayText()} violates: $violatedRules"
}.joinToString("\n")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ open class GenerateModulesGraphTask : DefaultTask() {
@Input
lateinit var configurationsToLook: Set<String>

@Input
lateinit var aliases: Map<String, String>

@TaskAction
fun run() {
val dependencyGraph = project.createDependencyGraph(configurationsToLook)

val graphviz = GraphvizWriter.toGraphviz(dependencyGraph)
val graphviz = GraphvizWriter.toGraphviz(dependencyGraph, aliases)

if (shouldOutputFile()) {
getOutputFile().apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,26 @@ import org.junit.Test

class GraphvizWriterTest {

val EXPECTED_OUTPUT = """digraph G {
"app" -> "feature" [color=red style=bold]
"app" -> "feature-about"
"app" -> "lib"
"feature" -> "lib" [color=red style=bold]
"feature-about" -> "lib"
"feature-about" -> "core"
"lib" -> "core" [color=red style=bold]
}"""

@Test
fun testPrintsProperly() {
val graphvizText = GraphvizWriter.toGraphviz(testGraph())

assert(graphvizText == EXPECTED_OUTPUT)
}

@Test
fun testPrintsProperlyWithAliases() {
val aliases = mapOf(
"app" to "App",
"lib" to "Api",
"feature-about" to "Implementation"
)

val graphvizText = GraphvizWriter.toGraphviz(testGraph(), aliases)

assert(graphvizText == EXPECTED_OUTPUT_WITH_ALISASES)
}

private fun testGraph(): DependencyGraph {
return DependencyGraph.create(
"app" to "feature",
Expand All @@ -33,3 +36,23 @@ class GraphvizWriterTest {
)
}
}

private const val EXPECTED_OUTPUT = """digraph G {
"app" -> "feature" [color=red style=bold]
"app" -> "feature-about"
"app" -> "lib"
"feature" -> "lib" [color=red style=bold]
"feature-about" -> "lib"
"feature-about" -> "core"
"lib" -> "core" [color=red style=bold]
}"""

private const val EXPECTED_OUTPUT_WITH_ALISASES = """digraph G {
"app('App')" -> "feature" [color=red style=bold]
"app('App')" -> "feature-about('Implementation')"
"app('App')" -> "lib('Api')"
"feature" -> "lib('Api')" [color=red style=bold]
"feature-about('Implementation')" -> "lib('Api')"
"feature-about('Implementation')" -> "core"
"lib('Api')" -> "core" [color=red style=bold]
}"""
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@ package com.jraska.module.graph.assertion

import org.junit.Test

class DependencyToAssertTest {
class ModuleDependencyTest {
@Test
fun displayTextWorksWithAliases() {
val displayText = DependencyToAssert(":feature" to ":core-api", "Impl", "Api").displayText()
val displayText = ModuleDependency(":feature" to ":core-api", "Impl", "Api").assertDisplayText()

assert(displayText == """"Impl"(':feature') -> "Api"(':core-api')""")
}

@Test
fun displayTextWorksWithOneAlias() {
val displayText = DependencyToAssert(":feature" to ":core-api", null, "Api").displayText()
val displayText = ModuleDependency(":feature" to ":core-api", null, "Api").assertDisplayText()

assert(displayText == """':feature' -> "Api"(':core-api')""")
}

@Test
fun displayTextWorksWithNoAliases() {
val displayText = DependencyToAssert(":feature" to ":core-api", null, null).displayText()
val displayText = ModuleDependency(":feature" to ":core-api", null, null).assertDisplayText()

assert(displayText == "':feature' -> ':core-api'")
}
Expand Down

0 comments on commit 39773de

Please sign in to comment.