-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #98 from DataDog/anmarchenko/codeowners
[CIVIS-3035] CODEOWNERS support for test visibility
- Loading branch information
Showing
27 changed files
with
631 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* @DataDog/ruby-guild @DataDog/ci-app-libraries |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
# frozen_string_literal: true | ||
|
||
require_relative "rule" | ||
|
||
module Datadog | ||
module CI | ||
module Codeowners | ||
# Responsible for matching a test source file path to a list of owners | ||
class Matcher | ||
def initialize(codeowners_file_path) | ||
@rules = parse(codeowners_file_path) | ||
@rules.reverse! | ||
end | ||
|
||
def list_owners(file_path) | ||
# treat all file paths that we check as absolute from the repository root | ||
file_path = "/#{file_path}" unless file_path.start_with?("/") | ||
|
||
Datadog.logger.debug { "Matching file path #{file_path} to CODEOWNERS rules" } | ||
|
||
@rules.each do |rule| | ||
if rule.match?(file_path) | ||
Datadog.logger.debug { "Matched rule [#{rule.pattern}] with owners #{rule.owners}" } | ||
return rule.owners | ||
end | ||
end | ||
|
||
Datadog.logger.debug { "CODEOWNERS rule not matched" } | ||
nil | ||
end | ||
|
||
private | ||
|
||
def parse(codeowners_file_path) | ||
unless File.exist?(codeowners_file_path) | ||
Datadog.logger.debug { "CODEOWNERS file not found at #{codeowners_file_path}" } | ||
return [] | ||
end | ||
|
||
result = [] | ||
section_default_owners = [] | ||
|
||
File.open(codeowners_file_path, "r") do |f| | ||
f.each_line do |line| | ||
line.strip! | ||
|
||
next if line.empty? | ||
next if comment?(line) | ||
|
||
pattern, *line_owners = line.strip.split(/\s+/) | ||
next if pattern.nil? || pattern.empty? | ||
|
||
# if the current line starts with section record the default owners for this section | ||
if section?(pattern) | ||
section_default_owners = line_owners | ||
next | ||
end | ||
|
||
pattern = expand_pattern(pattern) | ||
# if the current line doesn't have any owners then use the default owners for this section | ||
if line_owners.empty? && !section_default_owners.empty? | ||
line_owners = section_default_owners | ||
end | ||
|
||
result << Rule.new(pattern, line_owners) | ||
end | ||
end | ||
|
||
result | ||
rescue => e | ||
Datadog.logger.warn( | ||
"Failed to parse codeowners file at #{codeowners_file_path}: " \ | ||
"#{e.class.name} #{e.message} at #{Array(e.backtrace).first}" | ||
) | ||
[] | ||
end | ||
|
||
def comment?(line) | ||
line.start_with?("#") | ||
end | ||
|
||
def section?(line) | ||
line.start_with?("[", "^[") && line.end_with?("]") | ||
end | ||
|
||
def expand_pattern(pattern) | ||
return pattern if pattern == "*" | ||
|
||
# if pattern ends with a slash then it matches everything deeply nested in this directory | ||
pattern += "**" if pattern.end_with?(::File::SEPARATOR) | ||
|
||
# if pattern doesn't start with a slash then it matches anywhere in the repository | ||
if !pattern.start_with?(::File::SEPARATOR, "**#{::File::SEPARATOR}", "*#{::File::SEPARATOR}") | ||
pattern = "**#{::File::SEPARATOR}#{pattern}" | ||
end | ||
|
||
pattern | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# frozen_string_literal: true | ||
|
||
require_relative "matcher" | ||
|
||
module Datadog | ||
module CI | ||
module Codeowners | ||
# Responsible for parsing a CODEOWNERS file | ||
class Parser | ||
DEFAULT_LOCATION = "CODEOWNERS" | ||
POSSIBLE_CODEOWNERS_LOCATIONS = [ | ||
"CODEOWNERS", | ||
".github/CODEOWNERS", | ||
".gitlab/CODEOWNERS", | ||
"docs/CODEOWNERS" | ||
].freeze | ||
|
||
def initialize(root_file_path) | ||
@root_file_path = root_file_path || Dir.pwd | ||
end | ||
|
||
def parse | ||
default_path = File.join(@root_file_path, DEFAULT_LOCATION) | ||
# We are using the first codeowners file that we find or | ||
# default location if nothing is found | ||
# | ||
# Matcher handles it internally and creates a class with | ||
# an empty list of rules if the file is not found | ||
codeowners_file_path = POSSIBLE_CODEOWNERS_LOCATIONS.map do |codeowners_location| | ||
File.join(@root_file_path, codeowners_location) | ||
end.find do |path| | ||
File.exist?(path) | ||
end || default_path | ||
|
||
::Datadog.logger.debug { "Using CODEOWNERS file from: #{codeowners_file_path}" } | ||
|
||
Matcher.new(codeowners_file_path) | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
module Datadog | ||
module CI | ||
module Codeowners | ||
class Rule | ||
attr_reader :pattern, :owners | ||
|
||
def initialize(pattern, owners) | ||
@pattern = pattern | ||
@owners = owners | ||
end | ||
|
||
def match?(file_path) | ||
res = false | ||
# if pattern does not end with a separator or a wildcard, it could be either a directory or a file | ||
if !pattern.end_with?(::File::SEPARATOR, "*") | ||
directory_pattern = "#{pattern}#{::File::SEPARATOR}*" | ||
res ||= File.fnmatch?(directory_pattern, file_path, flags) | ||
end | ||
|
||
res ||= File.fnmatch?(pattern, file_path, flags) | ||
res | ||
end | ||
|
||
private | ||
|
||
def flags | ||
return ::File::FNM_PATHNAME if pattern.end_with?("#{::File::SEPARATOR}*") | ||
0 | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
module Datadog | ||
module CI | ||
module Codeowners | ||
class Matcher | ||
@rules: Array[Rule] | ||
|
||
def initialize: (String codeowners_file_path) -> void | ||
|
||
def list_owners: (String file_path) -> Array[String]? | ||
|
||
private | ||
|
||
def parse: (String file_path) -> Array[Rule] | ||
|
||
def comment?: (String line) -> bool | ||
|
||
def section?: (String line) -> bool | ||
|
||
def expand_pattern: (String pattern) -> String | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
module Datadog | ||
module CI | ||
module Codeowners | ||
class Parser | ||
@root_file_path: String | ||
|
||
DEFAULT_LOCATION: "CODEOWNERS" | ||
|
||
POSSIBLE_CODEOWNERS_LOCATIONS: ::Array["CODEOWNERS" | ".github/CODEOWNERS" | ".gitlab/CODEOWNERS" | "docs/CODEOWNERS"] | ||
|
||
def initialize: (String? root_file_path) -> void | ||
|
||
def parse: () -> Datadog::CI::Codeowners::Matcher | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
module Datadog | ||
module CI | ||
module Codeowners | ||
class Rule | ||
@pattern: String | ||
|
||
@owners: Array[String] | ||
|
||
attr_reader pattern: String | ||
|
||
attr_reader owners: Array[String] | ||
|
||
def initialize: (String pattern, Array[String] owners) -> void | ||
|
||
def match?: (String file_path) -> untyped | ||
|
||
private | ||
|
||
def flags: () -> Integer | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.