diff --git a/pom.xml b/pom.xml index 0fe50a1c28..11e37a54df 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,8 @@ 6 2 + 128m + -XX:MaxPermSize=${permgen.size} false 1.14.2 @@ -175,6 +177,18 @@ 1.10.19 test + + org.powermock + powermock-module-junit4 + 1.6.2 + test + + + org.powermock + powermock-api-mockito + 1.6.2 + test + org.apache.httpcomponents httpclient diff --git a/src/main/java/jenkins/plugins/git/AbstractGitSCMSource.java b/src/main/java/jenkins/plugins/git/AbstractGitSCMSource.java index c4f5a2d086..8d2ae9273b 100644 --- a/src/main/java/jenkins/plugins/git/AbstractGitSCMSource.java +++ b/src/main/java/jenkins/plugins/git/AbstractGitSCMSource.java @@ -39,6 +39,7 @@ import hudson.plugins.git.BranchSpec; import hudson.plugins.git.GitException; import hudson.plugins.git.GitSCM; +import hudson.plugins.git.GitTool; import hudson.plugins.git.Revision; import hudson.plugins.git.SubmoduleConfig; import hudson.plugins.git.UserRemoteConfig; @@ -148,6 +149,16 @@ public String getRemoteName() { return "origin"; } + @CheckForNull + protected GitTool resolveGitTool() { + GitTool tool = Jenkins.getInstance().getDescriptorByType(GitTool.DescriptorImpl.class) + .getInstallation(getGitTool()); + if (getGitTool() == null) { + tool = GitTool.getDefaultInstallation(); + } + return tool; + } + @CheckForNull @Override protected SCMRevision retrieve(@NonNull SCMHead head, @NonNull TaskListener listener) @@ -157,7 +168,8 @@ protected SCMRevision retrieve(@NonNull SCMHead head, @NonNull TaskListener list cacheLock.lock(); try { File cacheDir = getCacheDir(cacheEntry); - Git git = Git.with(listener, new EnvVars(EnvVars.masterEnvVars)).in(cacheDir); + GitTool tool = resolveGitTool(); + Git git = Git.with(listener, new EnvVars(EnvVars.masterEnvVars)).using(tool.getGitExe()).in(cacheDir); GitClient client = git.getClient(); client.addDefaultCredentials(getCredentials()); if (!client.hasGitRepo()) { @@ -193,7 +205,8 @@ protected void retrieve(@NonNull final SCMHeadObserver observer, cacheLock.lock(); try { File cacheDir = getCacheDir(cacheEntry); - Git git = Git.with(listener, new EnvVars(EnvVars.masterEnvVars)).in(cacheDir); + GitTool tool = resolveGitTool(); + Git git = Git.with(listener, new EnvVars(EnvVars.masterEnvVars)).using(tool.getGitExe()).in(cacheDir); GitClient client = git.getClient(); client.addDefaultCredentials(getCredentials()); if (!client.hasGitRepo()) { diff --git a/src/test/java/jenkins/plugins/git/AbstractGitSCMSourceRetrieveHeadsTest.java b/src/test/java/jenkins/plugins/git/AbstractGitSCMSourceRetrieveHeadsTest.java new file mode 100644 index 0000000000..88e492f8c9 --- /dev/null +++ b/src/test/java/jenkins/plugins/git/AbstractGitSCMSourceRetrieveHeadsTest.java @@ -0,0 +1,129 @@ +package jenkins.plugins.git; + +import java.io.File; +import java.util.Collections; +import java.util.List; + +import hudson.FilePath; +import hudson.model.TaskListener; +import hudson.plugins.git.GitTool; +import jenkins.scm.api.SCMHead; +import jenkins.scm.api.SCMHeadObserver; +import org.eclipse.jgit.transport.RefSpec; +import org.jenkinsci.plugins.gitclient.Git; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +/** + * Tests for {@link AbstractGitSCMSource} + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest(Git.class) +public class AbstractGitSCMSourceRetrieveHeadsTest { + + public static final String EXPECTED_GIT_EXE = "git-custom"; + + private AbstractGitSCMSource gitSCMSource; + + @Before + public void setup() throws Exception { + // Mock GitTool + GitTool mockedTool = PowerMockito.mock(GitTool.class, Mockito.RETURNS_DEFAULTS); + PowerMockito.doReturn(EXPECTED_GIT_EXE).when(mockedTool).getGitExe(); + + // Mock git implementation + Git git = Mockito.mock(Git.class, Mockito.CALLS_REAL_METHODS); + PowerMockito.doThrow(new GitToolSpecified()).when(git).using(EXPECTED_GIT_EXE); + PowerMockito.doThrow(new GitToolNotSpecified()).when(git).getClient(); + PowerMockito.doReturn(git).when(git).in(Mockito.any(File.class)); + PowerMockito.doReturn(git).when(git).in(Mockito.any(FilePath.class)); + + // mock static factory to return our git mock + PowerMockito.mockStatic(Git.class, Mockito.CALLS_REAL_METHODS); + PowerMockito.doReturn(git).when(Git.class, "with", Mockito.any(), Mockito.any()); + + // Partial mock our AbstractGitSCMSourceImpl + gitSCMSource = PowerMockito.spy(new AbstractGitSCMSourceImpl()); + // Always resolve to mocked GitTool + PowerMockito.doReturn(mockedTool).when(gitSCMSource).resolveGitTool(); + } + + /** + * Validate that the correct git installation is used when fetching latest heads. + * That means {@link Git#using(String)} is called properly. + */ + @Test(expected = GitToolSpecified.class) + public void correctGitToolIsUsed() throws Exception { + try { + // Should throw exception confirming that Git#using was used correctly + gitSCMSource.retrieve(new SCMHead("master"), TaskListener.NULL); + } catch (GitToolNotSpecified e) { + Assert.fail("Git client was constructed wirth arbitrary git tool"); + } + } + + /** + * Validate that the correct git installation is used when fetching latest heads. + * That means {@link Git#using(String)} is called properly. + */ + @Test(expected = GitToolSpecified.class) + public void correctGitToolIsUsed2() throws Exception { + try { + // Should throw exception confirming that Git#using was used correctly + gitSCMSource.retrieve(PowerMockito.mock(SCMHeadObserver.class), TaskListener.NULL); + } catch (GitToolNotSpecified e) { + Assert.fail("Git client was constructed with arbitrary git tool"); + } + } + + public static class GitToolSpecified extends RuntimeException { + + } + + public static class GitToolNotSpecified extends RuntimeException { + + } + + public static class AbstractGitSCMSourceImpl extends AbstractGitSCMSource { + + public AbstractGitSCMSourceImpl() { + super("AbstractGitSCMSourceImpl-id"); + } + + @Override + public String getGitTool() { + return "EXPECTED_GIT_EXE"; + } + + @Override + public String getCredentialsId() { + return ""; + } + + @Override + public String getRemote() { + return ""; + } + + @Override + public String getIncludes() { + return ""; + } + + @Override + public String getExcludes() { + return ""; + } + + @Override + protected List getRefSpecs() { + return Collections.emptyList(); + } + } +}