visualize_packs 0.5.4 → 0.5.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 01f6c9f4bc79fee9a854283bdae4b57d12fa2a29fc53c1610765ef137f69dd68
4
- data.tar.gz: bfb38e97af2696a7ee295341782905340a1458cc62004cd58b077a3caeb1d514
3
+ metadata.gz: bd8d9c383e056e9ca083b753f77d14ff951d2f0245d3cccb8570eb4a6ac5cf72
4
+ data.tar.gz: 98edaf0dd58faabbfc57e3d42b24ca43c5f5ea65227627f519815811a03970a6
5
5
  SHA512:
6
- metadata.gz: 39ee40c6a79f5c883ee1f14ebe9c964fedb65281aadf7ee43163f07a3f9e8f1401379baaf4efd0ccaedb7593d7ab18e28ff8d743e076da6a0028844b2180bb47
7
- data.tar.gz: '0997b1cdf11c0095cb2a0bc00ba0dcd04b9ce58a1aff50b9fd106181806d0be3f36df316111946a2c1719014899043c173216dea0f4bd3301f99fdb5d1d6f368'
6
+ metadata.gz: 541e54ff0460769bccc2d7e8788a57a86c1fbb5929af3cc7b01bbcac36daf0f26bf7378745e89bf189c51fa63b3484c3b34d6493e85e1603cf976f1b6780945e
7
+ data.tar.gz: d0622a5d36ee4816b497f6fb2488be4ee1a86679729432f8304b27ce1120ff16e28fd1baefc790a1372b227932d9cd54ca5c13e7221f91271d33e717ff01f682
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 violations, 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:
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
@@ -10,20 +10,34 @@ 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|
14
27
  opt.on('--no-legend', "Don't show legend") { |o| options.show_legend = false }
15
28
  opt.on('--no-layers', "Don't show architectural layers") { |o| options.show_layers = false }
16
29
  opt.on('--no-dependencies', "Don't show accepted dependencies") { |o| options.show_dependencies = false }
17
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) }
18
32
  opt.on('--no-privacy', "Don't show privacy enforcement") { |o| options.show_privacy = false }
19
33
  opt.on('--no-teams', "Don't show team colors") { |o| options.show_teams = false }
20
34
 
21
35
  opt.on('--focus-on=PACKAGE', "Focus on a specific package") { |o| options.focus_package = o }
22
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 }
23
37
 
24
- 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 }
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 }
25
39
  opt.on('--focus_folder=FOLDER', "Draw package diagram only for packages in FOLDER") { |o| options.focus_folder = o }
26
- opt.on('--no_nested_relationships', "Don't draw nested package relationships") { |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 }
27
41
 
28
42
  opt.on('--exclude-packs=pack1,pack2,etc', "Exclude these packs from diagram") { |o| options.exclude_packs = o.to_s.split(",") }
29
43
 
data/lib/graph.dot.erb CHANGED
@@ -81,26 +81,30 @@ digraph package_diagram {
81
81
  <%- end -%>
82
82
  <%- if options.show_todos -%>
83
83
  <%- all_packages.each do |package| -%>
84
- <%- violations_by_package = package.violations.group_by(&:to_package_name) -%>
85
- <%- violations_by_package.keys.each do |violations_to_package| -%>
86
- <%- violation_types = violations_by_package[violations_to_package].group_by(&:type) -%>
87
- <%- violation_types.keys.each do |violation_type| -%>
88
- <%- if show_edge.call(package.name, violations_to_package) -%>
89
- "<%= package.name -%>" -> "<%= violations_to_package -%>"<%= violation_type == 'privacy' ? ':private' : '' -%> [ color=darkred style=dashed
84
+ <%- filtered_todos = package.violations -%>
85
+ <%- if options.only_todo_types.any? -%>
86
+ <%- filtered_todos = filtered_todos.select { options.only_todo_types.include?(_1.type) } -%>
87
+ <%- end -%>
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
90
94
  constraint=false
91
- # headlabel="<%= violation_type -%>"
92
- <%- if violation_type == 'privacy' -%>
95
+ # headlabel="<%= todo_type -%>"
96
+ <%- if todo_type == 'privacy' -%>
93
97
  arrowhead=crow
94
- <%- elsif violation_type == 'architecture' -%>
98
+ <%- elsif todo_type == 'architecture' -%>
95
99
  arrowhead=invodot
96
- <%- elsif violation_type == 'visibility' -%>
100
+ <%- elsif todo_type == 'visibility' -%>
97
101
  arrowhead=obox
98
- <%- elsif violation_type == 'dependency' -%>
102
+ <%- elsif todo_type == 'dependency' -%>
99
103
  arrowhead=odot
100
104
  <%- end -%>
101
105
  <%-
102
106
  max_edge_width = 10
103
- edge_width = (violation_types[violation_type].count / max_violation_count.to_f * max_edge_width).to_i
107
+ edge_width = (todo_types[todo_type].count / max_todo_count.to_f * max_edge_width).to_i
104
108
  -%>
105
109
  penwidth=<%= edge_width -%>
106
110
  ]
@@ -135,7 +139,7 @@ digraph package_diagram {
135
139
  K [ fontsize=12 shape=box label="package"]
136
140
  L [ fontsize=12 shape=box label="package"]
137
141
  A -> B [label="accepted dependency" color=darkgreen]
138
- C -> D [label="privac todo" color=darkred style=dashed arrowhead=crow]
142
+ C -> D [label="privacy todo" color=darkred style=dashed arrowhead=crow]
139
143
  E -> F [label="architecture todo" color=darkred style=dashed arrowhead=invodot]
140
144
  G -> H [label="visibility todo" color=darkred style=dashed arrowhead=obox]
141
145
  I -> J [label="dependency todo" color=darkred style=dashed arrowhead=odot]
data/lib/options.rb CHANGED
@@ -8,13 +8,14 @@ class Options < T::Struct
8
8
  prop :show_layers, T::Boolean, default: true
9
9
  prop :show_dependencies, T::Boolean, default: true
10
10
  prop :show_todos, T::Boolean, default: true
11
+ prop :only_todo_types, T::Array[String], default: []
11
12
  prop :show_privacy, T::Boolean, default: true
12
13
  prop :show_teams, T::Boolean, default: true
13
14
 
14
15
  prop :focus_package, T.nilable(String)
15
16
  prop :show_only_edges_to_focus_package, T::Boolean, default: false
16
17
 
17
- prop :roll_nested_todos_into_top_level, T::Boolean, default: false
18
+ prop :roll_nested_into_parent_packs, T::Boolean, default: false
18
19
  prop :focus_folder, T.nilable(String)
19
20
  prop :show_nested_relationships, T::Boolean, default: true
20
21
 
@@ -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.roll_nested_todos_into_top_level
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
- max_violation_count = max_violation_count(all_packages, show_edge)
21
+ max_todo_count = max_todo_count(all_packages, show_edge)
22
22
 
23
- title = diagram_title(options, max_violation_count)
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, max_violation_count)
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"
@@ -62,28 +62,26 @@ module VisualizePacks
62
62
  options.show_layers ? nil : "hiding layers",
63
63
  options.show_dependencies ? nil : "hiding dependencies",
64
64
  options.show_todos ? nil : "hiding todos",
65
+ options.only_todo_types.empty? ? nil : "only #{limited_sentence(options.only_todo_types)} todos",
65
66
  options.show_privacy ? nil : "hiding privacy",
66
67
  options.show_teams ? nil : "hiding teams",
67
- options.roll_nested_todos_into_top_level ? "hiding nested packs" : nil,
68
+ options.roll_nested_into_parent_packs ? "hiding nested packs" : nil,
68
69
  options.show_nested_relationships ? nil : "hiding nested relationships",
69
- options.exclude_packs.empty? ? nil : "excluding pack#{options.exclude_packs.size > 1 ? 's' : ''}: #{exclude_packs_info(options.exclude_packs)}",
70
+ options.exclude_packs.empty? ? nil : "excluding pack#{options.exclude_packs.size > 1 ? 's' : ''}: #{limited_sentence(options.exclude_packs)}",
70
71
  ].compact.join(', ').strip
71
72
  main_title = "#{app_name}: #{focus_info}#{skipped_info != '' ? ' - ' + skipped_info : ''}"
72
73
  sub_title = ""
73
- if options.show_todos && max_violation_count
74
- sub_title = "<br/><font point-size='12'>Widest todo edge is #{max_violation_count} violation#{max_violation_count > 1 ? 's' : ''}</font>"
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>"
75
76
  end
76
77
  "<<b>#{main_title}</b>#{sub_title}>"
77
78
  end
78
79
 
79
- def self.exclude_packs_info(exclude_packs)
80
- case exclude_packs.size
81
- when 1
82
- exclude_packs.first
83
- when 2
84
- exclude_packs.join(" and ")
80
+ def self.limited_sentence(list)
81
+ if list.size <= 2
82
+ list.join(" and ")
85
83
  else
86
- "#{exclude_packs[0, 2].join(", ")}, and #{exclude_packs.size - 2} more."
84
+ "#{list[0, 2].join(", ")}, and #{list.size - 2} more"
87
85
  end
88
86
  end
89
87
 
@@ -115,22 +113,22 @@ module VisualizePacks
115
113
  end
116
114
  end
117
115
 
118
- def self.max_violation_count(all_packages, show_edge)
119
- violation_counts = {}
116
+ def self.max_todo_count(all_packages, show_edge)
117
+ todo_counts = {}
120
118
  all_packages.each do |package|
121
- violations_by_package = package.violations.group_by(&:to_package_name)
122
- violations_by_package.keys.each do |violations_to_package|
123
- violation_types = violations_by_package[violations_to_package].group_by(&:type)
124
- violation_types.keys.each do |violation_type|
125
- if show_edge.call(package.name, violations_to_package)
126
- key = "#{package.name}->#{violations_to_package}:#{violation_type}"
127
- violation_counts[key] = violation_types[violation_type].count
128
- # violation_counts[key] += 1
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
129
127
  end
130
128
  end
131
129
  end
132
130
  end
133
- violation_counts.values.max
131
+ todo_counts.values.max
134
132
  end
135
133
 
136
134
  def self.filtered(packages, filter_package, filter_folder, exclude_packs)
@@ -161,13 +159,12 @@ module VisualizePacks
161
159
  def self.all_nested_packages(all_package_names)
162
160
  all_package_names.reject { |p| p == '.' }.inject({}) do |result, package|
163
161
  package_map_tally = all_package_names.map { |other_package| Pathname.new(package).parent.to_s.include?(other_package) }
164
- if package_map_tally.tally[true].nil?
165
- #nothing to do
166
- elsif package_map_tally.tally[true] > 1
167
- raise "Can't handle multiple levels of nesting atm"
168
- elsif package_map_tally.tally[true] == 1
169
- result[package] = all_package_names[package_map_tally.find_index(true)]
170
- end
162
+
163
+ acc = []
164
+ all_package_names.each_with_index { |pack, idx| acc << pack if package_map_tally[idx] }
165
+ acc.sort_by(&:length)
166
+ result[package] = acc.first unless acc.empty?
167
+
171
168
  result
172
169
  end
173
170
  end
@@ -203,7 +200,7 @@ module VisualizePacks
203
200
  nested_packages[d] || d
204
201
  end.uniq.reject { |p| p == package.name }
205
202
 
206
- morphed_violations = package.violations.map do |v|
203
+ morphed_todos = package.violations.map do |v|
207
204
  ParsePackwerk::Violation.new(
208
205
  type: v.type,
209
206
  to_package_name: nested_packages[v.to_package_name] || v.to_package_name,
@@ -221,10 +218,10 @@ module VisualizePacks
221
218
  metadata: package.metadata,
222
219
  dependencies: morphed_dependencies,
223
220
  config: package.config,
224
- violations: morphed_violations
221
+ violations: morphed_todos
225
222
  )
226
223
  # add dependencies TO nested packages to top-level package
227
- # add violations TO nested packages to top-level package
224
+ # add todos TO nested packages to top-level package
228
225
  end
229
226
  end
230
227
 
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
4
+ version: 0.5.6
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-25 00:00:00.000000000 Z
11
+ date: 2023-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler