code_ownership 1.28.0 → 1.28.2
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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf48240fd31979132287823a3f9d40d6b03776df405583c31a56cb87e6dfbe40
|
4
|
+
data.tar.gz: 1cbd9b0fee826c7a23dd71335043eab358f99157bb7f677a94b8d4abc1782f4e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68721e648bcd3e8888f3f94d33baf0d38b642c3d6104db0964e6aff3194860407e72c9ad88ffec357285006bff87490b49b92a238fbbf83d37509d34868ea0fe
|
7
|
+
data.tar.gz: 0d878620986f0fe3e6168fa8ea0db1a1a530d27c0f35410f70b3f876146df2b184f9db3486ef9e4e74c0583a067b48ad4462af6877d7452e5d1574bec61ebd8f
|
data/README.md
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
# CodeOwnership
|
2
|
-
This gem helps engineering teams declare ownership of code.
|
3
2
|
|
4
|
-
|
3
|
+
This gem helps engineering teams declare ownership of code. This gem works best in large, usually monolithic code bases where many teams work together.
|
5
4
|
|
6
|
-
Check out `
|
5
|
+
Check out [`lib/code_ownership.rb`](https://github.com/rubyatscale/code_ownership/blob/main/lib/code_ownership.rb) to see the public API.
|
6
|
+
|
7
|
+
Check out [`code_ownership_spec.rb`](https://github.com/rubyatscale/code_ownership/blob/main/spec/lib/code_ownership_spec.rb) to see examples of how code ownership is used.
|
7
8
|
|
8
9
|
There is also a [companion VSCode Extension]([url](https://github.com/rubyatscale/code-ownership-vscode)) for this gem. Just search `Gusto.code-ownership-vscode` in the VSCode Extension Marketplace.
|
9
10
|
|
10
11
|
## Usage: Declaring Ownership
|
12
|
+
|
11
13
|
There are three ways to declare code ownership using this gem.
|
14
|
+
|
12
15
|
### Package-Based Ownership
|
13
16
|
Package based ownership integrates [`packwerk`](https://github.com/Shopify/packwerk) and has ownership defined per package. To define that all files within a package are owned by one team, configure your `package.yml` like this:
|
14
17
|
```yml
|
@@ -31,6 +34,29 @@ File annotations are a last resort if there is no clear home for your code. File
|
|
31
34
|
```ruby
|
32
35
|
# @team MyTeam
|
33
36
|
```
|
37
|
+
|
38
|
+
### Javascript Package Ownership
|
39
|
+
Javascript package based ownership allows you to specify an owenrship key in a `package.json`. To use this, configure your `package.json` like this:
|
40
|
+
|
41
|
+
```json
|
42
|
+
{
|
43
|
+
// other keys
|
44
|
+
"metadata": {
|
45
|
+
"owner": "My Team"
|
46
|
+
}
|
47
|
+
// other keys
|
48
|
+
}
|
49
|
+
```
|
50
|
+
|
51
|
+
You can also tell `code_ownership` where to find JS packages in the configuration, like this:
|
52
|
+
```yml
|
53
|
+
js_package_paths:
|
54
|
+
- frontend/javascripts/packages/*
|
55
|
+
- frontend/other_location_for_packages/*
|
56
|
+
```
|
57
|
+
|
58
|
+
This defaults `**/`, which makes it look for `package.json` files across your application.
|
59
|
+
|
34
60
|
## Usage: Reading CodeOwnership
|
35
61
|
### `for_file`
|
36
62
|
`CodeOwnership.for_file`, given a relative path to a file returns a `CodeTeams::Team` if there is a team that owns the file, `nil` otherwise.
|
@@ -71,7 +97,9 @@ See `code_ownership_spec.rb` for an example.
|
|
71
97
|
A `CODEOWNERS` file defines who owns specific files or paths in a repository. When you run `bin/codeownership validate`, a `.github/CODEOWNERS` file will automatically be generated and updated.
|
72
98
|
|
73
99
|
## Proper Configuration & Validation
|
100
|
+
|
74
101
|
CodeOwnership comes with a validation function to ensure the following things are true:
|
102
|
+
|
75
103
|
1) Only one mechanism is defining file ownership. That is -- you can't have a file annotation on a file owned via package-based or glob-based ownership. This helps make ownership behavior more clear by avoiding concerns about precedence.
|
76
104
|
2) All teams referenced as an owner for any file or package is a valid team (i.e. it's in the list of `CodeTeams.all`).
|
77
105
|
3) All files have ownership. You can specify in `unowned_globs` to represent a TODO list of files to add ownership to.
|
@@ -16,7 +16,7 @@ module CodeOwnership
|
|
16
16
|
returns(T.nilable(::CodeTeams::Team))
|
17
17
|
end
|
18
18
|
def map_file_to_owner(file)
|
19
|
-
package =
|
19
|
+
package = ParsePackwerk.package_from_path(file)
|
20
20
|
|
21
21
|
return nil if package.nil?
|
22
22
|
|
@@ -80,41 +80,6 @@ module CodeOwnership
|
|
80
80
|
def bust_caches!
|
81
81
|
@@package_yml_cache = {} # rubocop:disable Style/ClassVars
|
82
82
|
end
|
83
|
-
|
84
|
-
private
|
85
|
-
|
86
|
-
# takes a file and finds the relevant `package.yml` file by walking up the directory
|
87
|
-
# structure. Example, given `packs/a/b/c.rb`, this looks for `packs/a/b/package.yml`, `packs/a/package.yml`,
|
88
|
-
# `packs/package.yml`, and `package.yml` in that order, stopping at the first file to actually exist.
|
89
|
-
# We do additional caching so that we don't have to check for file existence every time
|
90
|
-
sig { params(file: String).returns(T.nilable(ParsePackwerk::Package)) }
|
91
|
-
def map_file_to_relevant_package(file)
|
92
|
-
file_path = Pathname.new(file)
|
93
|
-
path_components = file_path.each_filename.to_a.map { |path| Pathname.new(path) }
|
94
|
-
|
95
|
-
(path_components.length - 1).downto(0).each do |i|
|
96
|
-
potential_relative_path_name = T.must(path_components[0...i]).reduce(Pathname.new('')) { |built_path, path| built_path.join(path) }
|
97
|
-
potential_package_yml_path = potential_relative_path_name.
|
98
|
-
join(ParsePackwerk::PACKAGE_YML_NAME)
|
99
|
-
|
100
|
-
potential_package_yml_string = potential_package_yml_path.to_s
|
101
|
-
|
102
|
-
package = nil
|
103
|
-
if @@package_yml_cache.key?(potential_package_yml_string)
|
104
|
-
package = @@package_yml_cache[potential_package_yml_string]
|
105
|
-
elsif potential_package_yml_path.exist?
|
106
|
-
package = ParsePackwerk::Package.from(potential_package_yml_path)
|
107
|
-
|
108
|
-
@@package_yml_cache[potential_package_yml_string] = package
|
109
|
-
else
|
110
|
-
@@package_yml_cache[potential_package_yml_string] = nil
|
111
|
-
end
|
112
|
-
|
113
|
-
return package unless package.nil?
|
114
|
-
end
|
115
|
-
|
116
|
-
nil
|
117
|
-
end
|
118
83
|
end
|
119
84
|
end
|
120
85
|
end
|
@@ -32,6 +32,16 @@ module CodeOwnership
|
|
32
32
|
name: package_name,
|
33
33
|
metadata: package_loaded_json[METADATA] || {}
|
34
34
|
)
|
35
|
+
rescue JSON::ParserError => e
|
36
|
+
error_message = <<~MESSAGE
|
37
|
+
#{e.inspect}
|
38
|
+
|
39
|
+
#{pathname} has invalid JSON, so code ownership cannot be determined.
|
40
|
+
|
41
|
+
Please either make the JSON in that file valid or specify `js_package_paths` in config/code_ownership.yml.
|
42
|
+
MESSAGE
|
43
|
+
|
44
|
+
raise InvalidCodeOwnershipConfigurationError.new(error_message)
|
35
45
|
end
|
36
46
|
|
37
47
|
sig { returns(Pathname) }
|
@@ -6,12 +6,18 @@
|
|
6
6
|
|
7
7
|
module ParsePackwerk
|
8
8
|
class << self
|
9
|
-
sig {
|
10
|
-
def all
|
9
|
+
sig { returns(T::Array[::ParsePackwerk::Package]) }
|
10
|
+
def all; end
|
11
|
+
|
12
|
+
sig { void }
|
13
|
+
def bust_cache!; end
|
11
14
|
|
12
15
|
sig { params(name: ::String).returns(T.nilable(::ParsePackwerk::Package)) }
|
13
16
|
def find(name); end
|
14
17
|
|
18
|
+
sig { params(file_path: T.any(::Pathname, ::String)).returns(T.nilable(::ParsePackwerk::Package)) }
|
19
|
+
def package_from_path(file_path); end
|
20
|
+
|
15
21
|
sig { params(package: ::ParsePackwerk::Package).void }
|
16
22
|
def write_package_yml!(package); end
|
17
23
|
|
@@ -27,12 +33,24 @@ end
|
|
27
33
|
|
28
34
|
class ParsePackwerk::Configuration < ::T::Struct
|
29
35
|
const :exclude, T::Array[::String]
|
36
|
+
const :package_paths, T::Array[::String]
|
30
37
|
|
31
38
|
class << self
|
39
|
+
sig { params(config_hash: T::Hash[T.untyped, T.untyped]).returns(T::Array[::String]) }
|
40
|
+
def excludes(config_hash); end
|
41
|
+
|
42
|
+
sig { returns(::ParsePackwerk::Configuration) }
|
43
|
+
def fetch; end
|
44
|
+
|
32
45
|
def inherited(s); end
|
46
|
+
|
47
|
+
sig { params(config_hash: T::Hash[T.untyped, T.untyped]).returns(T::Array[::String]) }
|
48
|
+
def package_paths(config_hash); end
|
33
49
|
end
|
34
50
|
end
|
35
51
|
|
52
|
+
ParsePackwerk::DEFAULT_EXCLUDE_GLOBS = T.let(T.unsafe(nil), Array)
|
53
|
+
ParsePackwerk::DEFAULT_PACKAGE_PATHS = T.let(T.unsafe(nil), Array)
|
36
54
|
ParsePackwerk::DEPENDENCIES = T.let(T.unsafe(nil), String)
|
37
55
|
ParsePackwerk::DEPRECATED_REFERENCES_YML_NAME = T.let(T.unsafe(nil), String)
|
38
56
|
|
@@ -91,6 +109,23 @@ class ParsePackwerk::Package < ::T::Struct
|
|
91
109
|
end
|
92
110
|
end
|
93
111
|
|
112
|
+
class ParsePackwerk::PackageSet
|
113
|
+
class << self
|
114
|
+
sig do
|
115
|
+
params(
|
116
|
+
package_pathspec: T::Array[::String],
|
117
|
+
exclude_pathspec: T::Array[::String]
|
118
|
+
).returns(T::Array[::ParsePackwerk::Package])
|
119
|
+
end
|
120
|
+
def from(package_pathspec:, exclude_pathspec:); end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
sig { params(globs: T::Array[::String], path: ::Pathname).returns(T::Boolean) }
|
125
|
+
def exclude_path?(globs, path); end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
94
129
|
ParsePackwerk::ROOT_PACKAGE_NAME = T.let(T.unsafe(nil), String)
|
95
130
|
|
96
131
|
class ParsePackwerk::Violation < ::T::Struct
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: code_ownership
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.28.
|
4
|
+
version: 1.28.2
|
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-08-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: code_teams
|
@@ -150,7 +150,7 @@ files:
|
|
150
150
|
- lib/code_ownership/private/validations/interface.rb
|
151
151
|
- sorbet/config
|
152
152
|
- sorbet/rbi/gems/code_teams@1.0.0.rbi
|
153
|
-
- sorbet/rbi/gems/parse_packwerk@0.
|
153
|
+
- sorbet/rbi/gems/parse_packwerk@0.12.0.rbi
|
154
154
|
- sorbet/rbi/manual.rbi
|
155
155
|
- sorbet/rbi/todo.rbi
|
156
156
|
homepage: https://github.com/rubyatscale/code_ownership
|