Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkEWaite committed Feb 3, 2015
2 parents d1cded9 + 6a6fcef commit a18a90e
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 5 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Expand Up @@ -11,3 +11,10 @@ work/
.settings/

/nb-configuration.xml

# Vim
*.swp
Session.vim

# Exhuberant ctags
tags
17 changes: 14 additions & 3 deletions src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java
Expand Up @@ -480,6 +480,7 @@ public MergeCommand merge() {
return new MergeCommand() {
public ObjectId rev;
public String strategy;
public String fastForwardMode;

public MergeCommand setRevisionToMerge(ObjectId rev) {
this.rev = rev;
Expand All @@ -491,12 +492,22 @@ public MergeCommand setStrategy(MergeCommand.Strategy strategy) {
return this;
}

public MergeCommand setGitPluginFastForwardMode(MergeCommand.GitPluginFastForwardMode fastForwardMode) {
this.fastForwardMode = fastForwardMode.toString();
return this;
}

public void execute() throws GitException, InterruptedException {
ArgumentListBuilder args = new ArgumentListBuilder();
args.add("merge");
try {
if (strategy != null && !strategy.isEmpty() && !strategy.equals(MergeCommand.Strategy.DEFAULT.toString())) {
launchCommand("merge", "-s", strategy, rev.name()); }
else {
launchCommand("merge", rev.name()); }
args.add("-s");
args.add(strategy);
}
args.add(fastForwardMode);
args.add(rev.name());
launchCommand(args);
} catch (GitException e) {
throw new GitException("Could not merge " + rev, e);
}
Expand Down
17 changes: 15 additions & 2 deletions src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java
Expand Up @@ -51,6 +51,7 @@
import org.eclipse.jgit.api.ListBranchCommand;
import org.eclipse.jgit.api.LsRemoteCommand;
import org.eclipse.jgit.api.MergeResult;
import org.eclipse.jgit.api.MergeCommand.FastForwardMode;
import org.eclipse.jgit.api.ResetCommand;
import org.eclipse.jgit.api.ShowNoteCommand;
import org.eclipse.jgit.api.errors.CheckoutConflictException;
Expand Down Expand Up @@ -1318,6 +1319,7 @@ public MergeCommand merge() {

ObjectId rev;
MergeStrategy strategy;
FastForwardMode fastForwardMode;

public MergeCommand setRevisionToMerge(ObjectId rev) {
this.rev = rev;
Expand All @@ -1343,16 +1345,27 @@ public MergeCommand setStrategy(MergeCommand.Strategy strategy) {
return this;
}

public MergeCommand setGitPluginFastForwardMode(MergeCommand.GitPluginFastForwardMode fastForwardMode) {
if (fastForwardMode == MergeCommand.GitPluginFastForwardMode.FF) {
this.fastForwardMode = FastForwardMode.FF;
} else if (fastForwardMode == MergeCommand.GitPluginFastForwardMode.FF_ONLY) {
this.fastForwardMode = FastForwardMode.FF_ONLY;
} else if (fastForwardMode == MergeCommand.GitPluginFastForwardMode.NO_FF) {
this.fastForwardMode = FastForwardMode.NO_FF;
}
return this;
}

public void execute() throws GitException, InterruptedException {
Repository repo = null;
try {
repo = getRepository();
Git git = git(repo);
MergeResult mergeResult;
if (strategy != null)
mergeResult = git.merge().setStrategy(strategy).include(rev).call();
mergeResult = git.merge().setStrategy(strategy).setFastForward(fastForwardMode).include(rev).call();
else
mergeResult = git.merge().include(rev).call();
mergeResult = git.merge().setFastForward(fastForwardMode).include(rev).call();
if (!mergeResult.getMergeStatus().isSuccessful()) {
git.reset().setMode(HARD).call();
throw new GitException("Failed to merge " + rev);
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/org/jenkinsci/plugins/gitclient/MergeCommand.java
Expand Up @@ -19,4 +19,22 @@ public String toString() {
return name().toLowerCase();
}
}

/**
* Select the fast forward mode.
* The name FastForwardMode collides with org.eclipse.jgit.api.MergeCommand.FastForwardMode
* so we have to choose a different name.
*/
MergeCommand setGitPluginFastForwardMode(GitPluginFastForwardMode fastForwardMode);

public enum GitPluginFastForwardMode {
FF, // Default option, fast forward update the branch pointer only
FF_ONLY, // Create a merge commit even for a fast forward
NO_FF; // Abort unless the merge is a fast forward

@Override
public String toString() {
return "--"+name().toLowerCase().replace("_","-");
}
}
}
116 changes: 116 additions & 0 deletions src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java
Expand Up @@ -2168,6 +2168,122 @@ public void test_merge_strategy_correct_fail() throws Exception {
}
}

@Bug(12402)
public void test_merge_fast_forward_mode_ff() throws Exception {
w.init();

w.commitEmpty("init");
w.git.branch("branch1");
w.git.checkout("branch1");
w.touch("file1", "content1");
w.git.add("file1");
w.git.commit("commit1");
final ObjectId branch1 = w.head();

w.git.checkout("master");
w.git.branch("branch2");
w.git.checkout("branch2");
w.touch("file2", "content2");
w.git.add("file2");
w.git.commit("commit2");
final ObjectId branch2 = w.head();

w.git.checkout("master");

// The first merge is a fast-forward, master moves to branch1
w.git.merge().setGitPluginFastForwardMode(MergeCommand.GitPluginFastForwardMode.FF).setRevisionToMerge(w.git.getHeadRev(w.repoPath(), "branch1")).execute();
assertEquals("Fast-forward merge failed. master and branch1 should be the same.",w.head(),branch1);

// The second merge calls for fast-forward (FF), but a merge commit will result
// This tests that calling for FF gracefully falls back to a commit merge
// master moves to a new commit ahead of branch1 and branch2
w.git.merge().setGitPluginFastForwardMode(MergeCommand.GitPluginFastForwardMode.FF).setRevisionToMerge(w.git.getHeadRev(w.repoPath(), "branch2")).execute();
// The merge commit (head) should have branch2 and branch1 as parents
List<ObjectId> revList = w.git.revList("HEAD^1");
assertEquals("Merge commit failed. branch1 should be a parent of HEAD but it isn't.",revList.get(0).name(), branch1.name());
revList = w.git.revList("HEAD^2");
assertEquals("Merge commit failed. branch2 should be a parent of HEAD but it isn't.",revList.get(0).name(), branch2.name());
}

public void test_merge_fast_forward_mode_ff_only() throws Exception {
w.init();
w.commitEmpty("init");
w.git.branch("branch1");
w.git.checkout("branch1");
w.touch("file1", "content1");
w.git.add("file1");
w.git.commit("commit1");
final ObjectId branch1 = w.head();

w.git.checkout("master");
w.git.branch("branch2");
w.git.checkout("branch2");
w.touch("file2", "content2");
w.git.add("file2");
w.git.commit("commit2");
final ObjectId branch2 = w.head();

w.git.checkout("master");
final ObjectId master = w.head();

// The first merge is a fast-forward, master moves to branch1
w.git.merge().setGitPluginFastForwardMode(MergeCommand.GitPluginFastForwardMode.FF_ONLY).setRevisionToMerge(w.git.getHeadRev(w.repoPath(), "branch1")).execute();
assertEquals("Fast-forward merge failed. master and branch1 should be the same but aren't.",w.head(),branch1);

// The second merge calls for fast-forward only (FF_ONLY), but a merge commit is required, hence it is expected to fail
try {
w.git.merge().setGitPluginFastForwardMode(MergeCommand.GitPluginFastForwardMode.FF_ONLY).setRevisionToMerge(w.git.getHeadRev(w.repoPath(), "branch2")).execute();
fail("Exception not thrown: the fast-forward only mode should have failed");
} catch (GitException e) {
// expected
assertEquals("Fast-forward merge abort failed. master and branch1 should still be the same as the merge was aborted.",w.head(),branch1);
}
}

public void test_merge_fast_forward_mode_no_ff() throws Exception {
w.init();
w.commitEmpty("init");
final ObjectId base = w.head();
w.git.branch("branch1");
w.git.checkout("branch1");
w.touch("file1", "content1");
w.git.add("file1");
w.git.commit("commit1");
final ObjectId branch1 = w.head();

w.git.checkout("master");
w.git.branch("branch2");
w.git.checkout("branch2");
w.touch("file2", "content2");
w.git.add("file2");
w.git.commit("commit2");
final ObjectId branch2 = w.head();

w.git.checkout("master");
final ObjectId master = w.head();

// The first merge is normally a fast-forward, but we're calling for a merge commit which is expected to work
w.git.merge().setGitPluginFastForwardMode(MergeCommand.GitPluginFastForwardMode.NO_FF).setRevisionToMerge(w.git.getHeadRev(w.repoPath(), "branch1")).execute();

// The first merge will have base and branch1 as parents
List<ObjectId> revList = null;
revList = w.git.revList("HEAD^1");
assertEquals("Merge commit failed. base should be a parent of HEAD but it isn't.",revList.get(0).name(), base.name());
revList = w.git.revList("HEAD^2");
assertEquals("Merge commit failed. branch1 should be a parent of HEAD but it isn't.",revList.get(0).name(), branch1.name());

final ObjectId base2 = w.head();

// Calling for NO_FF when required is expected to work
w.git.merge().setGitPluginFastForwardMode(MergeCommand.GitPluginFastForwardMode.NO_FF).setRevisionToMerge(w.git.getHeadRev(w.repoPath(), "branch2")).execute();

// The second merge will have base2 and branch2 as parents
revList = w.git.revList("HEAD^1");
assertEquals("Merge commit failed. base2 should be a parent of HEAD but it isn't.",revList.get(0).name(), base2.name());
revList = w.git.revList("HEAD^2");
assertEquals("Merge commit failed. branch2 should be a parent of HEAD but it isn't.",revList.get(0).name(), branch2.name());
}

@Deprecated
public void test_merge_refspec() throws Exception {
w.init();
Expand Down

0 comments on commit a18a90e

Please sign in to comment.