@@ -317,10 +317,20 @@ remotes:
317317 t .Run (fmt .Sprintf ("%d: %s" , n , tt .name ), func (t * testing.T ) {
318318 assert := assert .New (t )
319319
320+ // Prepend git config commands required by getHooksPathConfig() in install.go.
321+ // These commands are always called at the start of Install() to detect core.hooksPath conflicts.
322+ gitCmds := tt .git
323+ if len (gitCmds ) == 0 || gitCmds [0 ].Command != "git config --local core.hooksPath" {
324+ gitCmds = append ([]cmdtest.Out {
325+ {Command : "git config --local core.hooksPath" },
326+ {Command : "git config --global core.hooksPath" },
327+ }, gitCmds ... )
328+ }
329+
320330 repo := gittest .NewRepositoryBuilder ().
321331 Root (root ).
322332 Fs (fs ).
323- Cmd (cmdtest .NewOrdered (t , tt . git )).
333+ Cmd (cmdtest .NewOrdered (t , gitCmds )).
324334 Build ()
325335 lefthook := & Lefthook {
326336 fs : fs ,
@@ -708,3 +718,183 @@ remotes:
708718 })
709719 }
710720}
721+
722+ func TestLefthookInstallWithCoreHooksPath (t * testing.T ) {
723+ root , err := filepath .Abs ("src" )
724+ assert .NoError (t , err )
725+
726+ configPath := filepath .Join (root , "lefthook.yml" )
727+
728+ hookPath := func (hook string ) string {
729+ return filepath .Join (gittest .GitPath (root ), "hooks" , hook )
730+ }
731+
732+ infoPath := func (file string ) string {
733+ return filepath .Join (gittest .GitPath (root ), "info" , file )
734+ }
735+
736+ configContent := `
737+ pre-commit:
738+ commands:
739+ tests:
740+ run: yarn test
741+ `
742+
743+ for n , tt := range [... ]struct {
744+ name string
745+ force bool
746+ resetHooksPath bool
747+ git []cmdtest.Out
748+ wantError bool
749+ wantErrorMsg string
750+ wantExist []string
751+ }{
752+ {
753+ name : "with local and global core.hooksPath without flags" ,
754+ force : false ,
755+ resetHooksPath : false ,
756+ git : []cmdtest.Out {
757+ {
758+ Command : "git config --local core.hooksPath" ,
759+ Output : ".custom-hooks" ,
760+ },
761+ {
762+ Command : "git config --global core.hooksPath" ,
763+ Output : "/usr/local/hooks" ,
764+ },
765+ },
766+ wantError : true ,
767+ wantErrorMsg : "core.hooksPath" ,
768+ },
769+ {
770+ name : "with local and global core.hooksPath with --force" ,
771+ force : true ,
772+ resetHooksPath : false ,
773+ git : []cmdtest.Out {
774+ {
775+ Command : "git config --local core.hooksPath" ,
776+ Output : ".custom-hooks" ,
777+ },
778+ {
779+ Command : "git config --global core.hooksPath" ,
780+ Output : "/usr/local/hooks" ,
781+ },
782+ },
783+ wantError : false ,
784+ wantExist : []string {
785+ configPath ,
786+ hookPath ("pre-commit" ),
787+ infoPath (config .ChecksumFileName ),
788+ },
789+ },
790+ {
791+ name : "with local and global core.hooksPath with --reset-hooks-path" ,
792+ force : false ,
793+ resetHooksPath : true ,
794+ git : []cmdtest.Out {
795+ {
796+ Command : "git config --local core.hooksPath" ,
797+ Output : ".custom-hooks" ,
798+ },
799+ {
800+ Command : "git config --global core.hooksPath" ,
801+ Output : "/usr/local/hooks" ,
802+ },
803+ {
804+ Command : "git config --local --unset-all core.hooksPath" ,
805+ },
806+ {
807+ Command : "git config --global --unset-all core.hooksPath" ,
808+ },
809+ },
810+ wantError : false ,
811+ wantExist : []string {
812+ configPath ,
813+ hookPath ("pre-commit" ),
814+ infoPath (config .ChecksumFileName ),
815+ },
816+ },
817+ {
818+ name : "with only global core.hooksPath with --force" ,
819+ force : true ,
820+ resetHooksPath : false ,
821+ git : []cmdtest.Out {
822+ {
823+ Command : "git config --local core.hooksPath" ,
824+ Output : "" ,
825+ },
826+ {
827+ Command : "git config --global core.hooksPath" ,
828+ Output : "/usr/local/hooks" ,
829+ },
830+ },
831+ wantError : false ,
832+ wantExist : []string {
833+ configPath ,
834+ hookPath ("pre-commit" ),
835+ infoPath (config .ChecksumFileName ),
836+ },
837+ },
838+ {
839+ name : "with only local core.hooksPath with --reset-hooks-path" ,
840+ force : false ,
841+ resetHooksPath : true ,
842+ git : []cmdtest.Out {
843+ {
844+ Command : "git config --local core.hooksPath" ,
845+ Output : ".custom-hooks" ,
846+ },
847+ {
848+ Command : "git config --global core.hooksPath" ,
849+ Output : "" ,
850+ },
851+ {
852+ Command : "git config --local --unset-all core.hooksPath" ,
853+ },
854+ },
855+ wantError : false ,
856+ wantExist : []string {
857+ configPath ,
858+ hookPath ("pre-commit" ),
859+ infoPath (config .ChecksumFileName ),
860+ },
861+ },
862+ } {
863+ fs := afero .NewMemMapFs ()
864+
865+ t .Run (fmt .Sprintf ("%d: %s" , n , tt .name ), func (t * testing.T ) {
866+ assert := assert .New (t )
867+
868+ repo := gittest .NewRepositoryBuilder ().
869+ Root (root ).
870+ Fs (fs ).
871+ Cmd (cmdtest .NewOrdered (t , tt .git )).
872+ Build ()
873+ lefthook := & Lefthook {
874+ fs : fs ,
875+ repo : repo ,
876+ }
877+
878+ // Create configuration file
879+ assert .NoError (afero .WriteFile (fs , configPath , []byte (configContent ), 0o644 ))
880+ timestamp := time .Date (2022 , time .June , 22 , 10 , 40 , 10 , 1 , time .UTC )
881+ assert .NoError (fs .Chtimes (configPath , timestamp , timestamp ))
882+
883+ // Do install
884+ err := lefthook .Install (t .Context (), InstallArgs {Force : tt .force , ResetHooksPath : tt .resetHooksPath }, nil )
885+ if tt .wantError {
886+ if assert .Error (err ) && tt .wantErrorMsg != "" {
887+ assert .Contains (err .Error (), tt .wantErrorMsg )
888+ }
889+ } else {
890+ assert .NoError (err )
891+ // Test files that should exist
892+ for _ , file := range tt .wantExist {
893+ ok , err := afero .Exists (fs , file )
894+ assert .NoError (err )
895+ assert .True (ok )
896+ }
897+ }
898+ })
899+ }
900+ }
0 commit comments