visualize_packs 0.5.10 → 0.5.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/visualize_packs +3 -3
- data/lib/graph.dot.erb +1 -1
- data/lib/options.rb +1 -1
- data/lib/visualize_packs.rb +70 -34
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1c97e3f2997e104fa0359775892adfb5e8cc40d22a85d886bf0f8a1d608398a8
|
4
|
+
data.tar.gz: 7b933103509243b81126bc29cd193daf9536a46860d36ad40f1d988df29d77b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e0c1ca8ea26ee9cbd57b3e4066960868ea9362de4bae5fad1517481376ba8f3dd476ff8ad1f43c186d9b9c9d291a7332c203b877e37d5e9d6e07f4277d70899
|
7
|
+
data.tar.gz: 632e641dc9e1c45dd744bf9d09bff3cc9723138bc8eb27c1d6771afdc51ad3aef2de988801420b64a1c7f27155fb530fcbfe66cd3c4c65e7eb3b4c6de5e220e6
|
data/bin/visualize_packs
CHANGED
@@ -32,12 +32,12 @@ OptionParser.new do |opt|
|
|
32
32
|
opt.on('--no-privacy', "Don't show privacy enforcement") { |o| options.show_privacy = false }
|
33
33
|
opt.on('--no-teams', "Don't show team colors") { |o| options.show_teams = false }
|
34
34
|
|
35
|
-
opt.on('--focus-
|
35
|
+
opt.on('--focus-folder=FOLDER', "Draw package diagram only for packages in FOLDER. Matches with 'include' for partial matches") { |o| options.focus_folder = o.empty? ? nil : o }
|
36
|
+
opt.on('--focus-pack=pack1,pack2', "Focus on a specific package(s). Wildcards support: 'packs/*'") { |o| options.focus_package = o.to_s.split(",") }
|
36
37
|
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
38
|
|
38
39
|
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
|
-
opt.on('--
|
40
|
-
opt.on('--no_nested_relationships', "Don't draw relationships between parents and nested packs") { |o| options.show_nested_relationships = false }
|
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 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(",") }
|
43
43
|
opt.on('--include-packs=pack1,pack2,etc', "Include only listed packs in diagram. If used with exclude you will get all included that are not excluded. Wildcards support: 'packs/ignores/*'") { |o| options.include_packs = o.to_s.split(",") }
|
data/lib/graph.dot.erb
CHANGED
@@ -33,7 +33,7 @@ digraph package_diagram {
|
|
33
33
|
<%- end -%>
|
34
34
|
<%- grouped_packages[layer_name].each do |package| -%>
|
35
35
|
"<%= package.name -%>" [
|
36
|
-
fontsize=<%= options.focus_package &&
|
36
|
+
fontsize=<%= options.focus_package.any? && options.focus_package.any? {|p| File.fnmatch(p, package.name)} ? 18.0 : 12.0 -%>
|
37
37
|
<%- if options.remote_base_url %>
|
38
38
|
URL="<%= options.remote_base_url %>/<%= package.name == '.' ? '' : package.name -%>"
|
39
39
|
<%- end %>
|
data/lib/options.rb
CHANGED
@@ -12,7 +12,7 @@ class Options < T::Struct
|
|
12
12
|
prop :show_privacy, T::Boolean, default: true
|
13
13
|
prop :show_teams, T::Boolean, default: true
|
14
14
|
|
15
|
-
prop :focus_package, T
|
15
|
+
prop :focus_package, T::Array[String], default: []
|
16
16
|
prop :show_only_edges_to_focus_package, T::Boolean, default: false
|
17
17
|
|
18
18
|
prop :roll_nested_into_parent_packs, T::Boolean, default: false
|
data/lib/visualize_packs.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# typed:
|
2
|
+
# typed: strict
|
3
3
|
|
4
4
|
require 'erb'
|
5
5
|
require 'packs-specification'
|
@@ -7,14 +7,14 @@ require 'parse_packwerk'
|
|
7
7
|
require 'digest/md5'
|
8
8
|
|
9
9
|
module VisualizePacks
|
10
|
+
extend T::Sig
|
10
11
|
|
12
|
+
sig { params(options: Options, raw_config: T::Hash[String, T.untyped], packages: T::Array[ParsePackwerk::Package]).returns(String) }
|
11
13
|
def self.package_graph!(options, raw_config, packages)
|
12
|
-
|
13
|
-
|
14
|
-
all_packages = filtered(packages, options.focus_package, options.focus_folder, options.include_packs, options.exclude_packs).sort_by {|x| x.name }
|
14
|
+
all_packages = filtered(packages, options).compact.sort_by {|x| x.name }
|
15
15
|
all_package_names = all_packages.map &:name
|
16
16
|
|
17
|
-
all_packages = remove_nested_packs(all_packages
|
17
|
+
all_packages = remove_nested_packs(all_packages, options)
|
18
18
|
|
19
19
|
show_edge = show_edge_builder(options, all_package_names)
|
20
20
|
node_color = node_color_builder()
|
@@ -48,14 +48,16 @@ module VisualizePacks
|
|
48
48
|
|
49
49
|
private
|
50
50
|
|
51
|
+
sig { params(package: ParsePackwerk::Package).returns(T.nilable(String)) }
|
51
52
|
def self.code_owner(package)
|
52
53
|
package.config.dig("metadata", "owner") || package.config["owner"]
|
53
54
|
end
|
54
55
|
|
56
|
+
sig { params(options: Options, max_todo_count: T.nilable(Integer)).returns(String) }
|
55
57
|
def self.diagram_title(options, max_todo_count)
|
56
58
|
app_name = File.basename(Dir.pwd)
|
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
|
-
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
|
+
focus_edge_info = options.focus_package.any? && options.show_only_edges_to_focus_package ? "showing only edges to/from focus pack" : "showing all edges between visible packs"
|
60
|
+
focus_info = options.focus_package.any? || options.focus_folder ? "Focus on #{[limited_sentence(options.focus_package), options.focus_folder].compact.join(' and ')} (#{focus_edge_info})" : "All packs"
|
59
61
|
skipped_info =
|
60
62
|
[
|
61
63
|
options.show_legend ? nil : "hiding legend",
|
@@ -78,14 +80,18 @@ module VisualizePacks
|
|
78
80
|
"<<b>#{main_title}</b>#{sub_title}>"
|
79
81
|
end
|
80
82
|
|
83
|
+
sig { params(list: T.nilable(T::Array[String])).returns(T.nilable(String)) }
|
81
84
|
def self.limited_sentence(list)
|
85
|
+
return nil if !list || list.empty?
|
86
|
+
|
82
87
|
if list.size <= 2
|
83
88
|
list.join(" and ")
|
84
89
|
else
|
85
|
-
"#{list[0, 2].join(", ")}, and #{list.size - 2} more"
|
90
|
+
"#{T.must(list[0, 2]).join(", ")}, and #{list.size - 2} more"
|
86
91
|
end
|
87
92
|
end
|
88
93
|
|
94
|
+
sig { params(options: Options, all_package_names: T::Array[String]).returns(T.proc.params(arg0: String, arg1: String).returns(T::Boolean)) }
|
89
95
|
def self.show_edge_builder(options, all_package_names)
|
90
96
|
return lambda do |start_node, end_node|
|
91
97
|
(
|
@@ -97,11 +103,15 @@ module VisualizePacks
|
|
97
103
|
options.show_only_edges_to_focus_package &&
|
98
104
|
all_package_names.include?(start_node) &&
|
99
105
|
all_package_names.include?(end_node) &&
|
100
|
-
|
106
|
+
(
|
107
|
+
match_packs?(start_node, options.focus_package) ||
|
108
|
+
match_packs?(end_node, options.focus_package)
|
109
|
+
)
|
101
110
|
)
|
102
111
|
end
|
103
112
|
end
|
104
113
|
|
114
|
+
sig { returns(T.nilable(T.proc.params(arg0: String).returns(String))) }
|
105
115
|
def self.node_color_builder
|
106
116
|
return lambda do |text|
|
107
117
|
return unless text
|
@@ -114,17 +124,17 @@ module VisualizePacks
|
|
114
124
|
end
|
115
125
|
end
|
116
126
|
|
127
|
+
sig { params(all_packages: T::Array[ParsePackwerk::Package], show_edge: T.proc.params(arg0: String, arg1: String).returns(T::Boolean)).returns(T.nilable(Integer)) }
|
117
128
|
def self.max_todo_count(all_packages, show_edge)
|
118
129
|
todo_counts = {}
|
119
130
|
all_packages.each do |package|
|
120
|
-
todos_by_package = package.violations
|
121
|
-
todos_by_package
|
122
|
-
todo_types = todos_by_package[todos_to_package]
|
123
|
-
todo_types
|
131
|
+
todos_by_package = package.violations&.group_by(&:to_package_name)
|
132
|
+
todos_by_package&.keys&.each do |todos_to_package|
|
133
|
+
todo_types = todos_by_package&& todos_by_package[todos_to_package]&.group_by(&:type)
|
134
|
+
todo_types&.keys&.each do |todo_type|
|
124
135
|
if show_edge.call(package.name, todos_to_package)
|
125
136
|
key = "#{package.name}->#{todos_to_package}:#{todo_type}"
|
126
|
-
todo_counts[key] = todo_types[todo_type]
|
127
|
-
# todo_counts[key] += 1
|
137
|
+
todo_counts[key] = todo_types && todo_types[todo_type]&.count
|
128
138
|
end
|
129
139
|
end
|
130
140
|
end
|
@@ -132,6 +142,7 @@ module VisualizePacks
|
|
132
142
|
todo_counts.values.max
|
133
143
|
end
|
134
144
|
|
145
|
+
sig { params(todo_count: Integer, max_count: Integer).returns(T.any(Float, Integer)) }
|
135
146
|
def self.todo_edge_width(todo_count, max_count)
|
136
147
|
# Limits
|
137
148
|
min_width = 1
|
@@ -151,22 +162,44 @@ module VisualizePacks
|
|
151
162
|
edge_width.round(2)
|
152
163
|
end
|
153
164
|
|
154
|
-
|
155
|
-
|
165
|
+
sig { params(packages: T::Array[ParsePackwerk::Package], options: Options).returns(T::Array[ParsePackwerk::Package]) }
|
166
|
+
def self.filtered(packages, options)
|
167
|
+
focus_package = options.focus_package
|
168
|
+
focus_folder = options.focus_folder
|
169
|
+
include_packs = options.include_packs
|
170
|
+
exclude_packs = options.exclude_packs
|
171
|
+
|
172
|
+
return packages unless focus_package.any? || focus_folder || include_packs || exclude_packs.any?
|
173
|
+
|
174
|
+
nested_packages = all_nested_packages(packages.map { |p| p.name })
|
156
175
|
|
176
|
+
packages_by_name = packages.inject({}) do |res, p|
|
177
|
+
res[p.name] = p
|
178
|
+
res
|
179
|
+
end
|
180
|
+
|
181
|
+
result = T.let([], T::Array[T.nilable(String)])
|
157
182
|
result = packages.map { |pack| pack.name }
|
158
183
|
|
159
|
-
if
|
160
|
-
result = [
|
161
|
-
result += packages.
|
162
|
-
result +=
|
163
|
-
result += packages.select{ |p| p.violations
|
164
|
-
|
184
|
+
if !focus_package.empty?
|
185
|
+
result = []
|
186
|
+
result += packages.map { |pack| pack.name }.select { |p| match_packs?(p, focus_package) }
|
187
|
+
result += packages.select{ |p| p.dependencies.any? { |d| match_packs?(d, focus_package) }}.map { |pack| pack.name }
|
188
|
+
result += packages.select{ |p| p.violations&.map(&:to_package_name)&.any? { |v| match_packs?(v, focus_package) }}.map { |pack| pack.name }
|
189
|
+
packages.map { |pack| pack.name }.select { |p| match_packs?(p, focus_package) }.each do |p|
|
190
|
+
result += packages_by_name[p].dependencies
|
191
|
+
result += packages_by_name[p].violations.map(&:to_package_name)
|
192
|
+
end
|
165
193
|
result = result.uniq
|
194
|
+
parent_packs = result.inject([]) do |res, package_name|
|
195
|
+
res << nested_packages[package_name]
|
196
|
+
res
|
197
|
+
end
|
198
|
+
result = (result + parent_packs).uniq.compact
|
166
199
|
end
|
167
200
|
|
168
|
-
if
|
169
|
-
result = result.select { |p| p.include?
|
201
|
+
if focus_folder
|
202
|
+
result = result.select { |p| p.include? focus_folder }
|
170
203
|
end
|
171
204
|
|
172
205
|
if include_packs
|
@@ -177,9 +210,10 @@ module VisualizePacks
|
|
177
210
|
result = result.reject { |p| match_packs?(p, exclude_packs) }
|
178
211
|
end
|
179
212
|
|
180
|
-
result.map { |pack_name|
|
213
|
+
result.map { |pack_name| packages_by_name[pack_name] }
|
181
214
|
end
|
182
215
|
|
216
|
+
sig { params(all_package_names: T::Array[String]).returns(T::Hash[String, String]) }
|
183
217
|
def self.all_nested_packages(all_package_names)
|
184
218
|
all_package_names.reject { |p| p == '.' }.inject({}) do |result, package|
|
185
219
|
package_map_tally = all_package_names.map { |other_package| Pathname.new(package).parent.to_s.include?(other_package) }
|
@@ -193,7 +227,10 @@ module VisualizePacks
|
|
193
227
|
end
|
194
228
|
end
|
195
229
|
|
196
|
-
|
230
|
+
sig { params(packages: T::Array[ParsePackwerk::Package], options: Options).returns(T::Array[ParsePackwerk::Package]) }
|
231
|
+
def self.remove_nested_packs(packages, options)
|
232
|
+
return packages unless options.roll_nested_into_parent_packs
|
233
|
+
|
197
234
|
nested_packages = all_nested_packages(packages.map { |p| p.name })
|
198
235
|
|
199
236
|
# top-level packages
|
@@ -212,9 +249,9 @@ module VisualizePacks
|
|
212
249
|
enforce_privacy: package.enforce_privacy,
|
213
250
|
public_path: package.public_path,
|
214
251
|
metadata: package.metadata,
|
215
|
-
dependencies: package.dependencies + nested_package.dependencies,
|
252
|
+
dependencies: package.dependencies + T.must(nested_package).dependencies,
|
216
253
|
config: package.config,
|
217
|
-
violations: package.violations + nested_package.violations
|
254
|
+
violations: T.must(package.violations) + T.must(T.must(nested_package).violations)
|
218
255
|
)
|
219
256
|
end
|
220
257
|
end
|
@@ -224,7 +261,7 @@ module VisualizePacks
|
|
224
261
|
nested_packages[d] || d
|
225
262
|
end.uniq.reject { |p| p == package.name }
|
226
263
|
|
227
|
-
morphed_todos = package.violations.map do |v|
|
264
|
+
morphed_todos = T.must(package.violations).map do |v|
|
228
265
|
ParsePackwerk::Violation.new(
|
229
266
|
type: v.type,
|
230
267
|
to_package_name: nested_packages[v.to_package_name] || v.to_package_name,
|
@@ -244,15 +281,14 @@ module VisualizePacks
|
|
244
281
|
config: package.config,
|
245
282
|
violations: morphed_todos
|
246
283
|
)
|
247
|
-
# add dependencies TO nested packages to top-level package
|
248
|
-
# add todos TO nested packages to top-level package
|
249
284
|
end
|
250
285
|
end
|
251
286
|
|
252
287
|
morphed_packages.reject { |p| nested_packages.keys.include?(p.name) }
|
253
288
|
end
|
254
289
|
|
255
|
-
|
256
|
-
|
290
|
+
sig { params(pack: String, packs_name_with_wildcards: T::Array[String]).returns(T::Boolean) }
|
291
|
+
def self.match_packs?(pack, packs_name_with_wildcards)
|
292
|
+
packs_name_with_wildcards.any? {|p| File.fnmatch(p, pack)}
|
257
293
|
end
|
258
294
|
end
|