visualize_packs 0.5.5 → 0.5.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/bin/visualize_packs +2 -2
- data/lib/graph.dot.erb +15 -19
- data/lib/options.rb +1 -1
- data/lib/visualize_packs.rb +46 -28
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 698ac9ebae377a99e2b9b5fe62c3646bcaa8b4ce81439feee7354d81d80682c1
|
4
|
+
data.tar.gz: 15335a5ce4cc6eb90926af902da548c268bc6c86caa8ae6fd9df5127cfb7e071
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79f8106bfafe0a7cd9c17ff6f886871b4a24990e562a389b5dab45ff5838a3a0a22fc225d44ea7afcdeb8d8a20ff98e2037b74ed95cd170964027b8b53d40176
|
7
|
+
data.tar.gz: 5e5d466148f46ee4876baa8ae184187115bc5d77f66d36d8396867c4fb61066f47ac6b32e22781fcbd4d98c7b387f60f271a8b0cc1a89f91ba383462ca48fcec
|
data/README.md
CHANGED
@@ -16,7 +16,7 @@ This will generate a local dependency diagram for every pack in your app
|
|
16
16
|
find . -iname 'package.yml' | sed 's/\/package.yml//g' | sed 's/\.\///' | xargs -I % sh -c "bundle exec visualize_packs --only=% > %/packs.dot && dot %/packs.dot -Tpng -o %/packs.png"
|
17
17
|
```
|
18
18
|
|
19
|
-
If your app is large and has many packages and
|
19
|
+
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
20
|
|
21
21
|
```
|
22
22
|
find . -iname 'package.yml' | sed 's/\/package.yml//g' | sed 's/\.\///' | xargs -I % sh -c "bundle exec visualize_packs --only=% --only-edges-to-focus > %/packs.dot && dot %/packs.dot -Tpng -o %/packs.png"
|
data/bin/visualize_packs
CHANGED
@@ -35,9 +35,9 @@ OptionParser.new do |opt|
|
|
35
35
|
opt.on('--focus-on=PACKAGE', "Focus on a specific package") { |o| options.focus_package = o }
|
36
36
|
opt.on('--only-edges-to-focus', "If focus is set, this shows only the edges to/from the focus node instead of all edges in the focussed graph. This only has effect when --focus-on is set.") { |o| options.show_only_edges_to_focus_package = true }
|
37
37
|
|
38
|
-
opt.on('--
|
38
|
+
opt.on('--roll-nested-into-parent-packs', "Don't show nested packages (not counting root). Connect edges to top-level package instead") { |o| options.roll_nested_into_parent_packs = true }
|
39
39
|
opt.on('--focus_folder=FOLDER', "Draw package diagram only for packages in FOLDER") { |o| options.focus_folder = o }
|
40
|
-
opt.on('--no_nested_relationships', "Don't draw nested
|
40
|
+
opt.on('--no_nested_relationships', "Don't draw relationships between parents and nested packs") { |o| options.show_nested_relationships = false }
|
41
41
|
|
42
42
|
opt.on('--exclude-packs=pack1,pack2,etc', "Exclude these packs from diagram") { |o| options.exclude_packs = o.to_s.split(",") }
|
43
43
|
|
data/lib/graph.dot.erb
CHANGED
@@ -81,32 +81,28 @@ digraph package_diagram {
|
|
81
81
|
<%- end -%>
|
82
82
|
<%- if options.show_todos -%>
|
83
83
|
<%- all_packages.each do |package| -%>
|
84
|
-
<%-
|
84
|
+
<%- filtered_todos = package.violations -%>
|
85
85
|
<%- if options.only_todo_types.any? -%>
|
86
|
-
<%-
|
86
|
+
<%- filtered_todos = filtered_todos.select { options.only_todo_types.include?(_1.type) } -%>
|
87
87
|
<%- end -%>
|
88
|
-
<%-
|
89
|
-
<%-
|
90
|
-
<%- todo_types =
|
91
|
-
<%- todo_types.keys.each do |
|
92
|
-
<%- if show_edge.call(package.name,
|
93
|
-
"<%= package.name -%>" -> "<%=
|
88
|
+
<%- todos_by_package = filtered_todos.group_by(&:to_package_name) -%>
|
89
|
+
<%- todos_by_package.keys.each do |todos_to_package| -%>
|
90
|
+
<%- todo_types = todos_by_package[todos_to_package].group_by(&:type) -%>
|
91
|
+
<%- todo_types.keys.each do |todo_type| -%>
|
92
|
+
<%- if show_edge.call(package.name, todos_to_package) -%>
|
93
|
+
"<%= package.name -%>" -> "<%= todos_to_package -%>"<%= todo_type == 'privacy' ? ':private' : '' -%> [ color=darkred style=dashed
|
94
94
|
constraint=false
|
95
|
-
# headlabel="<%=
|
96
|
-
<%- if
|
95
|
+
# headlabel="<%= todo_type -%>"
|
96
|
+
<%- if todo_type == 'privacy' -%>
|
97
97
|
arrowhead=crow
|
98
|
-
<%- elsif
|
98
|
+
<%- elsif todo_type == 'architecture' -%>
|
99
99
|
arrowhead=invodot
|
100
|
-
<%- elsif
|
100
|
+
<%- elsif todo_type == 'visibility' -%>
|
101
101
|
arrowhead=obox
|
102
|
-
<%- elsif
|
102
|
+
<%- elsif todo_type == 'dependency' -%>
|
103
103
|
arrowhead=odot
|
104
104
|
<%- end -%>
|
105
|
-
|
106
|
-
max_edge_width = 10
|
107
|
-
edge_width = (todo_types[violation_type].count / max_violation_count.to_f * max_edge_width).to_i
|
108
|
-
-%>
|
109
|
-
penwidth=<%= edge_width -%>
|
105
|
+
penwidth=<%= todo_edge_width(todo_types[todo_type].count, max_todo_count) -%>
|
110
106
|
]
|
111
107
|
<%- end -%>
|
112
108
|
<%- end -%>
|
@@ -139,7 +135,7 @@ digraph package_diagram {
|
|
139
135
|
K [ fontsize=12 shape=box label="package"]
|
140
136
|
L [ fontsize=12 shape=box label="package"]
|
141
137
|
A -> B [label="accepted dependency" color=darkgreen]
|
142
|
-
C -> D [label="
|
138
|
+
C -> D [label="privacy todo" color=darkred style=dashed arrowhead=crow]
|
143
139
|
E -> F [label="architecture todo" color=darkred style=dashed arrowhead=invodot]
|
144
140
|
G -> H [label="visibility todo" color=darkred style=dashed arrowhead=obox]
|
145
141
|
I -> J [label="dependency todo" color=darkred style=dashed arrowhead=odot]
|
data/lib/options.rb
CHANGED
@@ -15,7 +15,7 @@ class Options < T::Struct
|
|
15
15
|
prop :focus_package, T.nilable(String)
|
16
16
|
prop :show_only_edges_to_focus_package, T::Boolean, default: false
|
17
17
|
|
18
|
-
prop :
|
18
|
+
prop :roll_nested_into_parent_packs, T::Boolean, default: false
|
19
19
|
prop :focus_folder, T.nilable(String)
|
20
20
|
prop :show_nested_relationships, T::Boolean, default: true
|
21
21
|
|
data/lib/visualize_packs.rb
CHANGED
@@ -14,13 +14,13 @@ module VisualizePacks
|
|
14
14
|
all_packages = filtered(packages, options.focus_package, options.focus_folder, options.exclude_packs).sort_by {|x| x.name }
|
15
15
|
all_package_names = all_packages.map &:name
|
16
16
|
|
17
|
-
all_packages = remove_nested_packs(all_packages) if options.
|
17
|
+
all_packages = remove_nested_packs(all_packages) if options.roll_nested_into_parent_packs
|
18
18
|
|
19
19
|
show_edge = show_edge_builder(options, all_package_names)
|
20
20
|
node_color = node_color_builder()
|
21
|
-
|
21
|
+
max_todo_count = max_todo_count(all_packages, show_edge)
|
22
22
|
|
23
|
-
title = diagram_title(options,
|
23
|
+
title = diagram_title(options, max_todo_count)
|
24
24
|
|
25
25
|
architecture_layers = (raw_config['architecture_layers'] || []) + ["NotInLayer"]
|
26
26
|
grouped_packages = architecture_layers.inject({}) do |result, key|
|
@@ -52,7 +52,7 @@ module VisualizePacks
|
|
52
52
|
package.config.dig("metadata", "owner") || package.config["owner"]
|
53
53
|
end
|
54
54
|
|
55
|
-
def self.diagram_title(options,
|
55
|
+
def self.diagram_title(options, max_todo_count)
|
56
56
|
app_name = File.basename(Dir.pwd)
|
57
57
|
focus_edge_info = options.focus_package && options.show_only_edges_to_focus_package ? "showing only edges to/from focus pack" : "showing all edges between visible packs"
|
58
58
|
focus_info = options.focus_package || options.focus_folder ? "Focus on #{[options.focus_package, options.focus_folder].compact.join(' and ')} (#{focus_edge_info})" : "All packs"
|
@@ -65,14 +65,14 @@ module VisualizePacks
|
|
65
65
|
options.only_todo_types.empty? ? nil : "only #{limited_sentence(options.only_todo_types)} todos",
|
66
66
|
options.show_privacy ? nil : "hiding privacy",
|
67
67
|
options.show_teams ? nil : "hiding teams",
|
68
|
-
options.
|
68
|
+
options.roll_nested_into_parent_packs ? "hiding nested packs" : nil,
|
69
69
|
options.show_nested_relationships ? nil : "hiding nested relationships",
|
70
70
|
options.exclude_packs.empty? ? nil : "excluding pack#{options.exclude_packs.size > 1 ? 's' : ''}: #{limited_sentence(options.exclude_packs)}",
|
71
71
|
].compact.join(', ').strip
|
72
72
|
main_title = "#{app_name}: #{focus_info}#{skipped_info != '' ? ' - ' + skipped_info : ''}"
|
73
73
|
sub_title = ""
|
74
|
-
if options.show_todos &&
|
75
|
-
sub_title = "<br/><font point-size='12'>Widest todo edge is #{
|
74
|
+
if options.show_todos && max_todo_count
|
75
|
+
sub_title = "<br/><font point-size='12'>Widest todo edge is #{max_todo_count} todo#{max_todo_count > 1 ? 's' : ''}</font>"
|
76
76
|
end
|
77
77
|
"<<b>#{main_title}</b>#{sub_title}>"
|
78
78
|
end
|
@@ -113,24 +113,43 @@ module VisualizePacks
|
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
|
-
def self.
|
117
|
-
|
116
|
+
def self.max_todo_count(all_packages, show_edge)
|
117
|
+
todo_counts = {}
|
118
118
|
all_packages.each do |package|
|
119
|
-
|
120
|
-
|
121
|
-
todo_types =
|
122
|
-
todo_types.keys.each do |
|
123
|
-
if show_edge.call(package.name,
|
124
|
-
key = "#{package.name}->#{
|
125
|
-
|
126
|
-
#
|
119
|
+
todos_by_package = package.violations.group_by(&:to_package_name)
|
120
|
+
todos_by_package.keys.each do |todos_to_package|
|
121
|
+
todo_types = todos_by_package[todos_to_package].group_by(&:type)
|
122
|
+
todo_types.keys.each do |todo_type|
|
123
|
+
if show_edge.call(package.name, todos_to_package)
|
124
|
+
key = "#{package.name}->#{todos_to_package}:#{todo_type}"
|
125
|
+
todo_counts[key] = todo_types[todo_type].count
|
126
|
+
# todo_counts[key] += 1
|
127
127
|
end
|
128
128
|
end
|
129
129
|
end
|
130
130
|
end
|
131
|
-
|
131
|
+
todo_counts.values.max
|
132
132
|
end
|
133
133
|
|
134
|
+
def self.todo_edge_width(todo_count, max_count)
|
135
|
+
# Limits
|
136
|
+
min_width = 1
|
137
|
+
max_width = 10
|
138
|
+
min_count = 1 # Number of todos equivalent to min_width
|
139
|
+
|
140
|
+
# Ensure safe values
|
141
|
+
return 0 if todo_count < min_count
|
142
|
+
return max_width if todo_count > max_count
|
143
|
+
|
144
|
+
todo_range = max_count - min_count
|
145
|
+
width_range = max_width - min_width
|
146
|
+
count_delta = todo_count - min_count
|
147
|
+
|
148
|
+
width_delta = count_delta / todo_range.to_f * width_range
|
149
|
+
edge_width = min_width + width_delta
|
150
|
+
edge_width.round(2)
|
151
|
+
end
|
152
|
+
|
134
153
|
def self.filtered(packages, filter_package, filter_folder, exclude_packs)
|
135
154
|
return packages unless filter_package || filter_folder || exclude_packs.any?
|
136
155
|
|
@@ -159,13 +178,12 @@ module VisualizePacks
|
|
159
178
|
def self.all_nested_packages(all_package_names)
|
160
179
|
all_package_names.reject { |p| p == '.' }.inject({}) do |result, package|
|
161
180
|
package_map_tally = all_package_names.map { |other_package| Pathname.new(package).parent.to_s.include?(other_package) }
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
end
|
181
|
+
|
182
|
+
acc = []
|
183
|
+
all_package_names.each_with_index { |pack, idx| acc << pack if package_map_tally[idx] }
|
184
|
+
acc.sort_by(&:length)
|
185
|
+
result[package] = acc.first unless acc.empty?
|
186
|
+
|
169
187
|
result
|
170
188
|
end
|
171
189
|
end
|
@@ -201,7 +219,7 @@ module VisualizePacks
|
|
201
219
|
nested_packages[d] || d
|
202
220
|
end.uniq.reject { |p| p == package.name }
|
203
221
|
|
204
|
-
|
222
|
+
morphed_todos = package.violations.map do |v|
|
205
223
|
ParsePackwerk::Violation.new(
|
206
224
|
type: v.type,
|
207
225
|
to_package_name: nested_packages[v.to_package_name] || v.to_package_name,
|
@@ -219,10 +237,10 @@ module VisualizePacks
|
|
219
237
|
metadata: package.metadata,
|
220
238
|
dependencies: morphed_dependencies,
|
221
239
|
config: package.config,
|
222
|
-
violations:
|
240
|
+
violations: morphed_todos
|
223
241
|
)
|
224
242
|
# add dependencies TO nested packages to top-level package
|
225
|
-
# add
|
243
|
+
# add todos TO nested packages to top-level package
|
226
244
|
end
|
227
245
|
end
|
228
246
|
|
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.7
|
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-08-
|
11
|
+
date: 2023-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|