lib/code_ownership.rb in code_ownership-1.29.2 vs lib/code_ownership.rb in code_ownership-1.29.3

- old
+ new

@@ -56,11 +56,10 @@ ownership_information << 'This team owns nothing in this category.' else ownership_information += ownership_for_mapper end - ownership_information << "" end ownership_information.join("\n") end @@ -91,12 +90,30 @@ # Given a backtrace from either `Exception#backtrace` or `caller`, find the # first line that corresponds to a file with assigned ownership sig { params(backtrace: T.nilable(T::Array[String]), excluded_teams: T::Array[::CodeTeams::Team]).returns(T.nilable(::CodeTeams::Team)) } def for_backtrace(backtrace, excluded_teams: []) - return unless backtrace + first_owned_file_for_backtrace(backtrace, excluded_teams: excluded_teams)&.first + end + # Given a backtrace from either `Exception#backtrace` or `caller`, find the + # first owned file in it, useful for figuring out which file is being blamed. + sig { params(backtrace: T.nilable(T::Array[String]), excluded_teams: T::Array[::CodeTeams::Team]).returns(T.nilable([::CodeTeams::Team, String])) } + def first_owned_file_for_backtrace(backtrace, excluded_teams: []) + backtrace_with_ownership(backtrace).each do |(team, file)| + if team && !excluded_teams.include?(team) + return [team, file] + end + end + + nil + end + + sig { params(backtrace: T.nilable(T::Array[String])).returns(T::Enumerable[[T.nilable(::CodeTeams::Team), String]]) } + def backtrace_with_ownership(backtrace) + return [] unless backtrace + # The pattern for a backtrace hasn't changed in forever and is considered # stable: https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L303-L317 # # This pattern matches a line like the following: # @@ -108,21 +125,22 @@ (?<line>\d+) # Matches '43' :in\s `(?<function>.*)' # Matches "`block (3 levels) in create'" \z}x - backtrace.each do |line| + backtrace.lazy.filter_map do |line| match = line.match(backtrace_line) + next unless match - if match - team = CodeOwnership.for_file(T.must(match[:file])) - if team && !excluded_teams.include?(team) - return team - end - end + file = T.must(match[:file]) + + [ + CodeOwnership.for_file(file), + file, + ] end - nil end + private_class_method(:backtrace_with_ownership) sig { params(klass: T.nilable(T.any(Class, Module))).returns(T.nilable(::CodeTeams::Team)) } def for_class(klass) @memoized_values ||= T.let(@memoized_values, T.nilable(T::Hash[String, T.nilable(::CodeTeams::Team)])) @memoized_values ||= {}