@@ -13,6 +13,7 @@ struct DodConfig {
1313 checklist : Vec < String > ,
1414}
1515
16+ /// Reads the DoD configuration from `.dod.yml` file in the current directory (root of the git repository).
1617fn read_dod_config ( ) -> Result < DodConfig > {
1718 let content = fs:: read_to_string ( ".dod.yml" )
1819 . context ( "Failed to read .dod.yml" ) ?;
@@ -21,6 +22,7 @@ fn read_dod_config() -> Result<DodConfig> {
2122 Ok ( config)
2223}
2324
25+ /// Runs the checklist interactively, allowing the user to confirm each item before committing.
2426fn run_checklist_interactive ( checklist : & [ String ] ) -> anyhow:: Result < Vec < usize > > {
2527 let selections = MultiSelect :: with_theme ( & ColorfulTheme :: default ( ) )
2628 . with_prompt ( "Please confirm each item before committing:" )
@@ -29,6 +31,7 @@ fn run_checklist_interactive(checklist: &[String]) -> anyhow::Result<Vec<usize>>
2931 Ok ( selections)
3032}
3133
34+ /// Builds the TODO footer for the commit message based on unchecked items in the checklist.
3235fn build_todo_footer ( checklist : & [ String ] , checked_indices : & [ usize ] ) -> String {
3336 //let checked_indices: Vec<usize> = checked_indices.iter().cloned().collect();
3437 let unchecked_items: Vec < String > = checklist
@@ -45,6 +48,40 @@ fn build_todo_footer(checklist: &[String], checked_indices: &[usize]) -> String
4548 }
4649}
4750
51+ /// Handles the interactive commit process, including checklist confirmation and issue reference handling.
52+ fn handle_interactive_commit (
53+ config : & DodConfig ,
54+ base_message : & str ,
55+ issue : & Option < String > ,
56+ ) -> Result < Option < String > > {
57+ let mut commit_message = base_message. to_string ( ) ;
58+ if let Some ( issue_ref) = issue {
59+ commit_message = format ! ( "{} {}" , issue_ref, commit_message) ;
60+ }
61+
62+ let checked = run_checklist_interactive ( & config. checklist ) ?;
63+ if checked. len ( ) != config. checklist . len ( ) {
64+ if Confirm :: with_theme ( & ColorfulTheme :: default ( ) )
65+ . with_prompt ( "Warning: Not all DoD items were checked. Proceed by adding a 'TODO' list to the commit message?" )
66+ . interact ( ) ?
67+ {
68+ let todo_footer = build_todo_footer ( & config. checklist , & checked) ;
69+ commit_message. push_str ( & todo_footer) ;
70+ } else {
71+ println ! ( "Commit aborted." ) ;
72+ return Ok ( None ) ;
73+ }
74+ }
75+
76+ if config. issue_reference_required . unwrap_or ( false ) && issue. is_none ( ) {
77+ println ! ( "{}" , "Issue reference is required for commits." . red( ) ) ;
78+ return Err ( anyhow:: anyhow!( "Aborted: Issue reference required." ) ) ;
79+ }
80+
81+ Ok ( Some ( commit_message) )
82+ }
83+
84+ /// Main function that parses command line arguments and executes the appropriate git operations.
4885fn main ( ) -> anyhow:: Result < ( ) > {
4986 let cli = cli:: Cli :: parse ( ) ;
5087 let config = read_dod_config ( ) ?;
@@ -62,38 +99,25 @@ fn main() -> anyhow::Result<()> {
6299 println ! ( "--- Committing changes ---" ) ;
63100 let scope_part = scope. map_or ( "" . to_string ( ) , |s| format ! ( "({})" , s) ) ;
64101 let header = format ! ( "{}{}: {}" , r#type, scope_part, message) ;
65- let mut commit_message = format ! ( "{}" , header) ;
66- if let Some ( issue_ref) = & issue {
67- commit_message = format ! ( "{} {}" , issue_ref, commit_message) ;
68- }
69102
70- if !no_verify {
71- let checked = run_checklist_interactive ( & config. checklist ) ?;
72- if checked. len ( ) != config. checklist . len ( ) {
73- if Confirm :: with_theme ( & ColorfulTheme :: default ( ) )
74- . with_prompt ( "Warning: Not all DoD items were checked. Proceed by adding a 'TODO' list to the commit message? (Y/n)" )
75- . interact ( ) ?
76- {
77- let todo_footer = build_todo_footer ( & config. checklist , & checked) ;
78- commit_message. push_str ( & todo_footer) ;
79- } else {
80- println ! ( "Commit aborted." ) ;
81- return Ok ( ( ) ) ;
82- }
103+ let final_commit_message = if no_verify {
104+ let mut msg = header;
105+ if let Some ( issue_ref) = & issue {
106+ msg = format ! ( "{} {}" , issue_ref, msg) ;
83107 }
84- if config. issue_reference_required . unwrap_or ( false ) && issue. is_none ( ) {
85- println ! ( "{}" , "Issue reference is required for commits." . red( ) ) ;
86- return Err ( anyhow:: anyhow!( "Issue reference required" ) ) ;
87- }
88- }
108+ Some ( msg)
109+ } else {
110+ handle_interactive_commit ( & config, & header, & issue) ?
111+ } ;
89112
90- println ! ( "{}" , format!( "Commit message will be:\n ---\n {}\n ---" , commit_message) . blue( ) ) ;
91- // Stage changes first, before any other operations.
92- git:: add_all ( ) ?;
93- git:: pull_latest_with_rebase ( ) ?;
94- git:: commit ( & commit_message) ?;
95- git:: push ( ) ?;
96- println ! ( "{}" , "Successfully committed and pushed changes." . green( ) ) ;
113+ if let Some ( commit_message) = final_commit_message {
114+ println ! ( "{}" , format!( "Commit message will be:\n ---\n {}\n ---" , commit_message) . blue( ) ) ;
115+ git:: add_all ( ) ?;
116+ git:: pull_latest_with_rebase ( ) ?;
117+ git:: commit ( & commit_message) ?;
118+ git:: push ( ) ?;
119+ println ! ( "{}" , "Successfully committed and pushed changes." . green( ) ) ;
120+ }
97121 }
98122 }
99123 Ok ( ( ) )
0 commit comments