@@ -15,6 +15,7 @@ pub struct Config<'a> {
1515 pub force_detach : bool ,
1616 pub base : Option < & ' a str > ,
1717 pub and_rebase : bool ,
18+ pub rebase_options : & ' a Vec < & ' a str > ,
1819 pub whole_file : bool ,
1920 pub one_fixup_per_commit : bool ,
2021}
@@ -27,6 +28,12 @@ pub fn run(logger: &slog::Logger, config: &Config) -> Result<()> {
2728}
2829
2930fn run_with_repo ( logger : & slog:: Logger , config : & Config , repo : & git2:: Repository ) -> Result < ( ) > {
31+ if !config. rebase_options . is_empty ( ) && !config. and_rebase {
32+ return Err ( anyhow ! (
33+ "REBASE_OPTIONS were specified without --and-rebase flag"
34+ ) ) ;
35+ }
36+
3037 let config = config:: unify ( & config, repo) ;
3138 let stack = stack:: working_stack (
3239 repo,
@@ -367,6 +374,10 @@ fn run_with_repo(logger: &slog::Logger, config: &Config, repo: &git2::Repository
367374 let mut command = Command :: new ( "git" ) ;
368375 command. args ( [ "rebase" , "--interactive" , "--autosquash" , "--autostash" ] ) ;
369376
377+ for arg in config. rebase_options {
378+ command. arg ( arg) ;
379+ }
380+
370381 if number_of_parents == 0 {
371382 command. arg ( "--root" ) ;
372383 } else {
@@ -480,6 +491,7 @@ fn index_stats(repo: &git2::Repository) -> Result<git2::DiffStats> {
480491
481492#[ cfg( test) ]
482493mod tests {
494+ use git2:: message_trailers_strs;
483495 use std:: path:: PathBuf ;
484496
485497 use super :: * ;
@@ -525,7 +537,7 @@ mod tests {
525537 fn foreign_author ( ) {
526538 let ctx = repo_utils:: prepare_and_stage ( ) ;
527539
528- repo_utils:: become_new_author ( & ctx. repo ) ;
540+ repo_utils:: become_author ( & ctx. repo , "nobody2" , "nobody2@example.com" ) ;
529541
530542 // run 'git-absorb'
531543 let drain = slog:: Discard ;
@@ -543,7 +555,7 @@ mod tests {
543555 fn foreign_author_with_force_author_flag ( ) {
544556 let ctx = repo_utils:: prepare_and_stage ( ) ;
545557
546- repo_utils:: become_new_author ( & ctx. repo ) ;
558+ repo_utils:: become_author ( & ctx. repo , "nobody2" , "nobody2@example.com" ) ;
547559
548560 // run 'git-absorb'
549561 let drain = slog:: Discard ;
@@ -565,7 +577,7 @@ mod tests {
565577 fn foreign_author_with_force_author_config ( ) {
566578 let ctx = repo_utils:: prepare_and_stage ( ) ;
567579
568- repo_utils:: become_new_author ( & ctx. repo ) ;
580+ repo_utils:: become_author ( & ctx. repo , "nobody2" , "nobody2@example.com" ) ;
569581
570582 repo_utils:: set_config_flag ( & ctx. repo , "absorb.forceAuthor" ) ;
571583
@@ -663,6 +675,92 @@ mod tests {
663675 assert ! ( nothing_left_in_index( & ctx. repo) . unwrap( ) ) ;
664676 }
665677
678+ #[ test]
679+ fn and_rebase_flag ( ) {
680+ let ctx = repo_utils:: prepare_and_stage ( ) ;
681+ repo_utils:: set_config_option ( & ctx. repo , "core.editor" , "true" ) ;
682+
683+ // run 'git-absorb'
684+ let drain = slog:: Discard ;
685+ let logger = slog:: Logger :: root ( drain, o ! ( ) ) ;
686+ let config = Config {
687+ and_rebase : true ,
688+ ..DEFAULT_CONFIG
689+ } ;
690+ repo_utils:: run_in_repo ( & ctx, || run_with_repo ( & logger, & config, & ctx. repo ) ) . unwrap ( ) ;
691+
692+ let mut revwalk = ctx. repo . revwalk ( ) . unwrap ( ) ;
693+ revwalk. push_head ( ) . unwrap ( ) ;
694+
695+ assert_eq ! ( revwalk. count( ) , 1 ) ;
696+ assert ! ( nothing_left_in_index( & ctx. repo) . unwrap( ) ) ;
697+ }
698+
699+ #[ test]
700+ fn and_rebase_flag_with_rebase_options ( ) {
701+ let ctx = repo_utils:: prepare_and_stage ( ) ;
702+ repo_utils:: set_config_option ( & ctx. repo , "core.editor" , "true" ) ;
703+
704+ // run 'git-absorb'
705+ let drain = slog:: Discard ;
706+ let logger = slog:: Logger :: root ( drain, o ! ( ) ) ;
707+ let config = Config {
708+ and_rebase : true ,
709+ rebase_options : & vec ! [ "--signoff" ] ,
710+ ..DEFAULT_CONFIG
711+ } ;
712+ repo_utils:: run_in_repo ( & ctx, || run_with_repo ( & logger, & config, & ctx. repo ) ) . unwrap ( ) ;
713+
714+ let mut revwalk = ctx. repo . revwalk ( ) . unwrap ( ) ;
715+ revwalk. push_head ( ) . unwrap ( ) ;
716+ assert_eq ! ( revwalk. count( ) , 1 ) ;
717+
718+ let trailers = message_trailers_strs (
719+ ctx. repo
720+ . head ( )
721+ . unwrap ( )
722+ . peel_to_commit ( )
723+ . unwrap ( )
724+ . message ( )
725+ . unwrap ( ) ,
726+ )
727+ . unwrap ( ) ;
728+ assert_eq ! (
729+ trailers
730+ . iter( )
731+ . filter( |trailer| trailer. 0 == "Signed-off-by" )
732+ . count( ) ,
733+ 1
734+ ) ;
735+
736+ assert ! ( nothing_left_in_index( & ctx. repo) . unwrap( ) ) ;
737+ }
738+
739+ #[ test]
740+ fn rebase_options_without_and_rebase_flag ( ) {
741+ let ctx = repo_utils:: prepare_and_stage ( ) ;
742+
743+ // run 'git-absorb'
744+ let drain = slog:: Discard ;
745+ let logger = slog:: Logger :: root ( drain, o ! ( ) ) ;
746+ let config = Config {
747+ rebase_options : & vec ! [ "--some-option" ] ,
748+ ..DEFAULT_CONFIG
749+ } ;
750+ let result = run_with_repo ( & logger, & config, & ctx. repo ) ;
751+
752+ assert_eq ! (
753+ result. err( ) . unwrap( ) . to_string( ) ,
754+ "REBASE_OPTIONS were specified without --and-rebase flag"
755+ ) ;
756+
757+ let mut revwalk = ctx. repo . revwalk ( ) . unwrap ( ) ;
758+ revwalk. push_head ( ) . unwrap ( ) ;
759+ assert_eq ! ( revwalk. count( ) , 1 ) ;
760+ let is_something_in_index = !nothing_left_in_index ( & ctx. repo ) . unwrap ( ) ;
761+ assert ! ( is_something_in_index) ;
762+ }
763+
666764 fn autostage_common ( ctx : & repo_utils:: Context , file_path : & PathBuf ) -> ( PathBuf , PathBuf ) {
667765 // 1 modification w/o staging
668766 let path = ctx. join ( & file_path) ;
@@ -788,6 +886,7 @@ mod tests {
788886 force_detach : false ,
789887 base : None ,
790888 and_rebase : false ,
889+ rebase_options : & Vec :: new ( ) ,
791890 whole_file : false ,
792891 one_fixup_per_commit : false ,
793892 } ;
0 commit comments