3838import hudson .plugins .git .extensions .impl .PreBuildMerge ;
3939import hudson .scm .NullSCM ;
4040import hudson .tasks .BuildStepDescriptor ;
41+ import hudson .tasks .Builder ;
4142import hudson .util .StreamTaskListener ;
4243import org .eclipse .jgit .lib .Constants ;
4344import org .eclipse .jgit .lib .ObjectId ;
4445import org .jenkinsci .plugins .gitclient .MergeCommand ;
4546import org .jvnet .hudson .test .Issue ;
4647
48+ import java .io .File ;
4749import java .io .IOException ;
4850import java .util .ArrayList ;
4951import java .util .Collections ;
@@ -601,6 +603,50 @@ public void testMergeAndPushWithSkipTagEnabled() throws Exception {
601603 assertEquals (sha1 , testGitClient .revParse (Constants .HEAD ).name ());
602604 }
603605
606+ @ Test
607+ public void testRebaseBeforePush () throws Exception {
608+ FreeStyleProject project = setupSimpleProject ("master" );
609+
610+ GitSCM scm = new GitSCM (
611+ remoteConfigs (),
612+ Collections .singletonList (new BranchSpec ("master" )),
613+ false , Collections .<SubmoduleConfig >emptyList (),
614+ null , null ,
615+ Collections .<GitSCMExtension >emptyList ());
616+ project .setScm (scm );
617+
618+ BranchToPush btp = new BranchToPush ("origin" , "master" );
619+ btp .setRebaseBeforePush (true );
620+
621+ GitPublisher rebasedPublisher = new GitPublisher (
622+ Collections .<TagToPush >emptyList (),
623+ Collections .singletonList (btp ),
624+ Collections .<NoteToPush >emptyList (),
625+ true , true , true );
626+ project .getPublishersList ().add (rebasedPublisher );
627+
628+ project .getBuildersList ().add (new LongRunningCommit (testGitDir ));
629+ project .save ();
630+
631+ // Assume during our build someone else pushed changes (commitFile1) to the remote repo.
632+ // So our own changes (commitFile2) cannot be pushed back to the remote origin.
633+ //
634+ // * 0eb2599 (HEAD) Added a file named commitFile2
635+ // | * 64e71e7 (origin/master) Added a file named commitFile1
636+ // |/
637+ // * b2578eb init
638+ //
639+ // What we can do is to fetch the remote changes and rebase our own changes:
640+ //
641+ // * 0e7674c (HEAD) Added a file named commitFile2
642+ // * 64e71e7 (origin/master) Added a file named commitFile1
643+ // * b2578eb init
644+
645+
646+ // as we have set "rebaseBeforePush" to true we expect all files to be present after the build.
647+ FreeStyleBuild build = build (project , Result .SUCCESS , "commitFile1" , "commitFile2" );
648+ }
649+
604650 @ Issue ("JENKINS-24786" )
605651 @ Test
606652 public void testMergeAndPushWithCharacteristicEnvVar () throws Exception {
@@ -738,3 +784,29 @@ private boolean isWindows() {
738784 return java .io .File .pathSeparatorChar ==';' ;
739785 }
740786}
787+
788+ class LongRunningCommit extends Builder {
789+
790+ private File remoteGitDir ;
791+
792+ LongRunningCommit (File remoteGitDir ) {
793+ this .remoteGitDir = remoteGitDir ;
794+ }
795+
796+ @ Override
797+ public boolean perform (AbstractBuild <?, ?> build , Launcher launcher , BuildListener listener ) throws InterruptedException , IOException {
798+
799+ TestGitRepo workspaceGit = new TestGitRepo ("workspace" , new File (build .getWorkspace ().getRemote ()), listener );
800+ TestGitRepo remoteGit = new TestGitRepo ("remote" , this .remoteGitDir , listener );
801+
802+ // simulate an external commit and push to the remote during the build of our project.
803+ ObjectId headRev = remoteGit .git .revParse ("HEAD" );
804+ remoteGit .commit ("commitFile1" , remoteGit .johnDoe , "Added a file commitFile1" );
805+ remoteGit .git .checkout (headRev .getName ()); // allow to push to this repo later
806+
807+ // commit onto the initial commit (creates a head with our changes later).
808+ workspaceGit .commit ("commitFile2" , remoteGit .johnDoe , "Added a file commitFile2" );
809+
810+ return true ;
811+ }
812+ }
0 commit comments