code_ownership 1.36.3 → 1.38.0
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:
|
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
|