rubocop-packs 0.0.19 → 0.0.20

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f2f8bb6cbf9a0c8e6a903a9e94ecbc6b31b25f38caadee98b9d433ce0ea9d83
4
- data.tar.gz: '0843185e5171470039bf39ff147fcf8f5fc93269b11c955c1358891c6df6e95f'
3
+ metadata.gz: 49afe61bb4672111e0ba64bc690715756d3d2f7130c96d71f0036add413d18ac
4
+ data.tar.gz: 615a905e64ea7647eb922d25c87b9cbbd76c3826da207dccf3ce2b511d281ccb
5
5
  SHA512:
6
- metadata.gz: ea2a62a6152a629acef1a17cf95b7833573aad7e838adbd969820490683f8ad710ce06544e54e913b231f2426ee75a2f4fe331fac37f246ebb20fb21ae5263d9
7
- data.tar.gz: 5ee607be5da8cbe0d0d416c46f0ffe983d14dbdc8effc4e1551b0aa33a6d0a323f9a5e8fefb59a12ebc1acaab31d37f98e4e59141b06a85bf486f82c0f8d2fb3
6
+ metadata.gz: e15fc57d0f220c6b26015f0e93473e268cd01efba23c8e46d6aa9a3bb0fe4fb136aed35f69173b039e233a47e32ebd80465d81f8ff0a5a9a0a45b96ad42720c6
7
+ data.tar.gz: 20acb3ad05d415715751c228e01c21aa5e975da81d088394c1627d86b927303bf278348bbb2ba938a60463a830d6001d147265edf449ff441c7a84c59d7230de
data/README.md CHANGED
@@ -41,50 +41,8 @@ Packs/RootNamespaceIsPackName:
41
41
  - lib/example.rb
42
42
  ```
43
43
 
44
- ## Pack-Level `.rubocop.yml` and `.rubocop_todo.yml` files
45
- `rubocop-packs` also has some API that help you use rubocop in a pack-based context.
46
-
47
- ### Per-pack `.rubocop.yml`
48
- While `rubocop-packs` can be used like any other `rubocop` by configuring in your top-level `.rubocop.yml` file, we also have a number of tools to support per-pack configuration.
49
-
50
- To add a per-pack `.rubocop.yml`, you just need to create a `packs/your_pack/.rubocop.yml` and then include:
51
- ```yml
52
- inherit_from: '../../.rubocop.yml'
53
- ```
54
-
55
- Note though that inherited paths are relative to your pack-level `.rubocop.yml`. To avoid that, you can rename your `.rubocop.yml` to `.base_rubocop.yml`, set `.rubocop.yml` to:
56
- ```
57
- inherit_from: '.base_rubocop.yml'
58
- ```
59
- And then similarly change the `inherit_from` in `packs/your_pack/.rubocop.yml`.
60
-
61
- ### Per-pack `.rubocop_todo.yml`
62
- To create a per-pack `.rubocop_todo.yml`, you can use the following API from `rubocop-packs`:
63
- ```ruby
64
- RuboCop::Packs.auto_generate_rubocop_todo(packs: ParsePackwerk.all)
65
- ```
66
- This API will auto-generate a `packs/some_pack/.rubocop_todo.yml`. This allows a pack to own its own exception list.
67
-
68
- ### Configuration and Validation
69
- To use per-pack `.rubocop.yml` and `.rubocop_todo.yml` files, you need to configure `rubocop-packs`:
70
- ```ruby
71
- # config/rubocop_packs.rb
72
- RuboCop::Packs.configure do |config|
73
- config.permitted_pack_level_cops = ['Packs/RootNamespaceIsPackName']
74
- config.required_pack_level_cops = ['Packs/RootNamespaceIsPackName']
75
- end
76
- ```
77
-
78
- The above two settings have associated validations that run with `RuboCop::Packs.validate`, which returns an array of errors. We recommend validating this in your test suite, for example:
79
- ```ruby
80
- RSpec.describe 'rubocop-packs validations' do
81
- it { expect(RuboCop::Packs.validate).to be_empty }
82
- end
83
- ```
84
-
85
- Validations include:
86
- - Ensuring that `packs/*/.rubocop_todo.yml` files only contain exceptions for the allow-list of `permitted_pack_level_cops`
87
- - Ensuring that `packs/*/.rubocop.yml` files contain all of the cops listed in `required_pack_level_cops` and no other cops. This is to ensure that these files are only used to turn on and off an allow-list of cops, as most users would not want packs to configure most `rubocop` rules in a way that is different from the rest of the application.
44
+ ## Pack-Level `package_rubocop.yml` and `package_rubocop_todo.yml` files
45
+ See [ADVANCED_USAGE.md](ADVANCED_USAGE.md)
88
46
 
89
47
  ## Contributing
90
48
 
@@ -3,4 +3,4 @@
3
3
  # - https://docs.rubocop.org/rubocop/configuration.html#inheriting-configuration-from-a-dependency-gem
4
4
  # - ERB in a .rubocop.yml file
5
5
  # - https://docs.rubocop.org/rubocop/configuration.html#pre-processing
6
- <%= RuboCop::Packs.pack_based_rubocop_todos %>
6
+ <%= RuboCop::Packs.pack_based_rubocop_config %>
@@ -28,7 +28,7 @@ module RuboCop
28
28
  def self.rubocop_todo_ymls
29
29
  @rubocop_todo_ymls = T.let(@rubocop_todo_ymls, T.nilable(T::Array[T::Hash[T.untyped, T.untyped]]))
30
30
  @rubocop_todo_ymls ||= begin
31
- todo_files = Pathname.glob('**/.rubocop_todo.yml')
31
+ todo_files = Pathname.glob("**/#{PACK_LEVEL_RUBOCOP_TODO_YML}")
32
32
  todo_files.map do |todo_file|
33
33
  YAML.load_file(todo_file)
34
34
  end
@@ -38,7 +38,7 @@ module RuboCop
38
38
  sig { params(package: ParsePackwerk::Package).returns(T::Array[String]) }
39
39
  def self.validate_rubocop_todo_yml(package)
40
40
  errors = []
41
- rubocop_todo = package.directory.join('.rubocop_todo.yml')
41
+ rubocop_todo = package.directory.join(PACK_LEVEL_RUBOCOP_TODO_YML)
42
42
  return errors unless rubocop_todo.exist?
43
43
 
44
44
  loaded_rubocop_todo = YAML.load_file(rubocop_todo)
@@ -47,7 +47,7 @@ module RuboCop
47
47
  errors << <<~ERROR_MESSAGE
48
48
  #{rubocop_todo} contains invalid configuration for #{key}.
49
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.
50
+ For ignoring other cops, please instead modify the top-level #{PACK_LEVEL_RUBOCOP_TODO_YML} file.
51
51
  ERROR_MESSAGE
52
52
  elsif loaded_rubocop_todo[key].keys != ['Exclude']
53
53
  errors << <<~ERROR_MESSAGE
@@ -73,7 +73,7 @@ module RuboCop
73
73
  sig { params(package: ParsePackwerk::Package).returns(T::Array[String]) }
74
74
  def self.validate_rubocop_yml(package)
75
75
  errors = []
76
- rubocop_yml = package.directory.join('.rubocop.yml')
76
+ rubocop_yml = package.directory.join(PACK_LEVEL_RUBOCOP_YML)
77
77
  return errors unless rubocop_yml.exist?
78
78
 
79
79
  loaded_rubocop_yml = YAML.load_file(rubocop_yml)
@@ -85,8 +85,6 @@ module RuboCop
85
85
  end
86
86
 
87
87
  loaded_rubocop_yml.each_key do |key|
88
- next if key.to_s == 'inherit_from'
89
-
90
88
  if !Packs.config.permitted_pack_level_cops.include?(key)
91
89
  errors << <<~ERROR_MESSAGE
92
90
  #{rubocop_yml} contains invalid configuration for #{key}.
@@ -130,7 +128,7 @@ module RuboCop
130
128
  Packs.config.permitted_pack_level_cops.each do |cop|
131
129
  excludes = exclude_for_rule(cop)
132
130
 
133
- rubocop_yml = package.directory.join('.rubocop.yml')
131
+ rubocop_yml = package.directory.join(PACK_LEVEL_RUBOCOP_YML)
134
132
 
135
133
  next unless rubocop_yml.exist?
136
134
 
@@ -143,7 +141,7 @@ module RuboCop
143
141
  next if excludes_for_package.empty?
144
142
 
145
143
  formatted_excludes = excludes_for_package.map { |ex| "`#{ex}`" }.join(', ')
146
- 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`."
144
+ errors << "#{package.name} has set `#{cop}` to `FailureMode: strict` in `packs/some_pack/#{PACK_LEVEL_RUBOCOP_YML}`, forbidding new exceptions. Please either remove #{formatted_excludes} from the top-level and pack-specific `#{PACK_LEVEL_RUBOCOP_TODO_YML}` files or remove `FailureMode: strict`."
147
145
  end
148
146
 
149
147
  errors
data/lib/rubocop/packs.rb CHANGED
@@ -5,6 +5,14 @@ require 'rubocop/packs/private'
5
5
 
6
6
  module RuboCop
7
7
  module Packs
8
+ # Pack-level rubocop and rubocop_todo YML files are named differently because they are not integrated
9
+ # into rubocop in the standard way. For example, we could call these the standard `.rubocop.yml` and
10
+ # `.rubocop_todo.yml`. However, this introduces a number of path relativity issues (https://docs.rubocop.org/rubocop/configuration.html#path-relativity)
11
+ # that make this approach not possible. Therefore, for pack level rubocops, we name them in a way that mirrors packwerk `package_todo.yml` files
12
+ # for consistency and to ensure that thes are not read by rubocop except via the ERB templating mechanism.
13
+ PACK_LEVEL_RUBOCOP_YML = 'package_rubocop.yml'
14
+ PACK_LEVEL_RUBOCOP_TODO_YML = 'package_rubocop_todo.yml'
15
+
8
16
  class Error < StandardError; end
9
17
  extend T::Sig
10
18
 
@@ -45,7 +53,7 @@ module RuboCop
45
53
 
46
54
  new_rubocop_todo_exclusions.each do |pack_name, file_hash|
47
55
  pack = T.must(ParsePackwerk.find(pack_name))
48
- rubocop_todo_yml = pack.directory.join('.rubocop_todo.yml')
56
+ rubocop_todo_yml = pack.directory.join(PACK_LEVEL_RUBOCOP_TODO_YML)
49
57
  if rubocop_todo_yml.exist?
50
58
  rubocop_todo = YAML.load_file(rubocop_todo_yml)
51
59
  else
@@ -72,18 +80,17 @@ module RuboCop
72
80
  sig { params(packs: T::Array[ParsePackwerk::Package]).void }
73
81
  def self.set_default_rubocop_yml(packs:)
74
82
  packs.each do |pack|
75
- rubocop_yml = Pathname.new(pack.directory.join('.rubocop.yml'))
83
+ rubocop_yml = Pathname.new(pack.directory.join(PACK_LEVEL_RUBOCOP_YML))
76
84
  rubocop_yml_hash = {}
77
- rubocop_yml_hash['inherit_from'] = '../../.base_rubocop.yml'
78
85
  config.required_pack_level_cops.each do |cop|
79
86
  rubocop_yml_hash[cop] = { 'Enabled' => true }
80
87
  end
81
88
 
82
89
  formatted_yml = YAML.dump(rubocop_yml_hash).
83
- # Remove the `---` header at the top of the file
84
- gsub("---\n", '').
85
90
  # Find lines of the form \nCopDepartment/CopName: and add a new line before it.
86
- gsub(%r{^(\w+/\w+:)}, "\n\\1")
91
+ gsub(%r{^(\w+/\w+:)}, "\n\\1").
92
+ # Remove the `---` header at the top of the file
93
+ gsub("---\n\n", '')
87
94
 
88
95
  rubocop_yml.write(formatted_yml)
89
96
  end
@@ -92,26 +99,39 @@ module RuboCop
92
99
  sig { params(root_pathname: String).returns(String) }
93
100
  # It would be great if rubocop (upstream) could take in a glob for `inherit_from`, which
94
101
  # would allow us to delete this method and this additional complexity.
95
- def self.pack_based_rubocop_todos(root_pathname: Bundler.root)
96
- rubocop_todos = {}
102
+ def self.pack_based_rubocop_config(root_pathname: Bundler.root)
103
+ rubocop_config = {}
97
104
  # We do this because when the ERB is evaluated Dir.pwd is at the directory containing the YML.
98
105
  # Ideally rubocop wouldn't change the PWD before invoking this method.
99
106
  Dir.chdir(root_pathname) do
100
107
  ParsePackwerk.all.each do |package|
101
108
  next if package.name == ParsePackwerk::ROOT_PACKAGE_NAME
102
109
 
103
- rubocop_todo = package.directory.join('.rubocop_todo.yml')
104
- next unless rubocop_todo.exist?
110
+ rubocop_todo = package.directory.join(PACK_LEVEL_RUBOCOP_TODO_YML)
111
+ if rubocop_todo.exist?
112
+ loaded_rubocop_todo = YAML.load_file(rubocop_todo)
113
+ loaded_rubocop_todo.each do |cop_name, key_config|
114
+ rubocop_config[cop_name] ||= {}
115
+ rubocop_config[cop_name]['Exclude'] ||= []
116
+ rubocop_config[cop_name]['Exclude'] += key_config['Exclude']
117
+ end
118
+ end
119
+
120
+ pack_rubocop = package.directory.join('.pack_rubocop.yml')
121
+ next unless pack_rubocop.exist?
122
+
123
+ loaded_pack_rubocop = YAML.load_file(pack_rubocop)
124
+ loaded_pack_rubocop.each do |cop_name, key_config|
125
+ next unless key_config['Enabled']
105
126
 
106
- loaded_rubocop_todo = YAML.load_file(rubocop_todo)
107
- loaded_rubocop_todo.each do |protection_key, key_config|
108
- rubocop_todos[protection_key] ||= { 'Exclude' => [] }
109
- rubocop_todos[protection_key]['Exclude'] += key_config['Exclude']
127
+ rubocop_config[cop_name] ||= {}
128
+ rubocop_config[cop_name]['Include'] ||= []
129
+ rubocop_config[cop_name]['Include'] << package.directory.join('**/*').to_s
110
130
  end
111
131
  end
112
132
  end
113
133
 
114
- YAML.dump(rubocop_todos)
134
+ YAML.dump(rubocop_config)
115
135
  end
116
136
 
117
137
  sig { void }
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.19
4
+ version: 0.0.20
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-11-14 00:00:00.000000000 Z
11
+ date: 2022-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport