rubocop-packs 0.0.13 → 0.0.14

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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rubocop/cop/packs/namespace_convention.rb +12 -45
  3. data/lib/rubocop/packs/private/configuration.rb +10 -0
  4. data/lib/rubocop/packs/private.rb +112 -0
  5. data/lib/rubocop/packs.rb +11 -44
  6. metadata +2 -42
  7. data/sorbet/config +0 -3
  8. data/sorbet/rbi/gems/activesupport@7.0.4.rbi +0 -15914
  9. data/sorbet/rbi/gems/ast@2.4.2.rbi +0 -584
  10. data/sorbet/rbi/gems/coderay@1.1.3.rbi +0 -8
  11. data/sorbet/rbi/gems/concurrent-ruby@1.1.10.rbi +0 -11263
  12. data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +0 -1079
  13. data/sorbet/rbi/gems/i18n@1.12.0.rbi +0 -2296
  14. data/sorbet/rbi/gems/json@2.6.2.rbi +0 -1547
  15. data/sorbet/rbi/gems/method_source@1.0.0.rbi +0 -8
  16. data/sorbet/rbi/gems/minitest@5.16.3.rbi +0 -1459
  17. data/sorbet/rbi/gems/netrc@0.11.0.rbi +0 -161
  18. data/sorbet/rbi/gems/parallel@1.22.1.rbi +0 -277
  19. data/sorbet/rbi/gems/parse_packwerk@0.12.1.rbi +0 -203
  20. data/sorbet/rbi/gems/parser@3.1.2.1.rbi +0 -8944
  21. data/sorbet/rbi/gems/pry@0.14.1.rbi +0 -8
  22. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +0 -392
  23. data/sorbet/rbi/gems/rake@13.0.6.rbi +0 -2899
  24. data/sorbet/rbi/gems/rbi@0.0.16.rbi +0 -3007
  25. data/sorbet/rbi/gems/regexp_parser@2.6.0.rbi +0 -3498
  26. data/sorbet/rbi/gems/rexml@3.2.5.rbi +0 -4717
  27. data/sorbet/rbi/gems/rspec-core@3.11.0.rbi +0 -10934
  28. data/sorbet/rbi/gems/rspec-expectations@3.11.1.rbi +0 -8090
  29. data/sorbet/rbi/gems/rspec-mocks@3.11.1.rbi +0 -5291
  30. data/sorbet/rbi/gems/rspec-support@3.11.1.rbi +0 -1610
  31. data/sorbet/rbi/gems/rspec@3.11.0.rbi +0 -88
  32. data/sorbet/rbi/gems/rubocop-ast@1.21.0.rbi +0 -6898
  33. data/sorbet/rbi/gems/rubocop-extension-generator@0.5.1.rbi +0 -86
  34. data/sorbet/rbi/gems/rubocop-sorbet@0.6.11.rbi +0 -1002
  35. data/sorbet/rbi/gems/rubocop@1.36.0.rbi +0 -52209
  36. data/sorbet/rbi/gems/ruby-progressbar@1.11.0.rbi +0 -1239
  37. data/sorbet/rbi/gems/spoom@1.1.12.rbi +0 -2369
  38. data/sorbet/rbi/gems/tapioca@0.10.2.rbi +0 -3439
  39. data/sorbet/rbi/gems/thor@1.2.1.rbi +0 -3956
  40. data/sorbet/rbi/gems/tzinfo@2.0.5.rbi +0 -5896
  41. data/sorbet/rbi/gems/unicode-display_width@2.3.0.rbi +0 -48
  42. data/sorbet/rbi/gems/unparser@0.6.5.rbi +0 -4529
  43. data/sorbet/rbi/gems/webrick@1.7.0.rbi +0 -2586
  44. data/sorbet/rbi/gems/yard-sorbet@0.7.0.rbi +0 -389
  45. data/sorbet/rbi/gems/yard@0.9.28.rbi +0 -17775
  46. data/sorbet/rbi/todo.rbi +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1ae6001b8bc58c5541d1869363e9506de8e28326d449eb2eff7733391c62d9cb
4
- data.tar.gz: 07557221e1ac695c3eb5e1170dd6f0b3d45d4116d579cc56aaed94ac4ffee8f4
3
+ metadata.gz: be0363ed2023527b2c25a80a934abac48fd8e75c5c9b8f3882e0391305f2544c
4
+ data.tar.gz: 3a082b0eb17b5bf25a2cbba0fbe01322b7d56598512102551c87635bbaea2df9
5
5
  SHA512:
6
- metadata.gz: 1b262c2ded4ce2705f28b3d9a70b9a0a0a39864d53b198946f5b5da2de8b0dec29a1d1b9acbcf782e87f649dbc09f461d8f64ade2aa54f31f4ebfff1d3441212
7
- data.tar.gz: a9f4b9085ef8de3d7a2d6ed45fd105ac54fe2bcd4d6c013c8f6178ab88318aefb0e7ba58b9f49480d02d2bafb8bf9bbd49458e36e02e6e2a79e136f90a72c10f
6
+ metadata.gz: 06a8046673579208dbe40a4f46b9cb11ff7360af8712736b794b0e66cfc9ec0411f9cdf837bf2acfd03c2f11cbeb82b6ff9291ca768824ffe2fc19f0d15d7e17
7
+ data.tar.gz: 9debb88541b7c1e9506078c4de88ca6507d6f2b3fab95226269c70265a438c15533f1fae6dfc7a13b0707a93ec269093ec3fe0561a06047c83d05ed7e635fa18
@@ -11,6 +11,8 @@ module RuboCop
11
11
  # Note that this cop doesn't necessarily expect you to be using stimpack (https://github.com/rubyatscale/stimpack),
12
12
  # but it does expect packs to live in the organizational structure as described in the README.md of that gem.
13
13
  #
14
+ # This allows packs to opt in and also prevent *other* files from sitting in their namespace.
15
+ #
14
16
  # @example
15
17
  #
16
18
  # # bad
@@ -47,7 +49,7 @@ module RuboCop
47
49
 
48
50
  allowed_global_namespaces = Set.new([
49
51
  namespace_context.expected_namespace,
50
- *cop_config['GloballyPermittedNamespaces']
52
+ *RuboCop::Packs.config.globally_permitted_namespaces
51
53
  ])
52
54
 
53
55
  package_name = package_for_path.name
@@ -57,36 +59,18 @@ module RuboCop
57
59
  if allowed_global_namespaces.include?(actual_namespace)
58
60
  # No problem!
59
61
  else
60
- package_enforces_namespaces = (cop_config['IncludePacks'] || []).include?(package_for_path.name)
61
62
  expected_namespace = namespace_context.expected_namespace
62
63
  relative_desired_path = namespace_context.expected_filepath
63
- pack_owning_this_namespace = namespaces_to_packs[actual_namespace]
64
-
65
- if package_enforces_namespaces
66
- add_offense(
67
- source_range(processed_source.buffer, 1, 0),
68
- message: format(
69
- 'Based on the filepath, this file defines `%<current_fully_qualified_constant>s`, but it should be namespaced as `%<expected_namespace>s::%<current_fully_qualified_constant>s` with path `%<expected_path>s`.',
70
- package_name: package_name,
71
- expected_namespace: expected_namespace,
72
- expected_path: relative_desired_path,
73
- current_fully_qualified_constant: current_fully_qualified_constant
74
- )
64
+ add_offense(
65
+ source_range(processed_source.buffer, 1, 0),
66
+ message: format(
67
+ 'Based on the filepath, this file defines `%<current_fully_qualified_constant>s`, but it should be namespaced as `%<expected_namespace>s::%<current_fully_qualified_constant>s` with path `%<expected_path>s`.',
68
+ package_name: package_name,
69
+ expected_namespace: expected_namespace,
70
+ expected_path: relative_desired_path,
71
+ current_fully_qualified_constant: current_fully_qualified_constant
75
72
  )
76
- elsif pack_owning_this_namespace
77
- add_offense(
78
- source_range(processed_source.buffer, 1, 0),
79
- message: format(
80
- 'Based on the filepath, this file defines `%<current_fully_qualified_constant>s`. `%<pack_owning_this_namespace>s` prevents other packs from sitting in the `%<actual_namespace>s` namespace. This should be namespaced under `%<expected_namespace>s` with path `%<expected_path>s`.',
81
- package_name: package_name,
82
- pack_owning_this_namespace: pack_owning_this_namespace,
83
- expected_namespace: expected_namespace,
84
- actual_namespace: actual_namespace,
85
- current_fully_qualified_constant: current_fully_qualified_constant,
86
- expected_path: relative_desired_path
87
- )
88
- )
89
- end
73
+ )
90
74
  end
91
75
  end
92
76
 
@@ -104,23 +88,6 @@ module RuboCop
104
88
  @desired_zeitwerk_api ||= T.let(nil, T.nilable(DesiredZeitwerkApi))
105
89
  @desired_zeitwerk_api ||= DesiredZeitwerkApi.new
106
90
  end
107
-
108
- sig { returns(T::Hash[String, String]) }
109
- def namespaces_to_packs
110
- @namespaces_to_packs = T.let(nil, T.nilable(T::Hash[String, String]))
111
- @namespaces_to_packs ||= begin
112
- all_packs_enforcing_namespaces = ParsePackwerk.all.select do |p|
113
- (cop_config['IncludePacks'] || []).include?(p.name)
114
- end
115
-
116
- namespaces_to_packs = {}
117
- all_packs_enforcing_namespaces.each do |package|
118
- namespaces_to_packs[desired_zeitwerk_api.get_pack_based_namespace(package)] = package.name
119
- end
120
-
121
- namespaces_to_packs
122
- end
123
- end
124
91
  end
125
92
  end
126
93
  end
@@ -10,14 +10,24 @@ module RuboCop
10
10
  sig { returns(T::Array[String]) }
11
11
  attr_accessor :permitted_pack_level_cops
12
12
 
13
+ sig { returns(T::Array[String]) }
14
+ attr_accessor :required_pack_level_cops
15
+
16
+ sig { returns(T::Array[String]) }
17
+ attr_accessor :globally_permitted_namespaces
18
+
13
19
  sig { void }
14
20
  def initialize
15
21
  @permitted_pack_level_cops = T.let([], T::Array[String])
22
+ @globally_permitted_namespaces = T.let([], T::Array[String])
23
+ @required_pack_level_cops = T.let([], T::Array[String])
16
24
  end
17
25
 
18
26
  sig { void }
19
27
  def bust_cache!
20
28
  @permitted_pack_level_cops = []
29
+ @globally_permitted_namespaces = []
30
+ @required_pack_level_cops = []
21
31
  end
22
32
  end
23
33
  end
@@ -34,6 +34,118 @@ module RuboCop
34
34
  end
35
35
  end
36
36
  end
37
+
38
+ sig { params(package: ParsePackwerk::Package).returns(T::Array[String]) }
39
+ def self.validate_rubocop_todo_yml(package)
40
+ errors = []
41
+ rubocop_todo = package.directory.join('.rubocop_todo.yml')
42
+ return errors unless rubocop_todo.exist?
43
+
44
+ loaded_rubocop_todo = YAML.load_file(rubocop_todo)
45
+ loaded_rubocop_todo.each_key do |key|
46
+ if !Packs.config.permitted_pack_level_cops.include?(key)
47
+ errors << <<~ERROR_MESSAGE
48
+ #{rubocop_todo} contains invalid configuration for #{key}.
49
+ Please only configure the following cops on a per-pack basis: #{Packs.config.permitted_pack_level_cops.inspect}"
50
+ For ignoring other cops, please instead modify the top-level .rubocop_todo.yml file.
51
+ ERROR_MESSAGE
52
+ elsif loaded_rubocop_todo[key].keys != ['Exclude']
53
+ errors << <<~ERROR_MESSAGE
54
+ #{rubocop_todo} contains invalid configuration for #{key}.
55
+ Please ensure the only configuration for #{key} is `Exclude`
56
+ ERROR_MESSAGE
57
+ else
58
+ loaded_rubocop_todo[key]['Exclude'].each do |filepath|
59
+ return [] unless ParsePackwerk.package_from_path(filepath).name != package.name
60
+
61
+ errors << <<~ERROR_MESSAGE
62
+ #{rubocop_todo} contains invalid configuration for #{key}.
63
+ #{filepath} does not belong to #{package.name}. Please ensure you only add exclusions
64
+ for files within this pack.
65
+ ERROR_MESSAGE
66
+ end
67
+ end
68
+ end
69
+
70
+ errors
71
+ end
72
+
73
+ sig { params(package: ParsePackwerk::Package).returns(T::Array[String]) }
74
+ def self.validate_rubocop_yml(package)
75
+ errors = []
76
+ rubocop_yml = package.directory.join('.rubocop.yml')
77
+ return errors unless rubocop_yml.exist?
78
+
79
+ loaded_rubocop_yml = YAML.load_file(rubocop_yml)
80
+ missing_keys = Packs.config.required_pack_level_cops - loaded_rubocop_yml.keys
81
+ missing_keys.each do |key|
82
+ errors << <<~ERROR_MESSAGE
83
+ #{rubocop_yml} is missing configuration for #{key}.
84
+ ERROR_MESSAGE
85
+ end
86
+
87
+ loaded_rubocop_yml.each_key do |key|
88
+ if !Packs.config.permitted_pack_level_cops.include?(key)
89
+ errors << <<~ERROR_MESSAGE
90
+ #{rubocop_yml} contains invalid configuration for #{key}.
91
+ Please only configure the following cops on a per-pack basis: #{Packs.config.permitted_pack_level_cops.inspect}"
92
+ For ignoring other cops, please instead modify the top-level .rubocop.yml file.
93
+ ERROR_MESSAGE
94
+ elsif (loaded_rubocop_yml[key].keys - %w[Enabled FailureMode]).any?
95
+ errors << <<~ERROR_MESSAGE
96
+ #{rubocop_yml} contains invalid configuration for #{key}.
97
+ Please ensure the only configuration for #{key} is `Enabled` and `FailureMode`
98
+ ERROR_MESSAGE
99
+ end
100
+ end
101
+
102
+ errors
103
+ end
104
+
105
+ sig { params(rule: String).returns(T::Set[String]) }
106
+ def self.exclude_for_rule(rule)
107
+ excludes = T.let(Set.new, T::Set[String])
108
+
109
+ Private.rubocop_todo_ymls.each do |todo_yml|
110
+ next if !todo_yml
111
+
112
+ config = todo_yml[rule]
113
+ next if config.nil?
114
+
115
+ exclude_list = config['Exclude']
116
+ next if exclude_list.nil?
117
+
118
+ excludes += exclude_list
119
+ end
120
+
121
+ excludes
122
+ end
123
+
124
+ sig { params(package: ParsePackwerk::Package).returns(T::Array[String]) }
125
+ def self.validate_failure_mode_strict(package)
126
+ errors = T.let([], T::Array[String])
127
+
128
+ Packs.config.permitted_pack_level_cops.each do |cop|
129
+ excludes = exclude_for_rule(cop)
130
+
131
+ rubocop_yml = package.directory.join('.rubocop.yml')
132
+
133
+ next unless rubocop_yml.exist?
134
+
135
+ loaded_rubocop_yml = YAML.load_file(rubocop_yml)
136
+ next unless loaded_rubocop_yml[cop] && loaded_rubocop_yml[cop]['FailureMode'] == 'strict'
137
+
138
+ excludes_for_package = excludes.select do |exclude|
139
+ ParsePackwerk.package_from_path(exclude).name == package.name
140
+ end
141
+ next if excludes_for_package.empty?
142
+
143
+ formatted_excludes = excludes_for_package.map { |ex| "`#{ex}`" }.join(', ')
144
+ errors << "#{package.name} has set `#{cop}` to `FailureMode: strict` in `packs/some_pack/.rubocop.yml`, forbidding new exceptions. Please either remove #{formatted_excludes} from the top-level and pack-specific `.rubocop_todo.yml` files or remove `FailureMode: strict`."
145
+ end
146
+
147
+ errors
148
+ end
37
149
  end
38
150
 
39
151
  private_constant :Private
data/lib/rubocop/packs.rb CHANGED
@@ -107,59 +107,26 @@ module RuboCop
107
107
  @config ||= Private::Configuration.new
108
108
  end
109
109
 
110
+ # We can remove this function once package_protections is fully deprecated
110
111
  sig { params(rule: String).returns(T::Set[String]) }
111
112
  def self.exclude_for_rule(rule)
112
- excludes = T.let(Set.new, T::Set[String])
113
-
114
- Private.rubocop_todo_ymls.each do |todo_yml|
115
- next if !todo_yml
116
-
117
- config = todo_yml[rule]
118
- next if config.nil?
119
-
120
- exclude_list = config['Exclude']
121
- next if exclude_list.nil?
122
-
123
- excludes += exclude_list
124
- end
125
-
126
- excludes
113
+ Private.exclude_for_rule(rule)
127
114
  end
128
115
 
116
+ #
117
+ # Note: when we add per-pack `.rubocop.yml` files, we'll want to add some validations here
118
+ # to restrict what cops are permitted to be configured in those files.
119
+ # We might also want further (configurable?) constraints *requiring* that the "permitted pack level cops" be specified explicitly.
120
+ #
129
121
  sig { returns(T::Array[String]) }
130
122
  def self.validate
131
- errors = []
123
+ errors = T.let([], T::Array[String])
132
124
  ParsePackwerk.all.each do |package|
133
125
  next if package.name == ParsePackwerk::ROOT_PACKAGE_NAME
134
126
 
135
- rubocop_todo = package.directory.join('.rubocop_todo.yml')
136
- next unless rubocop_todo.exist?
137
-
138
- loaded_rubocop_todo = YAML.load_file(rubocop_todo)
139
- loaded_rubocop_todo.each_key do |key|
140
- if !config.permitted_pack_level_cops.include?(key)
141
- errors << <<~ERROR_MESSAGE
142
- #{rubocop_todo} contains invalid configuration for #{key}.
143
- Please ensure the only configuration is for package protection exclusions, which are one of the following cops: #{config.permitted_pack_level_cops.inspect}"
144
- For ignoring other cops, please instead modify the top-level .rubocop_todo.yml file.
145
- ERROR_MESSAGE
146
- elsif loaded_rubocop_todo[key].keys != ['Exclude']
147
- errors << <<~ERROR_MESSAGE
148
- #{rubocop_todo} contains invalid configuration for #{key}.
149
- Please ensure the only configuration for #{key} is `Exclude`
150
- ERROR_MESSAGE
151
- else
152
- loaded_rubocop_todo[key]['Exclude'].each do |filepath|
153
- next unless ParsePackwerk.package_from_path(filepath).name != package.name
154
-
155
- errors << <<~ERROR_MESSAGE
156
- #{rubocop_todo} contains invalid configuration for #{key}.
157
- #{filepath} does not belong to #{package.name}. Please ensure you only add exclusions
158
- for files within this pack.
159
- ERROR_MESSAGE
160
- end
161
- end
162
- end
127
+ errors += Private.validate_rubocop_todo_yml(package)
128
+ errors += Private.validate_rubocop_yml(package)
129
+ errors += Private.validate_failure_mode_strict(package)
163
130
  end
164
131
 
165
132
  errors
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-packs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.13
4
+ version: 0.0.14
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-10-24 00:00:00.000000000 Z
11
+ date: 2022-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -203,46 +203,6 @@ files:
203
203
  - lib/rubocop/packs/private.rb
204
204
  - lib/rubocop/packs/private/configuration.rb
205
205
  - lib/rubocop/packwerk_lite.rb
206
- - sorbet/config
207
- - sorbet/rbi/gems/activesupport@7.0.4.rbi
208
- - sorbet/rbi/gems/ast@2.4.2.rbi
209
- - sorbet/rbi/gems/coderay@1.1.3.rbi
210
- - sorbet/rbi/gems/concurrent-ruby@1.1.10.rbi
211
- - sorbet/rbi/gems/diff-lcs@1.5.0.rbi
212
- - sorbet/rbi/gems/i18n@1.12.0.rbi
213
- - sorbet/rbi/gems/json@2.6.2.rbi
214
- - sorbet/rbi/gems/method_source@1.0.0.rbi
215
- - sorbet/rbi/gems/minitest@5.16.3.rbi
216
- - sorbet/rbi/gems/netrc@0.11.0.rbi
217
- - sorbet/rbi/gems/parallel@1.22.1.rbi
218
- - sorbet/rbi/gems/parse_packwerk@0.12.1.rbi
219
- - sorbet/rbi/gems/parser@3.1.2.1.rbi
220
- - sorbet/rbi/gems/pry@0.14.1.rbi
221
- - sorbet/rbi/gems/rainbow@3.1.1.rbi
222
- - sorbet/rbi/gems/rake@13.0.6.rbi
223
- - sorbet/rbi/gems/rbi@0.0.16.rbi
224
- - sorbet/rbi/gems/regexp_parser@2.6.0.rbi
225
- - sorbet/rbi/gems/rexml@3.2.5.rbi
226
- - sorbet/rbi/gems/rspec-core@3.11.0.rbi
227
- - sorbet/rbi/gems/rspec-expectations@3.11.1.rbi
228
- - sorbet/rbi/gems/rspec-mocks@3.11.1.rbi
229
- - sorbet/rbi/gems/rspec-support@3.11.1.rbi
230
- - sorbet/rbi/gems/rspec@3.11.0.rbi
231
- - sorbet/rbi/gems/rubocop-ast@1.21.0.rbi
232
- - sorbet/rbi/gems/rubocop-extension-generator@0.5.1.rbi
233
- - sorbet/rbi/gems/rubocop-sorbet@0.6.11.rbi
234
- - sorbet/rbi/gems/rubocop@1.36.0.rbi
235
- - sorbet/rbi/gems/ruby-progressbar@1.11.0.rbi
236
- - sorbet/rbi/gems/spoom@1.1.12.rbi
237
- - sorbet/rbi/gems/tapioca@0.10.2.rbi
238
- - sorbet/rbi/gems/thor@1.2.1.rbi
239
- - sorbet/rbi/gems/tzinfo@2.0.5.rbi
240
- - sorbet/rbi/gems/unicode-display_width@2.3.0.rbi
241
- - sorbet/rbi/gems/unparser@0.6.5.rbi
242
- - sorbet/rbi/gems/webrick@1.7.0.rbi
243
- - sorbet/rbi/gems/yard-sorbet@0.7.0.rbi
244
- - sorbet/rbi/gems/yard@0.9.28.rbi
245
- - sorbet/rbi/todo.rbi
246
206
  homepage: https://github.com/rubyatscale/rubocop-packs
247
207
  licenses:
248
208
  - MIT
data/sorbet/config DELETED
@@ -1,3 +0,0 @@
1
- --dir
2
- .
3
- --ignore=/vendor/bundle