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 a26f51363b..1fcf96ec47 100644 --- a/src/main/java/hudson/plugins/git/GitSCM.java +++ b/src/main/java/hudson/plugins/git/GitSCM.java @@ -73,6 +73,7 @@ import javax.servlet.ServletException; +import java.util.HashMap; import java.io.File; import java.io.IOException; import java.io.OutputStreamWriter; @@ -711,9 +712,7 @@ private PollingResult compareRemoteRevisionWithImpl(Job project, Launcher if (buildData.lastBuild != null) { listener.getLogger().println("[poll] Last Built Revision: " + buildData.lastBuild.revision); } - final EnvVars pollEnv = project instanceof AbstractProject ? GitUtils.getPollEnvironment((AbstractProject) project, workspace, launcher, listener, false) : lastBuild.getEnvironment(listener); - final String singleBranch = getSingleBranch(pollEnv); if (!requiresWorkspaceForPolling(pollEnv)) { @@ -751,35 +750,50 @@ private PollingResult compareRemoteRevisionWithImpl(Job project, Launcher it.remove(); } } - + 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; Matcher matcher = GIT_REF.matcher(head); 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 alter users when branches are ignored. + if (branchSpec.matches(name, pollEnv)){ + headMatches.put(branchSpec, name); + } else { + continue; + } } - final ObjectId sha1 = entry.getValue(); Build built = buildData.getLastBuild(sha1); if (built != null) { listener.getLogger().println("[poll] Latest remote head revision on " + head + " is: " + sha1.getName() + " - already built by " + built.getBuildNumber()); 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 = "testing" == 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; @@ -809,7 +823,6 @@ private PollingResult compareRemoteRevisionWithImpl(Job project, Launcher } listener.getLogger().println("Polling for changes in"); - Collection candidates = getBuildChooser().getCandidateRevisions( true, singleBranch, git, listener, buildData, new BuildChooserContextImpl(project, null, environment)); @@ -1144,7 +1157,6 @@ public EnvVars getEnvironment() { if (candidates.isEmpty() ) { final String singleBranch = environment.expand( getSingleBranch(environment) ); - candidates = getBuildChooser().getCandidateRevisions( false, singleBranch, git, listener, buildData, context); } diff --git a/src/test/java/hudson/plugins/git/GitSCMTest.java b/src/test/java/hudson/plugins/git/GitSCMTest.java index 8f576e923b..98a795e62e 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; @@ -2448,6 +2449,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();