From ace3257db76eec36a53c87e574c266a9ccf46ccc Mon Sep 17 00:00:00 2001 From: jbq Date: Thu, 6 Sep 2007 15:56:09 +0000 Subject: [PATCH] Issue number: 763 Gracefully handle project deleted in SVN. Had to make AbstractProject.disabled field public, but we might want to find a more elegant solution for this. I've seen other fields public in Hudson, so I guess it's OK, but I'd rather put some more setters everywhere... git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@4665 71c3de6d-444a-0410-be80-ed276b4c234a --- .../java/hudson/model/AbstractProject.java | 24 +++++----- .../main/java/hudson/scm/SubversionSCM.java | 47 +++++++++++++++---- 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/core/src/main/java/hudson/model/AbstractProject.java b/core/src/main/java/hudson/model/AbstractProject.java index aebc116f01..2688d8144d 100644 --- a/core/src/main/java/hudson/model/AbstractProject.java +++ b/core/src/main/java/hudson/model/AbstractProject.java @@ -3,44 +3,46 @@ package hudson.model; import hudson.FeedAdapter; import hudson.FilePath; import hudson.Launcher; -import hudson.search.SearchIndexBuilder; -import hudson.tasks.BuildTrigger; import hudson.maven.MavenModule; import hudson.model.Descriptor.FormException; import hudson.model.Fingerprint.RangeSet; import hudson.model.RunMap.Constructor; import hudson.scm.ChangeLogSet; -import hudson.scm.ChangeLogSet.Entry; import hudson.scm.NullSCM; import hudson.scm.SCM; import hudson.scm.SCMS; +import hudson.scm.ChangeLogSet.Entry; +import hudson.search.SearchIndexBuilder; +import hudson.tasks.BuildTrigger; import hudson.triggers.Trigger; import hudson.triggers.TriggerDescriptor; import hudson.triggers.Triggers; import hudson.util.EditDistance; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; -import org.kohsuke.stapler.export.Exported; -import javax.servlet.ServletException; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.Vector; -import java.util.Set; -import java.util.Collections; -import java.util.HashSet; import java.util.logging.Level; import java.util.logging.Logger; +import javax.servlet.ServletException; + +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.export.Exported; + /** * Base implementation of {@link Job}s that build software. * @@ -92,7 +94,7 @@ public abstract class AbstractProject

,R extends A /** * True to suspend new builds. */ - protected boolean disabled; + public boolean disabled; /** * Identifies {@link JDK} to be used. diff --git a/core/src/main/java/hudson/scm/SubversionSCM.java b/core/src/main/java/hudson/scm/SubversionSCM.java index d53032a8f8..456e076170 100644 --- a/core/src/main/java/hudson/scm/SubversionSCM.java +++ b/core/src/main/java/hudson/scm/SubversionSCM.java @@ -292,7 +292,7 @@ public class SubversionSCM extends SCM implements Serializable { } public boolean checkout(AbstractBuild build, Launcher launcher, FilePath workspace, final BuildListener listener, File changelogFile) throws IOException, InterruptedException { - List externals = checkout(build.getTimestamp().getTime(),workspace,listener); + List externals = checkout(build,workspace,listener); if(externals==null) return false; @@ -333,9 +333,14 @@ public class SubversionSCM extends SCM implements Serializable { * if the operation failed. Otherwise the set of local workspace paths * (relative to the workspace root) that has loaded due to svn:external. */ - private List checkout(Date timestamp, FilePath workspace, TaskListener listener) throws IOException, InterruptedException { - boolean isUpdatable = useUpdate && workspace.act(new IsUpdatableTask(this, listener)); - return workspace.act(new CheckOutTask(this, timestamp, isUpdatable, listener)); + private List checkout(AbstractBuild build, FilePath workspace, TaskListener listener) throws IOException, InterruptedException { + if (projectDeleted(listener)) { + // Disable this project, see issue #763 + build.getProject().disabled = true; + return null; + } + Boolean isUpdatable = useUpdate && workspace.act(new IsUpdatableTask(this, listener)); + return workspace.act(new CheckOutTask(this, build.getTimestamp().getTime(), isUpdatable, listener)); } private static class CheckOutTask implements FileCallable> { @@ -487,7 +492,7 @@ public class SubversionSCM extends SCM implements Serializable { * @param remoteUrl * The target to run "svn info". */ - private SVNInfo parseSvnInfo(SVNURL remoteUrl, ISVNAuthenticationProvider authProvider) throws SVNException { + private static SVNInfo parseSvnInfo(SVNURL remoteUrl, ISVNAuthenticationProvider authProvider) throws SVNException { SVNWCClient svnWc = createSvnClientManager(authProvider).getWCClient(); return svnWc.doInfo(remoteUrl, SVNRevision.HEAD, SVNRevision.HEAD); } @@ -561,26 +566,28 @@ public class SubversionSCM extends SCM implements Serializable { private final TaskListener listener; private final ISVNAuthenticationProvider authProvider; private final ModuleLocation[] locations; - + IsUpdatableTask(SubversionSCM parent,TaskListener listener) { this.authProvider = parent.getDescriptor().createAuthenticationProvider(); this.listener = listener; this.locations = parent.getLocations(); } - + 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 - + if(!module.exists()) { listener.getLogger().println("Checking out a fresh workspace because "+module+" doesn't exist"); return false; } - + try { - SvnInfo svnInfo = new SvnInfo(parseSvnInfo(module, authProvider)); + SVNInfo svnkitInfo = parseSvnInfo(module, authProvider); + SvnInfo svnInfo = new SvnInfo(svnkitInfo); + if(!svnInfo.url.equals(url)) { listener.getLogger().println("Checking out a fresh workspace because the workspace is not "+url); return false; @@ -596,6 +603,26 @@ public class SubversionSCM extends SCM implements Serializable { private static final long serialVersionUID = 1L; } + /** + * Returns true if the project does not exist in SVN anymore + */ + public boolean projectDeleted(TaskListener listener) { + for (ModuleLocation l : locations) { + String url = l.remote; + try { + ISVNAuthenticationProvider authProvider = getDescriptor().createAuthenticationProvider(); + // This will throw an SVNException if the remote path does not exist anymore + parseSvnInfo(SVNURL.parseURIDecoded(url), authProvider); + } catch (SVNException e) { + // issue #763 Gracefully handle project deleted in SVN + listener.getLogger().println("Project does not exist anymore in SVN: " + url); + e.printStackTrace(listener.error(e.getMessage())); + return true; + } + } + return false; + } + public boolean pollChanges(AbstractProject project, Launcher launcher, FilePath workspace, TaskListener listener) throws IOException, InterruptedException { AbstractBuild lastBuild = (AbstractBuild) project.getLastBuild(); if(lastBuild==null) { -- GitLab