From 790c97c1f3177707c4b92bc1886db535ebb05593 Mon Sep 17 00:00:00 2001 From: jkapica Date: Thu, 3 Apr 2014 16:52:10 +0200 Subject: [PATCH] p4.prog reporting feature --- src/main/java/com/tek42/perforce/Depot.java | 17 +++ .../parse/AbstractPerforceTemplate.java | 40 ++++--- .../hudson/plugins/perforce/PerforceSCM.java | 102 +++++++++++++++++- .../plugins/perforce/PerforceSCM/config.jelly | 11 ++ .../plugins/perforce/PerforceSCM/global.jelly | 12 ++- src/main/webapp/help/p4ProgramName.html | 13 +++ .../webapp/help/p4ProgramNameDefault.html | 15 +++ .../webapp/help/p4ProgramPollingName.html | 16 +++ .../help/p4ProgramPollingNameDefault.html | 26 +++++ .../plugins/perforce/PerforceSCMTest.java | 18 ++-- 10 files changed, 247 insertions(+), 23 deletions(-) create mode 100644 src/main/webapp/help/p4ProgramName.html create mode 100644 src/main/webapp/help/p4ProgramNameDefault.html create mode 100644 src/main/webapp/help/p4ProgramPollingName.html create mode 100644 src/main/webapp/help/p4ProgramPollingNameDefault.html diff --git a/src/main/java/com/tek42/perforce/Depot.java b/src/main/java/com/tek42/perforce/Depot.java index 9423c8a..b6ba6a4 100644 --- a/src/main/java/com/tek42/perforce/Depot.java +++ b/src/main/java/com/tek42/perforce/Depot.java @@ -87,6 +87,8 @@ public class Depot { private Status status; private Groups groups; private Counters counters; + private String programName; + private String programVersion; public Depot() { this(new DefaultExecutorFactory()); @@ -572,5 +574,20 @@ public static boolean safeEquals(String newValue, String currentValue) { return newValue.equals(currentValue); } + public String getProgramName() { + return programName; + } + + public void setProgramName(String prog) { + this.programName = prog; + } + + public String getProgramVersion() { + return programVersion; + } + + public void setProgramVersion(String version) { + this.programVersion = version; + } } diff --git a/src/main/java/com/tek42/perforce/parse/AbstractPerforceTemplate.java b/src/main/java/com/tek42/perforce/parse/AbstractPerforceTemplate.java index d78e43b..62125c1 100644 --- a/src/main/java/com/tek42/perforce/parse/AbstractPerforceTemplate.java +++ b/src/main/java/com/tek42/perforce/parse/AbstractPerforceTemplate.java @@ -147,22 +147,38 @@ public boolean reject(String line){ * @return A (possibly) modified string array to be executed in place of the original. */ protected String[] getExtraParams(String cmd[]) { + List newCmd = new ArrayList(); + + // Copy over p4 executable + newCmd.add(cmd[0]); + + String program = depot.getProgramName(); + if (program != null) { + // Insert program to be reported to Perforce server + newCmd.add("-z"); + newCmd.add("prog=" + program); + } + + String version = depot.getProgramVersion(); + if (version != null) { + // Insert version to be reported to Perforce server + newCmd.add("-z"); + newCmd.add("version=" + version); + } + String ticket = depot.getP4Ticket(); - if(ticket != null) { // Insert the ticket for the password if tickets are being used... - String newCmds[] = new String[cmd.length + 2]; - newCmds[0] = getP4Exe(); - newCmds[1] = "-P"; - newCmds[2] = ticket; - for(int i = 3; (i - 2) < cmd.length; i++) { - newCmds[i] = cmd[i - 2]; - } - cmd = newCmds; - } else { - cmd[0] = getP4Exe(); + newCmd.add("-P"); + newCmd.add(ticket); + } + + // Append the remaining original parameters + for(int i = 1; i < cmd.length; i++) { + newCmd.add(cmd[i]); } - return cmd; + + return newCmd.toArray(new String[newCmd.size()]); } /** diff --git a/src/main/java/hudson/plugins/perforce/PerforceSCM.java b/src/main/java/hudson/plugins/perforce/PerforceSCM.java index 55f1c32..c280f5e 100644 --- a/src/main/java/hudson/plugins/perforce/PerforceSCM.java +++ b/src/main/java/hudson/plugins/perforce/PerforceSCM.java @@ -250,6 +250,17 @@ public class PerforceSCM extends SCM { * Hash */ String slaveClientNameFormat = null; + + /** + * Perforce program name to report to the Perforce server + */ + String p4ProgramName = null; + String p4ProgramPollingName = null; + + /** Regular expression for validation of p4 Program Name + */ + private static final String P4_PROGRAM_NAME_PATTERN = + "[_a-zA-Z0-9@.\\[\\]\\(\\)\\<\\>-]+"; /** * We need to store the changelog file name for the build so that we can expose @@ -328,7 +339,9 @@ public PerforceSCM( boolean excludedFilesCaseSensitivity, DepotType depotType, WorkspaceCleanupConfig cleanWorkspace, - MaskViewConfig useViewMask + MaskViewConfig useViewMask, + String p4ProgramName, + String p4ProgramPollingName ) { this.configVersion = 2L; @@ -423,6 +436,9 @@ public PerforceSCM( this.excludedUsers = Util.fixEmptyAndTrim(excludedUsers); this.excludedFiles = Util.fixEmptyAndTrim(excludedFiles); this.excludedFilesCaseSensitivity = excludedFilesCaseSensitivity; + + setP4ProgramName(p4ProgramName); + setP4ProgramPollingName(p4ProgramPollingName); } /** @@ -891,6 +907,16 @@ public boolean checkout(AbstractBuild build, Launcher launcher, } try { + String progName = getEffectiveP4ProgramName(); + if (progName != null) { + log.println("p4.prog=" + progName); + if (progName.matches(P4_PROGRAM_NAME_PATTERN)) { + depot.setProgramName(progName); + } else { + log.println("WARNING: p4.prog don't match " + P4_PROGRAM_NAME_PATTERN + " (ignoring it)"); + } + } + // keep projectPath local so any modifications for slaves don't get saved String projectPath; projectPath = getEffectiveProjectPath(build, build.getProject(), log, depot); @@ -1302,6 +1328,16 @@ protected PollingResult compareRemoteRevisionWith(AbstractProject project, depot = getDepot(buildNode.createLauncher(listener),buildNode.getRootPath(),project,null, buildNode); logger.println("Using node: " + buildNode.getDisplayName()); } + + String progName = getEffectiveP4ProgramPollingName(); + if (progName != null) { + logger.println("p4.prog=" + progName); + if (progName.matches(P4_PROGRAM_NAME_PATTERN)) { + depot.setProgramName(progName); + } else { + logger.println("WARNING: p4.prog don't match " + P4_PROGRAM_NAME_PATTERN + " (ignoring it)"); + } + } Workspace p4workspace = getPerforceWorkspace(project, getEffectiveProjectPath(null, project, logger, depot), depot, buildNode, null, launcher, workspace, listener, true); saveWorkspaceIfDirty(depot, p4workspace, logger); @@ -1851,6 +1887,9 @@ public static final class PerforceSCMDescriptor extends SCMDescriptor getAllLineEndChoices() { List allChoices = Arrays.asList( @@ -2351,6 +2404,14 @@ public String getAppName() { return Hudson.getInstance().getDisplayName(); } + public String getP4ProgramNameDefault() { + return p4ProgramNameDefault; + } + + public String getP4ProgramPollingNameDefault() { + return p4ProgramPollingNameDefault; + } + @Extension public static class ItemListenerImpl extends ItemListener { @Override @@ -3196,4 +3257,43 @@ public boolean supportsPolling() { return true; } + public String getP4ProgramName() { + return p4ProgramName; + } + + public void setP4ProgramName(String name) { + this.p4ProgramName = Util.fixEmptyAndTrim(name); + } + + public String getP4ProgramPollingName() { + return p4ProgramPollingName; + } + + public void setP4ProgramPollingName(String name) { + this.p4ProgramPollingName = Util.fixEmptyAndTrim(name); + } + + public String getEffectiveP4ProgramName() { + String name = getP4ProgramName(); + if (name == null) { + name = ((PerforceSCMDescriptor)getDescriptor()).getP4ProgramNameDefault(); + } + return Util.fixEmptyAndTrim(name); + } + + public String getEffectiveP4ProgramPollingName() { + String name = getP4ProgramPollingName(); + if (name == null) { + name = getP4ProgramName(); + } + if (name == null) { // Falback to global config + PerforceSCMDescriptor desc = (PerforceSCMDescriptor)getDescriptor(); + name = desc.getP4ProgramPollingNameDefault(); + if (name == null) { + name = desc.getP4ProgramNameDefault(); + } + } + return Util.fixEmptyAndTrim(name); + } + } diff --git a/src/main/resources/hudson/plugins/perforce/PerforceSCM/config.jelly b/src/main/resources/hudson/plugins/perforce/PerforceSCM/config.jelly index 2088b6c..0398b6a 100644 --- a/src/main/resources/hudson/plugins/perforce/PerforceSCM/config.jelly +++ b/src/main/resources/hudson/plugins/perforce/PerforceSCM/config.jelly @@ -246,6 +246,17 @@ + + + + + + + + + diff --git a/src/main/resources/hudson/plugins/perforce/PerforceSCM/global.jelly b/src/main/resources/hudson/plugins/perforce/PerforceSCM/global.jelly index f160472..c1f1c82 100644 --- a/src/main/resources/hudson/plugins/perforce/PerforceSCM/global.jelly +++ b/src/main/resources/hudson/plugins/perforce/PerforceSCM/global.jelly @@ -41,6 +41,16 @@ Option globally disables exposal of Perforce passwords - + + + + + + + + + \ No newline at end of file diff --git a/src/main/webapp/help/p4ProgramName.html b/src/main/webapp/help/p4ProgramName.html new file mode 100644 index 0000000..82bb7e7 --- /dev/null +++ b/src/main/webapp/help/p4ProgramName.html @@ -0,0 +1,13 @@ +
+

+ Set what Program Name shall be reported to Perforce server. +

+

+ Setting this value will add extra option "-z prog=name" every time + p4 is connecting to the Perforce server. This can be later examined + with p4 monitor by Perforce administrators. + + Useful to debug Perforce connections, group then together and identify + their source. +

+
diff --git a/src/main/webapp/help/p4ProgramNameDefault.html b/src/main/webapp/help/p4ProgramNameDefault.html new file mode 100644 index 0000000..713a5be --- /dev/null +++ b/src/main/webapp/help/p4ProgramNameDefault.html @@ -0,0 +1,15 @@ +
+

+ Set what Program Name shall be reported to Perforce server. +

+

+ Setting this value will add extra option "-z prog=name" every time + p4 is connecting to the Perforce server. This can be later examined + with p4 monitor command by Perforce administrators. + Useful to debug Perforce connections, group then together and identify + their source. + + This is a global setting that will be used for all Jenkins jobs, unless + not explicitly overridden in job specific Perforce configuration. +

+
diff --git a/src/main/webapp/help/p4ProgramPollingName.html b/src/main/webapp/help/p4ProgramPollingName.html new file mode 100644 index 0000000..6585e4b --- /dev/null +++ b/src/main/webapp/help/p4ProgramPollingName.html @@ -0,0 +1,16 @@ +
+

+ Set what Program Name shall be reported to Perforce server when job is + polling for new changes. +

+

+ This field's value will be used when polling for new changes. + If not set, the value of "p4 Program Name" field will be used. + Use it when you would like to have granular identification of what + connections are tied with polling and what with fetching stages. + + There is also corresponding "p4 Program Default Polling Name" option at + Jenkins global configuration. Although before that is used, the local + "p4 Program Name", if set, takes precedence. +

+
diff --git a/src/main/webapp/help/p4ProgramPollingNameDefault.html b/src/main/webapp/help/p4ProgramPollingNameDefault.html new file mode 100644 index 0000000..1c557fd --- /dev/null +++ b/src/main/webapp/help/p4ProgramPollingNameDefault.html @@ -0,0 +1,26 @@ +
+

+ Set what Program Name shall be reported to Perforce server when job is + polling for new changes. +

+

+ This field's value will be used when polling for new changes. + If not set, the value of "p4 Program Name" field will be used. + Use it when you would like to have granular identification of what + connections are tied with polling and what with fetching sources. + + This is a global setting that will be used for all Jenkins jobs, unless + not explicitly overridden in job specific Perforce configuration. + + This option is overridden by both job specific settings related to this + feature, i.e. "p4 Program Polling Name" and "p4 Program Name". + + The effective value resolution order is: +

+    job specific p4 "Program Polling Name"
+    else job specific p4 "Program Name"
+    else global p4 "Program Polling Name"
+    else global p4 "Program Name"
+    
+

+
diff --git a/src/test/java/hudson/plugins/perforce/PerforceSCMTest.java b/src/test/java/hudson/plugins/perforce/PerforceSCMTest.java index 875444c..108cecb 100644 --- a/src/test/java/hudson/plugins/perforce/PerforceSCMTest.java +++ b/src/test/java/hudson/plugins/perforce/PerforceSCMTest.java @@ -39,7 +39,7 @@ public void testConfigRoundtrip() throws Exception { PerforceSCM scm = new PerforceSCM( "user", "pass", "client", "port", "", "exe", "sysRoot", "sysDrive", "label", "counter", "upstreamProject", "shared", "charset", "charset2", "user", false, true, true, true, true, true, false, - false, true, false, false, false, "${basename}", 0, -1, browser, "exclude_user", "exclude_file", true, TEST_DEPOT, TEST_WORKSPACE_CLEANUP, TEST_MASKVIEW); + false, true, false, false, false, "${basename}", 0, -1, browser, "exclude_user", "exclude_file", true, TEST_DEPOT, TEST_WORKSPACE_CLEANUP, TEST_MASKVIEW, null, null); scm.setProjectPath("path"); project.setScm(scm); @@ -60,7 +60,7 @@ public void testConfigRoundtripWithNoSystemRoot() throws Exception { PerforceSCM scm = new PerforceSCM( "user", "pass", "client", "port", "", "exe", "", "", "label", "counter", "upstreamProject", "shared", "charset", "charset2", "user", false, true, true, true, true, true, false, - false, true, false, false, false, "${basename}", 0, -1, browser, "exclude_user", "exclude_file", true, EMPTY_DEPOT, EMPTY_WORKSPACE_CLEANUP, EMPTY_MASKVIEW); + false, true, false, false, false, "${basename}", 0, -1, browser, "exclude_user", "exclude_file", true, EMPTY_DEPOT, EMPTY_WORKSPACE_CLEANUP, EMPTY_MASKVIEW, null, null); assertEquals("", scm.getP4SysDrive()); assertEquals("", scm.getP4SysRoot()); scm.setProjectPath("path"); @@ -80,7 +80,7 @@ public void testConfigRoundtripWithStream() throws Exception { PerforceSCM scm = new PerforceSCM( "user", "pass", "client", "port", "", "exe", "sysRoot", "sysDrive", "label", "counter", "upstreamProject", "shared", "charset", "charset2", "user", false, true, true, true, true, true, false, - false, true, false, false, false, "${basename}", 0, -1, browser, "exclude_user", "exclude_file", true, EMPTY_DEPOT, EMPTY_WORKSPACE_CLEANUP, EMPTY_MASKVIEW); + false, true, false, false, false, "${basename}", 0, -1, browser, "exclude_user", "exclude_file", true, EMPTY_DEPOT, EMPTY_WORKSPACE_CLEANUP, EMPTY_MASKVIEW, null, null); scm.setP4Stream("stream"); scm.setUseStreamDepot(true); project.setScm(scm); @@ -107,7 +107,7 @@ public void testConfigPasswordEnctyptionAndDecription() throws Exception { PerforceSCM scm = new PerforceSCM( "user", password, "client", "port", "", "test_installation", "sysRoot", "sysDrive", "label", "counter", "upstreamProject", "shared", "charset", "charset2", "user", false, true, true, true, true, true, false, - false, true, false, false, false, "${basename}", 0, -1, browser, "exclude_user", "exclude_file", true, EMPTY_DEPOT, EMPTY_WORKSPACE_CLEANUP, EMPTY_MASKVIEW); + false, true, false, false, false, "${basename}", 0, -1, browser, "exclude_user", "exclude_file", true, EMPTY_DEPOT, EMPTY_WORKSPACE_CLEANUP, EMPTY_MASKVIEW, null, null); scm.setProjectPath("path"); project.setScm(scm); @@ -136,7 +136,7 @@ public void testDepotContainsUnencryptedPassword() throws Exception { PerforceSCM scm = new PerforceSCM( "user", password, "client", "port", "", "test_installation", "sysRoot", "sysDrive", "label", "counter", "upstreamProject", "shared", "charset", "charset2", "user", false, true, true, true, true, true, false, - false, true, false, false, false, "${basename}", 0, -1, browser, "exclude_user", "exclude_file", true, EMPTY_DEPOT, EMPTY_WORKSPACE_CLEANUP, EMPTY_MASKVIEW); + false, true, false, false, false, "${basename}", 0, -1, browser, "exclude_user", "exclude_file", true, EMPTY_DEPOT, EMPTY_WORKSPACE_CLEANUP, EMPTY_MASKVIEW, null, null); scm.setProjectPath("path"); project.setScm(scm); @@ -154,7 +154,7 @@ public void testConfigSaveReloadAndSaveDoesNotDoubleEncryptThePassword() throws PerforceSCM scm = new PerforceSCM( "user", password, "client", "port", "", "test_installation", "sysRoot", "sysDrive", "label", "counter", "upstreamProject", "shared", "charset", "charset2", "user", false, true, true, true, true, true, false, - false, true, false, false, false, "${basename}", 0, -1, browser, "exclude_user", "exclude_file", true, EMPTY_DEPOT, EMPTY_WORKSPACE_CLEANUP, EMPTY_MASKVIEW); + false, true, false, false, false, "${basename}", 0, -1, browser, "exclude_user", "exclude_file", true, EMPTY_DEPOT, EMPTY_WORKSPACE_CLEANUP, EMPTY_MASKVIEW, null, null); scm.setProjectPath("path"); project.setScm(scm); @@ -336,7 +336,7 @@ public void testDepotContainsUnencryptedPasswordWithgetProperty() throws Excepti PerforceSCM scm = new PerforceSCM( "user", password, "client", "port", "", "test_installation", "sysRoot", "sysDrive", "label", "counter", "upstreamProject", "shared", "charset", "charset2", "user", false, true, true, true, true, true, false, - false, false, true, false, false, "${basename}", 0, -1, browser, "exclude_user", "exclude_file", true, EMPTY_DEPOT, EMPTY_WORKSPACE_CLEANUP, EMPTY_MASKVIEW); + false, false, true, false, false, "${basename}", 0, -1, browser, "exclude_user", "exclude_file", true, EMPTY_DEPOT, EMPTY_WORKSPACE_CLEANUP, EMPTY_MASKVIEW, null, null); scm.setP4Stream("stream"); project.setScm(scm); @@ -374,7 +374,7 @@ public void testP4UpstreamProjectRenaming() throws Exception { PerforceSCM upstreamScm = new PerforceSCM( "user", "pass", "client", "port", "", "test_installation", "sysRoot", "sysDrive", null, null, null, "shared", "charset", "charset2", "user", false, true, true, true, true, true, false, - false, true, false, false, false, "${basename}", 0, -1, browser, "exclude_user", "exclude_file", true, EMPTY_DEPOT, EMPTY_WORKSPACE_CLEANUP, EMPTY_MASKVIEW); + false, true, false, false, false, "${basename}", 0, -1, browser, "exclude_user", "exclude_file", true, EMPTY_DEPOT, EMPTY_WORKSPACE_CLEANUP, EMPTY_MASKVIEW, null, null); upstreamScm.setProjectPath("path"); upstreamProject.setScm(upstreamScm); @@ -383,7 +383,7 @@ public void testP4UpstreamProjectRenaming() throws Exception { PerforceSCM downstreamScm = new PerforceSCM( "user", "pass", "client", "port", "", "test_installation", "sysRoot", "sysDrive", null, null, oldName, "shared", "charset", "charset2", "user", false, true, true, true, true, true, false, - false, true, false, false, false, "${basename}", 0, -1, browser, "exclude_user", "exclude_file", true, EMPTY_DEPOT, EMPTY_WORKSPACE_CLEANUP, EMPTY_MASKVIEW); + false, true, false, false, false, "${basename}", 0, -1, browser, "exclude_user", "exclude_file", true, EMPTY_DEPOT, EMPTY_WORKSPACE_CLEANUP, EMPTY_MASKVIEW, null, null); downstreamScm.setProjectPath("path"); downstreamProject.setScm(downstreamScm);