rubocop-packs 0.0.13 → 0.0.14

Sign up to get free protection for your applications and to get access to all the features.
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