From 62d9290616020fff738797a56f47c16e8fb3d771 Mon Sep 17 00:00:00 2001 From: "Tim Brown (Jenkins pod037-3)" Date: Tue, 26 Sep 2023 16:19:55 +0100 Subject: [PATCH 1/4] Use poll env when checking for ls-remote branches. --- .../java/hudson/plugins/git/BranchSpec.java | 2 +- src/main/java/hudson/plugins/git/GitSCM.java | 34 ++++++++++++------ .../java/hudson/plugins/git/GitSCMTest.java | 36 +++++++++++++++++++ 3 files changed, 60 insertions(+), 12 deletions(-) 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(); From 9c9f579b3e0cce216366f10d6ef7e0e1396a3efb Mon Sep 17 00:00:00 2001 From: "Tim Brown (Jenkins pod037-3)" Date: Tue, 26 Sep 2023 17:06:32 +0100 Subject: [PATCH 2/4] Fix string comparison - and remove test value --- src/main/java/hudson/plugins/git/GitSCM.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/hudson/plugins/git/GitSCM.java b/src/main/java/hudson/plugins/git/GitSCM.java index 1fcf96ec47..94856d90bb 100644 --- a/src/main/java/hudson/plugins/git/GitSCM.java +++ b/src/main/java/hudson/plugins/git/GitSCM.java @@ -790,7 +790,7 @@ private PollingResult compareRemoteRevisionWithImpl(Job project, Launcher // 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); + 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); } } From 745189eb00eca8911f0be389f50264f6b141d05f Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Thu, 9 Nov 2023 21:39:03 -0700 Subject: [PATCH 3/4] Reduce diffs due to empty lines --- src/main/java/hudson/plugins/git/GitSCM.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/hudson/plugins/git/GitSCM.java b/src/main/java/hudson/plugins/git/GitSCM.java index 94856d90bb..5acabb246e 100644 --- a/src/main/java/hudson/plugins/git/GitSCM.java +++ b/src/main/java/hudson/plugins/git/GitSCM.java @@ -712,7 +712,9 @@ 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)) { @@ -750,6 +752,7 @@ private PollingResult compareRemoteRevisionWithImpl(Job project, Launcher it.remove(); } } + Map headMatches = new HashMap<>(); for (BranchSpec branchSpec : getBranches()) { for (Entry entry : heads.entrySet()) { @@ -759,11 +762,13 @@ private PollingResult compareRemoteRevisionWithImpl(Job project, Launcher // Use pollEnv here to include Parameters from lastBuild. // first, check the a canonical git reference is configured 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; + // 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)){ @@ -772,12 +777,14 @@ private PollingResult compareRemoteRevisionWithImpl(Job project, Launcher 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; @@ -793,7 +800,7 @@ private PollingResult compareRemoteRevisionWithImpl(Job project, Launcher 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; @@ -823,6 +830,7 @@ 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)); @@ -1157,6 +1165,7 @@ public EnvVars getEnvironment() { if (candidates.isEmpty() ) { final String singleBranch = environment.expand( getSingleBranch(environment) ); + candidates = getBuildChooser().getCandidateRevisions( false, singleBranch, git, listener, buildData, context); } From ee9cceaf716431523a75ae1dc59a79155e55a21a Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 29 Jul 2024 20:19:16 -0600 Subject: [PATCH 4/4] Fix a spelling error in a comment --- src/main/java/hudson/plugins/git/GitSCM.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/hudson/plugins/git/GitSCM.java b/src/main/java/hudson/plugins/git/GitSCM.java index 852fa7a3ee..f6129831f6 100644 --- a/src/main/java/hudson/plugins/git/GitSCM.java +++ b/src/main/java/hudson/plugins/git/GitSCM.java @@ -768,7 +768,7 @@ private PollingResult compareRemoteRevisionWithImpl(Job project, Launcher else name = remote + "/" + head; // 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. + // 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 {