diff --git a/core/src/main/java/hudson/model/AbstractProject.java b/core/src/main/java/hudson/model/AbstractProject.java index 4da0cc2ef6664111466a90e47f0d9422c295db51..abea5887b76b72ee3e9fa928ad0ce60c44dcdc89 100644 --- a/core/src/main/java/hudson/model/AbstractProject.java +++ b/core/src/main/java/hudson/model/AbstractProject.java @@ -751,8 +751,13 @@ public abstract class AbstractProject

,R extends A for (JobProperty p : Util.fixNull(properties)) ta.addAll(p.getJobActions((P)this)); - for (TransientProjectActionFactory tpaf : TransientProjectActionFactory.all()) - ta.addAll(Util.fixNull(tpaf.createFor(this))); // be defensive against null + for (TransientProjectActionFactory tpaf : TransientProjectActionFactory.all()) { + try { + ta.addAll(Util.fixNull(tpaf.createFor(this))); // be defensive against null + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error loading transient project action factory."); + } + } return ta; } diff --git a/core/src/main/java/hudson/model/Actionable.java b/core/src/main/java/hudson/model/Actionable.java index ba19d39257960e4fdf77254ad94e9ebd9e3d0c70..ca1332aa0f5f86d7f09675b1bed99fd3f9b3e882 100644 --- a/core/src/main/java/hudson/model/Actionable.java +++ b/core/src/main/java/hudson/model/Actionable.java @@ -30,6 +30,9 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.logging.Level; +import java.util.logging.Logger; + import jenkins.model.ModelObjectWithContextMenu; import jenkins.model.TransientActionFactory; import org.kohsuke.stapler.StaplerRequest; @@ -91,7 +94,11 @@ public abstract class Actionable extends AbstractModelObject implements ModelObj List _actions = new ArrayList(getActions()); for (TransientActionFactory taf : ExtensionList.lookup(TransientActionFactory.class)) { if (taf.type().isInstance(this)) { - _actions.addAll(createFor(taf)); + try { + _actions.addAll(createFor(taf)); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error loading action.", e); + } } } return Collections.unmodifiableList(_actions); @@ -177,4 +184,6 @@ public abstract class Actionable extends AbstractModelObject implements ModelObj @Override public ContextMenu doContextMenu(StaplerRequest request, StaplerResponse response) throws Exception { return new ContextMenu().from(this,request,response); } + + private static final Logger LOGGER = Logger.getLogger(Actionable.class.getName()); } diff --git a/core/src/main/java/hudson/model/Project.java b/core/src/main/java/hudson/model/Project.java index 701ed893f7df0b5092fc63e187d4e730768308a4..894bb612d7e88a49e0f2f84aafcf1900a538496f 100644 --- a/core/src/main/java/hudson/model/Project.java +++ b/core/src/main/java/hudson/model/Project.java @@ -52,6 +52,9 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import java.util.logging.Level; +import java.util.logging.Logger; + import jenkins.triggers.SCMTriggerItem; /** @@ -234,15 +237,37 @@ public abstract class Project

,B extends Build> protected List createTransientActions() { List r = super.createTransientActions(); - for (BuildStep step : getBuildersList()) - r.addAll(step.getProjectActions(this)); - for (BuildStep step : getPublishersList()) - r.addAll(step.getProjectActions(this)); - for (BuildWrapper step : getBuildWrappers().values()) - r.addAll(step.getProjectActions(this)); - for (Trigger trigger : triggers()) - r.addAll(trigger.getProjectActions()); + for (BuildStep step : getBuildersList()) { + try { + r.addAll(step.getProjectActions(this)); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error loading build step.", e); + } + } + for (BuildStep step : getPublishersList()) { + try { + r.addAll(step.getProjectActions(this)); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error loading publisher.", e); + } + } + for (BuildWrapper step : getBuildWrappers().values()) { + try { + r.addAll(step.getProjectActions(this)); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error loading build wrapper.", e); + } + } + for (Trigger trigger : triggers()) { + try { + r.addAll(trigger.getProjectActions()); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error loading trigger.", e); + } + } return r; } + + private static final Logger LOGGER = Logger.getLogger(Project.class.getName()); } diff --git a/test/src/test/java/hudson/model/ItemGroupMixInTest.java b/test/src/test/java/hudson/model/ItemGroupMixInTest.java index b5514329d2b31e852814da8465efbe135533ab70..2a95dbe7a5fcca65119e9a15b9a037504ad4c584 100644 --- a/test/src/test/java/hudson/model/ItemGroupMixInTest.java +++ b/test/src/test/java/hudson/model/ItemGroupMixInTest.java @@ -24,11 +24,15 @@ package hudson.model; -import java.util.Collection; -import static org.junit.Assert.*; import hudson.Extension; +import hudson.tasks.BuildStepDescriptor; +import hudson.tasks.BuildStepMonitor; +import hudson.tasks.BuildTrigger; import hudson.tasks.BuildWrapper; import hudson.tasks.BuildWrapperDescriptor; +import hudson.tasks.Builder; +import hudson.tasks.Publisher; +import hudson.triggers.Trigger; import org.apache.commons.io.FileUtils; import org.junit.Rule; import org.junit.Test; @@ -39,8 +43,14 @@ import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.recipes.LocalData; import java.io.File; +import java.util.Collection; +import java.util.Iterator; import java.util.List; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + public class ItemGroupMixInTest { @Rule public JenkinsRule r = new JenkinsRule(); @@ -103,12 +113,17 @@ public class ItemGroupMixInTest { MockFolder d = r.jenkins.getItemByFullName("d", MockFolder.class); assertNotNull(d); Collection items = d.getItems(); - assertEquals(1, items.size()); - assertEquals("valid", items.iterator().next().getName()); + assertEquals(5, items.size()); + Iterator iterator = items.iterator(); + assertEquals("badBuildStep", iterator.next().getName()); + assertEquals("badBuildTrigger", iterator.next().getName()); + assertEquals("badBuildWrapper", iterator.next().getName()); + assertEquals("badPublisher", iterator.next().getName()); + assertEquals("valid", iterator.next().getName()); } @TestExtension - public static class MockBuilderThrowsError extends BuildWrapper { + public static class MockBuildWrapperThrowsError extends BuildWrapper { @Override public Collection getProjectActions(AbstractProject project){ throw new NullPointerException(); @@ -127,4 +142,62 @@ public class ItemGroupMixInTest { } } } + + @TestExtension + public static class MockBuilderThrowsError extends Builder { + @Override + public Collection getProjectActions(AbstractProject project){ + throw new NullPointerException(); + } + @Extension public static final Descriptor DESCRIPTOR = new DescriptorImpl(); + + public static class DescriptorImpl extends BuildStepDescriptor { + @Override + public boolean isApplicable(Class jobType) { + return false; + } + + @Override + public String getDisplayName() { + return null; + } + } + } + + @TestExtension + public static class MockBuildTriggerThrowsError extends Trigger { + @Override + public Collection getProjectActions() { + throw new NullPointerException(); + } + + @Extension public static final Descriptor DESCRIPTOR = new BuildTrigger.DescriptorImpl(); + } + + @TestExtension + public static class MockPublisherThrowsError extends Publisher { + @Override + public Collection getProjectActions(AbstractProject project) { + throw new NullPointerException(); + } + + @Override + public BuildStepMonitor getRequiredMonitorService() { + return null; + } + + @Extension public static final Descriptor DESCRIPTOR = new DescriptorImpl(); + + public static class DescriptorImpl extends BuildStepDescriptor { + @Override + public boolean isApplicable(Class jobType) { + return false; + } + + @Override + public String getDisplayName() { + return null; + } + } + } } diff --git a/test/src/test/resources/hudson/model/ItemGroupMixInTest/xmlFileReadExceptionOnLoad.zip b/test/src/test/resources/hudson/model/ItemGroupMixInTest/xmlFileReadExceptionOnLoad.zip index 70b2d12f980864ecc812c3c6b8c589a91d57d6d9..21a4e02c26b6940478b20acf97d8e4b64bb0399c 100644 Binary files a/test/src/test/resources/hudson/model/ItemGroupMixInTest/xmlFileReadExceptionOnLoad.zip and b/test/src/test/resources/hudson/model/ItemGroupMixInTest/xmlFileReadExceptionOnLoad.zip differ