From bdf1260dcafaf43bac23ec5d76f01916bc432e64 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Fri, 20 Mar 2015 17:52:25 -0400 Subject: [PATCH] [FIXED JENKINS-27531] In 1.597+ Run.getId() is not reliable while it is still being loaded. --- CHANGES.md | 1 + .../plugins/workflow/WorkflowRunTest.java | 19 ++++++++- .../loadMigratedBuildRecord.zip | Bin 0 -> 4674 bytes .../plugins/workflow/job/WorkflowRun.java | 40 +++++++++++++++++- 4 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 aggregator/src/test/resources/org/jenkinsci/plugins/workflow/WorkflowRunTest/loadMigratedBuildRecord.zip diff --git a/CHANGES.md b/CHANGES.md index f0e47058c..825d482ed 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ Only noting significant user-visible or major API changes, not internal code cle * Now based on Jenkins core 1.596.1. * Avoid some possible name clashes with function names in scripts (`build` reported). +* [JENKINS-27531](https://issues.jenkins-ci.org/browse/JENKINS-27531): startup error in 1.597+ loading build records migrated from before 1.597. ## 1.4 (Mar 16 2015) diff --git a/aggregator/src/test/java/org/jenkinsci/plugins/workflow/WorkflowRunTest.java b/aggregator/src/test/java/org/jenkinsci/plugins/workflow/WorkflowRunTest.java index 961e77e2d..45d599786 100644 --- a/aggregator/src/test/java/org/jenkinsci/plugins/workflow/WorkflowRunTest.java +++ b/aggregator/src/test/java/org/jenkinsci/plugins/workflow/WorkflowRunTest.java @@ -55,6 +55,7 @@ import org.junit.Test; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.recipes.LocalData; public class WorkflowRunTest { @@ -67,11 +68,11 @@ public class WorkflowRunTest { @Before public void setUp() throws Exception { - p = r.jenkins.createProject(WorkflowJob.class, "p"); r.jenkins.getInjector().injectMembers(this); } @Test public void basics() throws Exception { + p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("println('hello')")); WorkflowRun b1 = r.assertBuildStatusSuccess(p.scheduleBuild2(0)); assertFalse(b1.isBuilding()); @@ -85,6 +86,7 @@ public void setUp() throws Exception { } @Test public void parameters() throws Exception { + p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("node {sh('echo param=' + PARAM)}",true)); p.addProperty(new ParametersDefinitionProperty(new StringParameterDefinition("PARAM", null))); WorkflowRun b = r.assertBuildStatusSuccess(p.scheduleBuild2(0, new ParametersAction(new StringParameterValue("PARAM", "value")))); @@ -99,7 +101,7 @@ public void iconColor() throws Exception { // marker file I use for synchronization FilePath test = new FilePath(r.jenkins.root).child("touch"); - + p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition( "println('hello')\n"+ "watch(new File('"+test.getRemote()+"'))\n"+ @@ -169,6 +171,7 @@ public void iconColor() throws Exception { gmas.add(p, "devel"); } r.jenkins.setAuthorizationStrategy(gmas); + p = r.jenkins.createProject(WorkflowJob.class, "p"); final String groovy = "println 'hello'"; ACL.impersonate(User.get("devel").impersonate(), new Runnable() { @Override public void run() { @@ -194,7 +197,19 @@ private void assertColor(WorkflowRun b, BallColor color) throws IOException { @Test @Issue("JENKINS-25630") public void contextInjectionOfSubParameters() throws Exception { // see SubtypeInjectingStep + p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("node('master') { injectSubtypesAsContext() }")); r.assertBuildStatusSuccess(p.scheduleBuild2(0)); } + + @Issue("JENKINS-27531") + @LocalData + @Test public void loadMigratedBuildRecord() throws Exception { + WorkflowJob p = r.jenkins.getItemByFullName("p", WorkflowJob.class); + assertNotNull(p); + WorkflowRun b = p.getLastBuild(); + assertNotNull(b); + r.assertBuildStatusSuccess(JenkinsRuleExt.waitForCompletion(b)); + } + } diff --git a/aggregator/src/test/resources/org/jenkinsci/plugins/workflow/WorkflowRunTest/loadMigratedBuildRecord.zip b/aggregator/src/test/resources/org/jenkinsci/plugins/workflow/WorkflowRunTest/loadMigratedBuildRecord.zip new file mode 100644 index 0000000000000000000000000000000000000000..14c10ca4c472f289328e9bbbaf9b9e6dbd50cddf GIT binary patch literal 4674 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 w LOADING_RUNS = new HashMap(); + /** + * Same as {@link Run#getId} except it works before the run has been loaded from disk. + * TODO JENKINS-27531 this logic should be handled directly in Run.getId() instead. + */ + private static String getId(WorkflowRun r) { + String id = r.getId(); + Class runIdMigratorC; + try { + runIdMigratorC = Class.forName("jenkins.model.RunIdMigrator"); + } catch (ClassNotFoundException x) { + // 1.596 or earlier, so the ID is fine. + return id; + } + try { + RunMap runMap = r.getParent()._getRuns(); + Field runIdMigratorF = RunMap.class.getField("runIdMigrator"); + Object runIdMigratorO = runIdMigratorF.get(runMap); + Field idToNumberF = runIdMigratorC.getDeclaredField("idToNumber"); + idToNumberF.setAccessible(true); + Map idToNumberO = (Map) idToNumberF.get(runIdMigratorO); + int n = r.getNumber(); + for (Map.Entry entry : idToNumberO.entrySet()) { + if (entry.getValue().equals(n)) { + id = entry.getKey(); + LOGGER.log(Level.FINE, "recovered legacy ID {0} for {1}", new Object[] {id, r}); + return id; + } + } + } catch (Exception x) { + LOGGER.log(Level.WARNING, null, x); + } + return id; + } + private String key() { - return getParent().getFullName() + '/' + getId(); + return getParent().getFullName() + '/' + getId(this); } /** Hack to allow {@link #execution} to use an {@link Owner} referring to this run, even when it has not yet been loaded. */ @@ -541,7 +577,7 @@ private String key() { synchronized (LOADING_RUNS) { candidate = LOADING_RUNS.get(key()); } - if (candidate != null && candidate.getParent().getFullName().equals(job) && candidate.getId().equals(id)) { + if (candidate != null && candidate.getParent().getFullName().equals(job) && getId(candidate).equals(id)) { run = candidate; } else { Jenkins jenkins = Jenkins.getInstance();