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 +4 -4
- data/README.md +2 -44
- data/config/pack_config.yml +1 -1
- data/lib/rubocop/packs/private.rb +6 -8
- data/lib/rubocop/packs.rb +35 -15
- 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: 49afe61bb4672111e0ba64bc690715756d3d2f7130c96d71f0036add413d18ac
|
4
|
+
data.tar.gz: 615a905e64ea7647eb922d25c87b9cbbd76c3826da207dccf3ce2b511d281ccb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
45
|
-
|
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
|
|
data/config/pack_config.yml
CHANGED
@@ -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.
|
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(
|
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(
|
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
|
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(
|
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(
|
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
|
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(
|
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(
|
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.
|
96
|
-
|
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(
|
104
|
-
|
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
|
-
|
107
|
-
|
108
|
-
|
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(
|
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.
|
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-
|
11
|
+
date: 2022-11-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|