packwerk-extensions 0.1.6 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 11f152d73195983779e15ac10eb5af3f99b94b5a349a57b92c9cf91054192c84
4
- data.tar.gz: 4c2f4e77c228b45faecc415235b1cb8228d3b8f6b50cdd561c1700605506d622
3
+ metadata.gz: 077e4a805c3061339f9c18e26d1768bbe3c3966e9e4c958b078ba1bcd0292c07
4
+ data.tar.gz: c292cb8cb900a9746d20e426a94ca89fc2a55cea542662812cb14f450466ae55
5
5
  SHA512:
6
- metadata.gz: 9557efbe49651e123920eebdf84f4fd09da937fb822c73eb7848633fd8b17f64f0a53be5a24a75515f366c5f2d9621ff7e33bd483b70b060620b18a5563be1e2
7
- data.tar.gz: dc9384c7c35d1424301212d95a5fce9becffb6e791784e3c53f4a010a30421a5acaf988fe332386c03457b86c5b09404a65d254d4a9790d75e2ad9bd57ca9cf8
6
+ metadata.gz: 601a651716181f5da48a302a7dd3b9a5eb3d46fa81a13ebd7138602aef8c11576344d724a2907b7bb950161ba11f0bb2a68207a9338de4b4e780c569320e8900
7
+ data.tar.gz: 288a0af58508deebdc3904a4a716ff933c837f4ca1cf840ece8ef8f4509936dfc6839fa7737e0f6d5805a007a00803dcafde59054a8e4089a11228a1d4b2486e
data/README.md CHANGED
@@ -5,7 +5,8 @@
5
5
  Currently, it ships the following checkers to help improve the boundaries between packages. These checkers are:
6
6
  - A `privacy` checker that ensures other packages are using your package's public API
7
7
  - A `visibility` checker that allows packages to be private except to an explicit group of other packages.
8
- - An experimental `architecture` checker that allows packages to specify their "layer" and requires that each layer only communicate with layers below it.
8
+ - A `folder_visibility` checker that allows packages to their sibling packs and parent pack (to be used in an application that uses folder packs)
9
+ - An `architecture` checker that allows packages to specify their "layer" and requires that each layer only communicate with layers below it.
9
10
 
10
11
  ## Installation
11
12
 
@@ -24,6 +25,7 @@ Alternatively, you can require individual checkers:
24
25
  require:
25
26
  - packwerk/privacy/checker
26
27
  - packwerk/visibility/checker
28
+ - packwerk/folder_visibility/checker
27
29
  - packwerk/architecture/checker
28
30
  ```
29
31
 
@@ -87,6 +89,30 @@ visible_to:
87
89
  - components/other_package
88
90
  ```
89
91
 
92
+ ## Folder-Visibility Checker
93
+ The folder visibility checker can be used to allow a package to be private to their sibling packs and parent packs and will create todos if used by any other package.
94
+
95
+ To enforce visibility for your package, set `enforce_folder_visibility` to `true` on your pack.
96
+
97
+ ```yaml
98
+ # components/merchandising/package.yml
99
+ enforce_folder_visibility: true
100
+ ```
101
+
102
+ Here is an example of paths and whether their use of `packs/b/packs/e` is OK or not, assuming that protects itself via `enforce_folder_visibility`
103
+
104
+ ```
105
+ . OK (parent of parent)
106
+ packs/a VIOLATION
107
+ packs/b OK (parent)
108
+ packs/b/packs/d OK (sibling)
109
+ packs/b/packs/e ENFORCE_NESTED_VISIBILITY: TRUE
110
+ packs/b/packs/e/packs/f VIOLATION
111
+ packs/b/packs/e/packs/g VIOLATION
112
+ packs/b/packs/h OK (sibling)
113
+ packs/c VIOLATION
114
+ ```
115
+
90
116
  ## Architecture Checker
91
117
  The architecture checker can be used to enforce constraints on what can depend on what.
92
118
 
@@ -105,3 +131,19 @@ layer: utility
105
131
  ```
106
132
 
107
133
  Now this pack can only depend on other utility packages.
134
+
135
+
136
+ ## Contributing
137
+
138
+ Got another checker you would like to add? Add it to this repo!
139
+
140
+ Please ensure these commands pass for you locally:
141
+
142
+ ```
143
+ bundle
144
+ srb tc
145
+ bin/rubocop
146
+ bin/rake test
147
+ ```
148
+
149
+ Then, submit a PR!
@@ -0,0 +1,93 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require 'packwerk/folder_visibility/package'
5
+ require 'packwerk/folder_visibility/validator'
6
+
7
+ module Packwerk
8
+ module FolderVisibility
9
+ class Checker
10
+ extend T::Sig
11
+ include Packwerk::Checker
12
+
13
+ VIOLATION_TYPE = T.let('folder_visibility', String)
14
+
15
+ sig { override.returns(String) }
16
+ def violation_type
17
+ VIOLATION_TYPE
18
+ end
19
+
20
+ sig do
21
+ override
22
+ .params(reference: Packwerk::Reference)
23
+ .returns(T::Boolean)
24
+ end
25
+ def invalid_reference?(reference)
26
+ referencing_package = reference.package
27
+ referenced_package = reference.constant.package
28
+
29
+ return false if enforcement_disabled?(Package.from(referenced_package).enforce_folder_visibility)
30
+
31
+ # the root pack is parent folder of all packs, so we short-circuit this here
32
+ referencing_package_is_root_pack = referencing_package.name == '.'
33
+ return false if referencing_package_is_root_pack
34
+
35
+ packages_are_sibling_folders = Pathname.new(referenced_package.name).dirname == Pathname.new(referencing_package.name).dirname
36
+ return false if packages_are_sibling_folders
37
+
38
+ referencing_package_is_parent_folder = Pathname.new(referenced_package.name).to_s.start_with?(referencing_package.name)
39
+ return false if referencing_package_is_parent_folder
40
+
41
+ true
42
+ end
43
+
44
+ sig do
45
+ override
46
+ .params(listed_offense: Packwerk::ReferenceOffense)
47
+ .returns(T::Boolean)
48
+ end
49
+ def strict_mode_violation?(listed_offense)
50
+ publishing_package = listed_offense.reference.constant.package
51
+ publishing_package.config['enforce_folder_visibility'] == 'strict'
52
+ end
53
+
54
+ sig do
55
+ override
56
+ .params(reference: Packwerk::Reference)
57
+ .returns(String)
58
+ end
59
+ def message(reference)
60
+ source_desc = "'#{reference.package}'"
61
+
62
+ message = <<~MESSAGE
63
+ Folder Visibility violation: '#{reference.constant.name}' belongs to '#{reference.constant.package}', which is not visible to #{source_desc} as it is not a sibling pack or parent pack.
64
+ Is there a different package to use instead, or should '#{reference.constant.package}' also be visible to #{source_desc}?
65
+
66
+ #{standard_help_message(reference)}
67
+ MESSAGE
68
+
69
+ message.chomp
70
+ end
71
+
72
+ private
73
+
74
+ sig do
75
+ params(visibility_option: T.nilable(T.any(T::Boolean, String)))
76
+ .returns(T::Boolean)
77
+ end
78
+ def enforcement_disabled?(visibility_option)
79
+ [false, nil].include?(visibility_option)
80
+ end
81
+
82
+ sig { params(reference: Reference).returns(String) }
83
+ def standard_help_message(reference)
84
+ standard_message = <<~MESSAGE.chomp
85
+ Inference details: this is a reference to #{reference.constant.name} which seems to be defined in #{reference.constant.location}.
86
+ To receive help interpreting or resolving this error message, see: https://github.com/Shopify/packwerk/blob/main/TROUBLESHOOT.md#Troubleshooting-violations
87
+ MESSAGE
88
+
89
+ standard_message.chomp
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,23 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Packwerk
5
+ module FolderVisibility
6
+ class Package < T::Struct
7
+ extend T::Sig
8
+
9
+ const :enforce_folder_visibility, T.nilable(T.any(T::Boolean, String))
10
+
11
+ class << self
12
+ extend T::Sig
13
+
14
+ sig { params(package: ::Packwerk::Package).returns(Package) }
15
+ def from(package)
16
+ Package.new(
17
+ enforce_folder_visibility: package.config['enforce_folder_visibility']
18
+ )
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,36 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Packwerk
5
+ module FolderVisibility
6
+ class Validator
7
+ extend T::Sig
8
+ include Packwerk::Validator
9
+
10
+ Result = Packwerk::Validator::Result
11
+
12
+ sig { override.params(package_set: PackageSet, configuration: Configuration).returns(Result) }
13
+ def call(package_set, configuration)
14
+ results = T.let([], T::Array[Result])
15
+
16
+ package_manifests_settings_for(configuration, 'enforce_folder_visibility').each do |config, setting|
17
+ next if setting.nil?
18
+
19
+ next if [TrueClass, FalseClass].include?(setting.class) || setting == 'strict'
20
+
21
+ results << Result.new(
22
+ ok: false,
23
+ error_value: "\tInvalid 'enforce_folder_visibility' option: #{setting.inspect} in #{config.inspect}"
24
+ )
25
+ end
26
+
27
+ merge_results(results, separator: "\n---\n")
28
+ end
29
+
30
+ sig { override.returns(T::Array[String]) }
31
+ def permitted_keys
32
+ %w[enforce_folder_visibility]
33
+ end
34
+ end
35
+ end
36
+ end
@@ -31,7 +31,7 @@ module Packwerk
31
31
 
32
32
  sig { override.returns(T::Array[String]) }
33
33
  def permitted_keys
34
- %w[public_path enforce_privacy private_constants]
34
+ %w[public_path enforce_privacy private_constants ignored_private_constants]
35
35
  end
36
36
 
37
37
  private
@@ -6,6 +6,7 @@ require 'packwerk'
6
6
 
7
7
  require 'packwerk/privacy/checker'
8
8
  require 'packwerk/visibility/checker'
9
+ require 'packwerk/folder_visibility/checker'
9
10
  require 'packwerk/architecture/checker'
10
11
 
11
12
  module Packwerk
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: packwerk-extensions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gusto Engineers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-09 00:00:00.000000000 Z
11
+ date: 2023-10-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: packwerk
@@ -191,6 +191,9 @@ files:
191
191
  - lib/packwerk/architecture/layers.rb
192
192
  - lib/packwerk/architecture/package.rb
193
193
  - lib/packwerk/architecture/validator.rb
194
+ - lib/packwerk/folder_visibility/checker.rb
195
+ - lib/packwerk/folder_visibility/package.rb
196
+ - lib/packwerk/folder_visibility/validator.rb
194
197
  - lib/packwerk/privacy/checker.rb
195
198
  - lib/packwerk/privacy/package.rb
196
199
  - lib/packwerk/privacy/validator.rb