Skip to content

Commit 34f33b6

Browse files
authored
Re-added dot/graphviz support with command line output option (#5)
1 parent 4258079 commit 34f33b6

4 files changed

Lines changed: 46 additions & 7 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ This is the hardest part: dealing with obscure Xcode formats. But if we get that
128128
- `--base-branch`: Branch to compare against to find the relevant changes. If emitted, a local changeset is used (development mode).
129129
- `--test-plan`: Path to the test plan. If not given, tool would try to infer the path.
130130
- `--json`: Provide output in JSON format (STDOUT).
131-
- `--dependency-graph`: Opens Safari with a dependency graph visualization.
131+
- `--dependency-graph`: Opens Safari with a dependency graph visualization. Attention: if you don't trust Javascript ecosystem prefer using `--dot` option.
132+
- `--dot`: Output dependency graph in Dot (Graphviz) format. To be used with Graphviz: `brew install graphviz`, then `xcode-selective-test --dot | dot -Tsvg > output.svg && open output.svg`
132133
- `--verbose`: Provide verbose output.
133134

134135
## Configuration file `.xcode-selective-testing.yml`

Sources/SelectiveTestingCore/DependencyGraph+DOT.swift renamed to Sources/SelectiveTestingCore/DependencyGraph+Visualization.swift

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,35 @@ import Foundation
66
import Workspace
77
import PathKit
88

9-
extension DependencyGraph {
9+
extension TargetIdentity {
10+
var dotDescription: String {
11+
return "\"\(self.description.replacingOccurrences(of: "-", with: "_"))\""
12+
}
13+
}
14+
15+
extension DependencyGraph {
16+
func dot() -> String {
17+
var dot = """
18+
digraph {
19+
rankdir=TB
20+
"""
21+
let grouped = groupByPath()
22+
23+
grouped.keys.forEach { path in
24+
let targets = grouped[path]!
25+
26+
targets.forEach { target in
27+
let deps = dependencies(for: target)
28+
guard !deps.isEmpty else {
29+
return
30+
}
31+
dot = dot + "\n\t\(target.dotDescription) -> { \(deps.map(\.dotDescription).joined(separator: " ")) }"
32+
}
33+
}
34+
dot = dot + "\n}"
35+
return dot
36+
}
37+
1038
func mermaid(highlightTargets: Set<TargetIdentity>) -> String {
1139
var result = "graph TD\n"
1240
allTargets().forEach { target in

Sources/SelectiveTestingCore/SelectiveTestingTool.swift

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public final class SelectiveTestingTool {
1616
private let basePath: Path
1717
private let printJSON: Bool
1818
private let renderDependencyGraph: Bool
19+
private let dot: Bool
1920
private let verbose: Bool
2021
private let testPlan: String?
2122
private let config: Config?
@@ -25,6 +26,7 @@ public final class SelectiveTestingTool {
2526
testPlan: String?,
2627
printJSON: Bool = false,
2728
renderDependencyGraph: Bool = false,
29+
dot: Bool = false,
2830
verbose: Bool = false) throws {
2931

3032
if let configData = try? (Path.current + Config.defaultConfigName).read(),
@@ -44,6 +46,7 @@ public final class SelectiveTestingTool {
4446
self.basePath = Path(finalBasePath)
4547
self.printJSON = printJSON
4648
self.renderDependencyGraph = renderDependencyGraph
49+
self.dot = dot
4750
self.verbose = verbose
4851
self.testPlan = testPlan ?? config?.testPlan
4952
}
@@ -75,6 +78,13 @@ public final class SelectiveTestingTool {
7578
try Shell.exec("open -a Safari \"\(workspaceInfo.dependencyStructure.mermaidInURL(highlightTargets: affectedTargets))\"")
7679
}
7780

81+
if printJSON {
82+
try printJSON(affectedTargets: affectedTargets)
83+
}
84+
else if dot {
85+
print(workspaceInfo.dependencyStructure.dot())
86+
}
87+
7888
if verbose {
7989
workspaceInfo.dependencyStructure
8090
.allTargets()
@@ -108,10 +118,6 @@ public final class SelectiveTestingTool {
108118
}
109119
}
110120

111-
if printJSON {
112-
try printJSON(affectedTargets: affectedTargets)
113-
}
114-
115121
if let testPlan {
116122
// 4. Configure workspace to test given targets
117123
try enableTests(at: Path(testPlan),

Sources/xcode-selective-test/SelectiveTesting.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ struct SelectiveTesting: AsyncParsableCommand {
2222
@Flag(name: .long, help: "Output in JSON format")
2323
var JSON: Bool = false
2424

25-
@Flag(help: "Render dependency graph in the browser")
25+
@Flag(help: "Render dependency graph in the browser using Mermaid")
2626
var dependencyGraph: Bool = false
2727

28+
@Flag(help: "Output dependency graph in Dot (Graphviz) format")
29+
var dot: Bool = false
30+
2831
@Flag(help: "Produce verbose output")
2932
var verbose: Bool = false
3033

@@ -34,6 +37,7 @@ struct SelectiveTesting: AsyncParsableCommand {
3437
testPlan: testPlan,
3538
printJSON: JSON,
3639
renderDependencyGraph: dependencyGraph,
40+
dot: dot,
3741
verbose: verbose)
3842

3943
do {

0 commit comments

Comments
 (0)