package_protections 1.4.0 → 2.1.0
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/lib/package_protections/private/configuration.rb +12 -0
- data/lib/package_protections/private.rb +1 -7
- data/lib/package_protections.rb +19 -18
- data/lib/rubocop/cop/package_protections/namespaced_under_package_name/desired_zeitwerk_api.rb +110 -0
- data/lib/rubocop/cop/package_protections/namespaced_under_package_name.rb +99 -84
- data/lib/rubocop/cop/package_protections.rb +13 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7471704e495c4ffe4e849be40a9fad64eed08e3980e9d630300eeae5c8e0d006
|
4
|
+
data.tar.gz: dbb34a83f3b4f7ed1a3327d36ac2dd5191d17bba0206ebfa06344d056c35b43a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 77012017f0440763480a9f02ab289254870b9d937ff72cfa8f665331b04195cf01e1724562796d1a74414d38c855fa95710879d6efe105367792a3cf7b1bf60b
|
7
|
+
data.tar.gz: 48cb93ff9ec6b2b4785587c795fb6571ff55ade4de471c93b38fa3244113b4d4b0ecd6f431d335754ad4d5c6e7d23e3ec6701c71d0fca1328848dcf5a1f27836
|
@@ -8,9 +8,13 @@ module PackageProtections
|
|
8
8
|
sig { params(protections: T::Array[ProtectionInterface]).void }
|
9
9
|
attr_writer :protections
|
10
10
|
|
11
|
+
sig { params(globally_permitted_namespaces: T::Array[String]).void }
|
12
|
+
attr_writer :globally_permitted_namespaces
|
13
|
+
|
11
14
|
sig { void }
|
12
15
|
def initialize
|
13
16
|
@protections = T.let(default_protections, T::Array[ProtectionInterface])
|
17
|
+
@globally_permitted_namespaces = T.let([], T::Array[String])
|
14
18
|
end
|
15
19
|
|
16
20
|
sig { returns(T::Array[ProtectionInterface]) }
|
@@ -18,13 +22,21 @@ module PackageProtections
|
|
18
22
|
@protections
|
19
23
|
end
|
20
24
|
|
25
|
+
sig { returns(T::Array[String]) }
|
26
|
+
def globally_permitted_namespaces
|
27
|
+
@globally_permitted_namespaces
|
28
|
+
end
|
29
|
+
|
21
30
|
sig { void }
|
22
31
|
def bust_cache!
|
23
32
|
@protections = default_protections
|
33
|
+
@globally_permitted_namespaces = []
|
24
34
|
end
|
25
35
|
|
26
36
|
sig { returns(T::Array[ProtectionInterface]) }
|
27
37
|
def default_protections
|
38
|
+
require 'rubocop/cop/package_protections'
|
39
|
+
|
28
40
|
[
|
29
41
|
Private::OutgoingDependencyProtection.new,
|
30
42
|
Private::IncomingPrivacyProtection.new,
|
@@ -17,12 +17,6 @@ module PackageProtections
|
|
17
17
|
module Private
|
18
18
|
extend T::Sig
|
19
19
|
|
20
|
-
sig { returns(Private::Configuration) }
|
21
|
-
def self.config
|
22
|
-
@config = T.let(@config, T.nilable(Configuration))
|
23
|
-
@config ||= Private::Configuration.new
|
24
|
-
end
|
25
|
-
|
26
20
|
sig do
|
27
21
|
params(
|
28
22
|
packages: T::Array[ParsePackwerk::Package],
|
@@ -122,7 +116,7 @@ module PackageProtections
|
|
122
116
|
def self.bust_cache!
|
123
117
|
@protected_packages_indexed_by_name = nil
|
124
118
|
@private_cop_config = nil
|
125
|
-
config.bust_cache!
|
119
|
+
PackageProtections.config.bust_cache!
|
126
120
|
end
|
127
121
|
|
128
122
|
sig { params(identifier: Identifier).returns(T::Hash[T.untyped, T.untyped]) }
|
data/lib/package_protections.rb
CHANGED
@@ -1,20 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# typed: strict
|
4
|
+
|
4
5
|
require 'sorbet-runtime'
|
6
|
+
|
5
7
|
require 'open3'
|
6
8
|
require 'set'
|
7
9
|
require 'parse_packwerk'
|
8
|
-
require 'rubocop'
|
9
|
-
require 'rubocop-sorbet'
|
10
10
|
|
11
|
-
|
11
|
+
require 'zeitwerk'
|
12
|
+
loader = T.unsafe(Zeitwerk::Loader).for_gem
|
13
|
+
loader.ignore("#{__dir__}/rubocop")
|
14
|
+
loader.setup
|
15
|
+
|
12
16
|
# Welcome to PackageProtections!
|
13
17
|
# See https://github.com/rubyatscale/package_protections#readme for more info
|
14
18
|
#
|
15
19
|
# This file is a reference for the available API to `package_protections`, but all implementation details are private
|
16
20
|
# (which is why we delegate to `Private` for the actual implementation).
|
17
|
-
#
|
18
21
|
module PackageProtections
|
19
22
|
extend T::Sig
|
20
23
|
|
@@ -27,30 +30,24 @@ module PackageProtections
|
|
27
30
|
# This is currently the only handled exception that `PackageProtections` will throw.
|
28
31
|
class IncorrectPublicApiUsageError < StandardError; end
|
29
32
|
|
30
|
-
require 'package_protections/offense'
|
31
|
-
require 'package_protections/violation_behavior'
|
32
|
-
require 'package_protections/protected_package'
|
33
|
-
require 'package_protections/per_file_violation'
|
34
|
-
require 'package_protections/protection_interface'
|
35
|
-
require 'package_protections/rubocop_protection_interface'
|
36
|
-
require 'package_protections/private'
|
37
|
-
|
38
|
-
# Implementation of rubocop-based protections
|
39
|
-
require 'rubocop/cop/package_protections/namespaced_under_package_name'
|
40
|
-
require 'rubocop/cop/package_protections/typed_public_api'
|
41
|
-
|
42
33
|
class << self
|
43
34
|
extend T::Sig
|
44
35
|
|
45
36
|
sig { params(blk: T.proc.params(arg0: Private::Configuration).void).void }
|
46
37
|
def configure(&blk)
|
47
|
-
yield(
|
38
|
+
yield(PackageProtections.config)
|
48
39
|
end
|
49
40
|
end
|
50
41
|
|
51
42
|
sig { returns(T::Array[ProtectionInterface]) }
|
52
43
|
def self.all
|
53
|
-
|
44
|
+
config.protections
|
45
|
+
end
|
46
|
+
|
47
|
+
sig { returns(Private::Configuration) }
|
48
|
+
def self.config
|
49
|
+
@config = T.let(@config, T.nilable(Private::Configuration))
|
50
|
+
@config ||= Private::Configuration.new
|
54
51
|
end
|
55
52
|
|
56
53
|
#
|
@@ -122,3 +119,7 @@ module PackageProtections
|
|
122
119
|
RubocopProtectionInterface.bust_rubocop_todo_yml_cache
|
123
120
|
end
|
124
121
|
end
|
122
|
+
|
123
|
+
if defined?(Rubocop)
|
124
|
+
require 'rubocop/cop/package_protections'
|
125
|
+
end
|
data/lib/rubocop/cop/package_protections/namespaced_under_package_name/desired_zeitwerk_api.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module PackageProtections
|
6
|
+
class NamespacedUnderPackageName < Base
|
7
|
+
#
|
8
|
+
# This is a private class that represents API that we would prefer to be available somehow in Zeitwerk.
|
9
|
+
#
|
10
|
+
class DesiredZeitwerkApi
|
11
|
+
extend T::Sig
|
12
|
+
|
13
|
+
class NamespaceContext < T::Struct
|
14
|
+
const :current_namespace, String
|
15
|
+
const :expected_namespace, String
|
16
|
+
const :expected_filepath, String
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# For now, this API includes `package_for_path`
|
21
|
+
# If this were truly zeitwerk API, it wouldn't include any mention of packs and it would likely not need the package at all
|
22
|
+
# Since it could get the actual namespace without knowing anything about packs.
|
23
|
+
# However, we would need to pass to it the desired namespace based on the pack name for it to be able to suggest
|
24
|
+
# a desired filepath.
|
25
|
+
# Likely this means that our own cop should determine the desired namespace and pass that in
|
26
|
+
# and this can determine actual namespace and how to get to expected.
|
27
|
+
#
|
28
|
+
sig { params(relative_filename: String, package_for_path: ParsePackwerk::Package).returns(T.nilable(NamespaceContext)) }
|
29
|
+
def for_file(relative_filename, package_for_path)
|
30
|
+
package_name = package_for_path.name
|
31
|
+
|
32
|
+
# Zeitwerk establishes a standard convention by which namespaces are defined.
|
33
|
+
# The package protections namespace checker is coupled to a specific assumption about how auto-loading works.
|
34
|
+
#
|
35
|
+
# Namely, we expect the following autoload paths: `packs/**/app/**/`
|
36
|
+
# Examples:
|
37
|
+
# 1) `packs/package_1/app/public/package_1/my_constant.rb` produces constant `Package1::MyConstant`
|
38
|
+
# 2) `packs/package_1/app/services/package_1/my_service.rb` produces constant `Package1::MyService`
|
39
|
+
# 3) `packs/package_1/app/services/package_1.rb` produces constant `Package1`
|
40
|
+
# 4) `packs/package_1/app/public/package_1.rb` produces constant `Package1`
|
41
|
+
#
|
42
|
+
# Described another way, we expect any part of the directory labeled NAMESPACE to establish a portion of the fully qualified runtime constant:
|
43
|
+
# `packs/**/app/**/NAMESPACE1/NAMESPACE2/[etc]`
|
44
|
+
#
|
45
|
+
# Therefore, for our implementation, we substitute out the non-namespace producing portions of the filename to count the number of namespaces.
|
46
|
+
# Note this will *not work* properly in applications that have different assumptions about autoloading.
|
47
|
+
|
48
|
+
path_without_package_base = relative_filename.gsub(%r{#{package_name}/app/}, '')
|
49
|
+
if path_without_package_base.include?('concerns')
|
50
|
+
autoload_folder_name = path_without_package_base.split('/').first(2).join('/')
|
51
|
+
else
|
52
|
+
autoload_folder_name = path_without_package_base.split('/').first
|
53
|
+
end
|
54
|
+
|
55
|
+
remaining_file_path = path_without_package_base.gsub(%r{\A#{autoload_folder_name}/}, '')
|
56
|
+
actual_namespace = get_actual_namespace(remaining_file_path, package_name)
|
57
|
+
|
58
|
+
if relative_filename.include?('app/')
|
59
|
+
app_or_lib = 'app'
|
60
|
+
elsif relative_filename.include?('lib/')
|
61
|
+
app_or_lib = 'lib'
|
62
|
+
end
|
63
|
+
|
64
|
+
absolute_desired_path = root_pathname.join(
|
65
|
+
package_name,
|
66
|
+
T.must(app_or_lib),
|
67
|
+
T.must(autoload_folder_name),
|
68
|
+
get_package_last_name(package_for_path),
|
69
|
+
remaining_file_path
|
70
|
+
)
|
71
|
+
|
72
|
+
relative_desired_path = absolute_desired_path.relative_path_from(root_pathname)
|
73
|
+
|
74
|
+
NamespaceContext.new(
|
75
|
+
current_namespace: actual_namespace,
|
76
|
+
expected_namespace: get_pack_based_namespace(package_for_path),
|
77
|
+
expected_filepath: relative_desired_path.to_s
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
sig { params(pack: ParsePackwerk::Package).returns(String) }
|
82
|
+
def get_pack_based_namespace(pack)
|
83
|
+
get_package_last_name(pack).camelize
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
sig { returns(Pathname) }
|
89
|
+
def root_pathname
|
90
|
+
Pathname.pwd
|
91
|
+
end
|
92
|
+
|
93
|
+
sig { params(pack: ParsePackwerk::Package).returns(String) }
|
94
|
+
def get_package_last_name(pack)
|
95
|
+
T.must(pack.name.split('/').last)
|
96
|
+
end
|
97
|
+
|
98
|
+
sig { params(remaining_file_path: String, package_name: String).returns(String) }
|
99
|
+
def get_actual_namespace(remaining_file_path, package_name)
|
100
|
+
# If the remaining file path is a ruby file (not a directory), then it establishes a global namespace
|
101
|
+
# Otherwise, per Zeitwerk's conventions as listed above, its a directory that establishes another global namespace
|
102
|
+
T.must(remaining_file_path.split('/').first).gsub('.rb', '').camelize
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
private_constant :DesiredZeitwerkApi
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -1,92 +1,109 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
|
3
3
|
# For String#camelize
|
4
4
|
require 'active_support/core_ext/string/inflections'
|
5
|
+
require 'rubocop/cop/package_protections/namespaced_under_package_name/desired_zeitwerk_api'
|
5
6
|
|
6
7
|
module RuboCop
|
7
8
|
module Cop
|
8
9
|
module PackageProtections
|
10
|
+
#
|
11
|
+
# TODO:
|
12
|
+
# This class is in serious need of being split up into helpful abstractions.
|
13
|
+
# A really helpful abstraction would be one that takes a file path and can spit out information about
|
14
|
+
# namespacing, such as the exposed namespace, the file path for a different namespace, and more.
|
15
|
+
#
|
9
16
|
class NamespacedUnderPackageName < Base
|
10
17
|
extend T::Sig
|
11
18
|
|
12
19
|
include RangeHelp
|
13
20
|
include ::PackageProtections::RubocopProtectionInterface
|
14
21
|
|
22
|
+
sig { void }
|
15
23
|
def on_new_investigation
|
16
24
|
absolute_filepath = Pathname.new(processed_source.file_path)
|
17
25
|
relative_filepath = absolute_filepath.relative_path_from(Pathname.pwd)
|
18
26
|
relative_filename = relative_filepath.to_s
|
19
27
|
|
20
|
-
# This cop only works for files in `app`
|
21
|
-
return if !relative_filename.include?('app/')
|
22
|
-
|
23
|
-
package_name = ParsePackwerk.package_from_path(relative_filename)&.name
|
24
|
-
return if package_name.nil?
|
25
|
-
|
26
|
-
return if relative_filepath.extname != '.rb'
|
27
|
-
|
28
|
-
# Zeitwerk establishes a standard convention by which namespaces are defined.
|
29
|
-
# The package protections namespace checker is coupled to a specific assumption about how auto-loading works.
|
30
|
-
#
|
31
|
-
# Namely, we expect the following autoload paths: `packs/**/app/**/`
|
32
|
-
# Examples:
|
33
|
-
# 1) `packs/package_1/app/public/package_1/my_constant.rb` produces constant `Package1::MyConstant`
|
34
|
-
# 2) `packs/package_1/app/services/package_1/my_service.rb` produces constant `Package1::MyService`
|
35
|
-
# 3) `packs/package_1/app/services/package_1.rb` produces constant `Package1`
|
36
|
-
# 4) `packs/package_1/app/public/package_1.rb` produces constant `Package1`
|
37
|
-
#
|
38
|
-
# Described another way, we expect any part of the directory labeled NAMESPACE to establish a portion of the fully qualified runtime constant:
|
39
|
-
# `packs/**/app/**/NAMESPACE1/NAMESPACE2/[etc]`
|
40
|
-
#
|
41
|
-
# Therefore, for our implementation, we substitute out the non-namespace producing portions of the filename to count the number of namespaces.
|
42
|
-
# Note this will *not work* properly in applications that have different assumptions about autoloading.
|
43
|
-
package_last_name = T.must(package_name.split('/').last)
|
44
|
-
path_without_package_base = relative_filename.gsub(%r{#{package_name}/app/}, '')
|
45
|
-
if path_without_package_base.include?('concerns')
|
46
|
-
autoload_folder_name = path_without_package_base.split('/').first(2).join('/')
|
47
|
-
else
|
48
|
-
autoload_folder_name = path_without_package_base.split('/').first
|
49
|
-
end
|
28
|
+
# This cop only works for files ruby files in `app`
|
29
|
+
return if !relative_filename.include?('app/') || relative_filepath.extname != '.rb'
|
50
30
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
if allowed_namespaces.include?(actual_namespace)
|
55
|
-
# No problem!
|
56
|
-
elsif allowed_namespaces.count == 1
|
57
|
-
single_allowed_namespace = allowed_namespaces.first
|
58
|
-
if relative_filepath.to_s.include?('app/')
|
59
|
-
app_or_lib = 'app'
|
60
|
-
elsif relative_filepath.to_s.include?('lib/')
|
61
|
-
app_or_lib = 'lib'
|
62
|
-
end
|
31
|
+
relative_filename = relative_filepath.to_s
|
32
|
+
package_for_path = ParsePackwerk.package_from_path(relative_filename)
|
33
|
+
return if package_for_path.nil?
|
63
34
|
|
64
|
-
|
35
|
+
namespace_context = self.class.desired_zeitwerk_api.for_file(relative_filename, package_for_path)
|
36
|
+
return if namespace_context.nil?
|
65
37
|
|
66
|
-
|
38
|
+
allowed_global_namespaces = Set.new([
|
39
|
+
namespace_context.expected_namespace,
|
40
|
+
*::PackageProtections.config.globally_permitted_namespaces
|
41
|
+
])
|
67
42
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
expected_namespace: package_last_name.camelize,
|
74
|
-
expected_path: relative_desired_path
|
75
|
-
)
|
76
|
-
)
|
43
|
+
package_name = package_for_path.name
|
44
|
+
actual_namespace = namespace_context.current_namespace
|
45
|
+
|
46
|
+
if allowed_global_namespaces.include?(actual_namespace)
|
47
|
+
# No problem!
|
77
48
|
else
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
49
|
+
package_enforces_namespaces = !::PackageProtections::ProtectedPackage.from(package_for_path).violation_behavior_for(NamespacedUnderPackageName::IDENTIFIER).fail_never?
|
50
|
+
expected_namespace = namespace_context.expected_namespace
|
51
|
+
relative_desired_path = namespace_context.expected_filepath
|
52
|
+
pack_owning_this_namespace = self.class.namespaces_to_packs[actual_namespace]
|
53
|
+
|
54
|
+
if package_enforces_namespaces
|
55
|
+
add_offense(
|
56
|
+
source_range(processed_source.buffer, 1, 0),
|
57
|
+
message: format(
|
58
|
+
'`%<package_name>s` prevents modules/classes that are not submodules of the package namespace. Should be namespaced under `%<expected_namespace>s` with path `%<expected_path>s`. See https://go/packwerk_cheatsheet_namespaces for more info.',
|
59
|
+
package_name: package_name,
|
60
|
+
expected_namespace: expected_namespace,
|
61
|
+
expected_path: relative_desired_path
|
62
|
+
)
|
84
63
|
)
|
85
|
-
|
64
|
+
elsif pack_owning_this_namespace
|
65
|
+
add_offense(
|
66
|
+
source_range(processed_source.buffer, 1, 0),
|
67
|
+
message: format(
|
68
|
+
'`%<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`. See https://go/packwerk_cheatsheet_namespaces for more info.',
|
69
|
+
package_name: package_name,
|
70
|
+
pack_owning_this_namespace: pack_owning_this_namespace,
|
71
|
+
expected_namespace: expected_namespace,
|
72
|
+
actual_namespace: actual_namespace,
|
73
|
+
expected_path: relative_desired_path
|
74
|
+
)
|
75
|
+
)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# We override `cop_configs` for this protection.
|
81
|
+
# The default behavior disables cops when a package has turned off a protection.
|
82
|
+
# However: namespace violations can occur even when one package has TURNED OFF their namespace protection
|
83
|
+
# but another package has it turned on. Therefore, all packages must always be opted in no matter what.
|
84
|
+
#
|
85
|
+
sig do
|
86
|
+
params(packages: T::Array[::PackageProtections::ProtectedPackage])
|
87
|
+
.returns(T::Array[::PackageProtections::RubocopProtectionInterface::CopConfig])
|
88
|
+
end
|
89
|
+
def cop_configs(packages)
|
90
|
+
include_paths = T.let([], T::Array[String])
|
91
|
+
packages.each do |p|
|
92
|
+
included_globs_for_pack.each do |glob|
|
93
|
+
include_paths << p.original_package.directory.join(glob).to_s
|
94
|
+
end
|
86
95
|
end
|
96
|
+
|
97
|
+
[
|
98
|
+
::PackageProtections::RubocopProtectionInterface::CopConfig.new(
|
99
|
+
name: cop_name,
|
100
|
+
enabled: include_paths.any?,
|
101
|
+
include_paths: include_paths
|
102
|
+
)
|
103
|
+
]
|
87
104
|
end
|
88
105
|
|
89
|
-
IDENTIFIER = 'prevent_this_package_from_creating_other_namespaces'.freeze
|
106
|
+
IDENTIFIER = T.let('prevent_this_package_from_creating_other_namespaces'.freeze, String)
|
90
107
|
|
91
108
|
sig { override.returns(String) }
|
92
109
|
def identifier
|
@@ -123,15 +140,6 @@ module RuboCop
|
|
123
140
|
]
|
124
141
|
end
|
125
142
|
|
126
|
-
sig do
|
127
|
-
params(package: ::PackageProtections::ProtectedPackage).returns(T::Hash[T.untyped, T.untyped])
|
128
|
-
end
|
129
|
-
def custom_cop_config(package)
|
130
|
-
{
|
131
|
-
'GlobalNamespaces' => package.metadata['global_namespaces']
|
132
|
-
}
|
133
|
-
end
|
134
|
-
|
135
143
|
sig do
|
136
144
|
override.params(file: String).returns(String)
|
137
145
|
end
|
@@ -161,22 +169,29 @@ module RuboCop
|
|
161
169
|
MESSAGE
|
162
170
|
end
|
163
171
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
172
|
+
sig { returns(DesiredZeitwerkApi) }
|
173
|
+
def self.desired_zeitwerk_api
|
174
|
+
# This is cached at the class level so we will cache more expensive operations
|
175
|
+
# across rubocop requests.
|
176
|
+
@desired_zeitwerk_api ||= T.let(nil, T.nilable(DesiredZeitwerkApi))
|
177
|
+
@desired_zeitwerk_api ||= DesiredZeitwerkApi.new
|
170
178
|
end
|
171
179
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
180
|
+
sig { returns(T::Hash[String, String]) }
|
181
|
+
def self.namespaces_to_packs
|
182
|
+
@namespaces_to_packs = T.let(nil, T.nilable(T::Hash[String, String]))
|
183
|
+
@namespaces_to_packs ||= begin
|
184
|
+
all_packs_enforcing_namespaces = ParsePackwerk.all.reject do |p|
|
185
|
+
::PackageProtections::ProtectedPackage.from(p).violation_behavior_for(NamespacedUnderPackageName::IDENTIFIER).fail_never?
|
186
|
+
end
|
187
|
+
|
188
|
+
namespaces_to_packs = {}
|
189
|
+
all_packs_enforcing_namespaces.each do |package|
|
190
|
+
namespaces_to_packs[desired_zeitwerk_api.get_pack_based_namespace(package)] = package.name
|
191
|
+
end
|
177
192
|
|
178
|
-
|
179
|
-
|
193
|
+
namespaces_to_packs
|
194
|
+
end
|
180
195
|
end
|
181
196
|
end
|
182
197
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubocop'
|
2
|
+
require 'rubocop-sorbet'
|
3
|
+
|
4
|
+
module RuboCop
|
5
|
+
module Cop
|
6
|
+
module PackageProtections
|
7
|
+
autoload :NamespacedUnderPackageName, 'rubocop/cop/package_protections/namespaced_under_package_name'
|
8
|
+
autoload :TypedPublicApi, 'rubocop/cop/package_protections/typed_public_api'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Implementation of rubocop-based protections
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: package_protections
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 2.1.0
|
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
|
+
date: 2022-09-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: zeitwerk
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: rake
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -191,7 +205,9 @@ files:
|
|
191
205
|
- lib/package_protections/rspec/support.rb
|
192
206
|
- lib/package_protections/rubocop_protection_interface.rb
|
193
207
|
- lib/package_protections/violation_behavior.rb
|
208
|
+
- lib/rubocop/cop/package_protections.rb
|
194
209
|
- lib/rubocop/cop/package_protections/namespaced_under_package_name.rb
|
210
|
+
- lib/rubocop/cop/package_protections/namespaced_under_package_name/desired_zeitwerk_api.rb
|
195
211
|
- lib/rubocop/cop/package_protections/typed_public_api.rb
|
196
212
|
homepage: https://github.com/rubyatscale/package_protections
|
197
213
|
licenses:
|