parse_packwerk 0.26.1 → 0.28.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/parse_packwerk/configuration.rb +1 -0
- data/lib/parse_packwerk/constants.rb +14 -12
- data/lib/parse_packwerk/extensions.rb +1 -0
- data/lib/parse_packwerk/package.rb +31 -1
- data/lib/parse_packwerk/package_todo.rb +1 -0
- data/lib/parse_packwerk/violation.rb +1 -0
- data/lib/parse_packwerk.rb +32 -2
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c4fc93d51bdc321a094c0bf2b0bd7f3f062321e111533162e72281cb328286cd
|
|
4
|
+
data.tar.gz: 04aeeefa87b28e5052dce0af43cae614a31c5395981b86cc2f23454b81fe133c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ba7306916ccb40c76681157deec579b2f9f3c911e41811c83e509620b29b504525a15183e3b4a20a2233dfe5e4f9f36a5e2b55f50c4188606d9129339143a09d
|
|
7
|
+
data.tar.gz: 588d4b9695c2726f617197e10b8ba9315e74192debf423840dfbda942e023bfdb9ec50a74db85cd5cfadb585acce5a0ff306515a8a5395e6d1fbb2a1c40cf215
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module ParsePackwerk
|
|
4
|
-
ROOT_PACKAGE_NAME = T.let('.'
|
|
5
|
-
PACKAGE_YML_NAME = T.let('package.yml'
|
|
6
|
-
PACKWERK_YML_NAME = T.let('packwerk.yml'
|
|
7
|
-
PACKAGE_TODO_YML_NAME = T.let('package_todo.yml'
|
|
8
|
-
ENFORCE_DEPENDENCIES = T.let('enforce_dependencies'
|
|
9
|
-
ENFORCE_PRIVACY = T.let('enforce_privacy'
|
|
10
|
-
ENFORCE_LAYERS = T.let('enforce_layers'
|
|
11
|
-
DEPENDENCY_VIOLATION_TYPE = T.let('dependency'
|
|
12
|
-
PRIVACY_VIOLATION_TYPE = T.let('privacy'
|
|
13
|
-
PUBLIC_PATH = T.let('public_path'
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
ROOT_PACKAGE_NAME = T.let('.', String)
|
|
6
|
+
PACKAGE_YML_NAME = T.let('package.yml', String)
|
|
7
|
+
PACKWERK_YML_NAME = T.let('packwerk.yml', String)
|
|
8
|
+
PACKAGE_TODO_YML_NAME = T.let('package_todo.yml', String)
|
|
9
|
+
ENFORCE_DEPENDENCIES = T.let('enforce_dependencies', String)
|
|
10
|
+
ENFORCE_PRIVACY = T.let('enforce_privacy', String)
|
|
11
|
+
ENFORCE_LAYERS = T.let('enforce_layers', String)
|
|
12
|
+
DEPENDENCY_VIOLATION_TYPE = T.let('dependency', String)
|
|
13
|
+
PRIVACY_VIOLATION_TYPE = T.let('privacy', String)
|
|
14
|
+
PUBLIC_PATH = T.let('public_path', String)
|
|
15
|
+
OWNER = T.let('owner', String)
|
|
16
|
+
METADATA = T.let('metadata', String)
|
|
17
|
+
DEPENDENCIES = T.let('dependencies', String)
|
|
16
18
|
|
|
17
19
|
# Since this metadata is unstructured YAML, it could be any type. We leave it to clients of `ParsePackwerk::Package`
|
|
18
20
|
# to add types based on their known usage of metadata.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module ParsePackwerk
|
|
4
5
|
class Package < T::Struct
|
|
@@ -13,11 +14,15 @@ module ParsePackwerk
|
|
|
13
14
|
const :dependencies, T::Array[String]
|
|
14
15
|
const :config, T::Hash[T.untyped, T.untyped]
|
|
15
16
|
const :violations, T::Array[Violation]
|
|
17
|
+
# Stores the original key order from the YAML file for preserving order on write
|
|
18
|
+
const :original_key_order, T::Array[String], default: []
|
|
16
19
|
|
|
17
20
|
sig { params(pathname: Pathname).returns(Package) }
|
|
18
21
|
def self.from(pathname)
|
|
19
22
|
package_loaded_yml = YAML.load_file(pathname) || {}
|
|
20
23
|
package_name = pathname.dirname.cleanpath.to_s
|
|
24
|
+
# Capture the original key order from the YAML file
|
|
25
|
+
original_keys = package_loaded_yml.is_a?(Hash) ? package_loaded_yml.keys : []
|
|
21
26
|
|
|
22
27
|
new(
|
|
23
28
|
name: package_name,
|
|
@@ -28,7 +33,8 @@ module ParsePackwerk
|
|
|
28
33
|
metadata: package_loaded_yml[METADATA] || {},
|
|
29
34
|
dependencies: package_loaded_yml[DEPENDENCIES] || [],
|
|
30
35
|
config: package_loaded_yml,
|
|
31
|
-
violations: PackageTodo.from(PackageTodo.yml(directory(package_name))).violations
|
|
36
|
+
violations: PackageTodo.from(PackageTodo.yml(directory(package_name))).violations,
|
|
37
|
+
original_key_order: original_keys
|
|
32
38
|
)
|
|
33
39
|
end
|
|
34
40
|
|
|
@@ -66,5 +72,29 @@ module ParsePackwerk
|
|
|
66
72
|
def enforces_layers?
|
|
67
73
|
enforce_layers
|
|
68
74
|
end
|
|
75
|
+
|
|
76
|
+
# `owner` is read from `config` rather than stored as a prop, so edits through `config` and `with(owner:)` can't disagree.
|
|
77
|
+
# Only the top-level key is read. Unlike `CodeOwnership.for_package`, this doesn't fall back to `metadata.owner`.
|
|
78
|
+
sig { returns(T.nilable(String)) }
|
|
79
|
+
def owner
|
|
80
|
+
owner = config[OWNER]
|
|
81
|
+
owner if owner.is_a?(String)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
sig { params(changed_props: T::Hash[Symbol, T.untyped]).returns(Package) }
|
|
85
|
+
def with(changed_props)
|
|
86
|
+
return super unless changed_props.key?(:owner)
|
|
87
|
+
|
|
88
|
+
changes = changed_props.dup
|
|
89
|
+
new_owner = T.let(changes.delete(:owner), T.nilable(String))
|
|
90
|
+
# Edit the copy `super` returns rather than passing `config:` to it, which would stringify every nested key in the file.
|
|
91
|
+
super(changes).tap do |package|
|
|
92
|
+
if new_owner.nil?
|
|
93
|
+
package.config.delete(OWNER)
|
|
94
|
+
else
|
|
95
|
+
package.config[OWNER] = new_owner
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
69
99
|
end
|
|
70
100
|
end
|
data/lib/parse_packwerk.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
require 'sorbet-runtime'
|
|
4
5
|
require 'yaml'
|
|
@@ -31,6 +32,19 @@ module ParsePackwerk
|
|
|
31
32
|
|
|
32
33
|
extend T::Sig
|
|
33
34
|
|
|
35
|
+
# Configuration option to preserve the original key order when writing package.yml files.
|
|
36
|
+
# When true, keys will be written in their original order from the file rather than
|
|
37
|
+
# being sorted according to key_sort_order. This reduces diff churn when tools modify packages.
|
|
38
|
+
# Defaults to false for backwards compatibility.
|
|
39
|
+
@preserve_key_order = T.let(false, T::Boolean)
|
|
40
|
+
|
|
41
|
+
class << self
|
|
42
|
+
extend T::Sig
|
|
43
|
+
|
|
44
|
+
sig { returns(T::Boolean) }
|
|
45
|
+
attr_accessor :preserve_key_order
|
|
46
|
+
end
|
|
47
|
+
|
|
34
48
|
sig do
|
|
35
49
|
returns(T::Array[Package])
|
|
36
50
|
end
|
|
@@ -90,8 +104,7 @@ module ParsePackwerk
|
|
|
90
104
|
merged_config.merge!('metadata' => package.metadata)
|
|
91
105
|
end
|
|
92
106
|
|
|
93
|
-
|
|
94
|
-
merged_config = merged_config.to_a.sort_by { |key, _value| T.unsafe(sorted_keys).index(key) || 1000 }.to_h
|
|
107
|
+
merged_config = sort_keys(merged_config, package.original_key_order)
|
|
95
108
|
|
|
96
109
|
raw_yaml = YAML.dump(merged_config)
|
|
97
110
|
stylized_yaml = raw_yaml.gsub("---\n", '')
|
|
@@ -99,6 +112,23 @@ module ParsePackwerk
|
|
|
99
112
|
end
|
|
100
113
|
end
|
|
101
114
|
|
|
115
|
+
sig { params(config: T::Hash[T.untyped, T.untyped], original_key_order: T::Array[String]).returns(T::Hash[T.untyped, T.untyped]) }
|
|
116
|
+
def self.sort_keys(config, original_key_order)
|
|
117
|
+
if preserve_key_order && original_key_order.any?
|
|
118
|
+
# Preserve original key order: existing keys stay in their original position,
|
|
119
|
+
# new keys are appended in the default sort order
|
|
120
|
+
existing_keys = original_key_order & config.keys
|
|
121
|
+
new_keys = config.keys - original_key_order
|
|
122
|
+
sorted_new_keys = new_keys.sort_by { |key| key_sort_order.index(key) || 1000 }
|
|
123
|
+
|
|
124
|
+
ordered_keys = existing_keys + sorted_new_keys
|
|
125
|
+
ordered_keys.each_with_object({}) { |key, hash| hash[key] = config[key] if config.key?(key) }
|
|
126
|
+
else
|
|
127
|
+
# Default behavior: sort by canonical key order
|
|
128
|
+
config.to_a.sort_by { |key, _value| T.unsafe(key_sort_order).index(key) || 1000 }.to_h
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
102
132
|
sig { returns(T::Array[String]) }
|
|
103
133
|
def self.key_sort_order
|
|
104
134
|
%w[
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: parse_packwerk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.28.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gusto Engineers
|
|
@@ -194,14 +194,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
194
194
|
requirements:
|
|
195
195
|
- - ">="
|
|
196
196
|
- !ruby/object:Gem::Version
|
|
197
|
-
version: '
|
|
197
|
+
version: '3.3'
|
|
198
198
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
199
199
|
requirements:
|
|
200
200
|
- - ">="
|
|
201
201
|
- !ruby/object:Gem::Version
|
|
202
202
|
version: '0'
|
|
203
203
|
requirements: []
|
|
204
|
-
rubygems_version: 3.6.
|
|
204
|
+
rubygems_version: 3.6.9
|
|
205
205
|
specification_version: 4
|
|
206
206
|
summary: A low-dependency gem for parsing and writing packwerk YML files
|
|
207
207
|
test_files: []
|