1+ use std:: path:: PathBuf ;
12use std:: process:: Command ;
23
34use error_stack:: { Result , ResultExt } ;
@@ -20,6 +21,7 @@ pub struct Runner {
2021 ownership : Ownership ,
2122 cache : Cache ,
2223 config : Config ,
24+ codeowners_file_path : PathBuf ,
2325}
2426
2527pub fn version ( ) -> String {
@@ -55,9 +57,30 @@ pub(crate) fn config_from_run_config(run_config: &RunConfig) -> Result<Config, E
5557 Err ( msg) => Err ( error_stack:: Report :: new ( Error :: Io ( msg) ) ) ,
5658 }
5759}
60+
61+ /// Resolves the CODEOWNERS file path with the following priority:
62+ /// 1. Explicit `codeowners_file_path` in `RunConfig` (if provided from e.g. CLI flag)
63+ /// 2. `CODEOWNERS_PATH` environment variable (if set and not empty)
64+ /// 3. Computed from `codeowners_path` directory path in config + "CODEOWNERS" filename
65+ /// 4. Default fallback to `.github/CODEOWNERS` (using default codeowners_path from config)
66+ pub ( crate ) fn resolve_codeowners_file_path ( run_config : & RunConfig , config : & Config ) -> PathBuf {
67+ if let Some ( ref path) = run_config. codeowners_file_path {
68+ return path. clone ( ) ;
69+ }
70+
71+ if let Ok ( env_path) = std:: env:: var ( "CODEOWNERS_PATH" )
72+ && !env_path. is_empty ( )
73+ {
74+ return run_config. project_root . join ( env_path) ;
75+ }
76+
77+ run_config. project_root . join ( & config. codeowners_path ) . join ( "CODEOWNERS" )
78+ }
79+
5880impl Runner {
5981 pub fn new ( run_config : & RunConfig ) -> Result < Self , Error > {
6082 let config = config_from_run_config ( run_config) ?;
83+ let codeowners_file_path = resolve_codeowners_file_path ( run_config, & config) ;
6184
6285 let cache: Cache = if run_config. no_cache {
6386 NoopCache :: default ( ) . into ( )
@@ -71,12 +94,7 @@ impl Runner {
7194 . into ( )
7295 } ;
7396
74- let mut project_builder = ProjectBuilder :: new (
75- & config,
76- run_config. project_root . clone ( ) ,
77- run_config. codeowners_file_path . clone ( ) ,
78- & cache,
79- ) ;
97+ let mut project_builder = ProjectBuilder :: new ( & config, run_config. project_root . clone ( ) , codeowners_file_path. clone ( ) , & cache) ;
8098 let project = project_builder. build ( ) . change_context ( Error :: Io ( format ! (
8199 "Can't build project: {}" ,
82100 & run_config. config_path. to_string_lossy( )
@@ -93,6 +111,7 @@ impl Runner {
93111 ownership,
94112 cache,
95113 config,
114+ codeowners_file_path,
96115 } )
97116 }
98117
@@ -150,10 +169,10 @@ impl Runner {
150169
151170 pub fn generate ( & self , git_stage : bool ) -> RunResult {
152171 let content = self . ownership . generate_file ( ) ;
153- if let Some ( parent) = & self . run_config . codeowners_file_path . parent ( ) {
172+ if let Some ( parent) = & self . codeowners_file_path . parent ( ) {
154173 let _ = std:: fs:: create_dir_all ( parent) ;
155174 }
156- match std:: fs:: write ( & self . run_config . codeowners_file_path , content) {
175+ match std:: fs:: write ( & self . codeowners_file_path , content) {
157176 Ok ( _) => {
158177 if git_stage {
159178 self . git_stage ( ) ;
@@ -178,7 +197,7 @@ impl Runner {
178197 fn git_stage ( & self ) {
179198 let _ = Command :: new ( "git" )
180199 . arg ( "add" )
181- . arg ( & self . run_config . codeowners_file_path )
200+ . arg ( & self . codeowners_file_path )
182201 . current_dir ( & self . run_config . project_root )
183202 . output ( ) ;
184203 }
0 commit comments