Skip to content
This repository has been archived by the owner on Sep 29, 2023. It is now read-only.

Commit

Permalink
Add options for fixing unrecognized lines and updating patterns (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
ekadlecova authored Feb 22, 2019
1 parent 6b73132 commit 232b932
Show file tree
Hide file tree
Showing 19 changed files with 306 additions and 221 deletions.
22 changes: 15 additions & 7 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,27 +1,33 @@
PATH
remote: .
specs:
code-ownership-checker (0.1.0)
fuzzy_match
git
thor
codeowners-checker (0.1.0)
fuzzy_match (~> 2.1)
git (~> 1.5)
thor (~> 0.20.3)

GEM
remote: https://rubygems.org/
specs:
ast (2.4.0)
coderay (1.1.2)
diff-lcs (1.3)
docile (1.3.0)
fuzzy_match (2.1.0)
git (1.5.0)
jaro_winkler (1.5.1)
method_source (0.9.2)
json (2.1.0)
parallel (1.12.1)
parser (2.5.3.0)
ast (~> 2.4.0)
powerpack (0.1.2)
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
rainbow (3.0.0)
rake (10.5.0)
rb-readline (0.5.5)
rspec (3.8.0)
rspec-core (~> 3.8.0)
rspec-expectations (~> 3.8.0)
Expand Down Expand Up @@ -59,11 +65,13 @@ PLATFORMS

DEPENDENCIES
bundler (~> 1.16)
code-ownership-checker!
codeowners-checker!
pry (~> 0.12.2)
rake (~> 10.0)
rb-readline (~> 0.5.5)
rspec (~> 3.0)
rubocop
rubocop-rspec
rubocop (~> 0.61.1)
rubocop-rspec (~> 1.30)
simplecov

BUNDLED WITH
Expand Down
12 changes: 7 additions & 5 deletions codeowners-checker.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ Gem::Specification.new do |spec|
spec.executables = ['codeowners-checker']
spec.require_paths = ['lib']

spec.add_dependency 'fuzzy_match'
spec.add_dependency 'git'
spec.add_dependency 'thor'
spec.add_dependency 'fuzzy_match', '~> 2.1'
spec.add_dependency 'git', '~> 1.5'
spec.add_dependency 'thor', '~> 0.20.3'
spec.add_development_dependency 'bundler', '~> 1.16'
spec.add_development_dependency 'simplecov'
spec.add_development_dependency 'rake', '~> 10.0'
spec.add_development_dependency 'rspec', '~> 3.0'
spec.add_development_dependency 'rubocop'
spec.add_development_dependency 'rubocop-rspec'
spec.add_development_dependency 'rubocop', '~> 0.61.1'
spec.add_development_dependency 'rubocop-rspec', '~> 1.30'
spec.add_development_dependency 'pry', '~> 0.12.2'
spec.add_development_dependency 'rb-readline', '~> 0.5.5'
end
29 changes: 18 additions & 11 deletions lib/codeowners/checker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,13 @@

require_relative 'checker/code_owners'
require_relative 'checker/file_as_array'
require_relative 'checker/group'

module Codeowners
# Check if code owners are consistent between a git repository and the CODEOWNERS file.
# It compares what's being changed in the PR and check if the current files and folders
# are also being declared in the CODEOWNERS file.
class Checker
# Check some repo from a reference to another
def self.check!(repo, from, to)
new(repo, from, to).check!
end

attr_accessor :when_useless_pattern, :when_new_file

# Get repo metadata and compare with the owners
Expand All @@ -26,6 +22,10 @@ def initialize(repo, from, to)
@to = to
end

def transformers
@transformers ||= []
end

def changes_to_analyze
@git.diff(@from, @to).name_status
end
Expand All @@ -47,7 +47,7 @@ def changes_for_patterns(patterns)

def patterns_by_owner
@patterns_by_owner ||=
codeowners.list.each_with_object(hash_of_arrays) do |line, patterns_by_owner|
codeowners.each_with_object(hash_of_arrays) do |line, patterns_by_owner|
next unless line.pattern?

line.owners.each { |owner| patterns_by_owner[owner] << line.pattern }
Expand All @@ -67,7 +67,7 @@ def changes_with_ownership(owner = '')
end

def useless_pattern
codeowners.list.select do |line|
codeowners.select do |line|
next unless line.pattern?

unless pattern_has_files(line.pattern)
Expand All @@ -86,7 +86,7 @@ def pattern_has_files(pattern)
end

def defined_owner?(file)
codeowners.list.find do |line|
codeowners.find do |line|
next unless line.pattern?

return true if file == line.pattern
Expand All @@ -97,15 +97,22 @@ def defined_owner?(file)
end

def codeowners
@codeowners ||= CodeOwners.new(FileAsArray.new(codeowners_file))
@codeowners ||= CodeOwners.new(
FileAsArray.new(codeowners_filename),
transformers: transformers
)
end

def main_group
codeowners.main_group
end

def codeowners_file
def codeowners_filename
File.join(@repo_dir, '.github', 'CODEOWNERS')
end

def commit_changes!
@git.add(codeowners_file)
@git.add(codeowners_filename)
@git.commit('Fix pattern :robot:')
end
end
Expand Down
15 changes: 15 additions & 0 deletions lib/codeowners/checker/array.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

module Codeowners
class Checker
# Array.delete in contrary to Ruby documentation uses == instead of equal? for comparison.
# safe_delete removes an object from an array comparing objects by equal? method.
module Array
def safe_delete(object)
delete_at(index { |item| item.equal?(object) })
end
end
end
end

Array.prepend(Codeowners::Checker::Array)
42 changes: 31 additions & 11 deletions lib/codeowners/checker/code_owners.rb
Original file line number Diff line number Diff line change
@@ -1,33 +1,53 @@
# frozen_string_literal: true

require_relative 'group'
require_relative 'array'

module Codeowners
class Checker
# Manage CODEOWNERS file reading and re-writing.
class CodeOwners
attr_reader :list, :main_group, :file_manager
include Enumerable

def initialize(file_manager)
attr_reader :file_manager, :transform_line_procs

def initialize(file_manager, transformers: nil)
@file_manager = file_manager
parse_file
@main_group = Group.parse(@list)
@transform_line_procs = [
method(:build_line),
*transformers
]
end

def persist!
file_manager.content = main_group.to_content
file_manager.content = to_content
end

def main_group
@main_group ||= Group.parse(list)
end

def remove(content)
@list.delete(content)
def each(&block)
main_group.each(&block)
end

def to_content
main_group.to_content
end

private

def parse_file
@list = @file_manager.content.map(&Codeowners::Checker::Group::Line.method(:build))
@list.each { |line| line.parents << self }
# TODO: ask the user to fix unrecognized lines?
def list
@list ||= @file_manager.content.yield_self do |list|
transform_line_procs.each do |transform_line_proc|
list = list.flat_map { |line| transform_line_proc.call(line) }.compact
end
list
end
end

def build_line(line)
Codeowners::Checker::Group::Line.build(line)
end
end
end
Expand Down
74 changes: 49 additions & 25 deletions lib/codeowners/checker/group.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
# frozen_string_literal: true

require_relative 'line_grouper'
require_relative 'parentable'
require_relative 'group/line'
require_relative 'array'

module Codeowners
class Checker
# Manage the groups content and handle operations on the groups.
class Group
include Parentable
include Enumerable

attr_accessor :parent

def self.parse(lines)
new.parse(lines)
Expand All @@ -18,6 +20,16 @@ def initialize
@list = []
end

def each(&block)
@list.each do |object|
if object.is_a?(self.class)
object.each(&block)
else
block.call(object)
end
end
end

def parse(lines)
LineGrouper.call(self, lines)
end
Expand Down Expand Up @@ -46,10 +58,10 @@ def owner
owners.first
end

# Owners are ordered by the amount of occurences
# Owners are ordered by the amount of occurrences
def owners
all_owners.group_by(&:itself).sort_by do |_owner, occurences|
-occurences.count
all_owners.group_by(&:itself).sort_by do |_owner, occurrences|
-occurrences.count
end.map(&:first)
end

Expand All @@ -68,30 +80,36 @@ def title
@list.first.to_s
end

def add(content)
content.parents << self
@list << content
def create_subgroup
group = self.class.new
@list << group
group
end

def insert(pattern)
index = new_line_index(pattern)
def add(line)
line.parent = self
@list << line
end

pattern.parents << self
@list.insert(index, pattern)
def insert(line)
line.parent = self
index = insert_at_index(line)
@list.insert(index, line)
end

def remove(content)
@list.delete(content)
def remove(line)
@list.safe_delete(line)
remove! unless @list.any?(Pattern)
end

def remove!
@list.each(&:remove!)
super
parent&.remove(self)
self.parent = nil
end

def ==(other)
other.is_a?(Group) && other.list == list
other.kind_of?(Group) && other.list == list
end

protected
Expand All @@ -101,22 +119,28 @@ def ==(other)
private

def all_owners
@list.flat_map do |item|
item.owners if item.respond_to?(:owners)
flat_map do |item|
item.owners if item.pattern?
end.compact
end

def new_line_index(pattern)
def insert_at_index(line)
patterns = @list.grep(Pattern)
new_patterns_sorted = patterns.dup.push(pattern).sort
new_pattern_index = new_patterns_sorted.index(pattern)
new_patterns_sorted = patterns.dup.push(line).sort
new_pattern_index = new_patterns_sorted.index { |l| l.equal? line }

if new_pattern_index > 0
previous_line = new_patterns_sorted[new_pattern_index - 1]
@list.index(previous_line) + 1
if new_pattern_index > 0 # rubocop:disable Style/NumericPredicate
new_pattern_index + 1
else
@list.index { |item| !item.is_a?(Comment) } || 0
find_last_line_of_initial_comments
end
end

def find_last_line_of_initial_comments
@list.each_with_index do |item, index|
return index unless item.is_a?(Comment)
end
0
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/codeowners/checker/group/empty.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

require_relative 'line'

module Codeowners
class Checker
class Group
Expand Down
1 change: 1 addition & 0 deletions lib/codeowners/checker/group/group_begin_comment.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require_relative 'comment'

module Codeowners
class Checker
class Group
Expand Down
Loading

0 comments on commit 232b932

Please sign in to comment.