diff --git a/src/main/java/hudson/plugins/git/extensions/impl/SparseCheckoutPath.java b/src/main/java/hudson/plugins/git/extensions/impl/SparseCheckoutPath.java index c07399ca21..3c460d0ab6 100644 --- a/src/main/java/hudson/plugins/git/extensions/impl/SparseCheckoutPath.java +++ b/src/main/java/hudson/plugins/git/extensions/impl/SparseCheckoutPath.java @@ -3,6 +3,7 @@ import com.google.common.base.Function; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import hudson.EnvVars; import hudson.Extension; import hudson.model.AbstractDescribableImpl; import hudson.model.Descriptor; @@ -10,15 +11,18 @@ import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.Whitelisted; import org.kohsuke.stapler.DataBoundConstructor; +import javax.annotation.Nullable; import java.io.Serializable; import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class SparseCheckoutPath extends AbstractDescribableImpl implements Serializable { private static final long serialVersionUID = -6177158367915899356L; @SuppressFBWarnings(value="SE_TRANSIENT_FIELD_NOT_RESTORED", justification="Default value is OK in deserialization") - public static final transient SparseCheckoutPathToPath SPARSE_CHECKOUT_PATH_TO_PATH = new SparseCheckoutPathToPath(); + public static final transient SparseCheckoutPathToPath SPARSE_CHECKOUT_PATH_TO_PATH = new SparseCheckoutPathToPath(null); private final String path; @@ -56,9 +60,29 @@ public String toString() { return path; } - private static class SparseCheckoutPathToPath implements Function, Serializable { + public static class SparseCheckoutPathToPath implements Function, Serializable { + @Nullable + private EnvVars envVars; + + SparseCheckoutPathToPath(@Nullable EnvVars envVars) { + this.envVars = envVars; + } + public String apply(@NonNull SparseCheckoutPath sparseCheckoutPath) { - return sparseCheckoutPath.getPath(); + String path = sparseCheckoutPath.getPath(); + if (envVars == null) { + return path; + } + + // Pattern to look for substring of the form ${ENV_VAR}. + Pattern pattern = Pattern.compile("\\$\\{(.*?)\\}"); + Matcher matcher = pattern.matcher(path); + while (matcher.find()) { + String varName = matcher.group(1); + String value = envVars.get(varName, ""); + path = path.replace("${" + varName + "}", value); + } + return path; } } diff --git a/src/main/java/hudson/plugins/git/extensions/impl/SparseCheckoutPaths.java b/src/main/java/hudson/plugins/git/extensions/impl/SparseCheckoutPaths.java index 79d25572fc..08f90fb17f 100644 --- a/src/main/java/hudson/plugins/git/extensions/impl/SparseCheckoutPaths.java +++ b/src/main/java/hudson/plugins/git/extensions/impl/SparseCheckoutPaths.java @@ -1,6 +1,8 @@ package hudson.plugins.git.extensions.impl; import com.google.common.collect.Lists; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.Extension; import hudson.model.Run; import hudson.model.TaskListener; @@ -8,14 +10,13 @@ import hudson.plugins.git.GitSCM; import hudson.plugins.git.extensions.GitSCMExtension; import hudson.plugins.git.extensions.GitSCMExtensionDescriptor; +import hudson.plugins.git.extensions.impl.SparseCheckoutPath.SparseCheckoutPathToPath; import org.jenkinsci.plugins.gitclient.CheckoutCommand; import org.jenkinsci.plugins.gitclient.CloneCommand; import org.jenkinsci.plugins.gitclient.GitClient; import org.jenkinsci.plugins.gitclient.UnsupportedCommand; import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.Whitelisted; import org.kohsuke.stapler.DataBoundConstructor; -import edu.umd.cs.findbugs.annotations.NonNull; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.IOException; import java.util.Collections; @@ -45,7 +46,7 @@ public void decorateCloneCommand(GitSCM scm, Run build, GitClient git, Tas @Override public void decorateCheckoutCommand(GitSCM scm, Run build, GitClient git, TaskListener listener, CheckoutCommand cmd) throws IOException, InterruptedException, GitException { - cmd.sparseCheckoutPaths(Lists.transform(sparseCheckoutPaths, SparseCheckoutPath.SPARSE_CHECKOUT_PATH_TO_PATH)); + cmd.sparseCheckoutPaths(Lists.transform(sparseCheckoutPaths, new SparseCheckoutPathToPath(build.getEnvironment(listener)))); } @Override @@ -69,11 +70,11 @@ public boolean equals(Object o) { if (this == o) { return true; } - + if (o == null || getClass() != o.getClass()) { return false; } - + SparseCheckoutPaths that = (SparseCheckoutPaths) o; return Objects.equals(getSparseCheckoutPaths(), that.getSparseCheckoutPaths()); } @@ -85,7 +86,7 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(getSparseCheckoutPaths()); } - + /** * {@inheritDoc} */ diff --git a/src/test/java/hudson/plugins/git/extensions/impl/SparseCheckoutPathsTest.java b/src/test/java/hudson/plugins/git/extensions/impl/SparseCheckoutPathsTest.java index 5e8ca27aae..67a17a2650 100644 --- a/src/test/java/hudson/plugins/git/extensions/impl/SparseCheckoutPathsTest.java +++ b/src/test/java/hudson/plugins/git/extensions/impl/SparseCheckoutPathsTest.java @@ -23,6 +23,7 @@ */ package hudson.plugins.git.extensions.impl; +import hudson.EnvVars; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; @@ -40,9 +41,12 @@ import nl.jqno.equalsverifier.EqualsVerifier; import org.junit.Before; import org.junit.Test; +import org.mockito.Mock; import static org.hamcrest.MatcherAssert.*; import static org.hamcrest.Matchers.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class SparseCheckoutPathsTest { @@ -115,13 +119,32 @@ public void testDecorateCloneCommandEmpty() throws Exception { @Test public void testDecorateCheckoutCommand() throws Exception { GitSCM scm = null; - Run build = null; + Run build = mock(Run.class); + when(build.getEnvironment(listener)).thenReturn(new EnvVars()); GitClient git = null; MyCheckoutCommand cmd = new MyCheckoutCommand(); sparseCheckoutPaths.decorateCheckoutCommand(scm, build, git, listener, cmd); assertThat(cmd.getSparsePathNames(), hasItems(SRC_DIR_NAME)); } + @Test + public void testDecorateCheckoutCommandExpandsEnvVariable() throws Exception { + GitSCM scm = null; + GitClient git = null; + Run build = mock(Run.class); + EnvVars envVars = new EnvVars(); + envVars.put("SPARSE_CHECKOUT_DIRECTORY", SRC_DIR_NAME); + when(build.getEnvironment(listener)).thenReturn(envVars); + + MyCheckoutCommand cmd = new MyCheckoutCommand(); + List sparseCheckoutPathList = new ArrayList<>(); + sparseCheckoutPathList.add(new SparseCheckoutPath("${SPARSE_CHECKOUT_DIRECTORY}")); + SparseCheckoutPaths sparseCheckoutPaths = new SparseCheckoutPaths(sparseCheckoutPathList); + sparseCheckoutPaths.decorateCheckoutCommand(scm, build, git, listener, cmd); + + assertThat(cmd.getSparsePathNames(), hasItems(SRC_DIR_NAME)); + } + @Test public void equalsContract() { EqualsVerifier.forClass(SparseCheckoutPaths.class).usingGetClass().verify();