fast_code_owners 0.0.4-aarch64-linux-musl
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 +7 -0
- data/README.md +41 -0
- data/ext/fast_code_owners/tests/fixtures/valid_project/config/code_ownership.yml +10 -0
- data/ext/fast_code_owners/tests/fixtures/valid_project/config/teams/bar.yml +5 -0
- data/ext/fast_code_owners/tests/fixtures/valid_project/config/teams/foo.yml +5 -0
- data/ext/fast_code_owners/tests/fixtures/valid_project/ruby/app/bar/bar_none.rb +0 -0
- data/ext/fast_code_owners/tests/fixtures/valid_project/ruby/app/foo/foo_none.rb +0 -0
- data/lib/fast_code_owners/3.2/fast_code_owners.so +0 -0
- data/lib/fast_code_owners/3.4/fast_code_owners.so +0 -0
- data/lib/fast_code_owners/file_path_finder.rb +61 -0
- data/lib/fast_code_owners/file_path_team_cache.rb +39 -0
- data/lib/fast_code_owners/team_finder.rb +72 -0
- data/lib/fast_code_owners/version.rb +5 -0
- data/lib/fast_code_owners.rb +54 -0
- metadata +178 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2b664c5c60436878144d8efd8abae46afa74d873391118e883c7983756e5028a
|
4
|
+
data.tar.gz: e4f4f5a2c0c1cde3ddb65eef2a7f9012a4ca1dab2646a825bc345395c68e5722
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 033d1e2882662aaddaf6ab0c51fd6d1985598dccd41188d77645de52ab7af2ef4d17ead6f86cd46b49999729efb0e0204695c8af261fa16f143132a9329fbe32
|
7
|
+
data.tar.gz: ad68b6fa1c68dcb1cb59fca6a1b2a66e656297043160b1c9f6e4cd1463183b14e67cd4467b795cf92fc704e86117ff705c754f281813bf1db26c67400ca6925a
|
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# fast_code_owners
|
2
|
+
|
3
|
+
A thin Ruby wrapper around [codeowners-rs](https://github.com/rubyatscale/codeowners-rs)
|
4
|
+
|
5
|
+
## Why?
|
6
|
+
|
7
|
+
The [codeowners-rs](https://github.com/rubyatscale/codeowners-rs) CLI is a fast alternative to the Ruby gem [code_ownership](https://github.com/rubyatscale/code_ownership). However, since codeowners-rs is written in Rust, it can't provide direct Ruby APIs.
|
8
|
+
|
9
|
+
**fast_code_owners** provides Ruby APIs that delegate to codeowners-rs. Much of this code was lifted from [code_ownership](https://github.com/rubyatscale/code_ownership).
|
10
|
+
|
11
|
+
## Dependencies
|
12
|
+
|
13
|
+
- [Rust](https://www.rust-lang.org/tools/install) must be installed and in the PATH
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
```bash
|
18
|
+
gem install fast_code_owners
|
19
|
+
```
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
require 'fast_code_owners'
|
25
|
+
|
26
|
+
# Find the owning team for the provided file path
|
27
|
+
team = FastCodeOwners.for_file('path/to/file.rb')
|
28
|
+
|
29
|
+
# Find the owning team for the provided class
|
30
|
+
team = FastCodeOwners.for_class(MyClass)
|
31
|
+
|
32
|
+
# Find the owning team for the provided packwerk/pks package.yml
|
33
|
+
team = FastCodeOwners.for_package('packs/foo/package.yml')
|
34
|
+
|
35
|
+
# Find the owning team for the provided error backtrace
|
36
|
+
teams = FastCodeOwners.for_backtrace(error.backtrace)
|
37
|
+
```
|
38
|
+
|
39
|
+
## Contributing
|
40
|
+
|
41
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/rubyatscale/fast_code_owners.
|
File without changes
|
File without changes
|
Binary file
|
Binary file
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# typed: strict
|
4
|
+
|
5
|
+
module FastCodeOwners
|
6
|
+
module FilePathFinder
|
7
|
+
module_function
|
8
|
+
|
9
|
+
extend T::Sig
|
10
|
+
extend T::Helpers
|
11
|
+
|
12
|
+
# Returns a string version of the relative path to a Rails constant,
|
13
|
+
# or nil if it can't find anything
|
14
|
+
sig { params(klass: T.nilable(T.any(T::Class[T.anything], Module))).returns(T.nilable(String)) }
|
15
|
+
def path_from_klass(klass)
|
16
|
+
if klass
|
17
|
+
path = Object.const_source_location(klass.to_s)&.first
|
18
|
+
(path && Pathname.new(path).relative_path_from(Pathname.pwd).to_s) || nil
|
19
|
+
end
|
20
|
+
rescue NameError
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
sig { params(backtrace: T.nilable(T::Array[String])).returns(T::Enumerable[String]) }
|
25
|
+
def from_backtrace(backtrace)
|
26
|
+
return [] unless backtrace
|
27
|
+
|
28
|
+
# The pattern for a backtrace hasn't changed in forever and is considered
|
29
|
+
# stable: https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L303-L317
|
30
|
+
#
|
31
|
+
# This pattern matches a line like the following:
|
32
|
+
#
|
33
|
+
# ./app/controllers/some_controller.rb:43:in `block (3 levels) in create'
|
34
|
+
#
|
35
|
+
backtrace_line = if RUBY_VERSION >= '3.4.0'
|
36
|
+
%r{\A(#{Pathname.pwd}/|\./)?
|
37
|
+
(?<file>.+) # Matches 'app/controllers/some_controller.rb'
|
38
|
+
:
|
39
|
+
(?<line>\d+) # Matches '43'
|
40
|
+
:in\s
|
41
|
+
'(?<function>.*)' # Matches "`block (3 levels) in create'"
|
42
|
+
\z}x
|
43
|
+
else
|
44
|
+
%r{\A(#{Pathname.pwd}/|\./)?
|
45
|
+
(?<file>.+) # Matches 'app/controllers/some_controller.rb'
|
46
|
+
:
|
47
|
+
(?<line>\d+) # Matches '43'
|
48
|
+
:in\s
|
49
|
+
`(?<function>.*)' # Matches "`block (3 levels) in create'"
|
50
|
+
\z}x
|
51
|
+
end
|
52
|
+
|
53
|
+
backtrace.lazy.filter_map do |line|
|
54
|
+
match = line.match(backtrace_line)
|
55
|
+
next unless match
|
56
|
+
|
57
|
+
T.must(match[:file])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# typed: strict
|
4
|
+
|
5
|
+
module FastCodeOwners
|
6
|
+
module FilePathTeamCache
|
7
|
+
module_function
|
8
|
+
|
9
|
+
extend T::Sig
|
10
|
+
extend T::Helpers
|
11
|
+
|
12
|
+
sig { params(file_path: String).returns(T.nilable(CodeTeams::Team)) }
|
13
|
+
def get(file_path)
|
14
|
+
cache[file_path]
|
15
|
+
end
|
16
|
+
|
17
|
+
sig { params(file_path: String, team: T.nilable(CodeTeams::Team)).void }
|
18
|
+
def set(file_path, team)
|
19
|
+
cache[file_path] = team
|
20
|
+
end
|
21
|
+
|
22
|
+
sig { params(file_path: String).returns(T::Boolean) }
|
23
|
+
def cached?(file_path)
|
24
|
+
cache.key?(file_path)
|
25
|
+
end
|
26
|
+
|
27
|
+
sig { void }
|
28
|
+
def bust_cache!
|
29
|
+
@cache = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
sig { returns(T::Hash[String, T.nilable(CodeTeams::Team)]) }
|
33
|
+
def cache
|
34
|
+
@cache ||= T.let(@cache,
|
35
|
+
T.nilable(T::Hash[String, T.nilable(CodeTeams::Team)]))
|
36
|
+
@cache ||= {}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# typed: strict
|
4
|
+
|
5
|
+
module FastCodeOwners
|
6
|
+
module TeamFinder
|
7
|
+
module_function
|
8
|
+
|
9
|
+
extend T::Sig
|
10
|
+
extend T::Helpers
|
11
|
+
|
12
|
+
requires_ancestor { Kernel }
|
13
|
+
|
14
|
+
sig { params(file_path: String).returns(T.nilable(CodeTeams::Team)) }
|
15
|
+
def for_file(file_path)
|
16
|
+
return nil if file_path.start_with?('./')
|
17
|
+
return FilePathTeamCache.get(file_path) if FilePathTeamCache.cached?(file_path)
|
18
|
+
|
19
|
+
result = T.let(RustCodeOwners.for_file(file_path), T.nilable(T::Hash[Symbol, String]))
|
20
|
+
return if result.nil?
|
21
|
+
|
22
|
+
if result[:team_name].nil?
|
23
|
+
FilePathTeamCache.set(file_path, nil)
|
24
|
+
else
|
25
|
+
FilePathTeamCache.set(file_path, T.let(find_team!(T.must(result[:team_name])), T.nilable(CodeTeams::Team)))
|
26
|
+
end
|
27
|
+
|
28
|
+
FilePathTeamCache.get(file_path)
|
29
|
+
end
|
30
|
+
|
31
|
+
sig { params(klass: T.nilable(T.any(T::Class[T.anything], Module))).returns(T.nilable(::CodeTeams::Team)) }
|
32
|
+
def for_class(klass)
|
33
|
+
file_path = FilePathFinder.path_from_klass(klass)
|
34
|
+
return nil if file_path.nil?
|
35
|
+
|
36
|
+
for_file(file_path)
|
37
|
+
end
|
38
|
+
|
39
|
+
sig { params(package: Packs::Pack).returns(T.nilable(::CodeTeams::Team)) }
|
40
|
+
def for_package(package)
|
41
|
+
owner_name = package.raw_hash['owner'] || package.metadata['owner']
|
42
|
+
return nil if owner_name.nil?
|
43
|
+
|
44
|
+
find_team!(owner_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
sig { params(backtrace: T.nilable(T::Array[String]), excluded_teams: T::Array[::CodeTeams::Team]).returns(T.nilable(::CodeTeams::Team)) }
|
48
|
+
def for_backtrace(backtrace, excluded_teams: [])
|
49
|
+
first_owned_file_for_backtrace(backtrace, excluded_teams: excluded_teams)&.first
|
50
|
+
end
|
51
|
+
|
52
|
+
sig { params(backtrace: T.nilable(T::Array[String]), excluded_teams: T::Array[::CodeTeams::Team]).returns(T.nilable([::CodeTeams::Team, String])) }
|
53
|
+
def first_owned_file_for_backtrace(backtrace, excluded_teams: [])
|
54
|
+
FilePathFinder.from_backtrace(backtrace).each do |file|
|
55
|
+
team = for_file(file)
|
56
|
+
if team && !excluded_teams.include?(team)
|
57
|
+
return [team, file]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
|
64
|
+
sig { params(team_name: String).returns(CodeTeams::Team) }
|
65
|
+
def find_team!(team_name)
|
66
|
+
CodeTeams.find(team_name) ||
|
67
|
+
raise(StandardError, "Could not find team with name: `#{team_name}`. Make sure the team is one of `#{CodeTeams.all.map(&:name).sort}`")
|
68
|
+
end
|
69
|
+
|
70
|
+
private_class_method(:find_team!)
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# typed: strict
|
4
|
+
|
5
|
+
require 'code_teams'
|
6
|
+
require 'packs-specification'
|
7
|
+
require 'sorbet-runtime'
|
8
|
+
require_relative 'fast_code_owners/file_path_team_cache'
|
9
|
+
require_relative 'fast_code_owners/team_finder'
|
10
|
+
require_relative 'fast_code_owners/version'
|
11
|
+
require_relative 'fast_code_owners/fast_code_owners'
|
12
|
+
require_relative 'fast_code_owners/file_path_finder'
|
13
|
+
|
14
|
+
module FastCodeOwners
|
15
|
+
module_function
|
16
|
+
|
17
|
+
extend T::Sig
|
18
|
+
extend T::Helpers
|
19
|
+
requires_ancestor { Kernel }
|
20
|
+
|
21
|
+
sig { params(file_path: String).returns(T.nilable(CodeTeams::Team)) }
|
22
|
+
def for_file(file_path)
|
23
|
+
TeamFinder.for_file(file_path)
|
24
|
+
end
|
25
|
+
|
26
|
+
sig { params(klass: T.nilable(T.any(T::Class[T.anything], Module))).returns(T.nilable(::CodeTeams::Team)) }
|
27
|
+
def for_class(klass)
|
28
|
+
TeamFinder.for_class(klass)
|
29
|
+
end
|
30
|
+
|
31
|
+
sig { params(package: Packs::Pack).returns(T.nilable(::CodeTeams::Team)) }
|
32
|
+
def for_package(package)
|
33
|
+
TeamFinder.for_package(package)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Given a backtrace from either `Exception#backtrace` or `caller`, find the
|
37
|
+
# first line that corresponds to a file with assigned ownership
|
38
|
+
sig { params(backtrace: T.nilable(T::Array[String]), excluded_teams: T::Array[::CodeTeams::Team]).returns(T.nilable(::CodeTeams::Team)) }
|
39
|
+
def for_backtrace(backtrace, excluded_teams: [])
|
40
|
+
TeamFinder.for_backtrace(backtrace, excluded_teams: excluded_teams)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Given a backtrace from either `Exception#backtrace` or `caller`, find the
|
44
|
+
# first owned file in it, useful for figuring out which file is being blamed.
|
45
|
+
sig { params(backtrace: T.nilable(T::Array[String]), excluded_teams: T::Array[::CodeTeams::Team]).returns(T.nilable([::CodeTeams::Team, String])) }
|
46
|
+
def first_owned_file_for_backtrace(backtrace, excluded_teams: [])
|
47
|
+
TeamFinder.first_owned_file_for_backtrace(backtrace, excluded_teams: excluded_teams)
|
48
|
+
end
|
49
|
+
|
50
|
+
sig { void }
|
51
|
+
def bust_cache!
|
52
|
+
FilePathTeamCache.bust_cache!
|
53
|
+
end
|
54
|
+
end
|
metadata
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fast_code_owners
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
platform: aarch64-linux-musl
|
6
|
+
authors:
|
7
|
+
- Perry Hertler
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-05-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: code_teams
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: packs-specification
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sorbet-runtime
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: debug
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: railties
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: sorbet
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: tapioca
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: A ruby interface that determines file ownership for git repositories
|
126
|
+
email:
|
127
|
+
- perry.hertler@gusto.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- README.md
|
133
|
+
- ext/fast_code_owners/tests/fixtures/valid_project/config/code_ownership.yml
|
134
|
+
- ext/fast_code_owners/tests/fixtures/valid_project/config/teams/bar.yml
|
135
|
+
- ext/fast_code_owners/tests/fixtures/valid_project/config/teams/foo.yml
|
136
|
+
- ext/fast_code_owners/tests/fixtures/valid_project/ruby/app/bar/bar_none.rb
|
137
|
+
- ext/fast_code_owners/tests/fixtures/valid_project/ruby/app/foo/foo_none.rb
|
138
|
+
- lib/fast_code_owners.rb
|
139
|
+
- lib/fast_code_owners/3.2/fast_code_owners.so
|
140
|
+
- lib/fast_code_owners/3.4/fast_code_owners.so
|
141
|
+
- lib/fast_code_owners/file_path_finder.rb
|
142
|
+
- lib/fast_code_owners/file_path_team_cache.rb
|
143
|
+
- lib/fast_code_owners/team_finder.rb
|
144
|
+
- lib/fast_code_owners/version.rb
|
145
|
+
homepage: https://github.com/rubyatscale/fast_code_owners
|
146
|
+
licenses: []
|
147
|
+
metadata:
|
148
|
+
allowed_push_host: https://rubygems.org
|
149
|
+
homepage_uri: https://github.com/rubyatscale/fast_code_owners
|
150
|
+
source_code_uri: https://github.com/rubyatscale/fast_code_owners
|
151
|
+
changelog_uri: https://github.com/rubyatscale/fast_code_owners/releases
|
152
|
+
cargo_crate_name: fast_code_owners
|
153
|
+
post_install_message:
|
154
|
+
rdoc_options: []
|
155
|
+
require_paths:
|
156
|
+
- lib
|
157
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
158
|
+
requirements:
|
159
|
+
- - ">="
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '3.2'
|
162
|
+
- - "<"
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: 3.5.dev
|
165
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
166
|
+
requirements:
|
167
|
+
- - ">="
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
version: 3.3.11
|
170
|
+
- - ">="
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: 3.3.22
|
173
|
+
requirements: []
|
174
|
+
rubygems_version: 3.5.23
|
175
|
+
signing_key:
|
176
|
+
specification_version: 4
|
177
|
+
summary: Lightning fast codeowners-rs ruby wrapper
|
178
|
+
test_files: []
|