package org.jenkinsci.plugins.p4.scm; import com.cloudbees.hudson.plugins.folder.AbstractFolder; import com.cloudbees.hudson.plugins.folder.properties.FolderCredentialsProvider; import com.cloudbees.plugins.credentials.CredentialsProvider; import com.cloudbees.plugins.credentials.CredentialsScope; import com.cloudbees.plugins.credentials.CredentialsStore; import com.cloudbees.plugins.credentials.domains.Domain; import hudson.model.Result; import jenkins.branch.BranchSource; import jenkins.scm.api.SCMEvent; import jenkins.scm.api.SCMHeadEvent; import jenkins.scm.api.SCMSource; import net.sf.json.JSONObject; import org.jenkinsci.plugins.p4.DefaultEnvironment; import org.jenkinsci.plugins.p4.SampleServerRule; import org.jenkinsci.plugins.p4.credentials.P4BaseCredentials; import org.jenkinsci.plugins.p4.credentials.P4PasswordImpl; import org.jenkinsci.plugins.p4.populate.AutoCleanImpl; import org.jenkinsci.plugins.p4.review.ReviewProp; import org.jenkinsci.plugins.p4.scm.events.P4BranchSCMHeadEvent; import org.jenkinsci.plugins.p4.swarmAPI.SwarmHelper; import org.jenkinsci.plugins.p4.swarmAPI.SwarmProjectAPI; import org.jenkinsci.plugins.p4.swarmAPI.SwarmReviewAPI; import org.jenkinsci.plugins.p4.swarmAPI.SwarmReviewsAPI; import org.jenkinsci.plugins.p4.tasks.CheckoutStatus; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; import org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory; import org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject; import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.core.IsNull.notNullValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class PerforceSCMSourceTest extends DefaultEnvironment { private static Logger logger = Logger.getLogger(PerforceSCMSourceTest.class.getName()); private static final String P4ROOT = "tmp-ScmSourceTest-p4root"; @ClassRule public static JenkinsRule jenkins = new JenkinsRule(); @ClassRule public static SampleServerRule p4d = new SampleServerRule(P4ROOT, R15_1); @Before public void buildCredentials() throws Exception { createCredentials("jenkins", "jenkins", p4d.getRshPort(), CREDENTIAL); } @Test public void testMultiBranchWithStreams() throws Exception { String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = "//stream/..."; SCMSource source = new StreamsScmSource(CREDENTIAL, includes, null, format); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "multi-streams"); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); WorkflowJob job = multi.getItem("Ace-main"); assertThat("We now have a branch", job, notNullValue()); WorkflowRun build = job.getLastBuild(); assertThat("The branch was built", build, notNullValue()); assertThat("The branch was built", build.getNumber(), is(1)); } @Test public void testMultiBranchWithClassic() throws Exception { String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = "//stream/..."; SCMSource source = new BranchesScmSource(CREDENTIAL, includes, null, format); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "multi-classic"); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); WorkflowJob job = multi.getItem("Ace-main"); assertThat("We now have a branch", job, notNullValue()); WorkflowRun build = job.getLastBuild(); assertThat("The branch was built", build, notNullValue()); assertThat("The branch was built", build.getNumber(), is(1)); } @Test public void testNoMultiStreams() throws Exception { String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = "//depot/..."; SCMSource source = new StreamsScmSource(CREDENTIAL, includes, null, format); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "no-streams"); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We have no branches", multi.getItems(), containsInAnyOrder()); } @Test public void testSingleStream() throws Exception { String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = "//stream/Ace-main"; SCMSource source = new StreamsScmSource(CREDENTIAL, includes, null, format); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "single-streams"); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); } @Test public void testSimplePathStreams() throws Exception { String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = "//stream/..."; SCMSource source = new StreamsScmSource(CREDENTIAL, includes, null, format); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "path-streams"); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); } @Test public void testWildPathStreams() throws Exception { String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = "//stream/Ace-*"; SCMSource source = new StreamsScmSource(CREDENTIAL, includes, null, format); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "wild-streams"); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); } @Test public void testSimplePathClassic() throws Exception { String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = "//stream"; SCMSource source = new BranchesScmSource(CREDENTIAL, includes, null, format); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "path-classic"); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); } @Test public void testStarPathClassic() throws Exception { String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = "//stream/*"; SCMSource source = new BranchesScmSource(CREDENTIAL, includes, null, format); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "star-classic"); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); } @Test public void testRootPathClassic() throws Exception { String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = "//..."; SCMSource source = new BranchesScmSource(CREDENTIAL, includes, null, format); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "root-classic"); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); } @Test public void testSpacePathClassic() throws Exception { submitFile(jenkins, "//depot/space path/A/Jenkinsfile", "node() {}"); String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = "//depot/space path/..."; SCMSource source = new BranchesScmSource(CREDENTIAL, includes, null, format); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "space-classic"); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); } @Test public void testMappingPathClassic() throws Exception { submitFile(jenkins, "//depot/classic/A/src/fileA", "content"); submitFile(jenkins, "//depot/classic/A/tests/fileB", "content"); submitFile(jenkins, "//depot/classic/A/Jenkinsfile", "" + "pipeline {\n" + " agent any\n" + " stages {\n" + " stage('Test') {\n" + " steps {\n" + " script {\n" + " if(!fileExists('Jenkinsfile')) error 'missing Jenkinsfile'\n" + " if(!fileExists('depot/classic/A/src/fileA')) error 'missing fileA'\n" + " if(!fileExists('depot/classic/A/tests/fileB')) error 'missing fileB'\n" + " }\n" + " }\n" + " }\n" + " }\n" + "}"); String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = "//depot/classic/..."; BranchesScmSource source = new BranchesScmSource(CREDENTIAL, includes, null, format); source.setPopulate(new AutoCleanImpl()); String mappings = "src/...\ntests/..."; source.setMappings(mappings); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "mapping-classic"); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); WorkflowJob job = multi.getItem("A"); assertThat("We now have a branch", job, notNullValue()); WorkflowRun build = job.getLastBuild(); assertThat("The branch was built", build, notNullValue()); assertEquals(Result.SUCCESS, build.getResult()); } @Test public void testMappingDefaultsClassic() throws Exception { String base = "//depot/default"; sampleProject(base, new String[]{"Main"}, "Jenkinsfile"); String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = base + "/..."; BranchesScmSource source = new BranchesScmSource(CREDENTIAL, includes, null, format); source.setPopulate(new AutoCleanImpl()); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "mapping-default-classic"); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); WorkflowJob job = multi.getItem("Main"); assertThat("We now have a branch", job, notNullValue()); WorkflowRun build = job.getLastBuild(); assertThat("The branch was built", build, notNullValue()); assertEquals(Result.SUCCESS, build.getResult()); } @Test public void testRootPathStreams() throws Exception { String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = "//..."; SCMSource source = new StreamsScmSource(CREDENTIAL, includes, null, format); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "root-streams"); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); } @Test public void testMultiBranchClassicWithCredentialsInFolder() throws Exception { WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "multi-classic-creds-in-folder"); CredentialsStore folderStore = getFolderStore(multi); P4BaseCredentials inFolderCredentials = new P4PasswordImpl( CredentialsScope.GLOBAL, "idInFolder", "desc:passwd", p4d.getRshPort(), null, "jenkins", "0", "0", null, "jenkins"); folderStore.addCredentials(Domain.global(), inFolderCredentials); String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = "//stream/..."; SCMSource source = new BranchesScmSource(inFolderCredentials.getId(), includes, null, format); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertEquals("Branch Indexing succeeded", Result.SUCCESS, multi.getComputation().getResult()); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); } @Test public void testMultiBranchStreamWithCredentialsInFolder() throws Exception { WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "multi-streams-creds-in-folder"); CredentialsStore folderStore = getFolderStore(multi); P4BaseCredentials inFolderCredentials = new P4PasswordImpl( CredentialsScope.GLOBAL, "idInFolder", "desc:passwd", p4d.getRshPort(), null, "jenkins", "0", "0", null, "jenkins"); folderStore.addCredentials(Domain.global(), inFolderCredentials); String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = "//stream/..."; SCMSource source = new StreamsScmSource(inFolderCredentials.getId(), includes, null, format); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertEquals("Branch Indexing succeeded", Result.SUCCESS, multi.getComputation().getResult()); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); } @Test public void testMultiBranchClassicUpdateEvent() throws Exception { // Setup sample Multi Branch Project String base = "//depot/update"; String baseChange = sampleProject(base, new String[]{"Main", "Dev"}, "Jenkinsfile"); assertNotNull(baseChange); String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = base + "/..."; BranchesScmSource source = new BranchesScmSource(CREDENTIAL, includes, null, format); source.setPopulate(new AutoCleanImpl()); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "classic-update-event"); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); // Test on branch 'Main' String branch = "Main"; WorkflowJob job = multi.getItem(branch); assertThat("We now have a branch", job, notNullValue()); assertEquals(Result.SUCCESS, job.getLastBuild().getResult()); // Make a change String change = submitFile(jenkins, base + "/" + branch + "/src/fileA", "edit"); HashMap<String, String> map = new HashMap<>(); map.put(ReviewProp.P4_PORT.getProp(), p4d.getRshPort()); map.put(ReviewProp.P4_CHANGE.getProp(), change); JSONObject payload = JSONObject.fromObject(map); String origin = "testMultiBranchClassicUpdateEvent"; P4BranchSCMHeadEvent event = new P4BranchSCMHeadEvent(SCMEvent.Type.UPDATED, payload, origin); SCMHeadEvent.fireNow(event); TimeUnit.SECONDS.sleep(job.getQuietPeriod()); jenkins.waitUntilNoActivity(); WorkflowRun build = multi.getItem("Main").getLastBuild(); assertEquals("Main has built", 2, build.number); assertTrue("Dev has not built", multi.getItem("Dev").getLastBuild().number == 1); } @Test public void testMultiBranchClassicMultiUpdateEvents() throws Exception { // Setup sample Multi Branch Project String base = "//depot/multi"; String baseChange = sampleProject(base, new String[]{"Main", "Dev"}, "Jenkinsfile"); assertNotNull(baseChange); String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = base + "/..."; BranchesScmSource source = new BranchesScmSource(CREDENTIAL, includes, null, format); source.setPopulate(new AutoCleanImpl()); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "multi-update-events"); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); // Test on branch 'Main' String branch = "Main"; WorkflowJob job = multi.getItem(branch); assertThat("We now have a branch", job, notNullValue()); assertEquals(Result.SUCCESS, job.getLastBuild().getResult()); // Make a change String change = submitFile(jenkins, base + "/" + branch + "/src/fileA", "edit1"); HashMap<String, String> map = new HashMap<>(); map.put(ReviewProp.P4_PORT.getProp(), p4d.getRshPort()); map.put(ReviewProp.P4_CHANGE.getProp(), change); JSONObject payload = JSONObject.fromObject(map); // Another change that should not get sync'ed submitFile(jenkins, base + "/" + branch + "/src/fileB", "edit2"); String origin = "testMultiBranchClassicMultiUpdateEvents"; P4BranchSCMHeadEvent event = new P4BranchSCMHeadEvent(SCMEvent.Type.UPDATED, payload, origin); SCMHeadEvent.fireNow(event); TimeUnit.SECONDS.sleep(job.getQuietPeriod()); jenkins.waitUntilNoActivity(); WorkflowRun runMain = multi.getItem("Main").getLastBuild(); assertEquals("Main has built", 2, runMain.number); assertEquals(Result.SUCCESS, runMain.getResult()); assertTrue("Dev has not built", multi.getItem("Dev").getLastBuild().number == 1); jenkins.assertLogContains("P4 Task: syncing files at change: " + change, runMain); } @Test public void testMultiBranchSwarmCommittedTriggerEvent() throws Exception { // Setup sample Multi Branch Project String project = "SwarmTriggerCommit"; String base = "//depot/SwarmTriggerCommit"; String[] branches = new String[]{"Main", "Dev"}; String baseChange = sampleProject(base, branches, "Jenkinsfile"); assertNotNull(baseChange); SwarmHelper mockSwarm = sampleSwarmProject(project, base, branches); assertNotNull(mockSwarm); String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; SwarmScmSource source = new SwarmScmSource(CREDENTIAL, null, format); source.setProject(project); source.setSwarm(mockSwarm); source.setPopulate(new AutoCleanImpl()); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, project); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); // Test on branch 'Main' String branch = "Main"; WorkflowJob job = multi.getItem(branch); assertThat("We now have a branch", job, notNullValue()); assertEquals(Result.SUCCESS, job.getLastBuild().getResult()); // Make a shelve / fake review String commit = submitFile(jenkins, base + "/" + branch + "/src/fileA", "edit1"); assertNotNull(commit); assertTrue("Not a number", commit.chars().allMatch(Character::isDigit)); // Mock Changes/Reviews List<Long> changes = new ArrayList<>(); changes.add(Long.parseLong(commit)); HashMap<String, List<String>> projects = new HashMap<>(); projects.put(project, Arrays.asList("Main")); SwarmReviewAPI.Review mockReview = new SwarmReviewAPI.Review(changes, changes, projects); when(mockSwarm.getSwarmReview(anyString())).thenReturn(new SwarmReviewAPI(mockReview)); // Build JSON Payload HashMap<String, String> map = new HashMap<>(); map.put(ReviewProp.P4_PORT.getProp(), p4d.getRshPort()); map.put(ReviewProp.P4_CHANGE.getProp(), commit); JSONObject payload = JSONObject.fromObject(map); // Another change that should not get sync'ed submitFile(jenkins, base + "/" + branch + "/src/fileB", "edit2"); String origin = "testMultiBranchSwarmCommittedTriggerEvent"; P4BranchSCMHeadEvent event = new P4BranchSCMHeadEvent(SCMEvent.Type.UPDATED, payload, origin); SCMHeadEvent.fireNow(event); TimeUnit.SECONDS.sleep(job.getQuietPeriod()); jenkins.waitUntilNoActivity(); assertTrue("Dev should not build", multi.getItem("Dev").getLastBuild().number == 1); WorkflowRun runMain = multi.getItem("Main").getLastBuild(); assertEquals("Main should have built", 2, runMain.number); assertEquals(Result.SUCCESS, runMain.getResult()); jenkins.assertLogContains("P4 Task: syncing files at change: " + commit, runMain); } @Test public void testMultiBranchSwarmCommittedAPIEvent() throws Exception { // Setup sample Multi Branch Project String project = "SwarmCommit"; String base = "//depot/SwarmCommit"; String[] branches = new String[]{"Main", "Dev"}; String baseChange = sampleProject(base, branches, "Jenkinsfile"); assertNotNull(baseChange); SwarmHelper mockSwarm = sampleSwarmProject(project, base, branches); assertNotNull(mockSwarm); String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; SwarmScmSource source = new SwarmScmSource(CREDENTIAL, null, format); source.setProject(project); source.setSwarm(mockSwarm); source.setPopulate(new AutoCleanImpl()); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, project); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); // Test on branch 'Main' String branch = "Main"; WorkflowJob job = multi.getItem(branch); assertThat("We now have a branch", job, notNullValue()); assertEquals(Result.SUCCESS, job.getLastBuild().getResult()); // Make a shelve / fake review String commit = submitFile(jenkins, base + "/" + branch + "/src/fileA", "edit1"); assertNotNull(commit); assertTrue("Not a number", commit.chars().allMatch(Character::isDigit)); // Mock Changes/Reviews List<Long> changes = new ArrayList<>(); changes.add(Long.parseLong(commit)); HashMap<String, List<String>> projects = new HashMap<>(); projects.put(project, Arrays.asList("Main")); SwarmReviewAPI.Review mockReview = new SwarmReviewAPI.Review(changes, changes, projects); when(mockSwarm.getSwarmReview(anyString())).thenReturn(new SwarmReviewAPI(mockReview)); // Build JSON Payload HashMap<String, String> map = new HashMap<>(); map.put(ReviewProp.P4_PORT.getProp(), p4d.getRshPort()); map.put(ReviewProp.SWARM_PROJECT.getProp(), project); map.put(ReviewProp.SWARM_BRANCH.getProp(), branch); map.put(ReviewProp.SWARM_PATH.getProp(), base + "/" + branch); map.put(ReviewProp.P4_CHANGE.getProp(), commit); map.put(ReviewProp.SWARM_STATUS.getProp(), CheckoutStatus.COMMITTED.name()); JSONObject payload = JSONObject.fromObject(map); // Another change that should not get sync'ed submitFile(jenkins, base + "/" + branch + "/src/fileB", "edit2"); String origin = "testMultiBranchClassicUpdateEvent"; P4BranchSCMHeadEvent event = new P4BranchSCMHeadEvent(SCMEvent.Type.UPDATED, payload, origin); SCMHeadEvent.fireNow(event); TimeUnit.SECONDS.sleep(job.getQuietPeriod()); jenkins.waitUntilNoActivity(); assertTrue("Dev should not build", multi.getItem("Dev").getLastBuild().number == 1); WorkflowRun runMain = multi.getItem("Main").getLastBuild(); assertEquals("Main should have built", 2, runMain.number); jenkins.assertLogContains("P4 Task: syncing files at change: " + commit, runMain); assertEquals(Result.SUCCESS, runMain.getResult()); } @Test public void testMultiBranchSwarmMultiUpdateEvents() throws Exception { // Setup sample Multi Branch Project String project = "SwarmReview"; String base = "//depot/SwarmReview"; String[] branches = new String[]{"Main", "Dev"}; String baseChange = sampleProject(base, branches, "Jenkinsfile"); assertNotNull(baseChange); SwarmHelper mockSwarm = sampleSwarmProject(project, base, branches); assertNotNull(mockSwarm); String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; SwarmScmSource source = new SwarmScmSource(CREDENTIAL, null, format); source.setProject(project); source.setSwarm(mockSwarm); source.setPopulate(new AutoCleanImpl()); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, project); multi.getSourcesList().add(new BranchSource(source)); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); // Test on branch 'Main' String branch = "Main"; WorkflowJob job = multi.getItem(branch); assertThat("We now have a branch", job, notNullValue()); assertEquals(Result.SUCCESS, job.getLastBuild().getResult()); // Make a shelve / fake review String review = shelveFile(jenkins, base + "/" + branch + "/src/fileA", "edit1"); logger.info("Test: shelving " + review); assertNotNull(review); assertTrue("Not a number", review.chars().allMatch(Character::isDigit)); // Mock Changes/Reviews List<Long> changes = new ArrayList<>(); changes.add(Long.parseLong(review)); HashMap<String, List<String>> projects = new HashMap<>(); projects.put(project, Arrays.asList("Main")); SwarmReviewAPI.Review mockReview = new SwarmReviewAPI.Review(changes, changes, projects); when(mockSwarm.getSwarmReview(anyString())).thenReturn(new SwarmReviewAPI(mockReview)); List<SwarmReviewsAPI.Reviews> mockReviewsList = new ArrayList<>(); SwarmReviewsAPI.Reviews mockReviews = new SwarmReviewsAPI.Reviews(Long.parseLong(review), changes); mockReviewsList.add(mockReviews); when(mockSwarm.getActiveReviews(project)).thenReturn(mockReviewsList); // Build JSON Payload HashMap<String, String> map = new HashMap<>(); map.put(ReviewProp.P4_PORT.getProp(), p4d.getRshPort()); map.put(ReviewProp.SWARM_PROJECT.getProp(), project); map.put(ReviewProp.SWARM_BRANCH.getProp(), branch); map.put(ReviewProp.SWARM_PATH.getProp(), base + "/" + branch); map.put(ReviewProp.P4_CHANGE.getProp(), review); map.put(ReviewProp.SWARM_REVIEW.getProp(), review); map.put(ReviewProp.SWARM_STATUS.getProp(), CheckoutStatus.SHELVED.name()); JSONObject payload = JSONObject.fromObject(map); // Another change that should not get sync'ed String change = submitFile(jenkins, base + "/" + branch + "/src/fileB", "edit2"); logger.info("Test: submitting change " + change); String origin = "testMultiBranchSwarmMultiUpdateEvents"; P4BranchSCMHeadEvent event = new P4BranchSCMHeadEvent(SCMEvent.Type.CREATED, payload, origin); logger.fine("\n\nTest: Firing Event!"); SCMHeadEvent.fireNow(event); TimeUnit.SECONDS.sleep(job.getQuietPeriod()); jenkins.waitUntilNoActivity(); assertTrue("Dev should not built", multi.getItem("Dev").getLastBuild().number == 1); assertTrue("Main should not built", multi.getItem("Main").getLastBuild().number == 1); WorkflowJob revJob = multi.getItem("Main-" + review); assertNotNull(revJob); WorkflowRun revRun = revJob.getLastBuild(); assertNotNull(revJob); jenkins.assertLogContains("P4 Task: syncing files at change: " + review, revRun); jenkins.assertLogContains("P4 Task: unshelve review: " + review, revRun); assertEquals(Result.SUCCESS, revRun.getResult()); } @Test @Issue("JENKINS-54382") public void testMultiBranchDeepJenkinsfile() throws Exception { // Setup sample Multi Branch Project String base = "//depot/deep"; String scriptPath = "space build/jfile"; String baseChange = sampleProject(base, new String[]{"Main", "Dev"}, scriptPath); assertNotNull(baseChange); String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = base + "/..."; BranchesScmSource source = new BranchesScmSource(CREDENTIAL, includes, null, format); source.setPopulate(new AutoCleanImpl()); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "deep-jenkinsfile"); multi.getSourcesList().add(new BranchSource(source)); WorkflowBranchProjectFactory workflowBranchProjectFactory = new WorkflowBranchProjectFactory(); workflowBranchProjectFactory.setScriptPath(scriptPath); multi.setProjectFactory(workflowBranchProjectFactory); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); // Test on branch 'Main' String branch = "Main"; WorkflowJob job = multi.getItem(branch); assertThat("We now have a branch", job, notNullValue()); assertEquals(Result.SUCCESS, job.getLastBuild().getResult()); } @Test public void testMultiBranchMultiLineDeepJenkinsfile() throws Exception { // Setup sample Multi Branch Project String base = "//depot/mdeep"; String scriptPath = "space build/jfile"; submitFile(jenkins, "//depot/other/src/fileA", "content"); String baseChange = sampleProject(base, new String[]{"Main", "Dev"}, scriptPath); assertNotNull(baseChange); String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = base + "/..." + "\n" + "//depot/other/..."; BranchesScmSource source = new BranchesScmSource(CREDENTIAL, includes, null, format); source.setPopulate(new AutoCleanImpl()); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "multi-line-deep-jenkinsfile"); multi.getSourcesList().add(new BranchSource(source)); WorkflowBranchProjectFactory workflowBranchProjectFactory = new WorkflowBranchProjectFactory(); workflowBranchProjectFactory.setScriptPath(scriptPath); multi.setProjectFactory(workflowBranchProjectFactory); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); // Test on branch 'Main' String branch = "Main"; WorkflowJob job = multi.getItem(branch); assertThat("We now have a branch", job, notNullValue()); assertEquals(Result.SUCCESS, job.getLastBuild().getResult()); } @Test public void testMultiBranchRemoteJenkinsfile() throws Exception { // Setup sample Multi Branch Project String base = "//depot/Remote"; String scriptPath = "a space/jfile"; String branch = "Main"; // Remote Jenkinsfile submitFile(jenkins, base + "/" + branch + "/" + scriptPath, "" + "pipeline {\n" + " agent any\n" + " stages {\n" + " stage('Test') {\n" + " steps {\n" + " script {\n" + " if(!fileExists('" + scriptPath + "')) error 'missing " + scriptPath + "'\n" + " if(!fileExists('src/fileA')) error 'missing fileA'\n" + " if(!fileExists('src/fileB')) error 'missing fileB'\n" + " }\n" + " }\n" + " }\n" + " }\n" + "}"); // Source files String projBase = "//depot/ProjectA/Main"; submitFile(jenkins, projBase + "/src/fileA", "content"); String baseChange = submitFile(jenkins, projBase + "/src/fileB", "content"); assertNotNull(baseChange); // Setup MultiBranch String format = "jenkins-${NODE_NAME}-${JOB_NAME}"; String includes = base + "/..."; BranchesScmSource source = new BranchesScmSource(CREDENTIAL, includes, null, format); source.setPopulate(new AutoCleanImpl()); source.setMappings("//depot/ProjectA/${BRANCH_NAME}/..."); WorkflowMultiBranchProject multi = jenkins.jenkins.createProject(WorkflowMultiBranchProject.class, "multi-remote-jenkinsfile"); multi.getSourcesList().add(new BranchSource(source)); WorkflowBranchProjectFactory workflowBranchProjectFactory = new WorkflowBranchProjectFactory(); workflowBranchProjectFactory.setScriptPath(scriptPath); multi.setProjectFactory(workflowBranchProjectFactory); multi.scheduleBuild2(0); jenkins.waitUntilNoActivity(); assertThat("We now have branches", multi.getItems(), not(containsInAnyOrder())); // Test on branch 'Main' WorkflowJob job = multi.getItem(branch); assertThat("We now have a branch", job, notNullValue()); assertEquals(Result.SUCCESS, job.getLastBuild().getResult()); } /* ------------------------------------------------------------------------------------------------------------- */ /* Helper methods */ /* ------------------------------------------------------------------------------------------------------------- */ private CredentialsStore getFolderStore(AbstractFolder f) { Iterable<CredentialsStore> stores = CredentialsProvider.lookupStores(f); CredentialsStore folderStore = null; for (CredentialsStore s : stores) { if (s.getProvider() instanceof FolderCredentialsProvider && s.getContext() == f) { folderStore = s; break; } } return folderStore; } private String sampleProject(String base, String[] branches, String jfile) throws Exception { String id = null; for (String branch : branches) { submitFile(jenkins, base + "/" + branch + "/" + jfile, "" + "pipeline {\n" + " agent any\n" + " stages {\n" + " stage('Test') {\n" + " steps {\n" + " script {\n" + " if(!fileExists('" + jfile + "')) error 'missing " + jfile + "'\n" + " if(!fileExists('src/fileA')) error 'missing fileA'\n" + " if(!fileExists('src/fileB')) error 'missing fileB'\n" + " }\n" + " }\n" + " }\n" + " }\n" + "}"); submitFile(jenkins, base + "/" + branch + "/src/fileA", "content"); id = submitFile(jenkins, base + "/" + branch + "/src/fileB", "content"); } return id; } private SwarmHelper sampleSwarmProject(String project, String base, String[] branches) throws Exception { SwarmHelper mockSwarm = mock(SwarmHelper.class); when(mockSwarm.getBaseUrl()).thenReturn("mock"); when(mockSwarm.getActiveReviews(project)).thenReturn(new ArrayList<>()); // Mock Branches and Paths List<SwarmProjectAPI.Branch> swarmBranches = new ArrayList<>(); for (String branch : branches) { List<String> swarmMainPath = new ArrayList<>(); swarmMainPath.add(base + "/" + branch + "/..."); swarmBranches.add(new SwarmProjectAPI.Branch(branch, branch, swarmMainPath)); } when(mockSwarm.getBranchesInProject(project)).thenReturn(swarmBranches); return mockSwarm; } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#14 | 25115 | paul_allen |
Merge pull request #91 from p4charu/jenkinsci-master Fixed JENKINS-39107 and JENKINS-55826 |
||
#13 | 25035 | paul_allen | MultiBranch test to cover remote and local mapped files. | ||
#12 | 25015 | paul_allen | Enable/Disable MultiBranch Scan per change using Polling Filter. | ||
#11 | 25014 | paul_allen |
Scan per change support for MultiBranch with remote Jenkinsfiles. Only the 'Polling per Change' Filter is supported; need to disable or support the other filter types. JENKINS-53936 |
||
#10 | 25006 | paul_allen |
Support for remote Jenkinsfiles in a MultiBranch project. Jenkinsfile are idenitified by the Include branches path (e.g. //depot/Remote/...), but you must add a Mapping in the BranchSource->Advanced->View Mappings to locate the projects source and use a special ${BRANCH_NAME} in the path. e.g. //depot/ProjectA/${BRANCH_NAME}/... JENKINS-53936 |
||
#9 | 24829 | paul_allen |
Support Jenkinsfiles in sub directories. Preserve Jenkinsfile path in Client View. JENKINS-54382 |
||
#8 | 24662 | paul_allen |
Undo *SCMSource rename to original *ScmSource. Reslove configuration loading issue due to 1.9.0 bad release. |
||
#7 | 24597 | paul_allen | Fix P4Path bug on MultiBranch to include branch. | ||
#6 | 24571 | paul_allen |
Support for Swarm pre-commit review events. Swarm pre-commit review event creates a new 'Reviews' Tag in the MultiBranch and builds with specified change and shelf. |
||
#5 | 24536 | paul_allen |
Improved Swarm SCMRevision builder. Started to add Swarm Review Event support and exteded test case. JENKINS-52066 |
||
#4 | 24535 | paul_allen | Test cleanup. | ||
#3 | 24529 | paul_allen |
Swarm Commit Event support, refactoring and test. JENKINS-52605 (Fix doc in 'Includes' help bubble for MultiBranch) JENKINS-52066 (Improve Swarm Commit and Branch Event support) |
||
#2 | 24505 | paul_allen | Fix case-sensitive renames | ||
#1 | 24504 | paul_allen |
Tree walter for BranchSCMSource Events. On a change-submit event use the change number and grab a submitted file. Walk up the path looking for a Jenkinsfile, then derive 'Project' path, 'Branch' name and 'Path' for the SCMHead/Revision. This assumes that the Jenkinsfile is in the route of your projects. Alternatively use the Swarm Event and pass your own 'Project', 'Branch' and 'Path'. |
||
//guest/perforce_software/p4jenkins/main/src/test/java/org/jenkinsci/plugins/p4/scm/PerforceScmSourceTest.java | |||||
#13 | 24501 | paul_allen | Refactor to use P4SCMXxx naming convention. | ||
#12 | 24500 | paul_allen | Tidyup and refactor P4Ref classes. | ||
#11 | 24497 | paul_allen |
Force use of revision for Head. Update P4Head->P4Path revision with P4Revision to avoid builds on unbounded 'latest'. |
||
#10 | 24492 | paul_allen |
Initial work for MultiBranch Event trigger. JENKINS-52066 (Triggered Events and not Polling per change) |
||
#9 | 24455 | paul_allen |
Allow query of single streams by appending a `*` to a streams path. https://github.com/p4paul/p4-jenkins/issues/36 |
||
#8 | 24454 | paul_allen |
Exclude and Include mapping support. Refactored P4Path usage and added P4SwarmPath. JENKINS-49804 |
||
#7 | 24403 | paul_allen |
Support spaces in depot path for MultiBranch and DepotSource JENKINS-52604 |
||
#6 | 23819 | paul_allen | Cleanup test cases to use Credential ID. | ||
#5 | 23320 | paul_allen | Remove deprecated ID for SCMSource constructor. | ||
#4 | 22396 | paul_allen |
MultiBranch support for Perforce Swarm Reviews. A work in progress - adds Swarm API support to find branches and reviews from a Swarm project. #review-22354 |
||
#3 | 21936 | paul_allen |
Refactor tests for 17.1 release. Removed pseudo web server on FreeStyleTest |
||
#2 | 21794 | paul_allen |
Merge pull request #39 from Dohbedoh/JENKINS-34825 Jenkins 34825 |
||
#1 | 21758 | paul_allen |
Merge pull request #38 from jenkinsci/dev scm-api 2.0.2 updates |