diff --git a/core/src/main/java/hudson/scm/SubversionChangeLogBuilder.java b/core/src/main/java/hudson/scm/SubversionChangeLogBuilder.java index 9963401f157e30449ef7b98d5cc8ba0f1bedad17..fb41bcc1b7416a60c4fde5306de1f85715084f52 100644 --- a/core/src/main/java/hudson/scm/SubversionChangeLogBuilder.java +++ b/core/src/main/java/hudson/scm/SubversionChangeLogBuilder.java @@ -71,7 +71,7 @@ public final class SubversionChangeLogBuilder { logHandler.startDocument(); for (ModuleLocation l : scm.getLocations(build)) { - changelogFileCreated |= buildModule(l.remote, svnlc, logHandler); + changelogFileCreated |= buildModule(l.getURL(), svnlc, logHandler); } for(SubversionSCM.External ext : externals) { changelogFileCreated |= buildModule( diff --git a/core/src/main/java/hudson/scm/SubversionSCM.java b/core/src/main/java/hudson/scm/SubversionSCM.java index 9f97669bcc417da88688a51efe67794fb19be7a2..bb2f878bfccec71ba9b0ef0740a4f48745a4bc7e 100644 --- a/core/src/main/java/hudson/scm/SubversionSCM.java +++ b/core/src/main/java/hudson/scm/SubversionSCM.java @@ -87,7 +87,6 @@ import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Hashtable; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -429,7 +428,7 @@ public class SubversionSCM extends SCM implements Serializable { File local = new File(ws, l.local); svnuc.setEventHandler(new SubversionUpdateEventHandler(listener.getLogger(), externals,local,l.local)); - svnuc.doUpdate(local.getCanonicalFile(), revision, true); + svnuc.doUpdate(local.getCanonicalFile(), l.getRevision(revision), true); } catch (final SVNException e) { if(e.getErrorMessage().getErrorCode()== SVNErrorCode.WC_LOCKED) { @@ -465,12 +464,11 @@ public class SubversionSCM extends SCM implements Serializable { for (final ModuleLocation l : locations) { try { - final SVNURL url = SVNURL.parseURIEncoded(l.remote); - listener.getLogger().println("Checking out "+url); + listener.getLogger().println("Checking out "+l.remote); File local = new File(ws, l.local); svnuc.setEventHandler(new SubversionUpdateEventHandler(new PrintStream(pos), externals, local, l.local)); - svnuc.doCheckout(url, local.getCanonicalFile(), SVNRevision.HEAD, revision, true); + svnuc.doCheckout(l.getSVNURL(), local.getCanonicalFile(), SVNRevision.HEAD, l.getRevision(revision), true); } catch (SVNException e) { e.printStackTrace(listener.error("Failed to check out "+l.remote)); return null; @@ -487,8 +485,7 @@ public class SubversionSCM extends SCM implements Serializable { try { for (final ModuleLocation l : locations) { - final SVNURL url = SVNURL.parseURIEncoded(l.remote); - SVNDirEntry dir = manager.createRepository(url,true).info("/",-1); + SVNDirEntry dir = manager.createRepository(l.getSVNURL(),true).info("/",-1); if(dir!=null) {// I don't think this can ever be null, but be defensive if(dir.getDate().after(new Date())) listener.getLogger().println(Messages.SubversionSCM_ClockOutOfSync()); @@ -740,7 +737,6 @@ public class SubversionSCM extends SCM implements Serializable { public Boolean invoke(File ws, VirtualChannel channel) throws IOException { for (ModuleLocation l : locations) { - String url = l.remote; String moduleName = l.local; File module = new File(ws,moduleName).getCanonicalFile(); // canonicalize to remove ".." and ".". See #474 @@ -753,6 +749,7 @@ public class SubversionSCM extends SCM implements Serializable { SVNInfo svnkitInfo = parseSvnInfo(module, authProvider); SvnInfo svnInfo = new SvnInfo(svnkitInfo); + String url = l.getURL(); if(!svnInfo.url.equals(url)) { listener.getLogger().println("Checking out a fresh workspace because the workspace is not "+url); return false; @@ -1407,8 +1404,7 @@ public class SubversionSCM extends SCM implements Serializable { PrintStream out = listener.getLogger(); for (ModuleLocation l : getLocations(build)) - if (getDescriptor().checkRepositoryPath( - SVNURL.parseURIDecoded(l.remote)) == SVNNodeKind.NONE) { + if (getDescriptor().checkRepositoryPath(l.getSVNURL()) == SVNNodeKind.NONE) { out.println("Location '" + l.remote + "' does not exist"); ParametersAction params = build @@ -1465,7 +1461,16 @@ public class SubversionSCM extends SCM implements Serializable { * to make failure messages when doing a checkout possible */ public static final class ModuleLocation implements Serializable { + /** + * Subversion URL to check out. + * + * This may include "@NNN" at the end to indicate a fixed revision. + */ public final String remote; + /** + * Local directory to place the file to. + * Relative to the workspace root. + */ public final String local; public ModuleLocation(String remote, String local) { @@ -1476,18 +1481,58 @@ public class SubversionSCM extends SCM implements Serializable { this.local = local.trim(); } - public String toString() { + /** + * Returns the pure URL portion of {@link #remote} by removing + * possible "@NNN" suffix. + */ + public String getURL() { + int idx = remote.lastIndexOf('@'); + if(idx>0) { + try { + String n = remote.substring(idx+1); + Long.parseLong(n); + return remote.substring(0,idx); + } catch (NumberFormatException e) { + // not a revision number + } + } return remote; } - private static final long serialVersionUID = 1L; + /** + * Gets {@link #remote} as {@link SVNURL}. + */ + public SVNURL getSVNURL() throws SVNException { + return SVNURL.parseURIEncoded(getURL()); + } + /** + * Figures out which revision to check out. + * + * If {@link #remote} is {@code url@rev}, then this method + * returns that specific revision. + * + * @param defaultValue + * If "@NNN" portion is not in the URL, this value will be returned. + * Normally, this is the SVN revision timestamped at the build date. + */ + public SVNRevision getRevision(SVNRevision defaultValue) { + int idx = remote.lastIndexOf('@'); + if(idx>0) { + try { + String n = remote.substring(idx+1); + return SVNRevision.create(Long.parseLong(n)); + } catch (NumberFormatException e) { + // not a revision number + } + } + return defaultValue; + } - private String getExpandedRemote(AbstractBuild build) { + private String getExpandedRemote(AbstractBuild build) { String outRemote = remote; - ParametersAction parameters = build - .getAction(ParametersAction.class); + ParametersAction parameters = build.getAction(ParametersAction.class); if (parameters != null) outRemote = parameters.substitute(build, remote); @@ -1496,16 +1541,22 @@ public class SubversionSCM extends SCM implements Serializable { /** * Expand location value based on Build parametric execution. - * + * * @param build * Build instance for expanding parameters into their values - * + * * @return Output ModuleLocation expanded according to Build parameters * values. */ public ModuleLocation getExpandedLocation(AbstractBuild build) { return new ModuleLocation(getExpandedRemote(build), local); } + + public String toString() { + return remote; + } + + private static final long serialVersionUID = 1L; } private static final Logger LOGGER = Logger.getLogger(SubversionSCM.class.getName()); diff --git a/core/src/main/resources/hudson/scm/SubversionSCM/DescriptorImpl/url-help.jelly b/core/src/main/resources/hudson/scm/SubversionSCM/DescriptorImpl/url-help.jelly index 709d73fb3c522eb3af4cbe88f9b88ddaf3d060fe..4ce394f432d635b3575320e66baaf49396db06e5 100644 --- a/core/src/main/resources/hudson/scm/SubversionSCM/DescriptorImpl/url-help.jelly +++ b/core/src/main/resources/hudson/scm/SubversionSCM/DescriptorImpl/url-help.jelly @@ -2,6 +2,7 @@
${%description.1} + ${%description.explicitRevision}
${%description.2(rootURL)}
diff --git a/core/src/main/resources/hudson/scm/SubversionSCM/DescriptorImpl/url-help.properties b/core/src/main/resources/hudson/scm/SubversionSCM/DescriptorImpl/url-help.properties index f15de0a5214a2da6a7571ac8ab7007af5de89a5d..9396b6aab4ecac29290adeaf4dcc9757719352bf 100644 --- a/core/src/main/resources/hudson/scm/SubversionSCM/DescriptorImpl/url-help.properties +++ b/core/src/main/resources/hudson/scm/SubversionSCM/DescriptorImpl/url-help.properties @@ -1,10 +1,14 @@ description.1=\ Specify the subversion repository URL to check out, such as "http://svn.apache.org/repos/asf/ant/". +description.explicitRevision=\ + You can also add "@NNN" at the end of the URL to check out a specific revision number, if that's desirable. description.2=\ - When you enter URL, Hudson automatically checks if Hudson can connect to it. If access requires\ - authentication, it will ask you the necessary credential. If you already have a working\ + When you enter URL, Hudson automatically checks if Hudson can connect to it. If access requires \ + authentication, it will ask you the necessary credential. If you already have a working \ credential but would like to change it for other reasons, \ click this link and specify different credential. description.3=\ - During the build, revision number of the module that was checked out is available\ - through the environment variable SVN_REVISION + During the build, revision number of the module that was checked out is available \ + through the environment variable SVN_REVISION, provided that you are only checking out \ + one module. If you have multiple modules checked out, use \ + the svnversion command. diff --git a/core/src/main/resources/hudson/scm/SubversionSCM/DescriptorImpl/url-help_fr.properties b/core/src/main/resources/hudson/scm/SubversionSCM/DescriptorImpl/url-help_fr.properties index d99d2070430f733074a7f7f5f6a48c0119a6e91d..19273049a72a0cc1246a8fb6158670e98c6e7b84 100644 --- a/core/src/main/resources/hudson/scm/SubversionSCM/DescriptorImpl/url-help_fr.properties +++ b/core/src/main/resources/hudson/scm/SubversionSCM/DescriptorImpl/url-help_fr.properties @@ -1,10 +1,11 @@ +# OUTDATED description.1=\ - Spécifiez l''URL du repository Subversion à lire, par exemple "http://svn.apache.org/repos/asf/ant/". + Sp?cifiez l''URL du repository Subversion ? lire, par exemple "http://svn.apache.org/repos/asf/ant/". description.2=\ - Quand vous entrez une URL, Hudson vérifie automatiquement s''il peut s''y connecter. Si l''accès nécessite \ - une authentification, il vous demandera les informations nécessaires. Si vous avez déjà des informations d''identification \ - qui marchent mais vous voulez tout de même changer, cliquez sur ce lien \ - et indiquez des informations différentes. + Quand vous entrez une URL, Hudson v?rifie automatiquement s''il peut s''y connecter. Si l''acc?s n?cessite \ + une authentification, il vous demandera les informations n?cessaires. Si vous avez d?j? des informations d''identification \ + qui marchent mais vous voulez tout de m?me changer, cliquez sur ce lien \ + et indiquez des informations diff?rentes. description.3=\ - Au cours du build, le numéro de révision du module qui a été récupéré est disponible à travers la variable \ + Au cours du build, le num?ro de r?vision du module qui a ?t? r?cup?r? est disponible ? travers la variable \ d''environnement SVN_REVISION diff --git a/core/src/main/resources/hudson/scm/SubversionSCM/DescriptorImpl/url-help_ja.properties b/core/src/main/resources/hudson/scm/SubversionSCM/DescriptorImpl/url-help_ja.properties index fa768273f0c2936bf2ac306b805645ecfaa36029..4566d0a5abf969181402a266c13a5b25489d4e4c 100644 --- a/core/src/main/resources/hudson/scm/SubversionSCM/DescriptorImpl/url-help_ja.properties +++ b/core/src/main/resources/hudson/scm/SubversionSCM/DescriptorImpl/url-help_ja.properties @@ -1,3 +1,4 @@ +# OUTDATED description.1=\ \u30C1\u30A7\u30C3\u30AF\u30A2\u30A6\u30C8\u3059\u308BSubversion\u306E\u30EA\u30DD\u30B8\u30C8\u30EAURL\u3092\u3001"http://svn.apache.org/repos/asf/ant/"\u306E\u3088\u3046\u306B\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002. description.2=\ diff --git a/test/src/test/java/hudson/scm/SubversionSCMTest.java b/test/src/test/java/hudson/scm/SubversionSCMTest.java index d3b19dee6b471e9b067a146c29d177fcaff277c6..30b899bb7628f5bb6899d799f466f6edc10fb4db 100644 --- a/test/src/test/java/hudson/scm/SubversionSCMTest.java +++ b/test/src/test/java/hudson/scm/SubversionSCMTest.java @@ -104,4 +104,23 @@ public class SubversionSCMTest extends HudsonTestCase { assertBuildStatus(Result.SUCCESS,b); assertTrue(p.getWorkspace().child("jasf/maven.xml").exists()); } + + /** + * Tests the "URL@REV" format in SVN URL. + */ + @Bug(262) + public void testRevisionedCheckout() throws Exception { + FreeStyleProject p = createFreeStyleProject(); + p.setScm(new SubversionSCM( + new String[]{"https://svn.dev.java.net/svn/hudson/trunk/hudson/test-projects/trivial-ant@13000"}, + new String[]{null}, + true, null + )); + + FreeStyleBuild b = p.scheduleBuild2(0).get(); + System.out.println(b.getLog()); + assertTrue(b.getLog().contains("At revision 13000")); + assertBuildStatus(Result.SUCCESS,b); + assertTrue(p.getWorkspace().child("trivial-ant/build.xml").exists()); + } }