@@ -51,53 +51,74 @@ pub struct CodeownersEntryMatcher {
5151 pub override_matcher : Override ,
5252}
5353
54+ /// Error type for pattern matching failures
55+ #[ derive( Debug ) ]
56+ pub struct PatternError {
57+ pub pattern : String ,
58+ pub source_file : PathBuf ,
59+ pub message : String ,
60+ }
61+
62+ impl std:: fmt:: Display for PatternError {
63+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
64+ write ! (
65+ f,
66+ "Invalid pattern '{}' in {}: {}" ,
67+ self . pattern,
68+ self . source_file. display( ) ,
69+ self . message
70+ )
71+ }
72+ }
73+
74+ impl std:: error:: Error for PatternError { }
75+
76+ /// Converts a CodeownersEntry to a CodeownersEntryMatcher with pattern compilation.
77+ ///
78+ /// # Errors
79+ ///
80+ /// Returns a `PatternError` if:
81+ /// - The entry's source file has no parent directory
82+ /// - The pattern is invalid and cannot be compiled
83+ /// - The override matcher fails to build
5484#[ cfg( feature = "ignore" ) ]
55- pub fn codeowners_entry_to_matcher ( entry : & CodeownersEntry ) -> CodeownersEntryMatcher {
56- let codeowners_dir = match entry. source_file . parent ( ) {
57- Some ( dir) => dir,
58- None => {
59- eprintln ! (
60- "CODEOWNERS entry has no parent directory: {}" ,
61- entry. source_file. display( )
62- ) ;
63- panic ! ( "Invalid CODEOWNERS entry without parent directory" ) ;
64- }
65- } ;
85+ pub fn codeowners_entry_to_matcher (
86+ entry : & CodeownersEntry ,
87+ ) -> Result < CodeownersEntryMatcher , PatternError > {
88+ let codeowners_dir = entry. source_file . parent ( ) . ok_or_else ( || PatternError {
89+ pattern : entry. pattern . clone ( ) ,
90+ source_file : entry. source_file . clone ( ) ,
91+ message : "CODEOWNERS entry has no parent directory" . to_string ( ) ,
92+ } ) ?;
6693
6794 let mut builder = ignore:: overrides:: OverrideBuilder :: new ( codeowners_dir) ;
6895
6996 // Transform directory patterns to match GitHub CODEOWNERS behavior
7097 let pattern = normalize_codeowners_pattern ( & entry. pattern ) ;
7198
72- if let Err ( e) = builder. add ( & pattern) {
73- eprintln ! (
74- "Invalid pattern '{}' (normalized from '{}') in {}: {}" ,
75- pattern,
76- entry. pattern,
77- entry. source_file. display( ) ,
78- e
79- ) ;
80- panic ! ( "Invalid CODEOWNERS entry pattern" ) ;
81- }
82- let override_matcher: Override = match builder. build ( ) {
83- Ok ( o) => o,
84- Err ( e) => {
85- eprintln ! (
86- "Failed to build override for pattern '{}': {}" ,
87- entry. pattern, e
88- ) ;
89- panic ! ( "Failed to build CODEOWNERS entry matcher" ) ;
90- }
91- } ;
99+ builder. add ( & pattern) . map_err ( |e| PatternError {
100+ pattern : entry. pattern . clone ( ) ,
101+ source_file : entry. source_file . clone ( ) ,
102+ message : format ! (
103+ "Invalid pattern '{}' (normalized from '{}'): {}" ,
104+ pattern, entry. pattern, e
105+ ) ,
106+ } ) ?;
107+
108+ let override_matcher = builder. build ( ) . map_err ( |e| PatternError {
109+ pattern : entry. pattern . clone ( ) ,
110+ source_file : entry. source_file . clone ( ) ,
111+ message : format ! ( "Failed to build override matcher: {}" , e) ,
112+ } ) ?;
92113
93- CodeownersEntryMatcher {
114+ Ok ( CodeownersEntryMatcher {
94115 source_file : entry. source_file . clone ( ) ,
95116 line_number : entry. line_number ,
96117 pattern : entry. pattern . clone ( ) ,
97118 owners : entry. owners . clone ( ) ,
98119 tags : entry. tags . clone ( ) ,
99120 override_matcher,
100- }
121+ } )
101122}
102123
103124/// Detailed owner representation
@@ -355,7 +376,7 @@ mod tests {
355376 tags : vec ! [ ] ,
356377 } ;
357378
358- let matcher = codeowners_entry_to_matcher ( & entry) ;
379+ let matcher = codeowners_entry_to_matcher ( & entry) . unwrap ( ) ;
359380
360381 // Test files that should match
361382 let test_files = vec ! [
0 commit comments