visualize_packwerk 0.0.4 → 0.0.5

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: 5e1857563c4bf2c40025fbf771b4e5d0ee3d3b1a7623015097274ae1198a6ab6
4
- data.tar.gz: b917ec146a3e97aec95effe57ae0ab5905ec5456549a6bbd2d65dd5ed6a6fd2d
3
+ metadata.gz: dbd24c4c7be488fb37b173c00512196884dafe06e1788bbfb9fd3161988f395b
4
+ data.tar.gz: 0c4da79eef14eba7759074636a556d03f2e74a1b964b485bba0d7e090c83471b
5
5
  SHA512:
6
- metadata.gz: d4f389a11294cbd70ba330e6f7888e03f1dd1666aa80f15214d40914f3fdfe6d711103fc02b364ee5caf4c2344c7bdc343e3be32693bf99801decf94b031860e
7
- data.tar.gz: 2a500bb635dc10ac6785d648be7cc1e8dd8396d2dfd48a45059ee1ba924a8fe26d1b782bebeea1c43f94721eca08ef0ada4c41f1918d484f3eaa3380c6d11d1c
6
+ metadata.gz: 38855ce47c28b248a67de636f9e530e850425b5b7823ccc3bd1f13bde14c6bacd5aa32b68b68f54244325b6c75f8050586b36e98d5c5f0f2e90265728594f854
7
+ data.tar.gz: 68c24d06b1f0c9ae4d109806d0459b38a58e6d6827a07bc745fe6dafaddf17a15c359f80a9b21e495c386eac8ceeba5e8e66d40162d3ee572544c01b5fc35e10
@@ -27,7 +27,7 @@ module VisualizePackwerk
27
27
  # We would also need to ignore it when parsing PackageNodes.
28
28
  # next if p.name == ParsePackwerk::ROOT_PACKAGE_NAME
29
29
  owner = CodeOwnership.for_package(p)
30
- violations_by_package = PackageProtections::ProtectedPackage.from(p).violations.group_by(&:to_package_name).transform_values(&:count)
30
+ violations_by_package = p.violations.group_by(&:to_package_name).transform_values(&:count)
31
31
 
32
32
  package_nodes << PackageNode.new(
33
33
  name: p.name,
@@ -6,25 +6,6 @@ module VisualizePackwerk
6
6
 
7
7
  OUTPUT_FILENAME = T.let('packwerk.png'.freeze, String)
8
8
 
9
- sig { void }
10
- def initialize
11
- @colors_by_team = T.let({}, T::Hash[String, String])
12
- @remaining_colors = T.let(
13
- [
14
- # Found using https://htmlcolorcodes.com/color-picker/
15
- '#77EE77', # green
16
- '#DFEE77', # yellow
17
- '#77EEE6', # teal
18
- '#EEC077', # orange
19
- '#EE77BF', # pink
20
- '#EE6F6F', # red
21
- '#ED6EDE', # magenta
22
- '#8E8CFE', # blue
23
- '#EEA877', # red-orange
24
- ], T::Array[String]
25
- )
26
- end
27
-
28
9
  sig { params(teams: T::Array[CodeTeams::Team]).void }
29
10
  def create_package_graph_for_teams!(teams)
30
11
  packages = ParsePackwerk.all.select do |package|
@@ -38,27 +19,27 @@ module VisualizePackwerk
38
19
  def create_team_graph!(teams, show_all_teams: false)
39
20
  package_graph = PackageGraph.construct
40
21
  team_graph = TeamGraph.from_package_graph(package_graph)
41
- highlighted_node_names = teams.map(&:name)
22
+ node_names = teams.map(&:name)
42
23
 
43
- draw_graph!(team_graph, highlighted_node_names, show_all_nodes: show_all_teams)
24
+ draw_graph!(team_graph, node_names, show_all_nodes: show_all_teams)
44
25
  end
45
26
 
46
- sig { params(packages: T::Array[ParsePackwerk::Package], show_all_packs: T::Boolean).void }
47
- def create_package_graph!(packages, show_all_packs: false)
27
+ sig { params(packages: T::Array[ParsePackwerk::Package]).void }
28
+ def create_package_graph!(packages)
48
29
  graph = PackageGraph.construct
49
- highlighted_node_names = packages.map(&:name)
50
- draw_graph!(graph, highlighted_node_names, show_all_nodes: show_all_packs)
30
+ node_names = packages.map(&:name)
31
+ draw_graph!(graph, node_names)
51
32
  end
52
33
 
53
34
  sig { params(packages: T::Array[ParsePackwerk::Package], show_all_nodes: T::Boolean).void }
54
35
  def create_graph!(packages, show_all_nodes: false)
55
36
  graph = PackageGraph.construct
56
- highlighted_node_names = packages.map(&:name)
57
- draw_graph!(graph, highlighted_node_names, show_all_nodes: show_all_nodes)
37
+ node_names = packages.map(&:name)
38
+ draw_graph!(graph, node_names, show_all_nodes: show_all_nodes)
58
39
  end
59
40
 
60
- sig { params(graph: GraphInterface, highlighted_node_names: T::Array[String], show_all_nodes: T::Boolean).void }
61
- def draw_graph!(graph, highlighted_node_names, show_all_nodes: false)
41
+ sig { params(graph: GraphInterface, node_names: T::Array[String], show_all_nodes: T::Boolean).void }
42
+ def draw_graph!(graph, node_names, show_all_nodes: false)
62
43
  # SFDP looks better than dot in some cases, but less good in other cases.
63
44
  # If your visualization looks bad, change the layout to other_layout!
64
45
  # https://graphviz.org/docs/layouts/
@@ -69,13 +50,10 @@ module VisualizePackwerk
69
50
  # Create graph nodes
70
51
  graphviz_nodes = T.let({}, T::Hash[String, GraphViz::Node])
71
52
 
72
- nodes_to_draw = graph.nodes
53
+ nodes_to_draw = graph.nodes.select{|n| node_names.include?(n.name) }
73
54
 
74
55
  nodes_to_draw.each do |node|
75
- next unless highlighted_node_names.any? { |highlighted_node_name| node.depends_on?(highlighted_node_name) } || highlighted_node_names.include?(node.name)
76
-
77
- highlight_node = highlighted_node_names.include?(node.name) && !show_all_nodes
78
- graphviz_nodes[node.name] = add_node(node, graphviz_graph, highlight_node)
56
+ graphviz_nodes[node.name] = add_node(node, graphviz_graph)
79
57
  end
80
58
 
81
59
  max_edge_width = 10
@@ -83,7 +61,7 @@ module VisualizePackwerk
83
61
  # Draw all edges
84
62
  nodes_to_draw.each do |node|
85
63
  node.dependencies.each do |to_node|
86
- next unless highlighted_node_names.include?(to_node)
64
+ next unless node_names.include?(to_node)
87
65
 
88
66
  graphviz_graph.add_edges(
89
67
  graphviz_nodes[node.name],
@@ -93,7 +71,7 @@ module VisualizePackwerk
93
71
  end
94
72
 
95
73
  node.violations_by_node_name.each do |to_node_name, violation_count|
96
- next unless highlighted_node_names.include?(to_node_name)
74
+ next unless node_names.include?(to_node_name)
97
75
 
98
76
  edge_width = [
99
77
  [(violation_count / 5).to_i, 1].max, # rubocop:disable Lint/NumberConversion
@@ -114,44 +92,20 @@ module VisualizePackwerk
114
92
  puts 'Finished!'
115
93
  end
116
94
 
117
- sig { params(node: NodeInterface, graph: GraphViz, highlight_node: T::Boolean).returns(GraphViz::Node) }
118
- def add_node(node, graph, highlight_node)
119
- default_node_options = {
95
+ sig { params(node: NodeInterface, graph: GraphViz).returns(GraphViz::Node) }
96
+ def add_node(node, graph)
97
+ node_options = {
120
98
  fontsize: 26.0,
121
- fontcolor: 'white',
122
- fillcolor: 'black',
99
+ fontcolor: 'black',
100
+ fillcolor: 'white',
123
101
  color: 'black',
124
102
  height: 1.0,
125
103
  style: 'filled, rounded',
126
104
  shape: 'box',
127
105
  }
128
106
 
129
- node_options = if highlight_node
130
- default_node_options.merge(
131
- fillcolor: highlight_by_group(node),
132
- color: highlight_by_group(node),
133
- fontcolor: 'black'
134
- )
135
- else
136
- default_node_options
137
- end
138
-
139
107
  graph.add_nodes(node.name, **node_options)
140
108
  end
141
-
142
- sig { params(node: NodeInterface).returns(String) }
143
- def highlight_by_group(node)
144
- highlighted_package_color = @colors_by_team[node.group_name]
145
- if !highlighted_package_color
146
- highlighted_package_color = @remaining_colors.first
147
- raise 'Can only color nodes a max of 5 unique colors for now' if highlighted_package_color.nil?
148
-
149
- @remaining_colors.delete(highlighted_package_color)
150
- @colors_by_team[node.group_name] = highlighted_package_color
151
- end
152
-
153
- highlighted_package_color
154
- end
155
109
  end
156
110
 
157
111
  private_constant :PackageRelationships
@@ -27,7 +27,7 @@ module VisualizePackwerk
27
27
  end
28
28
  end
29
29
 
30
- PackageRelationships.new.create_package_graph!(packages, show_all_packs: show_all_packs)
30
+ PackageRelationships.new.create_package_graph!(packages)
31
31
  end
32
32
 
33
33
  # This creates the array of symbols that are needed to declare an argument to a rake task
@@ -4,7 +4,6 @@ module VisualizePackwerk
4
4
  require 'visualize_packwerk/railtie' if defined?(Rails)
5
5
  require 'parse_packwerk'
6
6
  require 'code_ownership'
7
- require 'package_protections'
8
7
  require 'graphviz'
9
8
 
10
9
  require 'visualize_packwerk/node_interface'
data/sorbet/config CHANGED
@@ -1,2 +1,3 @@
1
1
  --dir
2
2
  .
3
+ --ignore=/vendor/bundle
@@ -4,20 +4,30 @@
4
4
  # This is an autogenerated file for types exported from the `parse_packwerk` gem.
5
5
  # Please instead update this file by running `bin/tapioca gem parse_packwerk`.
6
6
 
7
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/constants.rb:3
7
8
  module ParsePackwerk
8
9
  class << self
10
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk.rb:28
9
11
  sig { returns(T::Array[::ParsePackwerk::Package]) }
10
12
  def all; end
11
13
 
14
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk.rb:112
15
+ sig { void }
16
+ def bust_cache!; end
17
+
18
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk.rb:33
12
19
  sig { params(name: ::String).returns(T.nilable(::ParsePackwerk::Package)) }
13
20
  def find(name); end
14
21
 
15
- sig { params(file_path: T.any(::Pathname, ::String)).returns(T.nilable(::ParsePackwerk::Package)) }
22
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk.rb:43
23
+ sig { params(file_path: T.any(::Pathname, ::String)).returns(::ParsePackwerk::Package) }
16
24
  def package_from_path(file_path); end
17
25
 
26
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk.rb:54
18
27
  sig { params(package: ::ParsePackwerk::Package).void }
19
28
  def write_package_yml!(package); end
20
29
 
30
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk.rb:38
21
31
  sig { returns(::ParsePackwerk::Configuration) }
22
32
  def yml; end
23
33
 
@@ -25,94 +35,148 @@ module ParsePackwerk
25
35
 
26
36
  # We memoize packages_by_name for fast lookup.
27
37
  # Since Graph is an immutable value object, we can create indexes and general caching mechanisms safely.
38
+ #
39
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk.rb:100
28
40
  sig { returns(T::Hash[::String, ::ParsePackwerk::Package]) }
29
41
  def packages_by_name; end
30
42
  end
31
43
  end
32
44
 
45
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/configuration.rb:4
33
46
  class ParsePackwerk::Configuration < ::T::Struct
34
47
  const :exclude, T::Array[::String]
35
48
  const :package_paths, T::Array[::String]
36
49
 
37
50
  class << self
51
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/configuration.rb:28
38
52
  sig { params(config_hash: T::Hash[T.untyped, T.untyped]).returns(T::Array[::String]) }
39
53
  def excludes(config_hash); end
40
54
 
55
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/configuration.rb:11
41
56
  sig { returns(::ParsePackwerk::Configuration) }
42
57
  def fetch; end
43
58
 
59
+ # source://sorbet-runtime-0.5.10323/lib/types/struct.rb:13
44
60
  def inherited(s); end
45
61
 
62
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/configuration.rb:40
46
63
  sig { params(config_hash: T::Hash[T.untyped, T.untyped]).returns(T::Array[::String]) }
47
64
  def package_paths(config_hash); end
48
65
  end
49
66
  end
50
67
 
68
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/constants.rb:20
51
69
  ParsePackwerk::DEFAULT_EXCLUDE_GLOBS = T.let(T.unsafe(nil), Array)
70
+
71
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/constants.rb:21
52
72
  ParsePackwerk::DEFAULT_PACKAGE_PATHS = T.let(T.unsafe(nil), Array)
73
+
74
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/constants.rb:22
75
+ ParsePackwerk::DEFAULT_PUBLIC_PATH = T.let(T.unsafe(nil), String)
76
+
77
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/constants.rb:12
53
78
  ParsePackwerk::DEPENDENCIES = T.let(T.unsafe(nil), String)
79
+
80
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/constants.rb:7
54
81
  ParsePackwerk::DEPRECATED_REFERENCES_YML_NAME = T.let(T.unsafe(nil), String)
55
82
 
83
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/deprecated_references.rb:4
56
84
  class ParsePackwerk::DeprecatedReferences < ::T::Struct
57
85
  const :pathname, ::Pathname
58
86
  const :violations, T::Array[::ParsePackwerk::Violation]
59
87
 
60
88
  class << self
89
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/deprecated_references.rb:11
61
90
  sig { params(package: ::ParsePackwerk::Package).returns(::ParsePackwerk::DeprecatedReferences) }
62
91
  def for(package); end
63
92
 
93
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/deprecated_references.rb:17
64
94
  sig { params(pathname: ::Pathname).returns(::ParsePackwerk::DeprecatedReferences) }
65
95
  def from(pathname); end
66
96
 
97
+ # source://sorbet-runtime-0.5.10323/lib/types/struct.rb:13
67
98
  def inherited(s); end
68
99
  end
69
100
  end
70
101
 
102
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/constants.rb:8
71
103
  ParsePackwerk::ENFORCE_DEPENDENCIES = T.let(T.unsafe(nil), String)
104
+
105
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/constants.rb:9
72
106
  ParsePackwerk::ENFORCE_PRIVACY = T.let(T.unsafe(nil), String)
107
+
108
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/constants.rb:11
73
109
  ParsePackwerk::METADATA = T.let(T.unsafe(nil), String)
74
110
 
75
111
  # Since this metadata is unstructured YAML, it could be any type. We leave it to clients of `ParsePackwerk::Package`
76
112
  # to add types based on their known usage of metadata.
113
+ #
114
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/constants.rb:16
77
115
  ParsePackwerk::MetadataYmlType = T.type_alias { T::Hash[T.untyped, T.untyped] }
78
116
 
117
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk.rb:14
79
118
  class ParsePackwerk::MissingConfiguration < ::StandardError
119
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk.rb:18
80
120
  sig { params(packwerk_file_name: ::Pathname).void }
81
121
  def initialize(packwerk_file_name); end
82
122
  end
83
123
 
124
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/constants.rb:5
84
125
  ParsePackwerk::PACKAGE_YML_NAME = T.let(T.unsafe(nil), String)
126
+
127
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/constants.rb:6
85
128
  ParsePackwerk::PACKWERK_YML_NAME = T.let(T.unsafe(nil), String)
86
129
 
130
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/constants.rb:10
131
+ ParsePackwerk::PUBLIC_PATH = T.let(T.unsafe(nil), String)
132
+
133
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/package.rb:4
87
134
  class ParsePackwerk::Package < ::T::Struct
88
135
  const :dependencies, T::Array[::String]
89
136
  const :enforce_dependencies, T::Boolean
90
137
  const :enforce_privacy, T::Boolean
91
138
  const :metadata, T::Hash[T.untyped, T.untyped]
92
139
  const :name, ::String
140
+ const :public_path, ::String, default: T.unsafe(nil)
93
141
 
142
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/package.rb:35
94
143
  sig { returns(::Pathname) }
95
144
  def directory; end
96
145
 
146
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/package.rb:45
97
147
  sig { returns(T::Boolean) }
98
148
  def enforces_dependencies?; end
99
149
 
150
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/package.rb:50
100
151
  sig { returns(T::Boolean) }
101
152
  def enforces_privacy?; end
102
153
 
154
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/package.rb:40
155
+ sig { returns(::Pathname) }
156
+ def public_directory; end
157
+
158
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/package.rb:55
159
+ sig { returns(T::Array[::ParsePackwerk::Violation]) }
160
+ def violations; end
161
+
162
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/package.rb:30
103
163
  sig { returns(::Pathname) }
104
164
  def yml; end
105
165
 
106
166
  class << self
167
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/package.rb:15
107
168
  sig { params(pathname: ::Pathname).returns(::ParsePackwerk::Package) }
108
169
  def from(pathname); end
109
170
 
171
+ # source://sorbet-runtime-0.5.10323/lib/types/struct.rb:13
110
172
  def inherited(s); end
111
173
  end
112
174
  end
113
175
 
176
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/package_set.rb:8
114
177
  class ParsePackwerk::PackageSet
115
178
  class << self
179
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/package_set.rb:12
116
180
  sig do
117
181
  params(
118
182
  package_pathspec: T::Array[::String],
@@ -123,26 +187,32 @@ class ParsePackwerk::PackageSet
123
187
 
124
188
  private
125
189
 
190
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/package_set.rb:28
126
191
  sig { params(globs: T::Array[::String], path: ::Pathname).returns(T::Boolean) }
127
192
  def exclude_path?(globs, path); end
128
193
  end
129
194
  end
130
195
 
196
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/constants.rb:4
131
197
  ParsePackwerk::ROOT_PACKAGE_NAME = T.let(T.unsafe(nil), String)
132
198
 
199
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/violation.rb:4
133
200
  class ParsePackwerk::Violation < ::T::Struct
134
201
  const :class_name, ::String
135
202
  const :files, T::Array[::String]
136
203
  const :to_package_name, ::String
137
204
  const :type, ::String
138
205
 
206
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/violation.rb:13
139
207
  sig { returns(T::Boolean) }
140
208
  def dependency?; end
141
209
 
210
+ # source://parse_packwerk-0.14.0/lib/parse_packwerk/violation.rb:18
142
211
  sig { returns(T::Boolean) }
143
212
  def privacy?; end
144
213
 
145
214
  class << self
215
+ # source://sorbet-runtime-0.5.10323/lib/types/struct.rb:13
146
216
  def inherited(s); end
147
217
  end
148
218
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: visualize_packwerk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.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: 2022-08-12 00:00:00.000000000 Z
11
+ date: 2022-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sorbet-runtime
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: package_protections
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: code_ownership
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -180,9 +166,8 @@ files:
180
166
  - sorbet/rbi/gems/json@2.6.2.rbi
181
167
  - sorbet/rbi/gems/method_source@1.0.0.rbi
182
168
  - sorbet/rbi/gems/minitest@5.16.2.rbi
183
- - sorbet/rbi/gems/package_protections@1.3.0.rbi
184
169
  - sorbet/rbi/gems/parallel@1.22.1.rbi
185
- - sorbet/rbi/gems/parse_packwerk@0.11.0.rbi
170
+ - sorbet/rbi/gems/parse_packwerk@0.14.0.rbi
186
171
  - sorbet/rbi/gems/parser@3.1.2.0.rbi
187
172
  - sorbet/rbi/gems/pry@0.14.1.rbi
188
173
  - sorbet/rbi/gems/rainbow@3.1.1.rbi
@@ -234,7 +219,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
234
219
  - !ruby/object:Gem::Version
235
220
  version: '0'
236
221
  requirements: []
237
- rubygems_version: 3.3.7
222
+ rubygems_version: 3.1.6
238
223
  signing_key:
239
224
  specification_version: 4
240
225
  summary: A gem to visualize connections in a Rails app that uses Packwerk
@@ -1,654 +0,0 @@
1
- # typed: true
2
-
3
- # DO NOT EDIT MANUALLY
4
- # This is an autogenerated file for types exported from the `package_protections` gem.
5
- # Please instead update this file by running `bin/tapioca gem package_protections`.
6
-
7
- # Welcome to PackageProtections!
8
- # See https://github.com/rubyatscale/package_protections#readme for more info
9
- #
10
- # This file is a reference for the available API to `package_protections`, but all implementation details are private
11
- # (which is why we delegate to `Private` for the actual implementation).
12
- module PackageProtections
13
- class << self
14
- sig { returns(T::Array[::PackageProtections::ProtectionInterface]) }
15
- def all; end
16
-
17
- sig { void }
18
- def bust_cache!; end
19
-
20
- # @yield [Private.config]
21
- sig { params(blk: T.proc.params(arg0: ::PackageProtections::Private::Configuration).void).void }
22
- def configure(&blk); end
23
-
24
- # This returns an array of a `Offense` which is how we represent the outcome of attempting to protect one or more packages,
25
- # each of which is configured with different violation behaviors for each protection.
26
- sig do
27
- params(
28
- packages: T::Array[::ParsePackwerk::Package],
29
- new_violations: T::Array[::PackageProtections::PerFileViolation]
30
- ).returns(T::Array[::PackageProtections::Offense])
31
- end
32
- def get_offenses(packages:, new_violations:); end
33
-
34
- sig do
35
- params(
36
- package_names: T::Array[::String],
37
- all_packages: T::Array[::ParsePackwerk::Package]
38
- ).returns(T::Array[::ParsePackwerk::Package])
39
- end
40
- def packages_for_names(package_names, all_packages); end
41
-
42
- # Do not use this method -- it's meant to be used by Rubocop cops to get directory-specific
43
- # parameters without needing to have directory-specific .rubocop.yml files.
44
- sig { params(identifier: ::String).returns(T::Hash[T.untyped, T.untyped]) }
45
- def private_cop_config(identifier); end
46
-
47
- # Why do we use Bundler.root here?
48
- # The reason is that this function is evaluated in `.client_rubocop.yml`, so when rubocop evaluates the
49
- # YML and parses the ERB, the working directory is inside this gem. We need to make sure it's at the root of the
50
- # application so that we can find all of the packwerk packages.
51
- # We use Bundler.root to get the root because:
52
- # A) We expect it to be reliable
53
- # B) We expect the client to be running bundle exec rubocop, which is typically done at the root, and also means
54
- # the client already has this dependency.
55
- sig { params(root_pathname: ::Pathname).returns(::String) }
56
- def rubocop_yml(root_pathname: T.unsafe(nil)); end
57
-
58
- # PackageProtections.set_defaults! sets any unset protections to their default enforcement
59
- sig do
60
- params(
61
- packages: T::Array[::ParsePackwerk::Package],
62
- protection_identifiers: T::Array[::String],
63
- verbose: T::Boolean
64
- ).void
65
- end
66
- def set_defaults!(packages, protection_identifiers: T.unsafe(nil), verbose: T.unsafe(nil)); end
67
-
68
- # This is a fast way to get a protection given an identifier
69
- sig { params(identifier: ::String).returns(::PackageProtections::ProtectionInterface) }
70
- def with_identifier(identifier); end
71
- end
72
- end
73
-
74
- PackageProtections::EXPECTED_PACK_DIRECTORIES = T.let(T.unsafe(nil), Array)
75
-
76
- # A protection identifier is just a string that identifies the name of the protection within a `package.yml`
77
- PackageProtections::Identifier = T.type_alias { ::String }
78
-
79
- # This is currently the only handled exception that `PackageProtections` will throw.
80
- class PackageProtections::IncorrectPublicApiUsageError < ::StandardError; end
81
-
82
- class PackageProtections::Offense < ::T::Struct
83
- const :file, ::String
84
- const :message, ::String
85
- const :package, ::ParsePackwerk::Package
86
- const :violation_type, ::String
87
-
88
- sig { returns(::String) }
89
- def package_name; end
90
-
91
- class << self
92
- def inherited(s); end
93
- end
94
- end
95
-
96
- PackageProtections::PROTECTIONS_TODO_YML = T.let(T.unsafe(nil), String)
97
-
98
- # Perhaps this should be in ParsePackwerk. For now, this is here to help us break down violations per file.
99
- # This is analogous to `Packwerk::ReferenceOffense`
100
- class PackageProtections::PerFileViolation < ::T::Struct
101
- const :class_name, ::String
102
- const :constant_source_package, ::String
103
- const :filepath, ::String
104
- const :reference_source_package, ::ParsePackwerk::Package
105
- const :type, ::String
106
-
107
- sig { returns(T::Boolean) }
108
- def dependency?; end
109
-
110
- sig { returns(T::Boolean) }
111
- def privacy?; end
112
-
113
- class << self
114
- sig do
115
- params(
116
- violation: ::ParsePackwerk::Violation,
117
- reference_source_package: ::ParsePackwerk::Package
118
- ).returns(T::Array[::PackageProtections::PerFileViolation])
119
- end
120
- def from(violation, reference_source_package); end
121
-
122
- def inherited(s); end
123
- end
124
- end
125
-
126
- # This module cannot be accessed by clients of `PackageProtections` -- only within the `PackageProtections` module itself.
127
- # All implementation details are in here to keep the main `PackageProtections` module easily scannable and to keep the private things private.
128
- module PackageProtections::Private
129
- class << self
130
- sig { returns(T::Array[::PackageProtections::ProtectedPackage]) }
131
- def all_protected_packages; end
132
-
133
- sig { void }
134
- def bust_cache!; end
135
-
136
- sig { returns(::PackageProtections::Private::Configuration) }
137
- def config; end
138
-
139
- sig do
140
- params(
141
- packages: T::Array[::ParsePackwerk::Package],
142
- new_violations: T::Array[::PackageProtections::PerFileViolation]
143
- ).returns(T::Array[::PackageProtections::Offense])
144
- end
145
- def get_offenses(packages:, new_violations:); end
146
-
147
- sig { params(name: ::String).returns(::PackageProtections::ProtectedPackage) }
148
- def get_package_with_name(name); end
149
-
150
- sig do
151
- params(
152
- package_names: T::Array[::String],
153
- all_packages: T::Array[::ParsePackwerk::Package]
154
- ).returns(T::Array[::ParsePackwerk::Package])
155
- end
156
- def packages_for_names(package_names, all_packages); end
157
-
158
- sig { params(identifier: ::String).returns(T::Hash[T.untyped, T.untyped]) }
159
- def private_cop_config(identifier); end
160
-
161
- sig { params(root_pathname: ::Pathname).returns(::String) }
162
- def rubocop_yml(root_pathname:); end
163
-
164
- sig do
165
- params(
166
- packages: T::Array[::ParsePackwerk::Package],
167
- protection_identifiers: T::Array[::String],
168
- verbose: T::Boolean
169
- ).void
170
- end
171
- def set_defaults!(packages, protection_identifiers:, verbose:); end
172
- end
173
- end
174
-
175
- class PackageProtections::Private::ColorizedString
176
- sig { params(original_string: ::String, color: ::PackageProtections::Private::ColorizedString::Color).void }
177
- def initialize(original_string, color = T.unsafe(nil)); end
178
-
179
- sig { returns(::PackageProtections::Private::ColorizedString) }
180
- def blue; end
181
-
182
- sig { returns(::String) }
183
- def colorized_to_s; end
184
-
185
- sig { returns(::PackageProtections::Private::ColorizedString) }
186
- def green; end
187
-
188
- sig { returns(::PackageProtections::Private::ColorizedString) }
189
- def light_blue; end
190
-
191
- sig { returns(::PackageProtections::Private::ColorizedString) }
192
- def pink; end
193
-
194
- sig { returns(::PackageProtections::Private::ColorizedString) }
195
- def red; end
196
-
197
- sig { returns(::String) }
198
- def to_s; end
199
-
200
- sig { returns(::PackageProtections::Private::ColorizedString) }
201
- def white; end
202
-
203
- sig { returns(::PackageProtections::Private::ColorizedString) }
204
- def yellow; end
205
-
206
- private
207
-
208
- sig { returns(::Integer) }
209
- def color_code; end
210
-
211
- sig do
212
- params(
213
- color: ::PackageProtections::Private::ColorizedString::Color
214
- ).returns(::PackageProtections::Private::ColorizedString)
215
- end
216
- def colorize(color); end
217
- end
218
-
219
- class PackageProtections::Private::ColorizedString::Color < ::T::Enum
220
- enums do
221
- Black = new
222
- Red = new
223
- Green = new
224
- Yellow = new
225
- Blue = new
226
- Pink = new
227
- LightBlue = new
228
- White = new
229
- end
230
- end
231
-
232
- class PackageProtections::Private::Configuration
233
- sig { void }
234
- def initialize; end
235
-
236
- sig { void }
237
- def bust_cache!; end
238
-
239
- sig { returns(T::Array[::PackageProtections::ProtectionInterface]) }
240
- def default_protections; end
241
-
242
- sig { returns(T::Array[::PackageProtections::ProtectionInterface]) }
243
- def protections; end
244
-
245
- sig { params(protections: T::Array[::PackageProtections::ProtectionInterface]).void }
246
- def protections=(protections); end
247
- end
248
-
249
- class PackageProtections::Private::IncomingPrivacyProtection
250
- include ::PackageProtections::ProtectionInterface
251
-
252
- sig do
253
- override
254
- .params(
255
- protected_packages: T::Array[::PackageProtections::ProtectedPackage]
256
- ).returns(T::Array[::PackageProtections::Offense])
257
- end
258
- def get_offenses_for_existing_violations(protected_packages); end
259
-
260
- sig do
261
- override
262
- .params(
263
- new_violations: T::Array[::PackageProtections::PerFileViolation]
264
- ).returns(T::Array[::PackageProtections::Offense])
265
- end
266
- def get_offenses_for_new_violations(new_violations); end
267
-
268
- sig { override.returns(::String) }
269
- def humanized_protection_description; end
270
-
271
- sig { override.returns(::String) }
272
- def humanized_protection_name; end
273
-
274
- sig { override.returns(::String) }
275
- def identifier; end
276
-
277
- sig do
278
- override
279
- .params(
280
- behavior: ::PackageProtections::ViolationBehavior,
281
- package: ::ParsePackwerk::Package
282
- ).returns(T.nilable(::String))
283
- end
284
- def unmet_preconditions_for_behavior(behavior, package); end
285
-
286
- private
287
-
288
- sig { params(per_file_violation: ::PackageProtections::PerFileViolation).returns(::String) }
289
- def message_for_fail_on_any(per_file_violation); end
290
-
291
- sig { params(per_file_violation: ::PackageProtections::PerFileViolation).returns(::String) }
292
- def message_for_fail_on_new(per_file_violation); end
293
- end
294
-
295
- PackageProtections::Private::IncomingPrivacyProtection::IDENTIFIER = T.let(T.unsafe(nil), String)
296
-
297
- class PackageProtections::Private::MetadataModifiers
298
- class << self
299
- sig do
300
- params(
301
- package: ::ParsePackwerk::Package,
302
- protection_identifier: ::String,
303
- violation_behavior: ::PackageProtections::ViolationBehavior
304
- ).returns(::ParsePackwerk::Package)
305
- end
306
- def package_with_modified_protection(package, protection_identifier, violation_behavior); end
307
- end
308
- end
309
-
310
- class PackageProtections::Private::OutgoingDependencyProtection
311
- include ::PackageProtections::ProtectionInterface
312
-
313
- sig do
314
- override
315
- .params(
316
- protected_packages: T::Array[::PackageProtections::ProtectedPackage]
317
- ).returns(T::Array[::PackageProtections::Offense])
318
- end
319
- def get_offenses_for_existing_violations(protected_packages); end
320
-
321
- sig do
322
- override
323
- .params(
324
- new_violations: T::Array[::PackageProtections::PerFileViolation]
325
- ).returns(T::Array[::PackageProtections::Offense])
326
- end
327
- def get_offenses_for_new_violations(new_violations); end
328
-
329
- sig { override.returns(::String) }
330
- def humanized_protection_description; end
331
-
332
- sig { override.returns(::String) }
333
- def humanized_protection_name; end
334
-
335
- sig { override.returns(::String) }
336
- def identifier; end
337
-
338
- sig do
339
- override
340
- .params(
341
- behavior: ::PackageProtections::ViolationBehavior,
342
- package: ::ParsePackwerk::Package
343
- ).returns(T.nilable(::String))
344
- end
345
- def unmet_preconditions_for_behavior(behavior, package); end
346
-
347
- private
348
-
349
- sig { params(per_file_violation: ::PackageProtections::PerFileViolation).returns(::String) }
350
- def message_for_fail_on_any(per_file_violation); end
351
-
352
- sig { params(per_file_violation: ::PackageProtections::PerFileViolation).returns(::String) }
353
- def message_for_fail_on_new(per_file_violation); end
354
- end
355
-
356
- PackageProtections::Private::OutgoingDependencyProtection::IDENTIFIER = T.let(T.unsafe(nil), String)
357
-
358
- class PackageProtections::Private::Output
359
- class << self
360
- sig { params(str: ::String).void }
361
- def p(str); end
362
-
363
- sig { params(str: ::PackageProtections::Private::ColorizedString, colorized: T::Boolean).void }
364
- def p_colorized(str, colorized:); end
365
- end
366
- end
367
-
368
- class PackageProtections::Private::VisibilityProtection
369
- include ::PackageProtections::ProtectionInterface
370
-
371
- # By default, this protection does not show up when creating a new package, and its default behavior is FailNever
372
- # A package that uses this protection is not considered strictly better -- in general, we want to design packages that
373
- # are consumable by all packages. Therefore, a package that is consumable by all packages is the happy path.
374
- #
375
- # If a user wants to turn on package visibility, they must do it explicitly.
376
- sig { returns(::PackageProtections::ViolationBehavior) }
377
- def default_behavior; end
378
-
379
- sig do
380
- override
381
- .params(
382
- protected_packages: T::Array[::PackageProtections::ProtectedPackage]
383
- ).returns(T::Array[::PackageProtections::Offense])
384
- end
385
- def get_offenses_for_existing_violations(protected_packages); end
386
-
387
- sig do
388
- override
389
- .params(
390
- new_violations: T::Array[::PackageProtections::PerFileViolation]
391
- ).returns(T::Array[::PackageProtections::Offense])
392
- end
393
- def get_offenses_for_new_violations(new_violations); end
394
-
395
- sig { override.returns(::String) }
396
- def humanized_protection_description; end
397
-
398
- sig { override.returns(::String) }
399
- def humanized_protection_name; end
400
-
401
- sig { override.returns(::String) }
402
- def identifier; end
403
-
404
- sig do
405
- override
406
- .params(
407
- behavior: ::PackageProtections::ViolationBehavior,
408
- package: ::ParsePackwerk::Package
409
- ).returns(T.nilable(::String))
410
- end
411
- def unmet_preconditions_for_behavior(behavior, package); end
412
-
413
- private
414
-
415
- sig { params(per_file_violation: ::PackageProtections::PerFileViolation).returns(::String) }
416
- def message_for_fail_on_any(per_file_violation); end
417
-
418
- sig { params(per_file_violation: ::PackageProtections::PerFileViolation).returns(::String) }
419
- def message_for_fail_on_new(per_file_violation); end
420
- end
421
-
422
- PackageProtections::Private::VisibilityProtection::IDENTIFIER = T.let(T.unsafe(nil), String)
423
-
424
- class PackageProtections::ProtectedPackage < ::T::Struct
425
- const :deprecated_references, ::ParsePackwerk::DeprecatedReferences
426
- const :original_package, ::ParsePackwerk::Package
427
- const :protections, T::Hash[::String, ::PackageProtections::ViolationBehavior]
428
-
429
- sig { returns(T::Array[::String]) }
430
- def dependencies; end
431
-
432
- sig { returns(T::Hash[T.untyped, T.untyped]) }
433
- def metadata; end
434
-
435
- sig { returns(::String) }
436
- def name; end
437
-
438
- sig { params(key: ::String).returns(::PackageProtections::ViolationBehavior) }
439
- def violation_behavior_for(key); end
440
-
441
- sig { returns(T::Array[::ParsePackwerk::Violation]) }
442
- def violations; end
443
-
444
- sig { returns(T::Set[::String]) }
445
- def visible_to; end
446
-
447
- sig { returns(::Pathname) }
448
- def yml; end
449
-
450
- class << self
451
- sig { params(original_package: ::ParsePackwerk::Package).returns(::PackageProtections::ProtectedPackage) }
452
- def from(original_package); end
453
-
454
- sig do
455
- params(
456
- protection: ::PackageProtections::ProtectionInterface,
457
- metadata: T::Hash[T.untyped, T.untyped],
458
- package: ::ParsePackwerk::Package
459
- ).returns(::PackageProtections::ViolationBehavior)
460
- end
461
- def get_violation_behavior(protection, metadata, package); end
462
-
463
- def inherited(s); end
464
- end
465
- end
466
-
467
- # @abstract Subclasses must implement the `abstract` methods below.
468
- module PackageProtections::ProtectionInterface
469
- requires_ancestor { Kernel }
470
-
471
- abstract!
472
-
473
- sig { returns(::PackageProtections::ViolationBehavior) }
474
- def default_behavior; end
475
-
476
- sig do
477
- params(
478
- protected_packages: T::Array[::PackageProtections::ProtectedPackage],
479
- new_violations: T::Array[::PackageProtections::PerFileViolation]
480
- ).returns(T::Array[::PackageProtections::Offense])
481
- end
482
- def get_offenses(protected_packages, new_violations); end
483
-
484
- # @abstract
485
- sig do
486
- abstract
487
- .params(
488
- protected_packages: T::Array[::PackageProtections::ProtectedPackage]
489
- ).returns(T::Array[::PackageProtections::Offense])
490
- end
491
- def get_offenses_for_existing_violations(protected_packages); end
492
-
493
- # @abstract
494
- sig do
495
- abstract
496
- .params(
497
- new_violations: T::Array[::PackageProtections::PerFileViolation]
498
- ).returns(T::Array[::PackageProtections::Offense])
499
- end
500
- def get_offenses_for_new_violations(new_violations); end
501
-
502
- # @abstract
503
- sig { abstract.returns(::String) }
504
- def humanized_protection_description; end
505
-
506
- # @abstract
507
- sig { abstract.returns(::String) }
508
- def humanized_protection_name; end
509
-
510
- # @abstract
511
- sig { abstract.returns(::String) }
512
- def identifier; end
513
-
514
- sig do
515
- params(
516
- behavior: ::PackageProtections::ViolationBehavior,
517
- package: ::ParsePackwerk::Package
518
- ).returns(T::Boolean)
519
- end
520
- def supports_violation_behavior?(behavior, package); end
521
-
522
- # @abstract
523
- sig do
524
- abstract
525
- .params(
526
- behavior: ::PackageProtections::ViolationBehavior,
527
- package: ::ParsePackwerk::Package
528
- ).returns(T.nilable(::String))
529
- end
530
- def unmet_preconditions_for_behavior(behavior, package); end
531
- end
532
-
533
- # @abstract Subclasses must implement the `abstract` methods below.
534
- module PackageProtections::RubocopProtectionInterface
535
- include ::PackageProtections::ProtectionInterface
536
-
537
- abstract!
538
-
539
- sig do
540
- params(
541
- packages: T::Array[::PackageProtections::ProtectedPackage]
542
- ).returns(T::Array[::PackageProtections::RubocopProtectionInterface::CopConfig])
543
- end
544
- def cop_configs(packages); end
545
-
546
- # Abstract Methods: These are methods that the client needs to implement
547
- #
548
- # @abstract
549
- sig { abstract.returns(::String) }
550
- def cop_name; end
551
-
552
- # Overriddable Methods: These are methods that the client can override,
553
- # but a default is provided.
554
- sig { params(package: ::PackageProtections::ProtectedPackage).returns(T::Hash[T.untyped, T.untyped]) }
555
- def custom_cop_config(package); end
556
-
557
- sig do
558
- override
559
- .params(
560
- protected_packages: T::Array[::PackageProtections::ProtectedPackage]
561
- ).returns(T::Array[::PackageProtections::Offense])
562
- end
563
- def get_offenses_for_existing_violations(protected_packages); end
564
-
565
- sig do
566
- override
567
- .params(
568
- new_violations: T::Array[::PackageProtections::PerFileViolation]
569
- ).returns(T::Array[::PackageProtections::Offense])
570
- end
571
- def get_offenses_for_new_violations(new_violations); end
572
-
573
- # @abstract
574
- sig { abstract.returns(T::Array[::String]) }
575
- def included_globs_for_pack; end
576
-
577
- # @abstract
578
- sig { abstract.params(file: ::String).returns(::String) }
579
- def message_for_fail_on_any(file); end
580
-
581
- sig do
582
- override
583
- .params(
584
- behavior: ::PackageProtections::ViolationBehavior,
585
- package: ::ParsePackwerk::Package
586
- ).returns(T.nilable(::String))
587
- end
588
- def unmet_preconditions_for_behavior(behavior, package); end
589
-
590
- private
591
-
592
- sig { params(rule: ::String).returns(T::Set[::String]) }
593
- def exclude_for_rule(rule); end
594
-
595
- class << self
596
- sig { void }
597
- def bust_rubocop_todo_yml_cache; end
598
-
599
- sig { returns(T.untyped) }
600
- def rubocop_todo_yml; end
601
- end
602
- end
603
-
604
- class PackageProtections::RubocopProtectionInterface::CopConfig < ::T::Struct
605
- const :enabled, T::Boolean, default: T.unsafe(nil)
606
- const :exclude_paths, T::Array[::String], default: T.unsafe(nil)
607
- const :include_paths, T::Array[::String], default: T.unsafe(nil)
608
- const :name, ::String
609
-
610
- sig { returns(::String) }
611
- def to_rubocop_yml_compatible_format; end
612
-
613
- class << self
614
- def inherited(s); end
615
- end
616
- end
617
-
618
- class PackageProtections::ViolationBehavior < ::T::Enum
619
- enums do
620
- FailOnAny = new
621
- FailOnNew = new
622
- FailNever = new
623
- end
624
-
625
- sig { returns(T::Boolean) }
626
- def enabled?; end
627
-
628
- sig { returns(T::Boolean) }
629
- def fail_never?; end
630
-
631
- sig { returns(T::Boolean) }
632
- def fail_on_any?; end
633
-
634
- sig { returns(T::Boolean) }
635
- def fail_on_new?; end
636
-
637
- class << self
638
- sig { params(value: T.untyped).returns(::PackageProtections::ViolationBehavior) }
639
- def from_raw_value(value); end
640
- end
641
- end
642
-
643
- RuboCop::Cop::PackageProtections::NamespacedUnderPackageName::IDENTIFIER = T.let(T.unsafe(nil), String)
644
-
645
- # This inherits from `Sorbet::StrictSigil` and doesn't change any behavior of it.
646
- # The only reason we do this is so that configuration for this cop can live under a different cop namespace.
647
- # This prevents this cop's configuration from clashing with other configurations for the same cop.
648
- # A concrete example of this would be if a user is using this package protection to make sure public APIs are typed,
649
- # and separately the application as a whole requiring strict typing in certain parts of the application.
650
- #
651
- # To prevent problems associated with needing to manage identical configurations for the same cop, we simply call it
652
- # something else in the context of this protection.
653
- #
654
- # We can apply this same pattern if we want to use other cops in the context of package protections and prevent clashing.