visualize_packs 0.5.3 → 0.5.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/visualize_packs +18 -1
- data/lib/graph.dot.erb +35 -27
- data/lib/options.rb +4 -0
- data/lib/visualize_packs.rb +21 -6
- 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: b4ade528fc794c71afb2470d457f31d72b2456b85a484f2b328ca1c73e7fc2cf
|
4
|
+
data.tar.gz: 239feaba7ced4136ac77625e6ed1632a031492e86ca6d1c0d025976b23e31300
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 18a67a3b983c99f4d273a8e32e390a63bb0fa0398c7da51d4552fee73eedda0e77debfe45a3e196cae5b8d0e370124f7eeb82d202f4daba7b68bb90fb5b15708
|
7
|
+
data.tar.gz: 60e06eaacba3c796ee9045223d47203f63b19e83664c58b9db69696c591f68169f217bc8172287fcb9cc61befaa2008c4a337e486febd0477b6a0b8d14100520
|
data/bin/visualize_packs
CHANGED
@@ -10,20 +10,37 @@ require_relative '../lib/options'
|
|
10
10
|
|
11
11
|
options = Options.new
|
12
12
|
|
13
|
+
supported_todo_types = %w[
|
14
|
+
privacy
|
15
|
+
architecture
|
16
|
+
visibility
|
17
|
+
dependency
|
18
|
+
].sort.freeze
|
19
|
+
|
20
|
+
def validated_list(o, valid_arguments)
|
21
|
+
list = o.to_s.split(",").uniq
|
22
|
+
raise OptionParser::InvalidArgument, o unless (list - valid_arguments).empty?
|
23
|
+
list
|
24
|
+
end
|
25
|
+
|
13
26
|
OptionParser.new do |opt|
|
27
|
+
opt.on('--no-legend', "Don't show legend") { |o| options.show_legend = false }
|
14
28
|
opt.on('--no-layers', "Don't show architectural layers") { |o| options.show_layers = false }
|
15
29
|
opt.on('--no-dependencies', "Don't show accepted dependencies") { |o| options.show_dependencies = false }
|
16
30
|
opt.on('--no-todos', "Don't show package todos") { |o| options.show_todos = false }
|
31
|
+
opt.on('--only-todo-types=privacy,architecture,etc', "Show only these types of todos (supported types: #{supported_todo_types.join(', ')})") { |o| options.only_todo_types = validated_list(o, supported_todo_types) }
|
17
32
|
opt.on('--no-privacy', "Don't show privacy enforcement") { |o| options.show_privacy = false }
|
18
33
|
opt.on('--no-teams', "Don't show team colors") { |o| options.show_teams = false }
|
19
34
|
|
20
|
-
opt.on('--focus-on=PACKAGE', "
|
35
|
+
opt.on('--focus-on=PACKAGE', "Focus on a specific package") { |o| options.focus_package = o }
|
21
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 }
|
22
37
|
|
23
38
|
opt.on('--roll_nested_todos_into_top_level', "Don't show nested packages (not counting root). Connect edges to top-level package instead") { |o| options.roll_nested_todos_into_top_level = true }
|
24
39
|
opt.on('--focus_folder=FOLDER', "Draw package diagram only for packages in FOLDER") { |o| options.focus_folder = o }
|
25
40
|
opt.on('--no_nested_relationships', "Don't draw nested package relationships") { |o| options.show_nested_relationships = false }
|
26
41
|
|
42
|
+
opt.on('--exclude-packs=pack1,pack2,etc', "Exclude these packs from diagram") { |o| options.exclude_packs = o.to_s.split(",") }
|
43
|
+
|
27
44
|
opt.on('--remote-base-url=PACKAGE', "Link package nodes to an URL (affects graphviz SVG generation)") { |o| options.remote_base_url = o }
|
28
45
|
|
29
46
|
opt.on_tail("-h", "--help", "Show this message") do
|
data/lib/graph.dot.erb
CHANGED
@@ -81,10 +81,14 @@ digraph package_diagram {
|
|
81
81
|
<%- end -%>
|
82
82
|
<%- if options.show_todos -%>
|
83
83
|
<%- all_packages.each do |package| -%>
|
84
|
-
<%-
|
84
|
+
<%- filtered_violations = package.violations -%>
|
85
|
+
<%- if options.only_todo_types.any? -%>
|
86
|
+
<%- filtered_violations = filtered_violations.select { options.only_todo_types.include?(_1.type) } -%>
|
87
|
+
<%- end -%>
|
88
|
+
<%- violations_by_package = filtered_violations.group_by(&:to_package_name) -%>
|
85
89
|
<%- violations_by_package.keys.each do |violations_to_package| -%>
|
86
|
-
<%-
|
87
|
-
<%-
|
90
|
+
<%- todo_types = violations_by_package[violations_to_package].group_by(&:type) -%>
|
91
|
+
<%- todo_types.keys.each do |violation_type| -%>
|
88
92
|
<%- if show_edge.call(package.name, violations_to_package) -%>
|
89
93
|
"<%= package.name -%>" -> "<%= violations_to_package -%>"<%= violation_type == 'privacy' ? ':private' : '' -%> [ color=darkred style=dashed
|
90
94
|
constraint=false
|
@@ -100,7 +104,7 @@ digraph package_diagram {
|
|
100
104
|
<%- end -%>
|
101
105
|
<%-
|
102
106
|
max_edge_width = 10
|
103
|
-
edge_width = (
|
107
|
+
edge_width = (todo_types[violation_type].count / max_violation_count.to_f * max_edge_width).to_i
|
104
108
|
-%>
|
105
109
|
penwidth=<%= edge_width -%>
|
106
110
|
]
|
@@ -118,28 +122,30 @@ digraph package_diagram {
|
|
118
122
|
<%- end -%>
|
119
123
|
<%- end -%>
|
120
124
|
<%- end -%>
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
125
|
+
<%- if options.show_legend -%>
|
126
|
+
subgraph cluster_legend {
|
127
|
+
fontsize=16
|
128
|
+
label="Edges Styles and Arrow Heads"
|
129
|
+
A [ fontsize=12 shape=box label="package"]
|
130
|
+
B [ fontsize=12 shape=box label="package"]
|
131
|
+
C [ fontsize=12 shape=box label="package"]
|
132
|
+
D [ fontsize=12 shape=box label="package"]
|
133
|
+
E [ fontsize=12 shape=box label="package"]
|
134
|
+
F [ fontsize=12 shape=box label="package"]
|
135
|
+
G [ fontsize=12 shape=box label="package"]
|
136
|
+
H [ fontsize=12 shape=box label="package"]
|
137
|
+
I [ fontsize=12 shape=box label="package"]
|
138
|
+
J [ fontsize=12 shape=box label="package"]
|
139
|
+
K [ fontsize=12 shape=box label="package"]
|
140
|
+
L [ fontsize=12 shape=box label="package"]
|
141
|
+
A -> B [label="accepted dependency" color=darkgreen]
|
142
|
+
C -> D [label="privac todo" color=darkred style=dashed arrowhead=crow]
|
143
|
+
E -> F [label="architecture todo" color=darkred style=dashed arrowhead=invodot]
|
144
|
+
G -> H [label="visibility todo" color=darkred style=dashed arrowhead=obox]
|
145
|
+
I -> J [label="dependency todo" color=darkred style=dashed arrowhead=odot]
|
146
|
+
K -> L [label="nested package" color=purple penwidth=3]
|
147
|
+
}
|
148
|
+
<%- end -%>
|
143
149
|
<%- if options.show_teams && all_team_names != [] -%>
|
144
150
|
subgraph cluster_teams_legend {
|
145
151
|
fontsize=16
|
@@ -157,6 +163,8 @@ digraph package_diagram {
|
|
157
163
|
<%- end %>
|
158
164
|
<%- end -%>
|
159
165
|
}
|
160
|
-
|
166
|
+
<%- if options.show_legend -%>
|
167
|
+
J -> "<%= all_team_names.last %><%= all_team_names.last %>" [style=invis]
|
168
|
+
<%- end -%>
|
161
169
|
<%- end -%>
|
162
170
|
}
|
data/lib/options.rb
CHANGED
@@ -4,9 +4,11 @@
|
|
4
4
|
class Options < T::Struct
|
5
5
|
extend T::Sig
|
6
6
|
|
7
|
+
prop :show_legend, T::Boolean, default: true
|
7
8
|
prop :show_layers, T::Boolean, default: true
|
8
9
|
prop :show_dependencies, T::Boolean, default: true
|
9
10
|
prop :show_todos, T::Boolean, default: true
|
11
|
+
prop :only_todo_types, T::Array[String], default: []
|
10
12
|
prop :show_privacy, T::Boolean, default: true
|
11
13
|
prop :show_teams, T::Boolean, default: true
|
12
14
|
|
@@ -17,5 +19,7 @@ class Options < T::Struct
|
|
17
19
|
prop :focus_folder, T.nilable(String)
|
18
20
|
prop :show_nested_relationships, T::Boolean, default: true
|
19
21
|
|
22
|
+
prop :exclude_packs, T::Array[String], default: []
|
23
|
+
|
20
24
|
prop :remote_base_url, T.nilable(String)
|
21
25
|
end
|
data/lib/visualize_packs.rb
CHANGED
@@ -11,7 +11,7 @@ module VisualizePacks
|
|
11
11
|
def self.package_graph!(options, raw_config, packages)
|
12
12
|
raise ArgumentError, "Package #{options.focus_package} does not exist. Found packages #{packages.map(&:name).join(", ")}" if options.focus_package && !packages.map(&:name).include?(options.focus_package)
|
13
13
|
|
14
|
-
all_packages = filtered(packages, options.focus_package, options.focus_folder).sort_by {|x| x.name }
|
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
17
|
all_packages = remove_nested_packs(all_packages) if options.roll_nested_todos_into_top_level
|
@@ -58,13 +58,16 @@ module VisualizePacks
|
|
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"
|
59
59
|
skipped_info =
|
60
60
|
[
|
61
|
+
options.show_legend ? nil : "hiding legend",
|
61
62
|
options.show_layers ? nil : "hiding layers",
|
62
63
|
options.show_dependencies ? nil : "hiding dependencies",
|
63
64
|
options.show_todos ? nil : "hiding todos",
|
65
|
+
options.only_todo_types.empty? ? nil : "only #{limited_sentence(options.only_todo_types)} todos",
|
64
66
|
options.show_privacy ? nil : "hiding privacy",
|
65
67
|
options.show_teams ? nil : "hiding teams",
|
66
68
|
options.roll_nested_todos_into_top_level ? "hiding nested packs" : nil,
|
67
69
|
options.show_nested_relationships ? nil : "hiding nested relationships",
|
70
|
+
options.exclude_packs.empty? ? nil : "excluding pack#{options.exclude_packs.size > 1 ? 's' : ''}: #{limited_sentence(options.exclude_packs)}",
|
68
71
|
].compact.join(', ').strip
|
69
72
|
main_title = "#{app_name}: #{focus_info}#{skipped_info != '' ? ' - ' + skipped_info : ''}"
|
70
73
|
sub_title = ""
|
@@ -74,6 +77,14 @@ module VisualizePacks
|
|
74
77
|
"<<b>#{main_title}</b>#{sub_title}>"
|
75
78
|
end
|
76
79
|
|
80
|
+
def self.limited_sentence(list)
|
81
|
+
if list.size <= 2
|
82
|
+
list.join(" and ")
|
83
|
+
else
|
84
|
+
"#{list[0, 2].join(", ")}, and #{list.size - 2} more"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
77
88
|
def self.show_edge_builder(options, all_package_names)
|
78
89
|
return lambda do |start_node, end_node|
|
79
90
|
(
|
@@ -107,11 +118,11 @@ module VisualizePacks
|
|
107
118
|
all_packages.each do |package|
|
108
119
|
violations_by_package = package.violations.group_by(&:to_package_name)
|
109
120
|
violations_by_package.keys.each do |violations_to_package|
|
110
|
-
|
111
|
-
|
121
|
+
todo_types = violations_by_package[violations_to_package].group_by(&:type)
|
122
|
+
todo_types.keys.each do |violation_type|
|
112
123
|
if show_edge.call(package.name, violations_to_package)
|
113
124
|
key = "#{package.name}->#{violations_to_package}:#{violation_type}"
|
114
|
-
violation_counts[key] =
|
125
|
+
violation_counts[key] = todo_types[violation_type].count
|
115
126
|
# violation_counts[key] += 1
|
116
127
|
end
|
117
128
|
end
|
@@ -120,8 +131,8 @@ module VisualizePacks
|
|
120
131
|
violation_counts.values.max
|
121
132
|
end
|
122
133
|
|
123
|
-
def self.filtered(packages, filter_package, filter_folder)
|
124
|
-
return packages unless filter_package || filter_folder
|
134
|
+
def self.filtered(packages, filter_package, filter_folder, exclude_packs)
|
135
|
+
return packages unless filter_package || filter_folder || exclude_packs.any?
|
125
136
|
|
126
137
|
result = packages.map { |pack| pack.name }
|
127
138
|
|
@@ -138,6 +149,10 @@ module VisualizePacks
|
|
138
149
|
result = result.select { |p| p.include? filter_folder }
|
139
150
|
end
|
140
151
|
|
152
|
+
if exclude_packs.any?
|
153
|
+
result = result.reject { |p| exclude_packs.include? p }
|
154
|
+
end
|
155
|
+
|
141
156
|
result.map { |pack_name| ParsePackwerk.find(pack_name) }
|
142
157
|
end
|
143
158
|
|
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.5
|
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-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|