diff --git a/lib/code_ownership/private/ownership_mappers/file_annotations.rb b/lib/code_ownership/private/ownership_mappers/file_annotations.rb index 4debcf3..657f455 100644 --- a/lib/code_ownership/private/ownership_mappers/file_annotations.rb +++ b/lib/code_ownership/private/ownership_mappers/file_annotations.rb @@ -73,19 +73,20 @@ def update_cache(cache, files) sig { params(filename: String).returns(T.nilable(CodeTeams::Team)) } def file_annotation_based_owner(filename) - # If for a directory is named with an ownable extension, we need to skip - # so File.foreach doesn't blow up below. This was needed because Cypress - # screenshots are saved to a folder with the test suite filename. - return if File.directory?(filename) - return unless File.file?(filename) - # The annotation should be on line 1 but as of this comment # there's no linter installed to enforce that. We therefore check the # first line (the Ruby VM makes a single `read(1)` call for 8KB), # and if the annotation isn't in the first two lines we assume it # doesn't exist. - line1 = File.foreach(filename).first + begin + line1 = File.foreach(filename).first + rescue Errno::EISDIR, Errno::ENOENT + # Ignore files that fail to read to avoid intermittent bugs. + # Ignoring directories is needed because, e.g., Cypress screenshots + # are saved to a folder with the test suite filename. + return + end return if !line1 diff --git a/spec/lib/code_ownership/private/ownership_mappers/file_annotations_spec.rb b/spec/lib/code_ownership/private/ownership_mappers/file_annotations_spec.rb index 2188b87..0fc17c9 100644 --- a/spec/lib/code_ownership/private/ownership_mappers/file_annotations_spec.rb +++ b/spec/lib/code_ownership/private/ownership_mappers/file_annotations_spec.rb @@ -37,6 +37,28 @@ module CodeOwnership end describe '.for_file' do + context 'path is a directory' do + it 'returns nil' do + write_configuration + write_file('config/teams/bar.yml', <<~CONTENTS) + name: Bar + CONTENTS + + expect(CodeOwnership.for_file('config/teams')).to be_nil + end + end + + context 'path does not exist' do + it 'returns nil' do + write_configuration + write_file('config/teams/bar.yml', <<~CONTENTS) + name: Bar + CONTENTS + + expect(CodeOwnership.for_file('config/teams/foo.yml')).to be_nil + end + end + context 'ruby owned file' do before do write_configuration