Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Delete client workspace and files on a delete Jenkins Job
Global Perforce options for delete files and/or delete client.
JENKINS-32454
  • Loading branch information
p4paul committed Jan 18, 2016
1 parent 458cbf6 commit 55480ee
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 95 deletions.
174 changes: 85 additions & 89 deletions src/main/java/org/jenkinsci/plugins/p4/PerforceScm.java
@@ -1,29 +1,5 @@
package org.jenkinsci.plugins.p4;

import hudson.AbortException;
import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.matrix.MatrixConfiguration;
import hudson.matrix.MatrixExecutionStrategy;
import hudson.matrix.MatrixBuild;
import hudson.matrix.MatrixProject;
import hudson.model.TaskListener;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Computer;
import hudson.model.Job;
import hudson.model.Node;
import hudson.model.Run;
import hudson.scm.ChangeLogParser;
import hudson.scm.PollingResult;
import hudson.scm.SCMDescriptor;
import hudson.scm.SCMRevisionState;
import hudson.scm.SCM;
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
Expand All @@ -33,38 +9,55 @@
import java.util.Map;
import java.util.logging.Logger;

import jenkins.model.Jenkins;
import net.sf.json.JSONObject;

import org.jenkinsci.plugins.p4.browsers.P4Browser;
import org.jenkinsci.plugins.p4.changes.P4ChangeEntry;
import org.jenkinsci.plugins.p4.changes.P4ChangeParser;
import org.jenkinsci.plugins.p4.changes.P4ChangeSet;
import org.jenkinsci.plugins.p4.changes.P4Revision;
import org.jenkinsci.plugins.p4.client.ClientHelper;
import org.jenkinsci.plugins.p4.client.ConnectionHelper;
import org.jenkinsci.plugins.p4.credentials.P4CredentialsImpl;
import org.jenkinsci.plugins.p4.filters.Filter;
import org.jenkinsci.plugins.p4.matrix.MatrixOptions;
import org.jenkinsci.plugins.p4.populate.ForceCleanImpl;
import org.jenkinsci.plugins.p4.populate.Populate;
import org.jenkinsci.plugins.p4.review.ReviewProp;
import org.jenkinsci.plugins.p4.tagging.TagAction;
import org.jenkinsci.plugins.p4.tasks.CheckoutTask;
import org.jenkinsci.plugins.p4.tasks.HostnameTask;
import org.jenkinsci.plugins.p4.tasks.PollTask;
import org.jenkinsci.plugins.p4.workspace.TemplateWorkspaceImpl;
import org.jenkinsci.plugins.p4.workspace.Workspace;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;

import com.perforce.p4java.impl.generic.core.Label;

import hudson.AbortException;
import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.matrix.MatrixBuild;
import hudson.matrix.MatrixConfiguration;
import hudson.matrix.MatrixExecutionStrategy;
import hudson.matrix.MatrixProject;
import hudson.model.AbstractBuild;
import hudson.model.Computer;
import hudson.model.Job;
import hudson.model.Node;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.scm.ChangeLogParser;
import hudson.scm.PollingResult;
import hudson.scm.SCM;
import hudson.scm.SCMDescriptor;
import hudson.scm.SCMRevisionState;
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;
import jenkins.model.Jenkins;
import net.sf.json.JSONObject;

public class PerforceScm extends SCM {

private static Logger logger = Logger
.getLogger(PerforceScm.class.getName());
private static Logger logger = Logger.getLogger(PerforceScm.class.getName());

private final String credential;
private final Workspace workspace;
Expand Down Expand Up @@ -107,8 +100,8 @@ public List<Integer> getChanges() {
* automatically copying values from a web form to a class.
*/
@DataBoundConstructor
public PerforceScm(String credential, Workspace workspace,
List<Filter> filter, Populate populate, P4Browser browser) {
public PerforceScm(String credential, Workspace workspace, List<Filter> filter, Populate populate,
P4Browser browser) {
this.credential = credential;
this.workspace = workspace;
this.filter = filter;
Expand All @@ -131,9 +124,8 @@ public PerforceScm(String credential, Workspace workspace, Populate populate) {
* the build as an Action for later retrieval.
*/
@Override
public SCMRevisionState calcRevisionsFromBuild(Run<?, ?> run,
FilePath buildWorkspace, Launcher launcher, TaskListener listener)
throws IOException, InterruptedException {
public SCMRevisionState calcRevisionsFromBuild(Run<?, ?> run, FilePath buildWorkspace, Launcher launcher,
TaskListener listener) throws IOException, InterruptedException {
// Method not required by Perforce
return null;
}
Expand All @@ -144,9 +136,8 @@ public SCMRevisionState calcRevisionsFromBuild(Run<?, ?> run,
* detected by this poll.
*/
@Override
public PollingResult compareRemoteRevisionWith(Job<?, ?> job,
Launcher launcher, FilePath buildWorkspace, TaskListener listener,
SCMRevisionState baseline) throws IOException, InterruptedException {
public PollingResult compareRemoteRevisionWith(Job<?, ?> job, Launcher launcher, FilePath buildWorkspace,
TaskListener listener, SCMRevisionState baseline) throws IOException, InterruptedException {

PollingResult state = PollingResult.NO_CHANGES;
Node node = workspaceToNode(buildWorkspace);
Expand All @@ -166,8 +157,7 @@ public PollingResult compareRemoteRevisionWith(Job<?, ?> job,
// Poll CHILDREN only
MatrixProject matrixProj = (MatrixProject) job;

Collection<MatrixConfiguration> configs = matrixProj
.getActiveConfigurations();
Collection<MatrixConfiguration> configs = matrixProj.getActiveConfigurations();

for (MatrixConfiguration config : configs) {
EnvVars envVars = config.getEnvironment(node, listener);
Expand Down Expand Up @@ -195,8 +185,8 @@ public PollingResult compareRemoteRevisionWith(Job<?, ?> job,
* @throws InterruptedException
* @throws IOException
*/
private PollingResult pollWorkspace(EnvVars envVars, TaskListener listener,
FilePath buildWorkspace) throws InterruptedException, IOException {
private PollingResult pollWorkspace(EnvVars envVars, TaskListener listener, FilePath buildWorkspace)
throws InterruptedException, IOException {
PrintStream log = listener.getLogger();

// set NODE_NAME to Node or default "master" if not set
Expand Down Expand Up @@ -244,9 +234,8 @@ private PollingResult pollWorkspace(EnvVars envVars, TaskListener listener,
* workspace. Authorisation
*/
@Override
public void checkout(Run<?, ?> run, Launcher launcher,
FilePath buildWorkspace, TaskListener listener, File changelogFile,
SCMRevisionState baseline) throws IOException, InterruptedException {
public void checkout(Run<?, ?> run, Launcher launcher, FilePath buildWorkspace, TaskListener listener,
File changelogFile, SCMRevisionState baseline) throws IOException, InterruptedException {

PrintStream log = listener.getLogger();
boolean success = true;
Expand All @@ -262,7 +251,7 @@ public void checkout(Run<?, ?> run, Launcher launcher,
// Set changes to build (used by polling), MUST clear after use.
ws = task.setNextChange(ws, changes);
changes = new ArrayList<Integer>();

// Set the Workspace and initialise
task.setWorkspace(ws);
task.initialise();
Expand Down Expand Up @@ -309,9 +298,7 @@ public void checkout(Run<?, ?> run, Launcher launcher,
P4ChangeSet.store(changelogFile, changes);
listener.getLogger().println("... done\n");
} else {
listener.getLogger()
.println(
"P4 Task: changeLogFile not set. Not saving built changes.");
listener.getLogger().println("P4 Task: changeLogFile not set. Not saving built changes.");
}
} else {
String msg = "P4: Build failed";
Expand Down Expand Up @@ -340,8 +327,7 @@ boolean isBuildParent(Job<?, ?> job) {
}
}

private List<P4ChangeEntry> calculateChanges(Run<?, ?> run,
CheckoutTask task) {
private List<P4ChangeEntry> calculateChanges(Run<?, ?> run, CheckoutTask task) {
List<P4ChangeEntry> list = new ArrayList<P4ChangeEntry>();

// Look for all changes since the last build
Expand Down Expand Up @@ -381,8 +367,7 @@ private List<P4ChangeEntry> calculateChanges(Run<?, ?> run,
}

@Override
public void
buildEnvVars(AbstractBuild<?, ?> build, Map<String, String> env) {
public void buildEnvVars(AbstractBuild<?, ?> build, Map<String, String> env) {
super.buildEnvVars(build, env);

TagAction tagAction = build.getAction(TagAction.class);
Expand Down Expand Up @@ -473,19 +458,26 @@ public ChangeLogParser createChangeLogParser() {
* opportunity to perform clean up.
*/
@Override
public boolean processWorkspaceBeforeDeletion(Job<?, ?> job,
FilePath workspace, Node node) throws IOException,
InterruptedException {

// CASTING: is this safe?
AbstractProject<?, ?> project = (AbstractProject<?, ?>) job;
PerforceScm scm = (PerforceScm) project.getScm();
String scmCredential = scm.getCredential();
public boolean processWorkspaceBeforeDeletion(Job<?, ?> job, FilePath workspace, Node node)
throws IOException, InterruptedException {

boolean deleteClient = ((DescriptorImpl) getDescriptor()).isDeleteClient();
boolean deleteFiles = ((DescriptorImpl) getDescriptor()).isDeleteFiles();

logger.info("processWorkspaceBeforeDeletion");

// Exit early if you want to keep the Client spec.
if (!deleteClient) {
// return deleteFiles; true continue, false stop delete.
return deleteFiles;
}

String scmCredential = getCredential();
Run<?, ?> run = job.getLastBuild();

if (run == null) {
logger.warning("P4: No previous builds found");
return true;
return deleteFiles;
}

// exit early if client workspace is undefined
Expand All @@ -495,34 +487,26 @@ public boolean processWorkspaceBeforeDeletion(Job<?, ?> job,
client = envVars.get("P4_CLIENT");
} catch (Exception e) {
logger.warning("P4: Unable to read P4_CLIENT");
return true;
return deleteFiles;
}

// exit early if client workspace does not exist
ConnectionHelper connection = new ConnectionHelper(scmCredential, null);
// remove client workspace
ConnectionHelper p4 = new ConnectionHelper(scmCredential, null);
try {
if (!connection.isClient(client)) {
return true;
if (p4.isClient(client)) {
p4.deleteClient(client);
} else {
logger.warning("P4: Cannot find: " + client);
return deleteFiles;
}
} catch (Exception e) {
logger.warning("P4: Not able to get connection");
return true;
}

// Remove have entries from client workspace
ClientHelper p4 = new ClientHelper(scmCredential, null, client, "utf8");
try {
ForceCleanImpl forceClean = new ForceCleanImpl(false, false,
populate.isQuiet(), null);
logger.info("P4: unsyncing client: " + client);
p4.syncFiles(new P4Revision(0), forceClean);
} catch (Exception e) {
logger.warning("P4: Not able to unsync client: " + client);
return true;
return deleteFiles;
} finally {
p4.disconnect();
}
return true;

return deleteFiles;
}

/**
Expand Down Expand Up @@ -550,6 +534,17 @@ public SCMDescriptor<PerforceScm> getDescriptor() {
@Extension
public static class DescriptorImpl extends SCMDescriptor<PerforceScm> {

private boolean deleteClient;
private boolean deleteFiles;

public boolean isDeleteClient() {
return deleteClient;
}

public boolean isDeleteFiles() {
return deleteFiles;
}

/**
* public no-argument constructor
*/
Expand All @@ -559,8 +554,7 @@ public DescriptorImpl() {
}

@Override
public SCM newInstance(StaplerRequest req, JSONObject formData)
throws FormException {
public SCM newInstance(StaplerRequest req, JSONObject formData) throws FormException {
PerforceScm scm = (PerforceScm) super.newInstance(req, formData);
return scm;
}
Expand All @@ -583,8 +577,11 @@ public String getDisplayName() {
*
*/
@Override
public boolean configure(StaplerRequest req, JSONObject json)
throws FormException {
public boolean configure(StaplerRequest req, JSONObject json) throws FormException {

deleteClient = json.getBoolean("deleteClient");
deleteFiles = json.getBoolean("deleteFiles");

save();
return true;
}
Expand Down Expand Up @@ -655,5 +652,4 @@ private static Node workspaceToNode(FilePath workspace) {
return jenkins;
}


}
Expand Up @@ -30,6 +30,7 @@
import com.perforce.p4java.impl.generic.core.file.FileSpec;
import com.perforce.p4java.impl.mapbased.server.Server;
import com.perforce.p4java.option.server.ChangelistOptions;
import com.perforce.p4java.option.server.DeleteClientOptions;
import com.perforce.p4java.option.server.GetChangelistsOptions;
import com.perforce.p4java.option.server.GetDepotFilesOptions;
import com.perforce.p4java.option.server.GetFixesOptions;
Expand Down Expand Up @@ -335,6 +336,18 @@ public boolean isClient(String name) throws Exception {
}
}

/**
* Delete a client workspace
*
* @param userName
* @return
* @throws Exception
*/
public void deleteClient(String name) throws Exception {
DeleteClientOptions opts = new DeleteClientOptions();
connection.deleteClient(name, opts);
}

public String getEmail(String userName) throws Exception {
IUser user = connection.getUser(userName);
if (user != null) {
Expand Down
@@ -1,8 +1,14 @@
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define"
xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">


<f:section title="Perforce Global settings">

<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define"
xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form"
xmlns:c="/lib/credentials">

<f:section title="Perforce: OnDelete Workspace Options">
<f:entry field="deleteClient">
<f:checkbox title="${%Delete Perforce client}" default="true"/>
</f:entry>
<f:entry field="deleteFiles">
<f:checkbox title="${%Delete Workspace files}" default="true"/>
</f:entry>
</f:section>

</j:jelly>

0 comments on commit 55480ee

Please sign in to comment.