Skip to content
This repository has been archived by the owner on Dec 15, 2021. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #97 from jglick/StackOverflowError-JENKINS-27531
[JENKINS-27531] Run.id-related error in 1.597+
  • Loading branch information
jglick committed Mar 23, 2015
2 parents f9c9213 + bdf1260 commit b5617c5
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Expand Up @@ -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)

Expand Down
Expand Up @@ -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 {

Expand All @@ -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());
Expand All @@ -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"))));
Expand All @@ -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"+
Expand Down Expand Up @@ -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() {
Expand All @@ -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));
}

}
Binary file not shown.
Expand Up @@ -41,6 +41,7 @@
import hudson.model.Queue;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.RunMap;
import hudson.model.StreamBuildListener;
import hudson.model.TaskListener;
import hudson.model.listeners.RunListener;
Expand All @@ -54,6 +55,7 @@
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
Expand Down Expand Up @@ -341,8 +343,42 @@ protected void eol(byte[] b, int len) throws IOException {

private static final Map<String,WorkflowRun> LOADING_RUNS = new HashMap<String,WorkflowRun>();

/**
* 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<WorkflowRun> runMap = r.getParent()._getRuns();
Field runIdMigratorF = RunMap.class.getField("runIdMigrator");
Object runIdMigratorO = runIdMigratorF.get(runMap);
Field idToNumberF = runIdMigratorC.getDeclaredField("idToNumber");
idToNumberF.setAccessible(true);
Map<String,Integer> idToNumberO = (Map<String,Integer>) idToNumberF.get(runIdMigratorO);
int n = r.getNumber();
for (Map.Entry<String,Integer> 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. */
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit b5617c5

Please sign in to comment.