package org.jenkinsci.plugins.p4.tasks; import java.io.IOException; import java.io.Serializable; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; import org.jenkinsci.plugins.p4.client.ClientHelper; import org.jenkinsci.plugins.p4.client.ConnectionHelper; import org.jenkinsci.plugins.p4.credentials.P4BaseCredentials; import org.jenkinsci.plugins.p4.review.ReviewProp; import org.jenkinsci.plugins.p4.workspace.TemplateWorkspaceImpl; import org.jenkinsci.plugins.p4.workspace.Workspace; import hudson.AbortException; import hudson.EnvVars; import hudson.FilePath; import hudson.model.Run; import hudson.model.TaskListener; public abstract class AbstractTask implements Serializable { private static final long serialVersionUID = 1L; private static Logger logger = Logger.getLogger(AbstractTask.class.getName()); private P4BaseCredentials credential; private TaskListener listener; private String client; private String charset; transient private Workspace workspace; /** * Implements the Perforce task to retry if necessary * * @param p4 * @throws Exception */ public abstract Object task(ClientHelper p4) throws Exception; public P4BaseCredentials getCredential() { return credential; } public void setCredential(String credential) { this.credential = ConnectionHelper.findCredential(credential); } public TaskListener getListener() { return listener; } public void setListener(TaskListener listener) { this.listener = listener; } public void setWorkspace(Workspace workspace) throws AbortException { this.workspace = workspace; this.client = workspace.getFullName(); this.charset = workspace.getCharset(); // setup the client workspace to use for the build. ClientHelper p4 = getConnection(); // Check connection (might be on remote slave) if (!checkConnection(p4)) { String err = "P4: Abort, no server connection.\n"; logger.severe(err); p4.log(err); throw new AbortException(err); } // Set the client try { p4.setClient(workspace); p4.log("... client: " + getClient()); } catch (Exception e) { String err = "P4: Unable to setup workspace: " + e; logger.severe(err); p4.log(err); throw new AbortException(err); } finally { p4.disconnect(); } } public Workspace setEnvironment(Run<?, ?> run, Workspace wsType, FilePath buildWorkspace) throws IOException, InterruptedException { Workspace ws = (Workspace) wsType.clone(); // Set environment EnvVars envVars = run.getEnvironment(listener); envVars.put("NODE_NAME", envVars.get("NODE_NAME", "master")); ws.setExpand(envVars); // Set workspace root (check for parallel execution) String root = buildWorkspace.getRemote(); if (root.contains("@")) { root = root.replace("@", "%40"); String client = ws.getFullName(); String name = buildWorkspace.getName(); String[] parts = name.split("@"); String exec = parts[1]; // Update Workspace before cloning 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); } ws.setRootPath(root); if (ws.isPinHost()) { String hostname = getHostName(buildWorkspace); ws.setHostName(hostname); } else { ws.setHostName(""); } return ws; } public Workspace setNextChange(Workspace ws, List<Integer> changes) { // Set label for changes to build if (changes != null) { if (!changes.isEmpty()) { String label = Integer.toString(changes.get(0)); ws.getExpand().set(ReviewProp.LABEL.toString(), label); } } return ws; } /** * Remote execute to find hostname. * * @param buildWorkspace */ private static String getHostName(FilePath buildWorkspace) { try { HostnameTask task = new HostnameTask(); String hostname = buildWorkspace.act(task); return hostname; } catch (Exception e) { return ""; } } protected String getClient() { return client; } protected Workspace getWorkspace() { return workspace; } protected ClientHelper getConnection() { ClientHelper p4 = new ClientHelper(credential, listener, client, charset); return p4; } protected boolean checkConnection(ClientHelper p4) { p4.log("\nP4 Task: establishing connection."); // test server connection if (!p4.isConnected()) { p4.log("P4: Server connection error: " + getCredential().getP4port()); return false; } p4.log("... server: " + getCredential().getP4port()); // test node hostname String host; try { host = InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException e) { host = "unknown"; } p4.log("... node: " + host); return true; } protected Object tryTask() throws AbortException { ClientHelper p4 = getConnection(); if (p4.hasAborted()) { String msg = "P4: Previous Task Aborted!"; logger.warning(msg); p4.log(msg); p4.disconnect(); throw new AbortException(msg); } // Check connection (might be on remote slave) if (!checkConnection(p4)) { String msg = "\nP4 Task: Unable to connect."; logger.warning(msg); p4.log(msg); throw new AbortException(msg); } int trys = 0; int attempt = p4.getRetry(); Exception last = null; while (trys <= attempt) { trys++; try { Object result = task(p4); p4.disconnect(); if (p4.hasAborted()) { String msg = "P4: Task Aborted!"; logger.warning(msg); p4.log(msg); throw new AbortException(msg); } return result; } catch (AbortException e) { throw e; } catch (Exception e) { last = e; String msg = "P4 Task: attempt: " + trys; logger.severe(msg); p4.log(msg); // back off n^2 seconds, before retry try { TimeUnit.SECONDS.sleep(trys ^ 2); } catch (InterruptedException e2) { Thread.currentThread().interrupt(); } } } p4.disconnect(); String msg = "P4 Task: failed: " + last; last.printStackTrace(); logger.warning(msg); p4.log(msg); throw new AbortException(msg); } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 19599 | mparfianowicz | "Forking branch Main of p4-jenkins to mparfianowicz-p4jenkins." | ||
//guest/perforce_software/p4jenkins/main/src/main/java/org/jenkinsci/plugins/p4/tasks/AbstractTask.java | |||||
#13 | 19593 | Paul Allen | More minor fixes to satisfy FindBugs Analysis. | ||
#12 | 16815 | Paul Allen |
Enable early binding for CHARSET Expose CHARSET to AbstractTask to allow the charset to be set at the point the client workspace is set as current in ClientHelper. |
||
#11 | 16514 | Paul Allen |
Unshelve and resolve build step. Implements a classic Jenkins Build step (i.e. not Workflow). Must provide a shelf change number and resolve options. The shelf change number supports variable expansion ${VAR}. |
||
#10 | 15656 | Paul Allen |
Updated credentials to extend BaseStandardCredentials. Allows users to set the ID at creation. JENKINS-29702 |
||
#9 | 15430 | Paul Allen |
Trap User Abort and stop Perforce. Uses the ‘tick’ function on Progress to check if the Thread has been interrupted. If a user aborts the build then the Perforce connection is dropped at the next tick. JENKINS-26650 |
||
#8 | 15293 | Paul Allen |
Add retry attempts to Perforce Tasks. If a task fails due to an exception then the task will retry based on the value specified in the connection Credential. |
||
#7 | 13700 | Paul Allen | minor tidy up. | ||
#6 | 13681 | Paul Allen |
Abstracted Expand class from Workspace. Added support for Label variable expansion in the name and description. |
||
#5 | 13604 | Paul Allen | Improved error handling and fixed test case issue. | ||
#4 | 13603 | Paul Allen | Improved Error for Publish step when connection is down. | ||
#3 | 12976 | Paul Allen | Improved logging to include 'actual' Perforce command. | ||
#2 | 12953 | Paul Allen |
Update logging to support expand/collapse divs. - Additional Publish logging |
||
#1 | 11334 | Paul Allen |
Remote slave support for Publish Perforce Publish commands need to be executed from the remote slave. - Includes refactoring into task package |