code_ownership 1.36.3 → 1.38.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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7883f0d73587e099adf43101b91f0a2f296912cfa3e994e2f1c70472de918e4b
|
4
|
+
data.tar.gz: 1e11b8c1ce41986fa40325b3edf10369b00a7ed8a42f47e2ed4fe9694f565642
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a381fc3a9867de019b70ada03aca768c427b05198449c4d6478f245f79fefd8e2bd56ab5df06fbe62577d12ce6f6bf80a6509f8347f65831ab8251075b1047f
|
7
|
+
data.tar.gz: 5ea28b28bbf41f5620fbf07d6d4083f8dcfea577648612fd8f05d4e128007ff73d6cec2e1a433ef84cf35a1e4b2c8b4a2d4fca0a8bbaeafedca948be293aaaba
|
data/README.md
CHANGED
@@ -8,6 +8,30 @@ Check out [`code_ownership_spec.rb`](https://github.com/rubyatscale/code_ownersh
|
|
8
8
|
|
9
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.
|
10
10
|
|
11
|
+
## Getting started
|
12
|
+
|
13
|
+
To get started there's a few things you should do.
|
14
|
+
|
15
|
+
1) Create a `config/code_ownership.yml` file and declare where your files live. Here's a sample to start with:
|
16
|
+
```yml
|
17
|
+
owned_globs:
|
18
|
+
- '{app,components,config,frontend,lib,packs,spec}/**/*.{rb,rake,js,jsx,ts,tsx}'
|
19
|
+
js_package_paths: []
|
20
|
+
unowned_globs:
|
21
|
+
- db/**/*
|
22
|
+
- app/services/some_file1.rb
|
23
|
+
- app/services/some_file2.rb
|
24
|
+
- frontend/javascripts/**/__generated__/**/*
|
25
|
+
```
|
26
|
+
2) Declare some teams. Here's an example, that would live at `config/teams/operations.yml`:
|
27
|
+
```yml
|
28
|
+
name: Operations
|
29
|
+
github:
|
30
|
+
team: '@my-org/operations-team'
|
31
|
+
```
|
32
|
+
3) Declare ownership. You can do this at a directory level or at a file level. All of the files within the `owned_globs` you declared in step 1 will need to have an owner assigned (or be opted out via `unowned_globs`). See the next section for more detail.
|
33
|
+
4) Run validations when you commit, and/or in CI. If you run validations in CI, ensure that if your `.github/CODEOWNERS` file gets changed, that gets pushed to the PR.
|
34
|
+
|
11
35
|
## Usage: Declaring Ownership
|
12
36
|
|
13
37
|
There are three ways to declare code ownership using this gem.
|
@@ -48,7 +48,8 @@ module CodeOwnership
|
|
48
48
|
.map(&:cleanpath)
|
49
49
|
.each_with_object({}) do |pathname, res|
|
50
50
|
owner = owner_for_codeowners_file(pathname)
|
51
|
-
|
51
|
+
glob = glob_for_codeowners_file(pathname)
|
52
|
+
res[glob] = owner
|
52
53
|
end
|
53
54
|
end
|
54
55
|
|
@@ -77,7 +78,7 @@ module CodeOwnership
|
|
77
78
|
# Takes a file and finds the relevant `.codeowner` file by walking up the directory
|
78
79
|
# structure. Example, given `a/b/c.rb`, this looks for `a/b/.codeowner`, `a/.codeowner`,
|
79
80
|
# and `.codeowner` in that order, stopping at the first file to actually exist.
|
80
|
-
# If the
|
81
|
+
# If the provided file is a directory, it will look for `.codeowner` in that directory and then upwards.
|
81
82
|
# We do additional caching so that we don't have to check for file existence every time.
|
82
83
|
sig { params(file: String).returns(T.nilable(CodeTeams::Team)) }
|
83
84
|
def map_file_to_relevant_owner(file)
|
@@ -123,6 +124,26 @@ module CodeOwnership
|
|
123
124
|
|
124
125
|
team
|
125
126
|
end
|
127
|
+
|
128
|
+
sig { params(codeowners_file: Pathname).returns(String) }
|
129
|
+
def glob_for_codeowners_file(codeowners_file)
|
130
|
+
unescaped = codeowners_file.dirname.cleanpath.join('**/**').to_s
|
131
|
+
|
132
|
+
# Globs can contain certain regex characters, like "[" and "]".
|
133
|
+
# However, when we are generating a glob from a .codeowner file, we
|
134
|
+
# need to escape bracket characters and interpret them literally.
|
135
|
+
# Otherwise the resulting glob will not actually match the directory
|
136
|
+
# containing the .codeowner file.
|
137
|
+
#
|
138
|
+
# Example
|
139
|
+
# file: "/some/[dir]/.codeowner"
|
140
|
+
# unescaped: "/some/[dir]/**/**"
|
141
|
+
# matches: "/some/d/file"
|
142
|
+
# matches: "/some/i/file"
|
143
|
+
# matches: "/some/r/file"
|
144
|
+
# does not match!: "/some/[dir]/file"
|
145
|
+
unescaped.gsub(/[\[\]]/) { |x| "\\#{x}" }
|
146
|
+
end
|
126
147
|
end
|
127
148
|
end
|
128
149
|
end
|
@@ -39,7 +39,8 @@ module CodeOwnership
|
|
39
39
|
owner = file_annotation_based_owner(filename_relative_to_root)
|
40
40
|
next unless owner
|
41
41
|
|
42
|
-
|
42
|
+
escaped_filename = escaped_path_for_codeowners_file(filename_relative_to_root)
|
43
|
+
mapping[escaped_filename] = owner
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
@@ -55,7 +56,8 @@ module CodeOwnership
|
|
55
56
|
|
56
57
|
invalid_files = cache.keys.select do |file|
|
57
58
|
# If a file is not tracked, it should be removed from the cache
|
58
|
-
|
59
|
+
unescaped_file = unescaped_path_for_codeowners_file(file)
|
60
|
+
!Private.file_tracked?(unescaped_file) ||
|
59
61
|
# If a file no longer has a file annotation (i.e. `globs_to_owner` doesn't map it)
|
60
62
|
# it should be removed from the cache
|
61
63
|
# We make sure to only apply this to the input files since otherwise `updated_cache_for_files.key?(file)` would always return `false` when files == []
|
@@ -126,6 +128,32 @@ module CodeOwnership
|
|
126
128
|
|
127
129
|
sig { override.void }
|
128
130
|
def bust_caches!; end
|
131
|
+
|
132
|
+
sig { params(filename: String).returns(String) }
|
133
|
+
def escaped_path_for_codeowners_file(filename)
|
134
|
+
# Globs can contain certain regex characters, like "[" and "]".
|
135
|
+
# However, when we are generating a glob from a file annotation, we
|
136
|
+
# need to escape bracket characters and interpret them literally.
|
137
|
+
# Otherwise the resulting glob will not actually match the directory
|
138
|
+
# containing the file.
|
139
|
+
#
|
140
|
+
# Example
|
141
|
+
# filename: "/some/[xId]/myfile.tsx"
|
142
|
+
# matches: "/some/1/file"
|
143
|
+
# matches: "/some/2/file"
|
144
|
+
# matches: "/some/3/file"
|
145
|
+
# does not match!: "/some/[xId]/myfile.tsx"
|
146
|
+
filename.gsub(/[\[\]]/) { |x| "\\#{x}" }
|
147
|
+
end
|
148
|
+
|
149
|
+
sig { params(filename: String).returns(String) }
|
150
|
+
def unescaped_path_for_codeowners_file(filename)
|
151
|
+
# Globs can contain certain regex characters, like "[" and "]".
|
152
|
+
# We escape bracket characters and interpret them literally for
|
153
|
+
# the CODEOWNERS file. However, we want to compare the unescaped
|
154
|
+
# glob to the actual file path when we check if the file was deleted.
|
155
|
+
filename.gsub(/\\([\[\]])/, '\1')
|
156
|
+
end
|
129
157
|
end
|
130
158
|
end
|
131
159
|
end
|
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.
|
4
|
+
version: 1.38.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: 2024-
|
11
|
+
date: 2024-11-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: code_teams
|
@@ -220,7 +220,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
220
220
|
- !ruby/object:Gem::Version
|
221
221
|
version: '0'
|
222
222
|
requirements: []
|
223
|
-
rubygems_version: 3.5.
|
223
|
+
rubygems_version: 3.5.22
|
224
224
|
signing_key:
|
225
225
|
specification_version: 4
|
226
226
|
summary: A gem to help engineering teams declare ownership of code
|