Skip to content

Commit

Permalink
Recover views after error in Jenkins.load (#10023)
Browse files Browse the repository at this point in the history
* Recover views after error in `Jenkins.load`

* Prevent infinite recursion in `Jenkins/sidepanel.jelly` when `Jenkins.primaryView` is null

---------

Co-authored-by: Tim Jacomb <[email protected]>
  • Loading branch information
jglick and timja authored Dec 12, 2024
1 parent d773eb9 commit 4943f16
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 4 deletions.
14 changes: 11 additions & 3 deletions core/src/main/java/jenkins/model/Jenkins.java
Original file line number Diff line number Diff line change
Expand Up @@ -3297,11 +3297,19 @@ public void load() throws IOException {
if (cfg.exists()) {
// reset some data that may not exist in the disk file
// so that we can take a proper compensation action later.
String originalPrimaryView = primaryView;
List<View> originalViews = new ArrayList<>(views);
primaryView = null;
views.clear();

// load from disk
cfg.unmarshal(Jenkins.this);
try {
// load from disk
cfg.unmarshal(Jenkins.this);
} catch (IOException | RuntimeException x) {
primaryView = originalPrimaryView;
views.clear();
views.addAll(originalViews);
throw x;
}
}
// initialize views by inserting the default view if necessary
// this is both for clean Jenkins and for backward compatibility.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,9 @@ THE SOFTWARE.
-->

<?jelly escape-by-default='true'?>
<st:include it="${it.primaryView}" page="sidepanel.jelly" xmlns:st="jelly:stapler" />
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler">
<j:set var="primaryView" value="${it.primaryView}"/>
<j:if test="${primaryView != null}">
<st:include it="${primaryView}" page="sidepanel.jelly"/>
</j:if>
</j:jelly>
16 changes: 16 additions & 0 deletions test/src/test/java/jenkins/model/JenkinsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@
import static org.awaitility.Awaitility.await;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isA;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
Expand All @@ -46,6 +48,7 @@
import hudson.XmlFile;
import hudson.init.InitMilestone;
import hudson.init.Initializer;
import hudson.model.AllView;
import hudson.model.Computer;
import hudson.model.Failure;
import hudson.model.FreeStyleProject;
Expand Down Expand Up @@ -101,6 +104,7 @@
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.TemporaryFolder;
import org.jvnet.hudson.reactor.ReactorException;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.JenkinsRule.WebClient;
Expand Down Expand Up @@ -755,4 +759,16 @@ public String getUrlName() {
return null;
}
}

@Test
public void reloadViews() throws Exception {
assertThat(j.jenkins.getPrimaryView(), isA(AllView.class));
assertThat(j.jenkins.getViews(), contains(isA(AllView.class)));
Files.writeString(j.jenkins.getConfigFile().getFile().toPath(), "<broken");
assertThrows(ReactorException.class, j.jenkins::reload);
j.createWebClient().goTo("manage/");
assertThat(j.jenkins.getPrimaryView(), isA(AllView.class));
assertThat(j.jenkins.getViews(), contains(isA(AllView.class)));
}

}

0 comments on commit 4943f16

Please sign in to comment.