diff --git a/src/main/java/hudson/plugins/git/BranchSpec.java b/src/main/java/hudson/plugins/git/BranchSpec.java index e083a75bc0..661f672dab 100644 --- a/src/main/java/hudson/plugins/git/BranchSpec.java +++ b/src/main/java/hudson/plugins/git/BranchSpec.java @@ -138,7 +138,7 @@ public List filterMatchingBranches(Collection branches, EnvVars return items; } - private String getExpandedName(EnvVars env) { + public String getExpandedName(EnvVars env) { String expandedName = env.expand(name); if (expandedName.length() == 0) { return "**"; diff --git a/src/main/java/hudson/plugins/git/GitSCM.java b/src/main/java/hudson/plugins/git/GitSCM.java index ceab12095a..2e5c1f7c8b 100644 --- a/src/main/java/hudson/plugins/git/GitSCM.java +++ b/src/main/java/hudson/plugins/git/GitSCM.java @@ -71,6 +71,7 @@ import javax.servlet.ServletException; +import java.util.HashMap; import java.io.File; import java.io.IOException; import java.io.OutputStreamWriter; @@ -750,13 +751,15 @@ private PollingResult compareRemoteRevisionWithImpl(Job project, Launcher } } + Map headMatches = new HashMap<>(); for (BranchSpec branchSpec : getBranches()) { for (Entry entry : heads.entrySet()) { final String head = entry.getKey(); // head is "refs/(heads|tags|whatever)/branchName + // Use pollEnv here to include Parameters from lastBuild. // first, check the a canonical git reference is configured - if (!branchSpec.matches(head, environment)) { + if (!branchSpec.matches(head, pollEnv)) { // convert head `refs/(heads|tags|whatever)/branch` into shortcut notation `remote/branch` String name; @@ -764,7 +767,13 @@ private PollingResult compareRemoteRevisionWithImpl(Job project, Launcher if (matcher.matches()) name = remote + head.substring(matcher.group(1).length()); else name = remote + "/" + head; - if (!branchSpec.matches(name, environment)) continue; + // Use pollEnv here to include Parameters from lastBuild. + // Record which branches in the spec we have found a match for so we can alert users when branches are ignored. + if (branchSpec.matches(name, pollEnv)){ + headMatches.put(branchSpec, name); + } else { + continue; + } } final ObjectId sha1 = entry.getValue(); @@ -774,10 +783,22 @@ private PollingResult compareRemoteRevisionWithImpl(Job project, Launcher continue; } + listener.getLogger().println(MessageFormat.format("[poll] pollEnv {0}", pollEnv)); listener.getLogger().println("[poll] Latest remote head revision on " + head + " is: " + sha1.getName()); return BUILD_NOW; } } + // Tell users if there are branches in the spec that are ignored. + for (BranchSpec branchSpec : getBranches()) { + // If there is a branch in the spec that doesn't exist in the remote, tell the users (as this could means they aren't building something they expect to). + if (!headMatches.containsKey(branchSpec)) { + // If the branchSpec gets expanded using variables in the environment then print the original and expanded versions. + String branchSpecString = branchSpec.toString(); + String expandedBranchSpec = branchSpec.getExpandedName(pollEnv); + String branchMessageString = branchSpecString.equals(expandedBranchSpec) ? String.format("'%s'", branchSpecString) : String.format("'%s' (%s)", branchSpecString, expandedBranchSpec); + listener.getLogger().println("[poll] Could not find remote head for branch in spec " + branchMessageString); + } + } } } return NO_CHANGES; diff --git a/src/test/java/hudson/plugins/git/GitSCMTest.java b/src/test/java/hudson/plugins/git/GitSCMTest.java index 96c6621cd2..30477a033c 100644 --- a/src/test/java/hudson/plugins/git/GitSCMTest.java +++ b/src/test/java/hudson/plugins/git/GitSCMTest.java @@ -44,6 +44,7 @@ import org.jenkinsci.plugins.tokenmacro.TokenMacro; import org.jenkinsci.plugins.gitclient.*; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; +import org.jenkinsci.plugins.workflow.cps.CpsScmFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; import org.junit.Rule; @@ -2467,6 +2468,41 @@ public void testPolling_environmentValueInBranchSpec() throws Exception { assertFalse("No changes to git since last build, thus no new build is expected", project.poll(listener).hasChanges()); } + @Test + @Issue("JENKINS-20427") + public void testPolling_environmentValueInBranchSpecTriggersBuild() throws Exception { + assumeTrue("Test class max time " + MAX_SECONDS_FOR_THESE_TESTS + " exceeded", isTimeAvailable()); + // create parameterized project with environment value in branch specification + WorkflowJob project = r.jenkins.createProject(WorkflowJob.class, "pipeline-remote-poll-with-param"); + List remotes = new ArrayList<>(); + remotes.addAll(testRepo.remoteConfigs()); + GitSCM scm = new GitSCM( + remotes, + Collections.singletonList(new BranchSpec("${MY_BRANCH}")), + null, null, + Collections.emptyList()); + project.setDefinition(new CpsScmFlowDefinition(scm, "./Jenkinsfile")); + project.addProperty(new ParametersDefinitionProperty(new StringParameterDefinition("MY_BRANCH", "master"))); + + // commit something in order to create an initial base version in git + commit( + "Jenkinsfile", + "node {\n" + + " echo 'Hello world!'\n" + + "}", + johnDoe, + "Add Jenkinsfile" + ); + + // build the project + Run run = r.buildAndAssertStatus(Result.SUCCESS, project); + + // commit something in order to check that polling detects the change. + commit("toto/commitFile2", johnDoe, "Commit number 2"); + + assertTrue("There are changes to git since last build, thus a new build is expected", project.poll(listener).hasChanges()); + } + public void baseTestPolling_parentHead(List extensions) throws Exception { // create parameterized project with environment value in branch specification FreeStyleProject project = createFreeStyleProject();