visualize_packs 0.5.21 → 0.5.23
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -4
- data/bin/visualize_packs +1 -46
- data/lib/graph.dot.erb +16 -9
- data/lib/visualize_packs/options.rb +1 -0
- data/lib/visualize_packs/options_parser.rb +55 -0
- data/lib/visualize_packs.rb +26 -8
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0e0cfe73d505dcc80ec3792514b251aa3320c5e7c9703c071202bf1c384ca77a
|
4
|
+
data.tar.gz: 0bff429e62083b1a193ddaeb15c443568363ac5400d22b06e5d220e38aea2b90
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd23c6aa9d40fc57d4b0272af1046c7a289062a27c809b78ef121c239b53347f7dee5e3ccd7afbebca49d25697ee01da6de9b92864c83d0524f1f3a394b8f0f3
|
7
|
+
data.tar.gz: d394fdfb12da6cb44fa0401aa33f17e9fcfcb801b201a485c92683260f5bb17be66054d7361bc01c95dea5bcb82e136d1da1c09040a43bf053ddc403521e1738
|
data/README.md
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
# visualize_packs
|
2
|
+
|
2
3
|
Visualize_packs helps you visualize the structure, intended and actual, of your package-based Ruby application.
|
3
4
|
|
4
5
|
This gem takes a minimal approach in that it only outputs a graph in the format of [graphviz](https://graphviz.org/)' [dot language](https://graphviz.org/doc/info/lang.html). Install graphviz and use one of the chains of commands from below to generate full or partial images of the graphs of your application.
|
5
6
|
|
6
7
|
## Visualize your entire application
|
8
|
+
|
7
9
|
```
|
8
10
|
bundle exec visualize_packs > packs.dot && dot packs.dot -Tpng -o packs.png && open packs.png
|
9
11
|
```
|
@@ -13,16 +15,15 @@ bundle exec visualize_packs > packs.dot && dot packs.dot -Tpng -o packs.png && o
|
|
13
15
|
This will generate a local dependency diagram for every pack in your app
|
14
16
|
|
15
17
|
```
|
16
|
-
find . -iname 'package.yml' | sed 's/\/package.yml//g' | sed 's/\.\///' | xargs -I % sh -c "bundle exec visualize_packs --
|
18
|
+
find . -iname 'package.yml' | sed 's/\/package.yml//g' | sed 's/\.\///' | xargs -I % sh -c "bundle exec visualize_packs --focus-pack=% > %/packs.dot && dot %/packs.dot -Tpng -o %/packs.png"
|
17
19
|
```
|
18
20
|
|
19
21
|
If your app is large and has many packages and todos, the above graphs will likely be too big. Try this version to get only the edges to and from the focus package for each diagram:
|
20
22
|
|
21
23
|
```
|
22
|
-
find . -iname 'package.yml' | sed 's/\/package.yml//g' | sed 's/\.\///' | xargs -I % sh -c "bundle exec visualize_packs --
|
24
|
+
find . -iname 'package.yml' | sed 's/\/package.yml//g' | sed 's/\.\///' | xargs -I % sh -c "bundle exec visualize_packs --focus-pack=% --focus-pack-edge-mode=inout > %/packs.dot && dot %/packs.dot -Tpng -o %/packs.png"
|
23
25
|
```
|
24
26
|
|
25
|
-
|
26
27
|
## Get help
|
27
28
|
|
28
29
|
```
|
@@ -49,4 +50,4 @@ Once you are ready, run the following and commit the new `diagram_examples.png`
|
|
49
50
|
./spec/update_cassettes.sh
|
50
51
|
```
|
51
52
|
|
52
|
-
Please check in a new `diagram_examples.png` only if there are actual visual changes.
|
53
|
+
Please check in a new `diagram_examples.png` only if there are actual visual changes.
|
data/bin/visualize_packs
CHANGED
@@ -1,55 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "pathname"
|
5
|
-
require "optparse"
|
6
|
-
require "ostruct"
|
7
|
-
|
8
4
|
require_relative '../lib/visualize_packs'
|
9
5
|
|
10
|
-
options = Options.new
|
11
|
-
|
12
|
-
OptionParser.new do |opt|
|
13
|
-
opt.on('--no-legend', "Don't show legend") { |o| options.show_legend = false }
|
14
|
-
|
15
|
-
opt.on('--no-dependency-arrows', "Don't show accepted dependency arrows") { |o| options.show_dependencies = false }
|
16
|
-
opt.on('--no-privacy-boxes', "Don't show privacy enforcement box on a pack") { |o| options.show_privacy = false }
|
17
|
-
opt.on('--no-layers', "Don't show architectural layers") { |o| options.show_layers = false }
|
18
|
-
opt.on('--no-visibility-arrows', "Don't show visibility arrows") { |o| options.show_visibility = false }
|
19
|
-
|
20
|
-
opt.on('--no-todo-edges', "Don't show todos for package relationships") { |o| options.show_relationship_todos = false }
|
21
|
-
opt.on("--edge-todo-types=STRING", "Show only the selected types of relationship todos. Comma-separated list of #{EdgeTodoTypes.values.map &:serialize}") { |o| options.relationship_todo_types = o.to_s.split(",").uniq.map { EdgeTodoTypes.deserialize(_1) } }
|
22
|
-
opt.on("--use-edge-todos-for-layout", "Show only the selected types of relationship todos. Comma-separated list of #{EdgeTodoTypes.values.map &:serialize}") { |o| options.use_relationship_todos_for_layout = true }
|
23
|
-
|
24
|
-
opt.on('--no-teams', "Don't show team colors") { |o| options.show_teams = false }
|
25
|
-
opt.on('--no-node-todos', "Don't show package-based todos") { |o| options.show_node_todos = false }
|
26
|
-
|
27
|
-
opt.on('--focus-pack=STRING', "Focus on a specific pack(s). Comma-separated list of packs. Wildcards supported: 'packs/*'") { |o| options.focus_pack = o.to_s.split(",") }
|
28
|
-
opt.on('--focus-pack-edge-mode=STRING', "If focus-pack is set, this shows only between focussed packs (when set to none) or the edges into / out of / in and out of the focus packs to non-focus packs (which will be re-added to the graph). One of #{FocusPackEdgeDirection.values.map &:serialize}") { |o| options.show_only_edges_to_focus_pack = FocusPackEdgeDirection.deserialize(o) }
|
29
|
-
opt.on('--exclude-packs=', "Exclude listed packs from diagram. If used with include you will get all included that are not excluded. Wildcards support: 'packs/ignores/*'") { |o| options.exclude_packs = o.to_s.split(",") }
|
30
|
-
|
31
|
-
opt.on('--roll-nested-into-parent-packs', "Don't show nested packs (not counting root). Connect edges to top-level pack instead") { |o| options.roll_nested_into_parent_packs = true }
|
32
|
-
opt.on('--no-nesting-arrows', "Don't draw relationships between parents and nested packs") { |o| options.show_nested_relationships = false }
|
33
|
-
|
34
|
-
opt.on('--remote-base-url=STRING', "Link pack packs to a URL (affects graphviz SVG generation)") { |o| options.remote_base_url = o }
|
35
|
-
|
36
|
-
opt.on('--title=STRING', "Set a custom diagram title") { |o| options.title = o }
|
37
|
-
|
38
|
-
opt.on('-V', '--version', "Show version") do
|
39
|
-
spec_path = File.expand_path("../visualize_packs.gemspec", __dir__)
|
40
|
-
spec = Gem::Specification::load(spec_path)
|
41
|
-
puts "Version #{spec.version}"
|
42
|
-
exit
|
43
|
-
end
|
44
|
-
|
45
|
-
opt.on_tail("-h", "--help", "Show this message") do
|
46
|
-
puts opt
|
47
|
-
exit
|
48
|
-
end
|
49
|
-
end.parse!
|
50
|
-
|
51
6
|
puts VisualizePacks.package_graph!(
|
52
|
-
|
7
|
+
ARGV,
|
53
8
|
ParsePackwerk::Configuration.fetch.raw,
|
54
9
|
Packs.all.map { ParsePackwerk.find(_1.name) }
|
55
10
|
)
|
data/lib/graph.dot.erb
CHANGED
@@ -105,6 +105,8 @@ digraph package_diagram {
|
|
105
105
|
<%= VisualizePacks::ArrowHead::ArchitectureTodo.serialize %>
|
106
106
|
<%- elsif todo_type == 'visibility' -%>
|
107
107
|
<%= VisualizePacks::ArrowHead::VisibilityTodo.serialize %>
|
108
|
+
<%- elsif todo_type == 'folder_visibility' -%>
|
109
|
+
<%= VisualizePacks::ArrowHead::FolderVisibilityTodo.serialize %>
|
108
110
|
<%- elsif todo_type == 'dependency' -%>
|
109
111
|
<%= VisualizePacks::ArrowHead::DependencyTodo.serialize %>
|
110
112
|
<%- end -%>
|
@@ -141,14 +143,14 @@ digraph package_diagram {
|
|
141
143
|
A -> B [label="accepted dependency" <%= VisualizePacks::ArrowHead::ConfiguredDependency.serialize %>]
|
142
144
|
<%- end -%>
|
143
145
|
<%- if options.show_nested_relationships -%>
|
144
|
-
K [ fontsize=12 shape=box label="package"]
|
145
|
-
L [ fontsize=12 shape=box label="package"]
|
146
|
-
K -> L [label="nested package" <%= VisualizePacks::ArrowHead::ConfiguredNested.serialize %>]
|
147
|
-
<%- end -%>
|
148
|
-
<%- if options.show_visibility -%>
|
149
146
|
M [ fontsize=12 shape=box label="package"]
|
150
147
|
N [ fontsize=12 shape=box label="package"]
|
151
|
-
M -> N [label="
|
148
|
+
M -> N [label="nested package" <%= VisualizePacks::ArrowHead::ConfiguredNested.serialize %>]
|
149
|
+
<%- end -%>
|
150
|
+
<%- if options.show_visibility -%>
|
151
|
+
O [ fontsize=12 shape=box label="package"]
|
152
|
+
P [ fontsize=12 shape=box label="package"]
|
153
|
+
O -> P [label="visible to" <%= VisualizePacks::ArrowHead::ConfiguredVisibleTo.serialize %>]
|
152
154
|
<%- end -%>
|
153
155
|
<%- if options.show_relationship_todos -%>
|
154
156
|
<%- if options.relationship_todo_types.include?(EdgeTodoTypes::Privacy) -%>
|
@@ -166,10 +168,15 @@ digraph package_diagram {
|
|
166
168
|
H [ fontsize=12 shape=box label="package"]
|
167
169
|
G -> H [label="visibility todo" <%= VisualizePacks::ArrowHead::VisibilityTodo.serialize %>]
|
168
170
|
<%- end -%>
|
169
|
-
<%- if options.relationship_todo_types.include?(EdgeTodoTypes::
|
171
|
+
<%- if options.relationship_todo_types.include?(EdgeTodoTypes::Folder_Visibility) -%>
|
170
172
|
I [ fontsize=12 shape=box label="package"]
|
171
173
|
J [ fontsize=12 shape=box label="package"]
|
172
|
-
I -> J [label="
|
174
|
+
I -> J [label="folder visibility todo" <%= VisualizePacks::ArrowHead::FolderVisibilityTodo.serialize %>]
|
175
|
+
<%- end -%>
|
176
|
+
<%- if options.relationship_todo_types.include?(EdgeTodoTypes::Dependency) -%>
|
177
|
+
K [ fontsize=12 shape=box label="package"]
|
178
|
+
L [ fontsize=12 shape=box label="package"]
|
179
|
+
K -> L [label="dependency todo" <%= VisualizePacks::ArrowHead::DependencyTodo.serialize %>]
|
173
180
|
<%- end -%>
|
174
181
|
<%- end -%>
|
175
182
|
LEGEND_NODE_1 [ label="" peripheries=0 height=0 width=0 style=invis ]
|
@@ -198,4 +205,4 @@ digraph package_diagram {
|
|
198
205
|
LEGEND_NODE_2 -> "<%= all_team_names.last %><%= all_team_names.last %>" [style=invis]
|
199
206
|
<%- end -%>
|
200
207
|
<%- end -%>
|
201
|
-
}
|
208
|
+
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#typed: strict
|
3
|
+
|
4
|
+
require "optparse"
|
5
|
+
|
6
|
+
class OptionsParser
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
sig { params(args: T::Array[String]).returns(Options) }
|
10
|
+
def self.parse(args)
|
11
|
+
options = Options.new
|
12
|
+
|
13
|
+
OptionParser.new do |opt|
|
14
|
+
opt.on('--no-legend', "Don't show legend") { |o| options.show_legend = false }
|
15
|
+
|
16
|
+
opt.on('--no-dependency-arrows', "Don't show accepted dependency arrows") { |o| options.show_dependencies = false }
|
17
|
+
opt.on('--no-privacy-boxes', "Don't show privacy enforcement box on a pack") { |o| options.show_privacy = false }
|
18
|
+
opt.on('--no-layers', "Don't show architectural layers") { |o| options.show_layers = false }
|
19
|
+
opt.on('--no-visibility-arrows', "Don't show visibility arrows") { |o| options.show_visibility = false }
|
20
|
+
|
21
|
+
opt.on('--no-todo-edges', "Don't show todos for package relationships") { |o| options.show_relationship_todos = false }
|
22
|
+
opt.on("--edge-todo-types=STRING", "Show only the selected types of relationship todos. Comma-separated list of #{EdgeTodoTypes.values.map &:serialize}") { |o| options.relationship_todo_types = o.to_s.split(",").uniq.map { EdgeTodoTypes.deserialize(_1) } }
|
23
|
+
opt.on("--use-edge-todos-for-layout", "Show only the selected types of relationship todos. Comma-separated list of #{EdgeTodoTypes.values.map &:serialize}") { |o| options.use_relationship_todos_for_layout = true }
|
24
|
+
|
25
|
+
opt.on('--no-teams', "Don't show team colors") { |o| options.show_teams = false }
|
26
|
+
opt.on('--no-node-todos', "Don't show package-based todos") { |o| options.show_node_todos = false }
|
27
|
+
|
28
|
+
opt.on('--focus-pack=STRING', "Focus on a specific pack(s). Comma-separated list of packs. Wildcards supported: 'packs/*'") { |o| options.focus_pack = o.to_s.split(",") }
|
29
|
+
opt.on('--focus-pack-edge-mode=STRING', "If focus-pack is set, this shows only between focussed packs (when set to none) or the edges into / out of / in and out of the focus packs to non-focus packs (which will be re-added to the graph). One of #{FocusPackEdgeDirection.values.map &:serialize}") { |o| options.show_only_edges_to_focus_pack = FocusPackEdgeDirection.deserialize(o) }
|
30
|
+
opt.on('--exclude-packs=', "Exclude listed packs from diagram. If used with include you will get all included that are not excluded. Wildcards support: 'packs/ignores/*'") { |o| options.exclude_packs = o.to_s.split(",") }
|
31
|
+
|
32
|
+
opt.on('--roll-nested-into-parent-packs', "Don't show nested packs (not counting root). Connect edges to top-level pack instead") { |o| options.roll_nested_into_parent_packs = true }
|
33
|
+
opt.on('--no-nesting-arrows', "Don't draw relationships between parents and nested packs") { |o| options.show_nested_relationships = false }
|
34
|
+
|
35
|
+
opt.on('--remote-base-url=STRING', "Link pack packs to a URL (affects graphviz SVG generation)") { |o| options.remote_base_url = o }
|
36
|
+
|
37
|
+
opt.on('--title=STRING', "Set a custom diagram title") { |o| options.title = o }
|
38
|
+
|
39
|
+
opt.on('-V', '--version', "Show version") do
|
40
|
+
spec_path = File.expand_path("../visualize_packs.gemspec", __dir__)
|
41
|
+
spec = Gem::Specification::load(spec_path)
|
42
|
+
puts "Version #{spec.version}"
|
43
|
+
exit
|
44
|
+
end
|
45
|
+
|
46
|
+
opt.on_tail("-h", "--help", "Show this message") do
|
47
|
+
puts opt
|
48
|
+
exit
|
49
|
+
end
|
50
|
+
end.parse(args)
|
51
|
+
|
52
|
+
options
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
data/lib/visualize_packs.rb
CHANGED
@@ -7,6 +7,7 @@ require 'parse_packwerk'
|
|
7
7
|
require 'digest/md5'
|
8
8
|
|
9
9
|
require 'visualize_packs/options'
|
10
|
+
require 'visualize_packs/options_parser'
|
10
11
|
|
11
12
|
module VisualizePacks
|
12
13
|
extend T::Sig
|
@@ -17,14 +18,17 @@ module VisualizePacks
|
|
17
18
|
PrivacyTodo = new('color=darkred style=dashed arrowhead=crow')
|
18
19
|
ArchitectureTodo = new('color=darkred style=dashed arrowhead=obox')
|
19
20
|
VisibilityTodo = new('color=darkred style=dashed arrowhead=tee')
|
21
|
+
FolderVisibilityTodo = new('color=darkred style=dashed arrowhead=odot')
|
20
22
|
ConfiguredDependency = new('color=darkgreen')
|
21
|
-
|
23
|
+
ConfiguredVisibleTo = new('color=blue')
|
22
24
|
ConfiguredNested = new('color=purple')
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
26
|
-
sig { params(
|
27
|
-
def self.package_graph!(
|
28
|
+
sig { params(args: T::Array[String], raw_config: T::Hash[String, T.untyped], packages: T::Array[ParsePackwerk::Package]).returns(String) }
|
29
|
+
def self.package_graph!(args, raw_config, packages)
|
30
|
+
options = OptionsParser.parse(args)
|
31
|
+
|
28
32
|
all_packages = filtered(packages, options).compact.sort_by {|x| x.name }
|
29
33
|
all_packages = remove_nested_packs(all_packages, options)
|
30
34
|
all_package_names = all_packages.map &:name
|
@@ -34,7 +38,7 @@ module VisualizePacks
|
|
34
38
|
node_protection = package_based_todos_text_maker()
|
35
39
|
max_todo_count = max_todo_count(all_packages, show_edge, options)
|
36
40
|
|
37
|
-
title = diagram_title(options, max_todo_count)
|
41
|
+
title = diagram_title(args, options, max_todo_count)
|
38
42
|
|
39
43
|
architecture_layers = (raw_config['architecture_layers'] || []) + ["NotInLayer"]
|
40
44
|
grouped_packages = architecture_layers.inject({}) do |result, key|
|
@@ -67,10 +71,24 @@ module VisualizePacks
|
|
67
71
|
package.config.dig("metadata", "owner") || package.config["owner"]
|
68
72
|
end
|
69
73
|
|
70
|
-
sig { params(options: Options, max_todo_count: T.nilable(Integer)).returns(String) }
|
71
|
-
def self.diagram_title(options, max_todo_count)
|
74
|
+
sig { params(args: T::Array[String], options: Options, max_todo_count: T.nilable(Integer)).returns(String) }
|
75
|
+
def self.diagram_title(args, options, max_todo_count)
|
72
76
|
return "<<b>#{options.title}</b>>" if options.title
|
73
77
|
|
78
|
+
sub_title1_length = 0
|
79
|
+
options_to_display = args.inject('') do |result, item|
|
80
|
+
sub_title1_length += item.length
|
81
|
+
if sub_title1_length > 90
|
82
|
+
sub_title1_length = 0
|
83
|
+
result += "<br/>#{item}"
|
84
|
+
else
|
85
|
+
result += " #{item}"
|
86
|
+
end
|
87
|
+
result
|
88
|
+
end
|
89
|
+
sub_title1 = "<br/>#{options_to_display}"
|
90
|
+
|
91
|
+
|
74
92
|
focus_info = if options.focus_pack
|
75
93
|
"Focus on #{limited_sentence(options.focus_pack)} (Edge mode: #{options.show_only_edges_to_focus_pack.serialize})"
|
76
94
|
else
|
@@ -98,9 +116,9 @@ module VisualizePacks
|
|
98
116
|
main_title = [focus_info, hidden_aspects_title, todo_types, exclusions].compact.join('. ')
|
99
117
|
|
100
118
|
if options.show_relationship_todos && max_todo_count
|
101
|
-
|
119
|
+
sub_title2 = "<br/><font point-size='12'>Widest todo edge is #{max_todo_count} todo#{max_todo_count > 1 ? 's' : ''}</font>"
|
102
120
|
end
|
103
|
-
"<<b>#{main_title}</b>#{
|
121
|
+
"<<b>#{main_title}</b>#{sub_title1}#{sub_title2}>"
|
104
122
|
end
|
105
123
|
|
106
124
|
sig { params(list: T.nilable(T::Array[String])).returns(T.nilable(String)) }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: visualize_packs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.23
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gusto Engineers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-12-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -122,6 +122,7 @@ files:
|
|
122
122
|
- lib/graph.dot.erb
|
123
123
|
- lib/visualize_packs.rb
|
124
124
|
- lib/visualize_packs/options.rb
|
125
|
+
- lib/visualize_packs/options_parser.rb
|
125
126
|
homepage: https://github.com/rubyatscale/visualize_packs
|
126
127
|
licenses:
|
127
128
|
- MIT
|