package org.jenkinsci.plugins.p4_client; import hudson.Extension; import hudson.FilePath; import hudson.Launcher; import hudson.model.BuildListener; import hudson.model.TaskListener; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.scm.ChangeLogParser; import hudson.scm.PollingResult; import hudson.scm.SCMDescriptor; import hudson.scm.SCMRevisionState; import hudson.scm.SCM; import hudson.security.ACL; import hudson.util.ListBoxModel; import java.io.File; import java.io.IOException; import java.util.List; import jenkins.model.Jenkins; import net.sf.json.JSONObject; import org.acegisecurity.Authentication; import org.jenkinsci.plugins.p4_client.client.AuthorisationConfig; import org.jenkinsci.plugins.p4_client.client.ConnectionConfig; import org.jenkinsci.plugins.p4_client.client.ConnectionHelper; import org.jenkinsci.plugins.p4_client.credentials.P4StandardCredentials; import org.jenkinsci.plugins.p4_client.workspace.Workspace; import org.jenkinsci.plugins.p4_client.workspace.WorkspaceDescriptor; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.StaplerRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.cloudbees.plugins.credentials.CredentialsProvider; import com.cloudbees.plugins.credentials.domains.DomainRequirement; public class PerforceScm extends SCM { private Logger logger = LoggerFactory.getLogger(PerforceScm.class); private final String credential; private final Workspace workspace; private ConnectionConfig connectionConfig; private AuthorisationConfig authorisationConfig; public String getCredential() { return credential; } public Workspace getWorkspace() { return workspace; } /** * Create a constructor that takes non-transient fields, and add the * annotation @DataBoundConstructor to it. Using the annotation helps the * Stapler class to find which constructor that should be used when * automatically copying values from a web form to a class. * * @param server * @param project * @param cleanCopy * @param username * @param password * @param domain * @param workspaceName */ @DataBoundConstructor public PerforceScm(String credential, Workspace workspace) { this.credential = credential; this.workspace = workspace; P4StandardCredentials c = findCredential(credential); if (c != null) { connectionConfig = new ConnectionConfig(c); authorisationConfig = new AuthorisationConfig(c); } } /** * Calculate the state of the workspace of the given build. The returned * object is then fed into compareRemoteRevisionWith as the baseline * SCMRevisionState to determine if the build is necessary, and is added to * the build as an Action for later retrieval. */ @Override public SCMRevisionState calcRevisionsFromBuild(AbstractBuild<?, ?> build, Launcher launcher, TaskListener listener) throws IOException, InterruptedException { // TODO Auto-generated method stub return null; } /** * This method does the actual polling and returns a PollingResult. The * change attribute of the PollingResult the significance of the changes * detected by this poll. */ @Override protected PollingResult compareRemoteRevisionWith( AbstractProject<?, ?> project, Launcher launcher, FilePath workspace, TaskListener listener, SCMRevisionState baseline) throws IOException, InterruptedException { // TODO Auto-generated method stub return null; } /** * The checkout method is expected to check out modified files into the * project workspace. In Perforce terms a 'p4 sync' on the project's * workspace. Authorisation */ @Override public boolean checkout(AbstractBuild<?, ?> build, Launcher launcher, FilePath buildWorkspace, BuildListener listener, File changelogFile) throws IOException, InterruptedException { // TODO Auto-generated method stub logger.info("connectionConfig: " + connectionConfig.toString()); logger.info("authorisationConfig: " + authorisationConfig.toString()); // IMPORTANT: set root, node and project or we can't get a workspace name. workspace.setNodeName(build.getBuiltOnStr()); workspace.setProjectName(build.getProject().getName()); workspace.setRootPath(build.getModuleRoot().getRemote()); // Test... try { ConnectionHelper p4 = new ConnectionHelper(connectionConfig); p4.login(authorisationConfig); p4.setClient(workspace); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return false; } /** * The checkout method should, besides checking out the modified files, * write a changelog.xml file that contains the changes for a certain build. * The changelog.xml file is specific for each SCM implementation, and the * createChangeLogParser returns a parser that can parse the file and return * a ChangeLogSet. */ @Override public ChangeLogParser createChangeLogParser() { // TODO Auto-generated method stub return null; } /** * Returns the ScmDescriptor<?> for the SCM object. The ScmDescriptor is * used to create new instances of the SCM. */ @Override public SCMDescriptor<PerforceScm> getDescriptor() { return (DescriptorImpl) super.getDescriptor(); } public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); /** * The relationship of Descriptor and SCM (the describable) is akin to class * and object. What this means is that the descriptor is used to create * instances of the describable. Usually the Descriptor is an internal class * in the SCM class named DescriptorImpl. The Descriptor should also contain * the global configuration options as fields, just like the SCM class * contains the configurations options for a job. * * @author pallen * */ @Extension public static class DescriptorImpl extends SCMDescriptor<PerforceScm> { private static Logger logger = LoggerFactory .getLogger(DescriptorImpl.class); /** * public no-argument constructor */ public DescriptorImpl() { super(PerforceScm.class, null); logger.info("load()..."); load(); } @Override public SCM newInstance(StaplerRequest req, JSONObject formData) throws FormException { PerforceScm scm = (PerforceScm) super.newInstance(req, formData); return scm; } /** * Returns the name of the SCM, this is the name that will show up next * to CVS and Subversion when configuring a job. */ @Override public String getDisplayName() { return "Perforce Software"; } /** * The configure method is invoked when the global configuration page is * submitted. In the method the data in the web form should be copied to * the Descriptor's fields. To persist the fields to the global * configuration XML file, the save() method must be called. Data is * defined in the global.jelly page. * */ @Override public boolean configure(StaplerRequest req, JSONObject json) throws FormException { save(); return true; } /** * Credentials list, a Jelly config method for a build job. * * @return A list of Perforce credential items to populate the jelly * Select list. */ public ListBoxModel doFillCredentialItems() { ListBoxModel list = new ListBoxModel(); List<P4StandardCredentials> credentials = getCredentials(); if (credentials.isEmpty()) { list.add("Select credential...", null); } for (P4StandardCredentials c : credentials) { list.add(c.getTitle(), c.getId()); } return list; } } /** * This methods determines if the SCM plugin can be used for polling */ @Override public boolean supportsPolling() { return true; } /** * This method should return true if the SCM requires a workspace for * polling. Perforce however can report submitted, pending and shelved * changes without needing a workspace */ @Override public boolean requiresWorkspaceForPolling() { return true; } /** * Finds all Perforce Credentials defined in Jenkins. * * @return List of P4StandardCredentials credentials. */ private static List<P4StandardCredentials> getCredentials() { Class<P4StandardCredentials> type = P4StandardCredentials.class; Jenkins scope = Jenkins.getInstance(); Authentication acl = ACL.SYSTEM; DomainRequirement domain = new DomainRequirement(); List<P4StandardCredentials> list; list = CredentialsProvider.lookupCredentials(type, scope, acl, domain); return list; } /** * Find a Perforce Credentials with matching id. * * @param id * @return */ private P4StandardCredentials findCredential(String id) { List<P4StandardCredentials> list = getCredentials(); for (P4StandardCredentials c : list) { if (id.equals(c.getId())) { return c; } } return null; } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#33 | 9672 | Paul Allen | Refactor name from 'p4_client' to 'p4'. | ||
#32 | 9495 | Paul Allen |
Fix Polling issue; using the wrong client. Removed static classes and internal referenced to PerforceScm attributes, to avoid threading issues. |
||
#31 | 9472 | Paul Allen |
Added support to pin build at a label in the populate configuration. - includes help and updates to tests. |
||
#30 | 9430 | Paul Allen |
Polling SCM: skip filter check if no filters - added more logging for Polling errors. |
||
#29 | 9429 | Paul Allen |
Fix SCM Polling bug. Client workspace was not set (unless by an earlier build). - Move listChanges method to ClientHelper. |
||
#28 | 9115 | Paul Allen |
Initial implementation of workspace Cleanup and Sync options. - Includes 3 modes: Automatic Clean/Sync, Force Clean/Sync, Sync Only Automatic Clean/Sync Uses reconcile to clean up workspace and sync changes. Force Clean/Sync Force sync of all files (does not remove files yet...) Sync Only Normal sync with no cleanup TODO: - remove of files in Force Clean/Sync mode - Inline help - Update docs - Add unit/functional tests |
||
#27 | 9091 | Paul Allen |
Added Changelist build filtering for SCM polling: - Configuration uses 'repeatableHeteroProperty' - Filter on Perforce username - Filter on Perforce Depot path (no wildcard support) |
||
#26 | 9069 | Paul Allen |
Adding initial support for tagging Jenkins builds as Perforce Automatic Labels. Only implements TagAction (manual labels); TagNotifier and test cases TODO. |
||
#25 | 9055 | Paul Allen |
Label support. Build at a label using the pram 'label'. This includes adding the label to the ChangeEntry, building the change reports and Browser links to Swarm. (TPI-102) |
||
#24 | 9038 | Paul Allen |
Improved error messages for Form Validate field checks. Uses Perforce Server messages (TPI-80) |
||
#23 | 8969 | Paul Allen |
Adds all contributing change-lists for the build to the change log (using p4 cstat). - Includes exception logging for server connection to the Jenkins console. |
||
#22 | 8940 | Paul Allen |
Major refactor for the ConnectionHelper class to simplify serialisation. Fixed remote Jenkins JNLP slave connection issue. ClientHelper now extends ConnectionHelper and takes on all methods that require a client workspace. P4StandardCredentials is sent to the remote node instead of Credentials ID due to an issue accessing the Credentials store over a remote connection. For simplicity Client ID (workspace name) is serialised instead of the Workspace object. |
||
#21 | 8929 | Paul Allen |
Clean up doCheck Warnings on configuration page (TPI-80). - Added check exceptions to log as warnings. |
||
#20 | 8915 | Paul Allen |
Support for ChangeLog and RepoBrowser. - Added RepoBrowser for Swarm (porting the others should be easy) - ChangeLog XML file now only stores the changelist number all other information is fetched from Perforce |
||
#19 | 8771 | Paul Allen |
Perforce Server 12.1 min check for: Build configuration and password/ticket credentials. Includes: - Added logging for Perforce connections (fine) and set connection pool to 2. - Add 'none' to empty charset list (connection bug?) - Supress P4Java errors for syncing ubinary, xtext, unicode |
||
#18 | 8770 | Paul Allen |
Implemented SCM hook for when Jenkins deletes a workspace. The PerforceScm plugin deletes the workspace, but leaves Jenkins to clean up the local files and directories. (includes dummy 'p4 cstat' code for change reporting) |
||
#17 | 8762 | Paul Allen |
Console Ouptut logging for SCM build steps. - Removed SLF4J and used old style logger (matching Jenkins) - Set Client Host filed to null, Jenkins sometimes gives an IP address. - Test p4java setps in SCM tasks for success(true/false) |
||
#16 | 8744 | Paul Allen |
Support basic SCM Polling. When Jenkins has "Poll SCM" checked the Perforce SCM provider just runs a 'p4 sync -n' on the Workspace. Simple and Fast. |
||
#15 | 8738 | Paul Allen |
Workspace Name Formatter. For Template and Stream workspaces it allows the substitution of the following tags: ${node} The name given to the slave Jenkins node. ${hostname} The hostname for the slave Jenkins node. ${project} The name of the Jenkins build Job. ${hash} Unique hash code of the Jenkins node. |
||
#14 | 8737 | Paul Allen |
Added basic Help for SCM Configuration page. Tidy up descriptions and fix (null:null) in Credential summary. |
||
#13 | 8694 | Paul Allen | Added support for unshelve and revert -w behaviour for builds. | ||
#12 | 8688 | Paul Allen | (Work in progress) Able to call build from review Action and pass URL params. | ||
#11 | 8664 | Paul Allen | Simplified connection to Perforce to get around the SCM initilisation (or lack of). | ||
#10 | 8663 | Paul Allen | Rollout of charset for all Workspace modes. | ||
#9 | 8661 | Paul Allen | Workspace auto fill | ||
#8 | 8641 | Paul Allen | Added workspace helper (setClient) and template/stream types. | ||
#7 | 8640 | Paul Allen |
Added Workspace and Singleton descriptor. Removed old connection code. |
||
#6 | 8639 | Paul Allen |
Added hint URL to Credentials page when no Credentials are defined. Minor refactor and UX changes. |
||
#5 | 8629 | Paul Allen |
Added p4java with connection/authorisation helper classes. Included SSL support and detection of Unicode servers. |
||
#4 | 8613 | Paul Allen | Tidy up unused Credentials data and for debug added getId() to SelectList title. | ||
#3 | 8612 | Paul Allen | Job can now select and save/load Credential choice (some cleanup TODO) | ||
#2 | 8611 | Paul Allen | Basic implementation of Credentials Store | ||
#1 | 8598 | Paul Allen | Experimentation with data binding for Jelly files and ExtensionPoint/Descriptor |