Skip to content

Commit d21b805

Browse files
fix: ensure output of GraphViewTask is fully sorted (therefore deterministic).
1 parent 73198be commit d21b805

File tree

4 files changed

+36
-17
lines changed

4 files changed

+36
-17
lines changed

src/main/kotlin/com/autonomousapps/internal/graph/GraphWriter.kt

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,33 @@
33
package com.autonomousapps.internal.graph
44

55
import com.autonomousapps.graph.Graphs.root
6-
import com.autonomousapps.graph.Graphs.shortestPaths
76
import com.autonomousapps.graph.Graphs.topological
87
import com.autonomousapps.internal.utils.appendReproducibleNewLine
98
import com.autonomousapps.model.Coordinates
109
import com.autonomousapps.model.ProjectCoordinates
10+
import com.google.common.graph.EndpointPair
1111
import com.google.common.graph.Graph
1212
import com.google.common.graph.Traverser
1313

1414
@Suppress("UnstableApiUsage")
1515
internal class GraphWriter(private val buildPath: String) {
1616

17+
private companion object {
18+
// TODO(tsr): similar code in moshi.kt
19+
val EDGE_COMPARATOR: Comparator<EndpointPair<Coordinates>> = Comparator { left, right ->
20+
compareBy(EndpointPair<Coordinates>::source)
21+
.thenComparing(EndpointPair<Coordinates>::target)
22+
.compare(left, right)
23+
}
24+
}
25+
1726
fun toDot(graph: Graph<Coordinates>): String = buildString {
1827
val projectNodes = graph.nodes().asSequence()
1928
// Maybe transform an IncludedBuildCoordinates into its resolvedProject for more human-readable reporting
2029
.map { it.maybeProjectCoordinates(buildPath) }
2130
.filterIsInstance<ProjectCoordinates>()
2231
.map { it.gav() }
32+
.sorted()
2333
.toList()
2434

2535
appendReproducibleNewLine("strict digraph DependencyGraph {")
@@ -34,15 +44,17 @@ internal class GraphWriter(private val buildPath: String) {
3444
if (projectNodes.isNotEmpty()) appendReproducibleNewLine()
3545

3646
// the graph itself
37-
graph.edges().forEach { edge ->
38-
val source = edge.nodeU().maybeProjectCoordinates(buildPath)
39-
val target = edge.nodeV().maybeProjectCoordinates(buildPath)
40-
val style =
41-
if (source is ProjectCoordinates && target is ProjectCoordinates) " [style=bold color=\"#FF6347\" weight=8]"
42-
else ""
43-
append(" \"${source.gav()}\" -> \"${target.gav()}\"$style;")
44-
append("\n")
45-
}
47+
graph.edges()
48+
.sortedWith(EDGE_COMPARATOR)
49+
.forEach { edge ->
50+
val source = edge.nodeU().maybeProjectCoordinates(buildPath)
51+
val target = edge.nodeV().maybeProjectCoordinates(buildPath)
52+
val style =
53+
if (source is ProjectCoordinates && target is ProjectCoordinates) " [style=bold color=\"#FF6347\" weight=8]"
54+
else ""
55+
append(" \"${source.gav()}\" -> \"${target.gav()}\"$style;")
56+
append("\n")
57+
}
4658
append("}")
4759
}
4860

src/main/kotlin/com/autonomousapps/internal/utils/moshi.kt

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,10 @@ internal class GraphAdapter {
205205
variant = graphView.variant,
206206
configurationName = graphView.configurationName,
207207
graphJson = GraphJson(
208-
nodes = graphView.graph.nodes(),
208+
nodes = graphView.graph.nodes().toSortedSet(),
209209
edges = graphView.graph.edges().asSequence().map { pair ->
210210
pair.nodeU() to pair.nodeV()
211-
}.toSet(),
211+
}.toSortedSet(),
212212
),
213213
)
214214
}
@@ -223,10 +223,10 @@ internal class GraphAdapter {
223223

224224
@ToJson fun graphToJson(graph: Graph<Coordinates>): GraphJson {
225225
return GraphJson(
226-
nodes = graph.nodes(),
226+
nodes = graph.nodes().toSortedSet(),
227227
edges = graph.edges().asSequence().map { pair ->
228228
pair.nodeU() to pair.nodeV()
229-
}.toSet(),
229+
}.toSortedSet(),
230230
)
231231
}
232232

@@ -265,5 +265,12 @@ internal class GraphAdapter {
265265
)
266266

267267
@JsonClass(generateAdapter = false)
268-
internal data class EdgeJson(val source: Coordinates, val target: Coordinates)
268+
internal data class EdgeJson(val source: Coordinates, val target: Coordinates) : Comparable<EdgeJson> {
269+
// TODO(tsr): similar code in GraphWriter
270+
override fun compareTo(other: EdgeJson): Int {
271+
return compareBy(EdgeJson::source)
272+
.thenComparing(EdgeJson::target)
273+
.compare(this, other)
274+
}
275+
}
269276
}

src/main/kotlin/com/autonomousapps/tasks/GraphViewTask.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ abstract class GraphViewTask : DefaultTask() {
153153

154154
output.bufferWriteJson(compileGraphView)
155155
outputDot.writeText(graphWriter.toDot(compileGraph))
156-
outputNodes.bufferWriteJson(CoordinatesContainer(compileGraphView.nodes))
156+
outputNodes.bufferWriteJson(CoordinatesContainer(compileGraphView.nodes.toSortedSet()))
157157
outputRuntime.bufferWriteJson(runtimeGraphView)
158158
outputRuntimeDot.writeText(graphWriter.toDot(runtimeGraph))
159159
}

src/test/kotlin/com/autonomousapps/model/internal/DependencyGraphViewTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ internal class DependencyGraphViewTest {
3030
val serialized = graphView.toJson()
3131
assertThat(serialized).isEqualTo(
3232
"""
33-
{"variant":{"variant":"main","kind":"MAIN"},"configurationName":"compileClasspath","graphJson":{"nodes":[{"type":"project","identifier":":secondary:root","gradleVariantIdentification":{"capabilities":[],"attributes":{}}},{"type":"project","identifier":":root","gradleVariantIdentification":{"capabilities":[],"attributes":{}}},{"type":"module","identifier":"foo:bar","resolvedVersion":"1","gradleVariantIdentification":{"capabilities":[],"attributes":{}}},{"type":"module","identifier":"bar:baz","resolvedVersion":"1","gradleVariantIdentification":{"capabilities":[],"attributes":{}}}],"edges":[{"source":{"type":"project","identifier":":root","gradleVariantIdentification":{"capabilities":[],"attributes":{}}},"target":{"type":"module","identifier":"foo:bar","resolvedVersion":"1","gradleVariantIdentification":{"capabilities":[],"attributes":{}}}},{"source":{"type":"module","identifier":"foo:bar","resolvedVersion":"1","gradleVariantIdentification":{"capabilities":[],"attributes":{}}},"target":{"type":"module","identifier":"bar:baz","resolvedVersion":"1","gradleVariantIdentification":{"capabilities":[],"attributes":{}}}}]}}
33+
{"variant":{"variant":"main","kind":"MAIN"},"configurationName":"compileClasspath","graphJson":{"nodes":[{"type":"module","identifier":"bar:baz","resolvedVersion":"1","gradleVariantIdentification":{"capabilities":[],"attributes":{}}},{"type":"module","identifier":"foo:bar","resolvedVersion":"1","gradleVariantIdentification":{"capabilities":[],"attributes":{}}},{"type":"project","identifier":":root","gradleVariantIdentification":{"capabilities":[],"attributes":{}}},{"type":"project","identifier":":secondary:root","gradleVariantIdentification":{"capabilities":[],"attributes":{}}}],"edges":[{"source":{"type":"module","identifier":"foo:bar","resolvedVersion":"1","gradleVariantIdentification":{"capabilities":[],"attributes":{}}},"target":{"type":"module","identifier":"bar:baz","resolvedVersion":"1","gradleVariantIdentification":{"capabilities":[],"attributes":{}}}},{"source":{"type":"project","identifier":":root","gradleVariantIdentification":{"capabilities":[],"attributes":{}}},"target":{"type":"module","identifier":"foo:bar","resolvedVersion":"1","gradleVariantIdentification":{"capabilities":[],"attributes":{}}}}]}}
3434
""".trimIndent()
3535
)
3636

0 commit comments

Comments
 (0)