Skip to content

Commit

Permalink
Polling fix for Multi client support in Pipeline.
Browse files Browse the repository at this point in the history
Jenkins polls for each SCM checkout, so must poll each workplace and
therefore need to lookup last build information for each sync.
Polling now uses same lookup as Change Summary.

Added extra test cases multi sync poll and poll again.

JENKINS-38401
JENKINS-37462
JENKINS-39652
  • Loading branch information
p4paul committed Dec 5, 2016
1 parent ad88e96 commit fb52353
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 48 deletions.
19 changes: 7 additions & 12 deletions src/main/java/org/jenkinsci/plugins/p4/PerforceScm.java
Expand Up @@ -268,22 +268,15 @@ public PollingResult compareRemoteRevisionWith(Job<?, ?> job, Launcher launcher,
return PollingResult.NO_CHANGES;
}

// Get change for last run
// Get last run and build workspace
Run<?, ?> lastRun = job.getLastBuild();
P4Revision last = TagAction.getHighestChange(lastRun, listener);

// if no previous run then build now.
if (last == null) {
return PollingResult.BUILD_NOW;
}

buildWorkspace = j.getRootPath();

if (job instanceof MatrixProject) {
if (isBuildParent(job)) {
// Poll PARENT only
EnvVars envVars = job.getEnvironment(node, listener);
state = pollWorkspace(envVars, listener, buildWorkspace, last);
state = pollWorkspace(envVars, listener, buildWorkspace, lastRun);
} else {
// Poll CHILDREN only
MatrixProject matrixProj = (MatrixProject) job;
Expand All @@ -292,7 +285,7 @@ public PollingResult compareRemoteRevisionWith(Job<?, ?> job, Launcher launcher,

for (MatrixConfiguration config : configs) {
EnvVars envVars = config.getEnvironment(node, listener);
state = pollWorkspace(envVars, listener, buildWorkspace, last);
state = pollWorkspace(envVars, listener, buildWorkspace, lastRun);
// exit early if changes found
if (state == PollingResult.BUILD_NOW) {
return PollingResult.BUILD_NOW;
Expand All @@ -301,7 +294,7 @@ public PollingResult compareRemoteRevisionWith(Job<?, ?> job, Launcher launcher,
}
} else {
EnvVars envVars = job.getEnvironment(node, listener);
state = pollWorkspace(envVars, listener, buildWorkspace, last);
state = pollWorkspace(envVars, listener, buildWorkspace, lastRun);
}

return state;
Expand All @@ -315,7 +308,7 @@ public PollingResult compareRemoteRevisionWith(Job<?, ?> job, Launcher launcher,
* @throws InterruptedException
* @throws IOException
*/
private PollingResult pollWorkspace(EnvVars envVars, TaskListener listener, FilePath buildWorkspace, P4Revision last)
private PollingResult pollWorkspace(EnvVars envVars, TaskListener listener, FilePath buildWorkspace, Run<?, ?> lastRun)
throws InterruptedException, IOException {
PrintStream log = listener.getLogger();

Expand Down Expand Up @@ -346,6 +339,8 @@ private PollingResult pollWorkspace(EnvVars envVars, TaskListener listener, File
ws.getExpand().set(ReviewProp.LABEL.toString(), pin);
}

P4Revision last = TagAction.getLastChange(lastRun, listener, client);

// Create task
PollTask task = new PollTask(filter, last);
task.setCredential(credential);
Expand Down
36 changes: 5 additions & 31 deletions src/main/java/org/jenkinsci/plugins/p4/tagging/TagAction.java
Expand Up @@ -179,21 +179,21 @@ public Label getLabel(String tag) throws Exception {
/**
* Change reporting...
*
* @param run The current build
* @param run The current build
* @param listener Listener for logging
* @return Perforce change
*/
public static P4Revision getLastChange(Run<?, ?> run, TaskListener listener, String client) {
P4Revision last = null;

List<TagAction> actions = lastActions(run, listener);
if(actions == null || client == null || client.isEmpty()) {
if (actions == null || client == null || client.isEmpty()) {
return last;
}

// look for action matching view
for (TagAction action : actions) {
if(client.equals(action.getClient())) {
if (client.equals(action.getClient())) {
last = action.getBuildChange();
}
}
Expand All @@ -205,13 +205,13 @@ public static P4Revision getLastChange(Run<?, ?> run, TaskListener listener, Str
/**
* Find the last action; use this for environment variable as the last action has the latest values.
*
* @param run The current build
* @param run The current build
* @param listener Listener for logging
* @return Action
*/
public static TagAction getLastAction(Run<?, ?> run, TaskListener listener) {
List<TagAction> actions = lastActions(run, listener);
if(actions == null) {
if (actions == null) {
return null;
}

Expand All @@ -220,32 +220,6 @@ public static TagAction getLastAction(Run<?, ?> run, TaskListener listener) {
return last;
}

/**
* Find the change with the highest change number, use this for polling. This isn't accurate if multiple
* workspaces are polled and are disjoint, but is accurate if the workspaces are subsets of each other.
*
* @param run The current build
* @param listener Listener for logging
* @return Perforce change
*/
public static P4Revision getHighestChange(Run<?, ?> run, TaskListener listener) {
List<TagAction> actions = lastActions(run, listener);
if(actions == null) {
return null;
}

// found previous build, set last change to the first action found.
TagAction last = actions.get(0);

// look for highest change number
for (TagAction action : actions) {
if (action.getBuildChange().compareTo(last.getBuildChange()) > 0) {
last = action;
}
}
return last.getBuildChange();
}

private static List<TagAction> lastActions(Run<?, ?> run, TaskListener listener) {
// get last run, if none then build now.
if (run == null) {
Expand Down
15 changes: 10 additions & 5 deletions src/main/java/org/jenkinsci/plugins/p4/tasks/AbstractTask.java
Expand Up @@ -109,11 +109,16 @@ public Workspace setEnvironment(Run<?, ?> run, Workspace wsType, FilePath buildW
setWorkspace(ws);

// Template workspace to .cloneN (where N is the @ number)
String charset = ws.getCharset();
boolean pin = ws.isPinHost();
String template = client + ".clone" + exec;
ws = new TemplateWorkspaceImpl(charset, pin, client, template);
ws.setExpand(envVars);
try {
int n = Integer.parseInt(exec);
String charset = ws.getCharset();
boolean pin = ws.isPinHost();
String template = client + ".clone" + n;
ws = new TemplateWorkspaceImpl(charset, pin, client, template);
ws.setExpand(envVars);
} catch (NumberFormatException e) {
// do not template; e.g. 'script' keeps original name
}
}
ws.setRootPath(root);

Expand Down
89 changes: 89 additions & 0 deletions src/test/java/org/jenkinsci/plugins/p4/client/JenkinsfileTest.java
Expand Up @@ -229,6 +229,95 @@ public void testMulitSync() throws Exception {
jenkins.assertLogContains("Found last change 13 on client jenkins-master-multiSync-2", run2);
}

@Test
public void testMulitSyncPolling() throws Exception {

String content1 = ""
+ "node {\n"
+ " p4sync charset: 'none', credential: '" + CREDENTIAL + "',\n"
+ " format: 'jenkins-${NODE_NAME}-${JOB_NAME}-1',\n"
+ " depotPath: '//depot/Data',\n"
+ " populate: [$class: 'AutoCleanImpl', pin: '17', quiet: true]\n"
+ " p4sync charset: 'none', credential: '" + CREDENTIAL + "',\n"
+ " format: 'jenkins-${NODE_NAME}-${JOB_NAME}-2',\n"
+ " depotPath: '//depot/Main',\n"
+ " populate: [$class: 'AutoCleanImpl', pin: '13', quiet: true]\n"
+ "}";

submitFile("//depot/Data/Jenkinsfile", content1);

// Manual workspace spec definition
String client = "jenkins-${NODE_NAME}-${JOB_NAME}-script";
String stream = null;
String line = "LOCAL";
String view = "//depot/Data/Jenkinsfile //" + client + "/Jenkinsfile";
WorkspaceSpec spec = new WorkspaceSpec(false, false, false, false, false, false, stream, line, view);
ManualWorkspaceImpl workspace = new ManualWorkspaceImpl("none", true, client, spec);

// SCM and Populate options
Populate populate = new AutoCleanImpl();
PerforceScm scm = new PerforceScm(CREDENTIAL, workspace, populate);

// SCM Jenkinsfile job
WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "multiSync");
job.setDefinition(new CpsScmFlowDefinition(scm, "Jenkinsfile"));

// Build 1
WorkflowRun run1 = job.scheduleBuild2(0).get();
jenkins.assertBuildStatusSuccess(run1);
assertEquals(1, job.getLastBuild().getNumber());
jenkins.assertLogContains("P4 Task: syncing files at change: 17", run1);
jenkins.assertLogContains("P4 Task: syncing files at change: 13", run1);

String content2 = ""
+ "node {\n"
+ " p4sync charset: 'none', credential: '" + CREDENTIAL + "',\n"
+ " format: 'jenkins-${NODE_NAME}-${JOB_NAME}-1',\n"
+ " depotPath: '//depot/Data',\n"
+ " populate: [$class: 'AutoCleanImpl', pin: '', quiet: true]\n"
+ " p4sync charset: 'none', credential: '" + CREDENTIAL + "',\n"
+ " format: 'jenkins-${NODE_NAME}-${JOB_NAME}-2',\n"
+ " depotPath: '//depot/Main',\n"
+ " populate: [$class: 'AutoCleanImpl', pin: '14', quiet: true]\n"
+ "}";

submitFile("//depot/Data/Jenkinsfile", content2);

// Build 2
WorkflowRun run2 = job.scheduleBuild2(0).get();
jenkins.assertBuildStatusSuccess(run2);
assertEquals(2, job.getLastBuild().getNumber());
jenkins.assertLogContains("P4 Task: syncing files at change: 42", run2);
jenkins.assertLogContains("P4 Task: syncing files at change: 14", run2);
jenkins.assertLogContains("Found last change 17 on client jenkins-master-multiSync-1", run2);
jenkins.assertLogContains("Found last change 13 on client jenkins-master-multiSync-2", run2);

// Add a trigger
P4Trigger trigger = new P4Trigger();
trigger.start(job, false);
job.addTrigger(trigger);
job.save();

// Add change to //depot/Data/...
submitFile("//depot/Data/new01", "Content");

// Test trigger, build 3
trigger.poke(job, auth.getP4port());
TimeUnit.SECONDS.sleep(job.getQuietPeriod());
jenkins.waitUntilNoActivity();
assertEquals(3, job.getLastBuild().getNumber());

List<String> log = job.getLastBuild().getLog(1000);
assertTrue(log.contains("Found last change 42 on client jenkins-master-multiSync-1"));
assertTrue(log.contains("Found last change 14 on client jenkins-master-multiSync-2"));

// Test trigger, no change
trigger.poke(job, auth.getP4port());
TimeUnit.SECONDS.sleep(job.getQuietPeriod());
jenkins.waitUntilNoActivity();
assertEquals(3, job.getLastBuild().getNumber());
}

private void submitFile(String path, String content) throws Exception {
String filename = path.substring(path.lastIndexOf("/") + 1, path.length());

Expand Down

0 comments on commit fb52353

Please sign in to comment.