packwerk-extensions 0.1.7 → 0.1.8

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: 15205fb6e29f594b5bfea27a6c2ef0488fa1ec2b2d6ae5265bfa906f7bac49a9
4
- data.tar.gz: 6e795da44e384491a129e496a8541284317d0c523db59d431731119529535bbb
3
+ metadata.gz: 077e4a805c3061339f9c18e26d1768bbe3c3966e9e4c958b078ba1bcd0292c07
4
+ data.tar.gz: c292cb8cb900a9746d20e426a94ca89fc2a55cea542662812cb14f450466ae55
5
5
  SHA512:
6
- metadata.gz: da2182b6b67511413dc606f943303130a955ba87f92e6798543a995eb94dc5577b1f1951decbb23751ce4c08535b361fc91778ebc6cea357d62f3860d4081e94
7
- data.tar.gz: ee4701f2cc1ecf037823ffa7abe0cce8fa8d5bb2c61dcf587b85ab4331611968f7dfad84439a141479341c38f5a8a326e4b76c1b3040fa3672429c483a39a52c
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
@@ -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.7
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