visualize_packs 0.5.15 → 0.5.17
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 +15 -27
- data/lib/graph.dot.erb +23 -13
- data/lib/visualize_packs/options.rb +24 -12
- data/lib/visualize_packs.rb +28 -44
- 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: 13042fc696d4570039e5edbb4b1ba1f9ea710b865be44cbf0054739137f21913
|
4
|
+
data.tar.gz: 660624c8afc17b6dabfefc7969c91af2dacd6858346997220c0a0bfac3382288
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7776c8d9a0aeee1aa2bc74e1fb071f1f2e76820883e30785a879b49dc86646701b12e82d9f4cdcfec1e6585f7509ab5a2ab81eb239a12bb1bc934f153ecfce99
|
7
|
+
data.tar.gz: 4a67c4ba2efbb24f5d084d8bf19e47d56a8d08b4faf5a02238eb939987c9fdc56b0055cff10049bd7257473f4015df1d5b8f4bc27ca77c998fa3de913b376395
|
data/README.md
CHANGED
@@ -19,7 +19,7 @@ find . -iname 'package.yml' | sed 's/\/package.yml//g' | sed 's/\.\///' | xargs
|
|
19
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
|
-
find . -iname 'package.yml' | sed 's/\/package.yml//g' | sed 's/\.\///' | xargs -I % sh -c "bundle exec visualize_packs --only=% --
|
22
|
+
find . -iname 'package.yml' | sed 's/\/package.yml//g' | sed 's/\.\///' | xargs -I % sh -c "bundle exec visualize_packs --only=% --focus-pack-edge-mode=inout > %/packs.dot && dot %/packs.dot -Tpng -o %/packs.png"
|
23
23
|
```
|
24
24
|
|
25
25
|
|
data/bin/visualize_packs
CHANGED
@@ -9,39 +9,27 @@ require_relative '../lib/visualize_packs'
|
|
9
9
|
|
10
10
|
options = Options.new
|
11
11
|
|
12
|
-
supported_todo_types = %w[
|
13
|
-
privacy
|
14
|
-
architecture
|
15
|
-
visibility
|
16
|
-
dependency
|
17
|
-
].sort.freeze
|
18
|
-
|
19
|
-
def validated_list(o, valid_arguments)
|
20
|
-
list = o.to_s.split(",").uniq
|
21
|
-
raise OptionParser::InvalidArgument, o unless (list - valid_arguments).empty?
|
22
|
-
list
|
23
|
-
end
|
24
|
-
|
25
12
|
OptionParser.new do |opt|
|
26
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 }
|
27
17
|
opt.on('--no-layers', "Don't show architectural layers") { |o| options.show_layers = false }
|
28
|
-
opt.on('--no-
|
29
|
-
opt.on('--no-todos', "Don't show package todos") { |o| options.show_todos = false }
|
30
|
-
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) }
|
31
|
-
opt.on('--no-privacy', "Don't show privacy enforcement") { |o| options.show_privacy = false }
|
32
|
-
opt.on('--no-teams', "Don't show team colors") { |o| options.show_teams = false }
|
18
|
+
opt.on('--no-visibility-arrows', "Don't show visibility arrows") { |o| options.show_visibility = false }
|
33
19
|
|
34
|
-
opt.on('--
|
35
|
-
opt.on(
|
36
|
-
|
20
|
+
opt.on('--no-todo-arrows', "Don't show pack todos") { |o| options.show_todos = false }
|
21
|
+
opt.on("--only-todo-types=", "Show only the selected types of todos. Comma-separated list of #{EdgeTodoTypes.values.map &:serialize}") { |o| options.only_todo_types = o.to_s.split(",").uniq.map { EdgeTodoTypes.deserialize(_1) } }
|
22
|
+
|
23
|
+
opt.on('--no-teams', "Don't show team colors") { |o| options.show_teams = false }
|
37
24
|
|
38
|
-
opt.on('--
|
39
|
-
opt.on('--
|
25
|
+
opt.on('--focus-pack=', "Focus on a specific pack(s). Comma-separated list of packs. Wildcards supported: 'packs/*'") { |o| options.focus_pack = o.to_s.split(",") }
|
26
|
+
opt.on('--focus-pack-edge-mode=', "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) }
|
27
|
+
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(",") }
|
40
28
|
|
41
|
-
opt.on('--
|
42
|
-
opt.on('--
|
29
|
+
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 }
|
30
|
+
opt.on('--no-nesting-arrows', "Don't draw relationships between parents and nested packs") { |o| options.show_nested_relationships = false }
|
43
31
|
|
44
|
-
opt.on('--remote-base-url=
|
32
|
+
opt.on('--remote-base-url=', "Link pack packs to a URL (affects graphviz SVG generation)") { |o| options.remote_base_url = o }
|
45
33
|
|
46
34
|
opt.on_tail("-h", "--help", "Show this message") do
|
47
35
|
puts opt
|
@@ -52,5 +40,5 @@ end.parse!
|
|
52
40
|
puts VisualizePacks.package_graph!(
|
53
41
|
options,
|
54
42
|
ParsePackwerk::Configuration.fetch.raw,
|
55
|
-
Packs.all.map {
|
43
|
+
Packs.all.map { ParsePackwerk.find(_1.name) }
|
56
44
|
)
|
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_pack
|
36
|
+
fontsize=<%= options.focus_pack && options.focus_pack.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 %>
|
@@ -81,10 +81,7 @@ digraph package_diagram {
|
|
81
81
|
<%- end -%>
|
82
82
|
<%- if options.show_todos -%>
|
83
83
|
<%- all_packages.each do |package| -%>
|
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 -%>
|
84
|
+
<%- filtered_todos = package.violations.select { options.only_todo_types.include?(EdgeTodoTypes.deserialize(_1.type)) } -%>
|
88
85
|
<%- todos_by_package = filtered_todos.group_by(&:to_package_name) -%>
|
89
86
|
<%- todos_by_package.keys.each do |todos_to_package| -%>
|
90
87
|
<%- todo_types = todos_by_package[todos_to_package].group_by(&:type) -%>
|
@@ -112,20 +109,32 @@ digraph package_diagram {
|
|
112
109
|
<%- end -%>
|
113
110
|
<%- end -%>
|
114
111
|
<%- if options.show_nested_relationships -%>
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
112
|
+
<%- all_packages.each do |package| -%>
|
113
|
+
<%- all_packages.each do |nested_package| -%>
|
114
|
+
<%- if nested_package.name.include?("#{package.name}/") && !(nested_package.name == package.name) -%>
|
115
|
+
"<%= package.name -%>" -> "<%= nested_package.name -%>" [ color=purple ]
|
116
|
+
<%- end -%>
|
117
|
+
<%- end -%>
|
118
|
+
<%- end -%>
|
119
|
+
<%- end -%>
|
120
|
+
<%- if options.show_visibility -%>
|
121
|
+
<%- all_packages.each do |package| -%>
|
122
|
+
<%- (package.config['visible_to'] || []).each do |other_package_name| -%>
|
123
|
+
"<%= package.name -%>" -> "<%= other_package_name -%>" [ color=blue constraint=false ]
|
119
124
|
<%- end -%>
|
120
125
|
<%- end -%>
|
121
126
|
<%- end -%>
|
122
|
-
<%- end -%>
|
123
127
|
<%- if options.show_legend -%>
|
124
128
|
subgraph cluster_legend {
|
125
129
|
fontsize=16
|
126
130
|
label="Edges Styles and Arrow Heads"
|
127
131
|
A [ fontsize=12 shape=box label="package"]
|
128
132
|
B [ fontsize=12 shape=box label="package"]
|
133
|
+
K [ fontsize=12 shape=box label="package"]
|
134
|
+
L [ fontsize=12 shape=box label="package"]
|
135
|
+
M [ fontsize=12 shape=box label="package"]
|
136
|
+
N [ fontsize=12 shape=box label="package"]
|
137
|
+
|
129
138
|
C [ fontsize=12 shape=box label="package"]
|
130
139
|
D [ fontsize=12 shape=box label="package"]
|
131
140
|
E [ fontsize=12 shape=box label="package"]
|
@@ -134,14 +143,15 @@ digraph package_diagram {
|
|
134
143
|
H [ fontsize=12 shape=box label="package"]
|
135
144
|
I [ fontsize=12 shape=box label="package"]
|
136
145
|
J [ fontsize=12 shape=box label="package"]
|
137
|
-
|
138
|
-
L [ fontsize=12 shape=box label="package"]
|
146
|
+
|
139
147
|
A -> B [label="accepted dependency" color=darkgreen]
|
148
|
+
K -> L [label="nested package" color=purple]
|
149
|
+
M -> N [label="visibile to" color=darkgreen]
|
150
|
+
|
140
151
|
C -> D [label="privacy todo" color=darkred style=dashed arrowhead=crow]
|
141
152
|
E -> F [label="architecture todo" color=darkred style=dashed arrowhead=invodot]
|
142
153
|
G -> H [label="visibility todo" color=darkred style=dashed arrowhead=obox]
|
143
154
|
I -> J [label="dependency todo" color=darkred style=dashed arrowhead=odot]
|
144
|
-
K -> L [label="nested package" color=purple penwidth=3]
|
145
155
|
}
|
146
156
|
<%- end -%>
|
147
157
|
<%- if options.show_teams && all_team_names != [] -%>
|
@@ -1,11 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
# typed: strict
|
3
3
|
|
4
|
+
class EdgeTodoTypes < T::Enum
|
5
|
+
enums do
|
6
|
+
Dependency = new
|
7
|
+
Privacy = new
|
8
|
+
Architecture = new
|
9
|
+
Visibility = new
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
4
13
|
class FocusPackEdgeDirection < T::Enum
|
5
14
|
enums do
|
6
|
-
|
7
|
-
|
8
|
-
|
15
|
+
None = new # don't include non-focus packs and thus show no edges to/from them
|
16
|
+
All = new # include non-focus packs and show all edges between all visible nodes
|
17
|
+
In = new # include non-focus packs and show edges that go towards focus packs (and show all edges between focus packs)
|
18
|
+
Out = new # include non-focus packs and show edges that go away from focus packs (and show all edges between focus packs)
|
19
|
+
InOut = new # include non-focus packs and show edges that go towards or away from focus packs (and show all edges between focus packs)
|
9
20
|
end
|
10
21
|
end
|
11
22
|
|
@@ -13,22 +24,23 @@ class Options < T::Struct
|
|
13
24
|
extend T::Sig
|
14
25
|
|
15
26
|
prop :show_legend, T::Boolean, default: true
|
16
|
-
|
27
|
+
|
17
28
|
prop :show_dependencies, T::Boolean, default: true
|
18
|
-
prop :show_todos, T::Boolean, default: true
|
19
|
-
prop :only_todo_types, T::Array[String], default: []
|
20
29
|
prop :show_privacy, T::Boolean, default: true
|
30
|
+
prop :show_layers, T::Boolean, default: true
|
31
|
+
prop :show_visibility, T::Boolean, default: true
|
32
|
+
|
33
|
+
prop :show_todos, T::Boolean, default: true
|
34
|
+
prop :only_todo_types, T::Array[EdgeTodoTypes], default: EdgeTodoTypes.values
|
35
|
+
|
21
36
|
prop :show_teams, T::Boolean, default: true
|
22
37
|
|
23
|
-
prop :
|
24
|
-
prop :
|
25
|
-
prop :
|
38
|
+
prop :focus_pack, T.nilable(T::Array[String]), default: nil
|
39
|
+
prop :show_only_edges_to_focus_pack, FocusPackEdgeDirection, default: FocusPackEdgeDirection::All
|
40
|
+
prop :exclude_packs, T::Array[String], default: []
|
26
41
|
|
27
42
|
prop :roll_nested_into_parent_packs, T::Boolean, default: false
|
28
43
|
prop :show_nested_relationships, T::Boolean, default: true
|
29
44
|
|
30
|
-
prop :exclude_packs, T::Array[String], default: []
|
31
|
-
prop :include_packs, T.nilable(T::Array[String]), default: nil
|
32
|
-
|
33
45
|
prop :remote_base_url, T.nilable(String)
|
34
46
|
end
|
data/lib/visualize_packs.rb
CHANGED
@@ -57,20 +57,20 @@ module VisualizePacks
|
|
57
57
|
sig { params(options: Options, max_todo_count: T.nilable(Integer)).returns(String) }
|
58
58
|
def self.diagram_title(options, max_todo_count)
|
59
59
|
app_name = File.basename(Dir.pwd)
|
60
|
-
focus_edge_info = options.focus_pack
|
61
|
-
focus_info = options.focus_pack
|
60
|
+
focus_edge_info = options.focus_pack && options.show_only_edges_to_focus_pack != FocusPackEdgeDirection::All ? "showing only edges to/from focus pack" : "showing all edges between visible packs"
|
61
|
+
focus_info = options.focus_pack ? "Focus on #{limited_sentence(options.focus_pack)} (#{focus_edge_info})" : "All packs"
|
62
62
|
skipped_info =
|
63
63
|
[
|
64
64
|
options.show_legend ? nil : "hiding legend",
|
65
65
|
options.show_layers ? nil : "hiding layers",
|
66
66
|
options.show_dependencies ? nil : "hiding dependencies",
|
67
67
|
options.show_todos ? nil : "hiding todos",
|
68
|
-
options.only_todo_types.
|
68
|
+
EdgeTodoTypes.values.size == options.only_todo_types.size ? nil : "only #{limited_sentence(options.only_todo_types.map &:serialize)} todos",
|
69
69
|
options.show_privacy ? nil : "hiding privacy",
|
70
70
|
options.show_teams ? nil : "hiding teams",
|
71
|
+
options.show_visibility ? nil : "hiding visibility",
|
71
72
|
options.roll_nested_into_parent_packs ? "hiding nested packs" : nil,
|
72
73
|
options.show_nested_relationships ? nil : "hiding nested relationships",
|
73
|
-
options.include_packs ? "including only: #{limited_sentence(options.include_packs)}" : nil,
|
74
74
|
options.exclude_packs.empty? ? nil : "excluding pack#{options.exclude_packs.size > 1 ? 's' : ''}: #{limited_sentence(options.exclude_packs)}",
|
75
75
|
].compact.join(', ').strip
|
76
76
|
main_title = "#{app_name}: #{focus_info}#{skipped_info != '' ? ' - ' + skipped_info : ''}"
|
@@ -95,25 +95,19 @@ module VisualizePacks
|
|
95
95
|
sig { params(options: Options, all_package_names: T::Array[String]).returns(T.proc.params(arg0: String, arg1: String).returns(T::Boolean)) }
|
96
96
|
def self.show_edge_builder(options, all_package_names)
|
97
97
|
return lambda do |start_node, end_node|
|
98
|
+
all_package_names.include?(start_node) &&
|
99
|
+
all_package_names.include?(end_node) &&
|
98
100
|
(
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
when FocusPackEdgeDirection::InOut then
|
110
|
-
match_packs?(start_node, options.focus_pack) || match_packs?(end_node, options.focus_pack)
|
111
|
-
when FocusPackEdgeDirection::In then
|
112
|
-
match_packs?(end_node, options.focus_pack)
|
113
|
-
when FocusPackEdgeDirection::Out then
|
114
|
-
match_packs?(start_node, options.focus_pack)
|
115
|
-
end
|
116
|
-
)
|
101
|
+
case options.show_only_edges_to_focus_pack
|
102
|
+
when FocusPackEdgeDirection::All then
|
103
|
+
true
|
104
|
+
when FocusPackEdgeDirection::InOut then
|
105
|
+
match_packs?(start_node, options.focus_pack) || match_packs?(end_node, options.focus_pack)
|
106
|
+
when FocusPackEdgeDirection::In then
|
107
|
+
match_packs?(end_node, options.focus_pack)
|
108
|
+
when FocusPackEdgeDirection::Out then
|
109
|
+
match_packs?(start_node, options.focus_pack)
|
110
|
+
end
|
117
111
|
)
|
118
112
|
end
|
119
113
|
end
|
@@ -140,7 +134,7 @@ module VisualizePacks
|
|
140
134
|
todos_by_package&.keys&.each do |todos_to_package|
|
141
135
|
todo_types = todos_by_package&& todos_by_package[todos_to_package]&.group_by(&:type)
|
142
136
|
todo_types&.keys&.each do |todo_type|
|
143
|
-
if options.only_todo_types.
|
137
|
+
if options.only_todo_types.include?(EdgeTodoTypes.deserialize(todo_type))
|
144
138
|
if show_edge.call(package.name, todos_to_package)
|
145
139
|
key = "#{package.name}->#{todos_to_package}:#{todo_type}"
|
146
140
|
todo_counts[key] = todo_types && todo_types[todo_type]&.count
|
@@ -173,16 +167,14 @@ module VisualizePacks
|
|
173
167
|
|
174
168
|
edge_width = min_width + width_delta
|
175
169
|
edge_width.round(2)
|
176
|
-
|
170
|
+
end
|
177
171
|
|
178
|
-
|
179
|
-
|
172
|
+
sig { params(packages: T::Array[ParsePackwerk::Package], options: Options).returns(T::Array[ParsePackwerk::Package]) }
|
173
|
+
def self.filtered(packages, options)
|
180
174
|
focus_pack = options.focus_pack
|
181
|
-
focus_folder = options.focus_folder
|
182
|
-
include_packs = options.include_packs
|
183
175
|
exclude_packs = options.exclude_packs
|
184
176
|
|
185
|
-
return packages unless focus_pack
|
177
|
+
return packages unless focus_pack || exclude_packs.any?
|
186
178
|
|
187
179
|
nested_packages = all_nested_packages(packages.map { |p| p.name })
|
188
180
|
|
@@ -194,16 +186,16 @@ module VisualizePacks
|
|
194
186
|
result = T.let([], T::Array[T.nilable(String)])
|
195
187
|
result = packages.map { |pack| pack.name }
|
196
188
|
|
197
|
-
if !focus_pack.empty?
|
189
|
+
if focus_pack && !focus_pack.empty?
|
198
190
|
result = []
|
199
191
|
result += packages.map { |pack| pack.name }.select { |p| match_packs?(p, focus_pack) }
|
200
192
|
if options.show_dependencies
|
201
193
|
result += packages.select { |p| p.dependencies.any? { |d| match_packs?(d, focus_pack) }}.map { |pack| pack.name }
|
202
194
|
end
|
203
|
-
if options.show_todos && [
|
195
|
+
if options.show_todos && [FocusPackEdgeDirection::All, FocusPackEdgeDirection::In, FocusPackEdgeDirection::InOut].include?(options.show_only_edges_to_focus_pack)
|
204
196
|
result += packages.select do
|
205
197
|
|p| (p.violations || []).inject([]) do |res, todo|
|
206
|
-
res << todo.to_package_name if options.only_todo_types.
|
198
|
+
res << todo.to_package_name if options.only_todo_types.include?(EdgeTodoTypes.deserialize(todo.type))
|
207
199
|
res
|
208
200
|
end.any? { |v| match_packs?(v, focus_pack) }
|
209
201
|
end.map { |pack| pack.name }
|
@@ -212,9 +204,9 @@ module VisualizePacks
|
|
212
204
|
if options.show_dependencies
|
213
205
|
result += packages_by_name[p].dependencies
|
214
206
|
end
|
215
|
-
if options.show_todos && [
|
207
|
+
if options.show_todos && [FocusPackEdgeDirection::All, FocusPackEdgeDirection::Out, FocusPackEdgeDirection::InOut].include?(options.show_only_edges_to_focus_pack)
|
216
208
|
result += (packages_by_name[p].violations || []).inject([]) do |res, todo|
|
217
|
-
res << todo.to_package_name if options.only_todo_types.
|
209
|
+
res << todo.to_package_name if options.only_todo_types.include?(EdgeTodoTypes.deserialize(todo.type))
|
218
210
|
res
|
219
211
|
end
|
220
212
|
end
|
@@ -227,14 +219,6 @@ module VisualizePacks
|
|
227
219
|
result = (result + parent_packs).uniq.compact
|
228
220
|
end
|
229
221
|
|
230
|
-
if focus_folder
|
231
|
-
result = result.select { |p| p.include? focus_folder }
|
232
|
-
end
|
233
|
-
|
234
|
-
if include_packs
|
235
|
-
result = result.select { |p| match_packs?(p, include_packs) }
|
236
|
-
end
|
237
|
-
|
238
222
|
if exclude_packs.any?
|
239
223
|
result = result.reject { |p| match_packs?(p, exclude_packs) }
|
240
224
|
end
|
@@ -316,8 +300,8 @@ module VisualizePacks
|
|
316
300
|
morphed_packages.reject { |p| nested_packages.keys.include?(p.name) }
|
317
301
|
end
|
318
302
|
|
319
|
-
sig { params(pack: String, packs_name_with_wildcards: T::Array[String]).returns(T::Boolean) }
|
303
|
+
sig { params(pack: String, packs_name_with_wildcards: T.nilable(T::Array[String])).returns(T::Boolean) }
|
320
304
|
def self.match_packs?(pack, packs_name_with_wildcards)
|
321
|
-
packs_name_with_wildcards.any? {|p| File.fnmatch(p, pack)}
|
305
|
+
!packs_name_with_wildcards || packs_name_with_wildcards.any? {|p| File.fnmatch(p, pack)}
|
322
306
|
end
|
323
307
|
end
|
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.17
|
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-09-
|
11
|
+
date: 2023-09-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|