fast_code_owners 0.0.4-aarch64-linux

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: dd2a151dee09ed1520cfdeac28e2ffbe2c3b9e4b115c2066f558992578396794
4
+ data.tar.gz: 4866ce308fb8dfed9ebeb57adfd774f9c37c287afb2615c100b573971e429010
5
+ SHA512:
6
+ metadata.gz: 9c64e5ebcd91a8155585803f1aec42b069604f93d6219ea46c6bd862237e8c49500b68ac1f92fef5452c5cd1f146dd1dcdd38953b7950d9240a7d18952ce332b
7
+ data.tar.gz: e651373f0793129ab8a37c54f827d5b1cf0a71f0f913ef59697fdd324b3a3caac2fe18c98ee31facae74af02f5631268166e0069ad25ae446cea5aca5b128902
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.
@@ -0,0 +1,10 @@
1
+ owned_globs:
2
+ - "**/*.{rb,tsx}"
3
+ ruby_package_paths:
4
+ - ruby/packages/**/*
5
+ javascript_package_paths:
6
+ - javascript/packages/**
7
+ team_file_glob:
8
+ - config/teams/**/*.yml
9
+ vendored_gems_path: gems
10
+ unowned_globs:
@@ -0,0 +1,5 @@
1
+ name: Bar
2
+ github:
3
+ team: '@BarTeam'
4
+ owned_globs:
5
+ - ruby/app/bar/**/*
@@ -0,0 +1,5 @@
1
+ name: Foo
2
+ github:
3
+ team: '@FooTeam'
4
+ owned_globs:
5
+ - ruby/app/foo/**/*
@@ -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,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FastCodeOwners
4
+ VERSION = '0.0.4'
5
+ 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,175 @@
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
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
+ requirements: []
171
+ rubygems_version: 3.5.23
172
+ signing_key:
173
+ specification_version: 4
174
+ summary: Lightning fast codeowners-rs ruby wrapper
175
+ test_files: []