diff --git a/src/main/java/hudson/scm/SubversionSCM.java b/src/main/java/hudson/scm/SubversionSCM.java index 684ae80e8..5b36db9a0 100755 --- a/src/main/java/hudson/scm/SubversionSCM.java +++ b/src/main/java/hudson/scm/SubversionSCM.java @@ -65,17 +65,10 @@ import hudson.Launcher; import hudson.Util; import hudson.init.InitMilestone; -import hudson.model.AbstractDescribableImpl; -import hudson.model.Descriptor; -import hudson.model.Item; -import hudson.model.ItemGroup; -import hudson.model.ModelObject; -import hudson.model.TaskListener; -import hudson.model.AbstractBuild; -import hudson.model.AbstractProject; -import hudson.model.Hudson; +import hudson.model.*; import java.io.ByteArrayOutputStream; +import java.net.URLClassLoader; import java.nio.charset.UnsupportedCharsetException; import java.security.KeyStore; import java.security.KeyStoreException; @@ -90,8 +83,6 @@ import hudson.util.ListBoxModel; import jenkins.model.Jenkins; import jenkins.model.Jenkins.MasterComputer; -import hudson.model.ParametersAction; -import hudson.model.Run; import hudson.remoting.Callable; import hudson.remoting.Channel; import hudson.remoting.VirtualChannel; @@ -194,7 +185,6 @@ import com.trilead.ssh2.DebugLogger; import com.trilead.ssh2.SCPClient; import com.trilead.ssh2.crypto.Base64; -import hudson.model.Job; /** * Subversion SCM. @@ -1402,7 +1392,7 @@ else if (project.getLastBuild()!=null) { for (ModuleLocation loc: getLocations()) { String url; try { - url = loc.getSVNURL().toDecodedString(); + url = loc.getExpandedLocation(project).getSVNURL().toDecodedString(); } catch (SVNException ex) { ex.printStackTrace(listener.error(Messages.SubversionSCM_pollChanges_exception(loc.getURL()))); return BUILD_NOW; @@ -2907,6 +2897,32 @@ public static List parse(String[] remoteLocations, String[] cred return modules; } + /** + * If a subversion remote uses $VAR or ${VAR} as a parameterized build, + * we expand the url. This will expand using the DEFAULT item. If there + * is a choice parameter, it will expand with the FIRST item. + */ + public ModuleLocation getExpandedLocation(Job project) { + String url = this.getURL(); + String returnURL = url; + for (JobProperty property : project.getProperties().values()) { + if (property instanceof ParametersDefinitionProperty) { + ParametersDefinitionProperty pdp = (ParametersDefinitionProperty) property; + for (String propertyName : pdp.getParameterDefinitionNames()) { + if (url.contains(propertyName)) { + ParameterDefinition pd = pdp.getParameterDefinition(propertyName); + String replacement = String.valueOf(pd.getDefaultParameterValue().createVariableResolver(null).resolve(propertyName)); + returnURL = returnURL.replace("${" + propertyName + "}", replacement); + returnURL = returnURL.replace("$" + propertyName, replacement); + } + } + } + } + + return new ModuleLocation(returnURL, credentialsId, getLocalDir(), getDepthOption(), + isIgnoreExternalsOption()); + } + @Extension public static class DescriptorImpl extends Descriptor { @@ -3082,12 +3098,12 @@ public FormValidation doCheckLocal(@QueryParameter String value) throws IOExcept /** * Property to control whether SCM polling happens from the slave or master */ - private static boolean POLL_FROM_MASTER = Boolean.getBoolean(SubversionSCM.class.getName()+".pollFromMaster"); + private static boolean POLL_FROM_MASTER = Boolean.getBoolean(SubversionSCM.class.getName() + ".pollFromMaster"); /** * If set to non-null, read configuration from this directory instead of "~/.subversion". */ - public static String CONFIG_DIR = System.getProperty(SubversionSCM.class.getName()+".configDir"); + public static String CONFIG_DIR = System.getProperty(SubversionSCM.class.getName() + ".configDir"); /** * Enables trace logging of Ganymed SSH library. diff --git a/src/test/java/hudson/scm/SubversionSCMTest.java b/src/test/java/hudson/scm/SubversionSCMTest.java index 55254fb98..618b11b13 100644 --- a/src/test/java/hudson/scm/SubversionSCMTest.java +++ b/src/test/java/hudson/scm/SubversionSCMTest.java @@ -25,83 +25,36 @@ */ package hudson.scm; -import static hudson.scm.SubversionSCM.compareSVNAuthentications; -import static org.jvnet.hudson.test.recipes.PresetData.DataSet.ANONYMOUS_READONLY; - import com.cloudbees.plugins.credentials.Credentials; import com.cloudbees.plugins.credentials.CredentialsScope; import com.cloudbees.plugins.credentials.SystemCredentialsProvider; import com.cloudbees.plugins.credentials.domains.Domain; import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl; +import com.gargoylesoftware.htmlunit.*; +import com.gargoylesoftware.htmlunit.html.HtmlAnchor; +import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import hudson.EnvVars; import hudson.FilePath; import hudson.Launcher; import hudson.Proc; -import hudson.model.BuildListener; -import hudson.model.FreeStyleBuild; -import hudson.model.Item; -import hudson.model.Result; -import hudson.model.TaskListener; -import hudson.model.AbstractBuild; -import hudson.model.AbstractProject; -import hudson.model.Cause; -import hudson.model.FreeStyleProject; -import hudson.model.ParametersAction; -import hudson.model.Run; -import hudson.model.StringParameterValue; +import hudson.model.*; import hudson.scm.ChangeLogSet.Entry; import hudson.scm.SubversionSCM.ModuleLocation; import hudson.scm.browsers.Sventon; -import hudson.scm.subversion.CheckoutUpdater; -import hudson.scm.subversion.UpdateUpdater; -import hudson.scm.subversion.UpdateWithCleanUpdater; -import hudson.scm.subversion.UpdateWithRevertUpdater; -import hudson.scm.subversion.WorkspaceUpdater; +import hudson.scm.subversion.*; import hudson.slaves.DumbSlave; import hudson.triggers.SCMTrigger; import hudson.util.FormValidation; import hudson.util.StreamTaskListener; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.PrintWriter; -import java.net.MalformedURLException; -import java.net.URL; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; - import org.dom4j.Document; import org.dom4j.io.DOMReader; import org.junit.Test; -import org.jvnet.hudson.test.Bug; -import org.jvnet.hudson.test.Email; +import org.jvnet.hudson.test.*; import org.jvnet.hudson.test.HudsonHomeLoader.CopyExisting; -import org.jvnet.hudson.test.TestBuilder; -import org.jvnet.hudson.test.Url; -import org.jvnet.hudson.test.CaptureEnvironmentBuilder; import org.jvnet.hudson.test.recipes.PresetData; -import org.tmatesoft.svn.core.SVNCancelException; -import org.tmatesoft.svn.core.SVNDepth; -import org.tmatesoft.svn.core.SVNErrorCode; -import org.tmatesoft.svn.core.SVNErrorMessage; -import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.SVNPropertyValue; -import org.tmatesoft.svn.core.SVNURL; -import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager; -import org.tmatesoft.svn.core.auth.SVNAuthentication; -import org.tmatesoft.svn.core.auth.SVNPasswordAuthentication; -import org.tmatesoft.svn.core.auth.SVNSSHAuthentication; -import org.tmatesoft.svn.core.auth.SVNSSLAuthentication; -import org.tmatesoft.svn.core.auth.SVNUserNameAuthentication; +import org.tmatesoft.svn.core.*; +import org.tmatesoft.svn.core.auth.*; import org.tmatesoft.svn.core.internal.wc.admin.SVNAdminAreaFactory; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.io.SVNRepositoryFactory; @@ -110,18 +63,17 @@ import org.tmatesoft.svn.core.wc.SVNStatus; import org.tmatesoft.svn.core.wc.SVNWCUtil; -import com.gargoylesoftware.htmlunit.ElementNotFoundException; -import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; -import com.gargoylesoftware.htmlunit.HttpMethod; -import com.gargoylesoftware.htmlunit.WebConnection; -import com.gargoylesoftware.htmlunit.WebRequestSettings; -import com.gargoylesoftware.htmlunit.WebResponse; -import com.gargoylesoftware.htmlunit.html.HtmlAnchor; -import com.gargoylesoftware.htmlunit.html.HtmlForm; -import com.gargoylesoftware.htmlunit.html.HtmlPage; -import hudson.EnvVars; -import hudson.model.EnvironmentContributor; -import hudson.model.TopLevelItem; +import java.io.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import static hudson.scm.SubversionSCM.compareSVNAuthentications; +import static org.jvnet.hudson.test.recipes.PresetData.DataSet.ANONYMOUS_READONLY; /** * @author Kohsuke Kawaguchi @@ -344,6 +296,73 @@ public void testRevisionParameter() throws Exception { assertBuildStatus(Result.SUCCESS,b); } + @Bug(22568) + public void testPollingWithDefaultParametersWithCurlyBraces() throws Exception { + FreeStyleProject p = createFreeStyleProject(); + + String url = "http://svn.codehaus.org/sxc/tags/sxc-0.5/sxc-core/src/test/java/com/envoisolutions/sxc/builder/"; + p.setScm(new SubversionSCM("${REPO}" + url.substring(10))); + String var = url.substring(0, 10); + ParametersDefinitionProperty property = new ParametersDefinitionProperty(new StringParameterDefinition("REPO", var)); + p.addProperty(property); + + FreeStyleBuild b = p.scheduleBuild2(0, new Cause.UserIdCause(), + new ParametersAction(new StringParameterValue("REPO", var))).get(); + + assertBuildStatus(Result.SUCCESS,b); + assertTrue(b.getWorkspace().child("Node.java").exists()); + + // as a baseline, this shouldn't detect any change + TaskListener listener = createTaskListener(); + PollingResult poll = p.poll(listener); + assertFalse("Polling shouldn't have any changes.", poll.hasChanges()); + } + + @Bug(22568) + public void testPollingWithDefaultParametersWithOutCurlyBraces() throws Exception { + FreeStyleProject p = createFreeStyleProject(); + + String url = "http://svn.codehaus.org/sxc/tags/sxc-0.5/sxc-core/src/test/java/com/envoisolutions/sxc/builder/"; + p.setScm(new SubversionSCM("$REPO" + url.substring(10))); + String var = url.substring(0, 10); + ParametersDefinitionProperty property = new ParametersDefinitionProperty(new StringParameterDefinition("REPO", var)); + p.addProperty(property); + + FreeStyleBuild b = p.scheduleBuild2(0, new Cause.UserIdCause(), + new ParametersAction(new StringParameterValue("REPO", var))).get(); + + assertBuildStatus(Result.SUCCESS,b); + assertTrue(b.getWorkspace().child("Node.java").exists()); + + // as a baseline, this shouldn't detect any change + TaskListener listener = createTaskListener(); + PollingResult poll = p.poll(listener); + assertFalse("Polling shouldn't have any changes.", poll.hasChanges()); + } + + @Bug(22568) + public void testPollingWithChoiceParametersWithOutCurlyBraces() throws Exception { + FreeStyleProject p = createFreeStyleProject(); + + String url = "http://svn.codehaus.org/sxc/tags/sxc-0.5/sxc-core/src/test/java/com/envoisolutions/sxc/builder/"; + p.setScm(new SubversionSCM("${REPO}" + url.substring(10))); + String var = url.substring(0, 10); + ParametersDefinitionProperty property = new ParametersDefinitionProperty(new ChoiceParameterDefinition("REPO", new String[] {var, "test"}, "")); + p.addProperty(property); + + FreeStyleBuild b = p.scheduleBuild2(0, new Cause.UserIdCause(), + new ParametersAction(new StringParameterValue("REPO", var))).get(); + + assertBuildStatus(Result.SUCCESS,b); + assertTrue(b.getWorkspace().child("Node.java").exists()); + + // as a baseline, this shouldn't detect any change + TaskListener listener = createTaskListener(); + PollingResult poll = p.poll(listener); + assertFalse("Polling shouldn't have any changes.", poll.hasChanges()); + } + + public void testRevisionParameterFolding() throws Exception { FreeStyleProject p = createFreeStyleProject(); String url = "https://svn.jenkins-ci.org/trunk/hudson/test-projects/trivial-ant";