package org.jenkinsci.plugins.p4.client; import com.perforce.p4java.client.IClient; import com.perforce.p4java.core.IMapEntry; import com.perforce.p4java.impl.generic.client.ClientView; import hudson.model.Result; import org.jenkinsci.plugins.p4.DefaultEnvironment; import org.jenkinsci.plugins.p4.SampleServerRule; import org.jenkinsci.plugins.p4.scm.GlobalLibraryScmSource; import org.jenkinsci.plugins.p4.workspace.Workspace; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; import org.jenkinsci.plugins.workflow.libs.GlobalLibraries; import org.jenkinsci.plugins.workflow.libs.LibraryConfiguration; import org.jenkinsci.plugins.workflow.libs.SCMSourceRetriever; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; import java.util.ArrayList; import java.util.Arrays; import java.util.logging.Logger; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; public class WorkflowTest extends DefaultEnvironment { private static Logger logger = Logger.getLogger(ConnectionTest.class.getName()); private static final String P4ROOT = "tmp-WorkflowTest-p4root"; @Rule public JenkinsRule jenkins = new JenkinsRule(); @Rule public SampleServerRule p4d = new SampleServerRule(P4ROOT, R15_1); @Before public void buildCredentials() throws Exception { createCredentials("jenkins", "jenkins", p4d.getRshPort(), CREDENTIAL); } @Test public void testWorkflow() throws Exception { WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "demo"); job.setDefinition(new CpsFlowDefinition("" + "node {\n" + " p4sync credential: '" + CREDENTIAL + "', template: 'test.ws'\n" + " p4tag rawLabelDesc: 'TestLabel', rawLabelName: 'jenkins-label'\n" + " publisher = [$class: 'SubmitImpl', description: 'Submitted by Jenkins', onlyOnSuccess: false, reopen: false]\n" + " buildWorkspace = [$class: 'TemplateWorkspaceImpl', charset: 'none', format: 'jenkins-${NODE_NAME}-${JOB_NAME}', pinHost: false, templateName: 'test.ws']\n" + " p4publish credential: '" + CREDENTIAL + "', publish: publisher, workspace: buildWorkspace" + " \n" + "}", false)); WorkflowRun run = jenkins.assertBuildStatusSuccess(job.scheduleBuild2(0)); jenkins.assertLogContains("P4 Task: syncing files at change", run); jenkins.assertLogContains("P4 Task: tagging build.", run); jenkins.assertLogContains("P4 Task: reconcile files to changelist.", run); } @Test public void testWorkflowEnv() throws Exception { WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "workflowEnv"); job.setDefinition(new CpsFlowDefinition("" + "node {\n" + " p4sync credential: '" + CREDENTIAL + "', template: 'test.ws'\n" + " println \"P4_CHANGELIST: ${env.P4_CHANGELIST}\"\n" + "}", false)); WorkflowRun run = jenkins.assertBuildStatusSuccess(job.scheduleBuild2(0)); jenkins.assertLogContains("P4 Task: syncing files at change", run); jenkins.assertLogContains("P4_CHANGELIST: 40", run); } @Test public void testManualP4Sync() throws Exception { WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "manualP4Sync"); job.setDefinition(new CpsFlowDefinition("" + "node {\n" + " def workspace = [$class: 'ManualWorkspaceImpl',\n" + " name: 'jenkins-${NODE_NAME}-${JOB_NAME}',\n" + " spec: [view: '//depot/... //jenkins-${NODE_NAME}-${JOB_NAME}/...']]\n" + " def syncOptions = [$class: 'org.jenkinsci.plugins.p4.populate.SyncOnlyImpl',\n" + " revert:true, have:true, modtime:true]\n" + " p4sync workspace:workspace, credential: '" + CREDENTIAL + "', populate: syncOptions\n" + "}", false)); WorkflowRun run = jenkins.assertBuildStatusSuccess(job.scheduleBuild2(0)); jenkins.assertLogContains("P4 Task: syncing files at change", run); } @Test public void testP4GroovyConnectAndSync() throws Exception { WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "p4groovy"); job.setDefinition(new CpsFlowDefinition("" + "node() {\n" + " ws = [$class: 'StreamWorkspaceImpl', charset: 'none', format: 'jenkins-${NODE_NAME}-${JOB_NAME}', pinHost: false, streamName: '//stream/main']\n" + " p4 = p4(credential: '" + CREDENTIAL + "', workspace: ws)\n" + " p4.run('sync', '//...')\n" + "}", false)); job.save(); WorkflowRun run = job.scheduleBuild2(0).get(); jenkins.assertLogContains("p4 sync //...", run); jenkins.assertLogContains("totalFileCount 10", run); } @Test public void testP4GroovySpecEdit() throws Exception { WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "p4groovy.spec"); job.setDefinition(new CpsFlowDefinition("" + "node() {\n" + " ws = [$class: 'StreamWorkspaceImpl', charset: 'none', format: 'jenkins-${NODE_NAME}-${JOB_NAME}', pinHost: false, streamName: '//stream/main']\n" + " p4 = p4(credential: '" + CREDENTIAL + "', workspace: ws)\n" + " clientName = p4.getClientName();\n" + " client = p4.fetch('client', clientName)\n" + " echo \"Client: $client\"\n" + " client.put('Description', 'foo')\n" + " p4.save('client', client)\n" + "}", false)); job.save(); WorkflowRun run = job.scheduleBuild2(0).get(); jenkins.assertLogContains("p4 client -o jenkins-master-p4groovy.spec", run); } @Test public void testP4GroovyForceSpecEdit() throws Exception { WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "p4groovy.spec.force"); job.setDefinition(new CpsFlowDefinition("" + "node() {\n" + " ws = [$class: 'StreamWorkspaceImpl', charset: 'none', format: 'jenkins-${NODE_NAME}-${JOB_NAME}', pinHost: false, streamName: '//stream/main']\n" + " p4 = p4(credential: '" + CREDENTIAL + "', workspace: ws)\n" + " clientName = p4.getClientName();\n" + " client = p4.fetch('client', clientName)\n" + " echo \"Client: $client\"\n" + " client.put('Description', 'foo')\n" + " res = p4.save('client', client, '-f')\n" + " echo \"Result: $res\"\n" + "}", false)); job.save(); WorkflowRun run = job.scheduleBuild2(0).get(); // Look for no permission as '-f' flag requires 'admin' permissions jenkins.assertLogContains("You don't have permission for this operation.", run); } @Test public void testSyncIDManualP4Sync() throws Exception { WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "syncIDmanualP4Sync"); job.setDefinition(new CpsFlowDefinition("" + "node {\n" + " def workspace = [$class: 'ManualWorkspaceImpl',\n" + " name: 'jenkins-${NODE_NAME}-${JOB_NAME}',\n" + " syncID: 'foo-${NODE_NAME}-${JOB_NAME}',\n" + " spec: [view: '//depot/... //jenkins-${NODE_NAME}-${JOB_NAME}/...']]\n" + " def syncOptions = [$class: 'org.jenkinsci.plugins.p4.populate.SyncOnlyImpl',\n" + " revert:true, have:true, modtime:true]\n" + " p4sync workspace:workspace, credential: '" + CREDENTIAL + "', populate: syncOptions\n" + "}", false)); WorkflowRun run = jenkins.assertBuildStatusSuccess(job.scheduleBuild2(0)); jenkins.assertLogContains("P4 Task: syncing files at change", run); WorkflowRun run2 = job.scheduleBuild2(job.getQuietPeriod()).get(); jenkins.assertBuildStatusSuccess(run2); assertEquals(2, job.getLastBuild().getNumber()); jenkins.assertLogContains("Found last change 40 on syncID foo-NODE_NAME-syncIDmanualP4Sync", run2); } @Test public void testP4GroovyMultiArg() throws Exception { WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "multiArg"); job.setDefinition(new CpsFlowDefinition("" + "node() {\n" + " ws = [$class: 'StreamWorkspaceImpl', charset: 'none', format: 'jenkins-${NODE_NAME}-${JOB_NAME}', pinHost: false, streamName: '//stream/main']\n" + " p4 = p4(credential: '" + CREDENTIAL + "', workspace: ws)\n" + " p4.run('sync', '//...')\n" + " p4.run('changes', '-m4', '//...@24,27')\n" + "}", false)); job.save(); WorkflowRun run = job.scheduleBuild2(0).get(); jenkins.assertLogContains("Change 27", run); jenkins.assertLogContains("Change 24", run); jenkins.assertLogNotContains("Change 1", run); jenkins.assertLogNotContains("Change 40", run); } @Test public void testCheckoutEnvironment() throws Exception { WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "checkoutEnv"); job.setDefinition(new CpsFlowDefinition("" + "node() {\n" + " stage('Sync files...') {\n" + " checkout([$class: 'PerforceScm', " + " credential: '" + CREDENTIAL + "', " + " populate: [$class: 'ForceCleanImpl', have: false, pin: '', quiet: true], " + " workspace: [$class: 'StreamWorkspaceImpl', charset: 'none', " + " format: 'jenkins-${NODE_NAME}-${JOB_NAME}', pinHost: false, " + " streamName: '//stream/main']])\n" + " }\n" + " stage ('Test env...') {\n" + " println \"P4_CHANGELIST=${env.P4_CHANGELIST}\"\n" + " println \"P4_CLIENT=${env.P4_CLIENT}\"\n" + " println \"HUDSON_CHANGELOG_FILE=${env.HUDSON_CHANGELOG_FILE}\"\n" + " println \"P4_USER=${env.P4_USER}\"\n" + " println \"P4_TICKET=${env.P4_TICKET}\"\n" + " }\n" + "}", false)); job.save(); WorkflowRun run = job.scheduleBuild2(0).get(); jenkins.assertLogContains("P4_CHANGELIST=39", run); jenkins.assertLogContains("P4_CLIENT=jenkins-master-checkoutEnv", run); jenkins.assertLogContains("P4_USER=jenkins", run); jenkins.assertLogNotContains("HUDSON_CHANGELOG_FILE=null", run); } @Test public void testCleanupClient() throws Exception { WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "cleanup"); job.setDefinition(new CpsFlowDefinition("" + "node () {\n" + " p4sync charset: 'none', \n" + " credential: '" + CREDENTIAL + "', \n" + " format: 'jenkins-${NODE_NAME}-${JOB_NAME}-1', \n" + " populate: forceClean(quiet: true), \n" + " source: streamSource('//stream/main')\n" + "\n" + " p4cleanup(true)\n" + "\n" + " p4sync charset: 'none', \n" + " credential: '" + CREDENTIAL + "', \n" + " format: 'jenkins-${NODE_NAME}-${JOB_NAME}-2', \n" + " populate: forceClean(quiet: true), \n" + " source: streamSource('//stream/main')\n" + "\n" + " p4cleanup(true)\n" + "}", false)); job.save(); WorkflowRun run = job.scheduleBuild2(0).get(); jenkins.assertLogContains("P4 Task: cleanup client: jenkins-master-cleanup-1", run); jenkins.assertLogContains("P4 Task: cleanup client: jenkins-master-cleanup-2", run); } @Test public void testGlobalLib() throws Exception { // submit test library String content = "" + "def call(String name = 'human') {\n" + " echo \"Hello again, ${name}.\"\n" + "}"; submitFile(jenkins, "//depot/library/vars/sayHello.groovy", content); // change in source (after library) submitFile(jenkins, "//depot/Data/fileA", content); // configure Global Library String path = "//depot/library"; GlobalLibraryScmSource scm = new GlobalLibraryScmSource(CREDENTIAL, null, path); SCMSourceRetriever source = new SCMSourceRetriever(scm); LibraryConfiguration config = new LibraryConfiguration("testLib", source); config.setImplicit(true); config.setDefaultVersion("now"); GlobalLibraries globalLib = (GlobalLibraries) jenkins.getInstance().getDescriptor(GlobalLibraries.class); assertNotNull(globalLib); globalLib.setLibraries(Arrays.asList(config)); // create job using library WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "useLib"); job.setDefinition(new CpsFlowDefinition("" + "node() {\n" + " p4sync charset: 'none', \n" + " credential: '" + CREDENTIAL + "', \n" + " populate: autoClean(quiet: true), \n" + " source: depotSource('//depot/Data/...')\n" + " sayHello 'Jenkins'\n" + " println \"SYNC_CHANGELIST: ${env.P4_CHANGELIST}\"\n" + "}", false)); job.save(); WorkflowRun run = job.scheduleBuild2(0).get(); assertEquals(Result.SUCCESS, run.getResult()); jenkins.assertLogContains("SYNC_CHANGELIST: 45", run); // Clear Global Libraries for other Jobs globalLib.setLibraries(new ArrayList<LibraryConfiguration>()); } @Test public void testPreviewCheckout() throws Exception { WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "previewCheckout"); job.setDefinition(new CpsFlowDefinition("" + "node {\n" + " def workspace = [$class: 'ManualWorkspaceImpl',\n" + " name: 'jenkins-${NODE_NAME}-${JOB_NAME}',\n" + " spec: [view: '//depot/... //jenkins-${NODE_NAME}-${JOB_NAME}/...']]\n" + " def syncOptions = [$class: 'CheckOnlyImpl', quiet:true]\n" + " p4sync workspace:workspace, credential: '" + CREDENTIAL + "', populate: syncOptions\n" + "}", false)); WorkflowRun run = jenkins.assertBuildStatusSuccess(job.scheduleBuild2(0)); jenkins.assertLogContains("p4 sync -n -q", run); } @Test public void testFlushCheckout() throws Exception { WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "flushCheckout"); job.setDefinition(new CpsFlowDefinition("" + "node {\n" + " def workspace = [$class: 'ManualWorkspaceImpl',\n" + " name: 'jenkins-${NODE_NAME}-${JOB_NAME}',\n" + " spec: [view: '//depot/... //jenkins-${NODE_NAME}-${JOB_NAME}/...']]\n" + " def syncOptions = [$class: 'FlushOnlyImpl', quiet:true]\n" + " p4sync workspace:workspace, credential: '" + CREDENTIAL + "', populate: syncOptions\n" + "}", false)); WorkflowRun run = jenkins.assertBuildStatusSuccess(job.scheduleBuild2(0)); jenkins.assertLogContains("p4 sync -k -q", run); } @Test public void testP4SyncEllipsisAndDot() throws Exception { WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "workflowEllipsis"); job.setDefinition(new CpsFlowDefinition("" + "node {\n" + " p4sync credential: '" + CREDENTIAL + "', " + " source: depotSource('''//depot/test/projA/1.1.0/...\n//depot/test/projA/1.2.0/...''')" + "}", false)); jenkins.assertBuildStatusSuccess(job.scheduleBuild2(0)); String name = "jenkins-master-workflowEllipsis-0"; Workspace workspace = defaultWorkspace(name); ClientHelper p4 = new ClientHelper(job.asItem(), CREDENTIAL, null, workspace); p4.login(); IClient client = p4.getConnection().getCurrentClient(); assertNotNull(client); ClientView view = client.getClientView(); assertNotNull(view); assertEquals("//jenkins-master-workflowEllipsis-0/depot/test/projA/1.1.0/...", view.getEntry(0).getRight()); assertEquals("//jenkins-master-workflowEllipsis-0/depot/test/projA/1.2.0/...", view.getEntry(1).getRight()); p4.disconnect(); } @Test public void testP4SyncSpaceInPath() throws Exception { WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "workflowSpace"); job.setDefinition(new CpsFlowDefinition("" + "node {\n" + " p4sync credential: '" + CREDENTIAL + "', " + " source: depotSource('''//depot/test/proj A/...\n//depot/test/proj B/...''')" + "}", false)); jenkins.assertBuildStatusSuccess(job.scheduleBuild2(0)); String name = "jenkins-master-workflowSpace-0"; Workspace workspace = defaultWorkspace(name); ClientHelper p4 = new ClientHelper(job.asItem(), CREDENTIAL, null, workspace); p4.login(); IClient client = p4.getConnection().getCurrentClient(); assertNotNull(client); ClientView view = client.getClientView(); assertNotNull(view); assertEquals("//jenkins-master-workflowSpace-0/depot/test/proj A/...", view.getEntry(0).getRight()); assertEquals("//jenkins-master-workflowSpace-0/depot/test/proj B/...", view.getEntry(1).getRight()); p4.disconnect(); } @Test public void testP4SyncFileOnly() throws Exception { WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "workflowFile"); job.setDefinition(new CpsFlowDefinition("" + "node {\n" + " p4sync credential: '" + CREDENTIAL + "', " + " source: depotSource('''//depot/Main/file-4.txt\n//depot/Main/file-5.txt''')" + "}", false)); jenkins.assertBuildStatusSuccess(job.scheduleBuild2(0)); String name = "jenkins-master-workflowFile-0"; Workspace workspace = defaultWorkspace(name); ClientHelper p4 = new ClientHelper(job.asItem(), CREDENTIAL, null, workspace); p4.login(); IClient client = p4.getConnection().getCurrentClient(); assertNotNull(client); ClientView view = client.getClientView(); assertNotNull(view); assertEquals("//jenkins-master-workflowFile-0/depot/Main/file-4.txt", view.getEntry(0).getRight()); assertEquals("//jenkins-master-workflowFile-0/depot/Main/file-5.txt", view.getEntry(1).getRight()); p4.disconnect(); } @Test public void testExcludeDepotSourcePath() throws Exception { WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "excludeDepotSource"); job.setDefinition(new CpsFlowDefinition("" + "node {\n" + " p4sync credential: '" + CREDENTIAL + "', " + " source: depotSource('''//depot/Main/file-4.txt\n-//depot/Main/file-5.txt''')" + "}", false)); jenkins.assertBuildStatusSuccess(job.scheduleBuild2(0)); String name = "jenkins-master-excludeDepotSource-0"; Workspace workspace = defaultWorkspace(name); ClientHelper p4 = new ClientHelper(job.asItem(), CREDENTIAL, null, workspace); p4.login(); IClient client = p4.getConnection().getCurrentClient(); assertNotNull(client); ClientView view = client.getClientView(); assertNotNull(view); assertEquals("//depot/Main/file-4.txt", view.getEntry(0).getLeft()); assertEquals("//depot/Main/file-5.txt", view.getEntry(1).getLeft()); assertEquals(IMapEntry.EntryType.EXCLUDE, view.getEntry(1).getType()); p4.disconnect(); } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#37 | 29476 | Paul Allen |
Merge pull request #174 from skumar7322/UpdateJenkins346 Update Jenkins Version to 2.346.3 |
||
#36 | 29411 | Paul Allen |
Merge pull request #171 from skumar7322/SecurityPatch Security Patch : Update Jenkins Version and Other Dependencies |
||
#35 | 28495 | Paul Allen |
Extend delay between running both Jobs. Windows seems to miss the second job. |
||
#34 | 28492 | Paul Allen |
Fix Workflow test JenkinsRule. The @Rule 'jenkins' must not be static. |
||
#33 | 28491 | Paul Allen |
Run each test in a new Jenkins instance. Slower, but might prevent failures on Windows |
||
#32 | 28490 | Paul Allen |
Reuse Jenkins Server for slower tests. Change slower tests to use ClassRule. |
||
#31 | 28489 | Paul Allen |
Extend JenkinsRule timeout. Wrap JenkinsRule and for problematic tests on Windows extend the timeout to 7mins. |
||
#30 | 26163 | Paul Allen |
Pre-load build environment. buildEnvironment() is called by Jenkins and tagAction may not be set - so use old pre-load behaviour. JENKINS-60074 |
||
#29 | 26122 | Paul Allen |
Added additional login to resolve parallel connection issue. Includes test case for parallel stages. JENKINS-52806 |
||
#28 | 26099 | Paul Allen |
Prevent infinite polling when last build and current are pinned to a label. Added test to verify support for static lables. JENKINS-58149 |
||
#27 | 24986 | Paul Allen |
Merge pull request #87 from p4charu/jenkinsci-master Test to confirm JENKINS-54628 is fixed. |
||
#26 | 24940 | Paul Allen |
Skip sync when PreviewSync is used with quiet option `p4 sync -q -n`. JENKINS-54153 |
||
#25 | 24780 | Paul Allen |
Merge pull request #80 from p4charu/master Fix and a test for concurrent global libraries using perforce workspaces. JENKINS-50975 |
||
#24 | 24767 | Paul Allen |
Global Library support for multiple instances. Enforce a depot syntax path ending of "/..." Remove 'beta' from Global Library configuration. Generate a unique workspace to sync multiple Libraries. JENKINS-53922 |
||
#23 | 24662 | Paul Allen |
Undo *SCMSource rename to original *ScmSource. Reslove configuration loading issue due to 1.9.0 bad release. |
||
#22 | 24501 | Paul Allen | Refactor to use P4SCMXxx naming convention. | ||
#21 | 24487 | Paul Allen | Perforce Connection Refactor. | ||
#20 | 24458 | Paul Allen |
Verify new View Mapping code supports DepotSource Excludes. JENKINS-52861 |
||
#19 | 24433 | Paul Allen |
Extra arguments support for P4Groovy save function. JENKINS-52782 |
||
#18 | 24404 | Paul Allen |
Support spaces in depot path for MultiBranch and DepotSource Includes filters for leading white space (spaces/tabs). JENKINS-52652 |
||
#17 | 24403 | Paul Allen |
Support spaces in depot path for MultiBranch and DepotSource JENKINS-52604 |
||
#16 | 24402 | Paul Allen |
Fix Ellipsis detection in ClientViewMappingGenerator 'p4sync' was mistaking a single '.' for '...' when building the view. JENKINS-52572 |
||
#15 | 24267 | Paul Allen |
Use JOB_NAME in the Global Library Workspace name. Global Library workspaces must be unique. JENKINS-49525 JENKINS-50975 |
||
#14 | 24233 | Paul Allen |
Merge pull request #74 from msmeeth56/master Updated tests to work against Windows, and lower spec computers. JENKINS-52145 |
||
#13 | 23819 | Paul Allen | Cleanup test cases to use Credential ID. | ||
#12 | 23624 | Paul Allen |
Extended test to cover issues when using global libraries. JENKINS-44800 |
||
#11 | 23320 | Paul Allen | Remove deprecated ID for SCMSource constructor. | ||
#10 | 22999 | Paul Allen |
Fix sync options on FlushOnly and CheckOnly. JENKINS-46352 |
||
#9 | 22894 | Paul Allen |
(minor) remove Pipeline Library after test. Clean up after testGlobalLib and minor refactor on PublishNotifier and PublishNotifierStep. |
||
#8 | 22866 | Paul Allen |
Merge pull request #55 from jenkinsci/hth Global Pipeline Library support. JENKINS-46121 JENKINS-46550 |
||
#7 | 22821 | Paul Allen |
Merge pull request #53 from jenkinsci/TagAction-order Get Last TagAction. JENKINS-37618 JENKINS-45613 |
||
#6 | 22408 | Paul Allen |
Set SCM Environment for Jenkins 2.60+ JENKINS-37584 JENKINS-40885 |
||
#5 | 21936 | Paul Allen |
Refactor tests for 17.1 release. Removed pseudo web server on FreeStyleTest |
||
#4 | 21449 | Paul Allen |
Rename and Deprecated the old P4Groovy run method. Force use of variable arg/Array method over a single String. Add support for List<String> PR #35 JENKINS-40454 |
||
#3 | 21372 | Paul Allen |
Support custom SyncID. Exclude BUILD_NUMBER from SyncID. Pushed logging to higher level, so it is not reporting TagActions when building the Environment. JENKINS-40460 |
||
#2 | 21190 | Paul Allen |
Test for pull request #34 Custom workspace support. |
||
#1 | 21171 | Paul Allen |
Jenkinsfile basic test. Moved Workflow tests out of Connection test class. |