Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-10147

Add 'poll SCM' option to build step

    XMLWordPrintable

    Details

    • Similar Issues:

      Description

      It would be nice, in at least the 'build step' part of the parameterized-trigger plugin, to have the option to build conditionally based on SCM polling.

        Attachments

          Issue Links

            Activity

            ganncamp G. Ann Campbell created issue -
            Hide
            abigos Andy Bigos added a comment -

            I'd like to see this feature also. There is short description of my use case here. Basically I'd like to be able to use the 'trigger build only if downstream job has SCM changes' functionality from the Downstream Ext plugin to be available when triggering downstream jobs with parameters.

            If possible I'd like to raise the priority of this request (rather than creating a duplicate with the higher priority) as it's quite important for our use case.

            Ta
            Andy

            Show
            abigos Andy Bigos added a comment - I'd like to see this feature also. There is short description of my use case here . Basically I'd like to be able to use the 'trigger build only if downstream job has SCM changes' functionality from the Downstream Ext plugin to be available when triggering downstream jobs with parameters. If possible I'd like to raise the priority of this request (rather than creating a duplicate with the higher priority) as it's quite important for our use case. Ta Andy
            kutzi kutzi made changes -
            Field Original Value New Value
            Link This issue is related to JENKINS-11455 [ JENKINS-11455 ]
            Hide
            tfields Thomas Fields added a comment -

            I'd also like to see this feature added. The parameterized-trigger is extremely useful for my setup but the fact it's lacking SCM polling really limits what I can do with it. If huybrechts is not able to fix this could it be assigned to someone else or give any pointers as to how I'd add the feature myself?

            Regards,
            Tom.

            Show
            tfields Thomas Fields added a comment - I'd also like to see this feature added. The parameterized-trigger is extremely useful for my setup but the fact it's lacking SCM polling really limits what I can do with it. If huybrechts is not able to fix this could it be assigned to someone else or give any pointers as to how I'd add the feature myself? Regards, Tom.
            Hide
            jpaverous Julien-Pierre Avérous added a comment -

            This message just to second the need of this option.

            Show
            jpaverous Julien-Pierre Avérous added a comment - This message just to second the need of this option.
            Hide
            jpaverous Julien-Pierre Avérous added a comment -

            I fixed the problem with a very-temporary hack in the code, waiting for an official patch.

            I have added this code :

            SCM scm = project.getScm();
            
            if (scm != null)
            {
            	// Check that we don't have change in SCM
            	PollingResult res = project.poll(LogTaskListener.NULL);
            
            	if (res == NO_CHANGES)
            	{
            		// Check that we have a sucessfull build
            		Run success = project.getLastSuccessfulBuild();
                					    
            		if (success != null)
            		{
            			listener.getLogger().println("Skipping " + HyperlinkNote.encodeTo('/'+ project.getUrl(), project.getFullDisplayName()) + ". No change happen since last build.");
            			continue;
            		}
            	}
            }
            

            just before

            futures.add(schedule(build, project, list));
            

            in 'perform' method of 'BuildTriggerConfig.java'

            and just before

            futures.put(project, schedule(build, project, list));
            

            in 'perform2' method of 'BuildTriggerConfig.java'

            This import should be added too in this file :

            import hudson.console.HyperlinkNote;
            import hudson.scm.SCM;
            import hudson.scm.PollingResult;
            import hudson.util.LogTaskListener;
            import hudson.model.Run;
            import static hudson.scm.PollingResult.*;
            

            This seem to work well for me.

            Caveats :

            • The line 'if (futures.isEmpty())' condition in TriggerBuilder.java print a bad log in the console when all project in the trigger list doesn't need to be rebuild. Not a problem, but not beautiful.
            • If the configuration of a project change but not the SCM, the build is not re-triggered.
            • Probably some others things.
            Show
            jpaverous Julien-Pierre Avérous added a comment - I fixed the problem with a very-temporary hack in the code, waiting for an official patch. I have added this code : SCM scm = project.getScm(); if (scm != null ) { // Check that we don't have change in SCM PollingResult res = project.poll(LogTaskListener.NULL); if (res == NO_CHANGES) { // Check that we have a sucessfull build Run success = project.getLastSuccessfulBuild(); if (success != null ) { listener.getLogger().println( "Skipping " + HyperlinkNote.encodeTo( '/' + project.getUrl(), project.getFullDisplayName()) + ". No change happen since last build." ); continue ; } } } just before futures.add(schedule(build, project, list)); in 'perform' method of 'BuildTriggerConfig.java' and just before futures.put(project, schedule(build, project, list)); in 'perform2' method of 'BuildTriggerConfig.java' This import should be added too in this file : import hudson.console.HyperlinkNote; import hudson.scm.SCM; import hudson.scm.PollingResult; import hudson.util.LogTaskListener; import hudson.model.Run; import static hudson.scm.PollingResult.*; This seem to work well for me. Caveats : The line 'if (futures.isEmpty())' condition in TriggerBuilder.java print a bad log in the console when all project in the trigger list doesn't need to be rebuild. Not a problem, but not beautiful. If the configuration of a project change but not the SCM, the build is not re-triggered. Probably some others things.
            Hide
            jpaverous Julien-Pierre Avérous added a comment -

            Caveats (2):

            • There is no option in the UI to activate / deactivate this hack.
            Show
            jpaverous Julien-Pierre Avérous added a comment - Caveats (2): There is no option in the UI to activate / deactivate this hack.
            Hide
            javerous Julien-Pierre Avérous added a comment -

            Here a git diff with a little bit cleaner implementation, with a check box in the UI to activate / deactivate this functionality.

            diff --git a/src/main/java/hudson/plugins/parameterizedtrigger/BlockableBuildTriggerConfig.java b/src/main/java/hudson/plugins/parameterizedtrigger/BlockableBuildTriggerConfig.java
            index d955f4c..304337d 100644
            --- a/src/main/java/hudson/plugins/parameterizedtrigger/BlockableBuildTriggerConfig.java
            +++ b/src/main/java/hudson/plugins/parameterizedtrigger/BlockableBuildTriggerConfig.java
            @@ -12,6 +12,11 @@ import hudson.model.Node;
             import hudson.model.Run;
             import org.kohsuke.stapler.DataBoundConstructor;
             
            +import hudson.scm.SCM;
            +import hudson.scm.PollingResult;
            +import hudson.util.LogTaskListener;
            +import static hudson.scm.PollingResult.*;
            +
             import com.google.common.collect.ArrayListMultimap;
             import com.google.common.collect.ListMultimap;
             
            @@ -27,22 +32,56 @@ import java.util.concurrent.Future;
              */
             public class BlockableBuildTriggerConfig extends BuildTriggerConfig {
                 private final BlockingBehaviour block;
            +    private final boolean           buildScm;
            +    
                 public boolean buildAllNodesWithLabel;
             
            -    public BlockableBuildTriggerConfig(String projects, BlockingBehaviour block, List<AbstractBuildParameters> configs) {
            +    public BlockableBuildTriggerConfig(String projects, BlockingBehaviour block, boolean buildScm, List<AbstractBuildParameters> configs) {
                     super(projects, ResultCondition.ALWAYS, false, configs);
                     this.block = block;
            +        this.buildScm = buildScm;
                 }
             
                 @DataBoundConstructor
            -    public BlockableBuildTriggerConfig(String projects, BlockingBehaviour block, List<AbstractBuildParameterFactory> configFactories,List<AbstractBuildParameters> configs) {
            +    public BlockableBuildTriggerConfig(String projects, BlockingBehaviour block, boolean buildScm, List<AbstractBuildParameterFactory> configFactories,List<AbstractBuildParameters> configs) {
                     super(projects, ResultCondition.ALWAYS, false, configFactories, configs);
                     this.block = block;
            +        this.buildScm = buildScm;
                 }
             
                 public BlockingBehaviour getBlock() {
                     return block;
                 }
            +    
            +    public boolean getBuildScm() {
            +        return buildScm;
            +    }
            +    
            +    @Override
            +    public boolean needRebuild(AbstractProject project)
            +	{	   
            +        if (getBuildScm() == false)
            +            return true;	
            +	
            +        SCM scm = project.getScm();
            +
            +        if (scm != null)
            +        {
            +            // Check that we don't have change in SCM
            +            PollingResult res = project.poll(LogTaskListener.NULL);
            +
            +            if (res == NO_CHANGES)
            +            {
            +                // Check that we have a sucessfull build
            +                Run success = project.getLastSuccessfulBuild();
            +                
            +                if (success != null)
            +                    return false;
            +            }
            +        }
            +        
            +        return true;
            +	}
             
                 @Override
                 public List<Future<AbstractBuild>> perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
            diff --git a/src/main/java/hudson/plugins/parameterizedtrigger/BuildTriggerConfig.java b/src/main/java/hudson/plugins/parameterizedtrigger/BuildTriggerConfig.java
            index d5144a7..c6f52be 100644
            --- a/src/main/java/hudson/plugins/parameterizedtrigger/BuildTriggerConfig.java
            +++ b/src/main/java/hudson/plugins/parameterizedtrigger/BuildTriggerConfig.java
            @@ -31,6 +31,8 @@ import hudson.plugins.parameterizedtrigger.AbstractBuildParameters.DontTriggerEx
             import hudson.tasks.Messages;
             import hudson.util.FormValidation;
             
            +import hudson.console.HyperlinkNote;
            +
             import jenkins.model.Jenkins;
             import org.apache.commons.lang.StringUtils;
             import org.kohsuke.stapler.AncestorInPath;
            @@ -201,6 +203,11 @@ public class BuildTriggerConfig implements Describable<BuildTriggerConfig> {
             		}
             		return actions;
             	}
            +	
            +	public boolean needRebuild(AbstractProject project)
            +	{
            +        return true;
            +	}
             
             	/**
                  * Note that with Hudson 1.341, trigger should be using
            @@ -222,7 +229,10 @@ public class BuildTriggerConfig implements Describable<BuildTriggerConfig> {
                                 for (AbstractProject project : getProjectList(build.getProject().getParent(),env)) {
                                     List<Action> list = getBuildActions(actions, project);
             
            -                        futures.add(schedule(build, project, list));
            +                        if (needRebuild(project))
            +                            futures.add(schedule(build, project, list));
            +                        else
            +                            listener.getLogger().println("Skipping " + HyperlinkNote.encodeTo('/'+ project.getUrl(), project.getFullDisplayName()) + ". Don't need to rebuild.");
                                 }
                             }
             
            @@ -247,7 +257,10 @@ public class BuildTriggerConfig implements Describable<BuildTriggerConfig> {
                                 for (AbstractProject project : getProjectList(build.getProject().getParent(),env)) {
                                     List<Action> list = getBuildActions(actions, project);
                                     
            -                        futures.put(project, schedule(build, project, list));
            +                        if (needRebuild(project))
            +                            futures.put(project, schedule(build, project, list));
            +                        else
            +                            listener.getLogger().println("Skipping " + HyperlinkNote.encodeTo('/'+ project.getUrl(), project.getFullDisplayName()) + ". Don't need to rebuild.");
                                 }
                             }
                             return futures;
            diff --git a/src/main/java/hudson/plugins/parameterizedtrigger/TriggerBuilder.java b/src/main/java/hudson/plugins/parameterizedtrigger/TriggerBuilder.java
            index b5b4262..fb6b100 100644
            --- a/src/main/java/hudson/plugins/parameterizedtrigger/TriggerBuilder.java
            +++ b/src/main/java/hudson/plugins/parameterizedtrigger/TriggerBuilder.java
            @@ -99,7 +99,7 @@ public class TriggerBuilder extends Builder implements DependecyDeclarer {
                             if(!projectList.isEmpty()){
                                 //handle non-blocking configs
                                 if(futures.isEmpty()){
            -                        listener.getLogger().println("Triggering projects: " + getProjectListAsString(projectList));
            +                        listener.getLogger().println("Triggering or skipped projects: " + getProjectListAsString(projectList));
                                     continue;
                                 }
                                 //handle blocking configs
            diff --git a/src/main/resources/hudson/plugins/parameterizedtrigger/BlockableBuildTriggerConfig/config.jelly b/src/main/resources/hudson/plugins/parameterizedtrigger/BlockableBuildTriggerConfig/config.jelly
            index 1c49bbd..a279ef5 100644
            --- a/src/main/resources/hudson/plugins/parameterizedtrigger/BlockableBuildTriggerConfig/config.jelly
            +++ b/src/main/resources/hudson/plugins/parameterizedtrigger/BlockableBuildTriggerConfig/config.jelly
            @@ -22,9 +22,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
             THE SOFTWARE.
             -->
             <j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
            +
               <f:entry title="${%Projects to build}" field="projects">
                 <f:textbox />
               </f:entry>
            +  
            +  <f:block>
            +    <f:checkbox title="${%Build triggered projects only if there is SCM changes}" field="buildScm" checked="${instance.buildScm==true}" />
            +  </f:block>
            +
               <!-- TODO: replace with <f:optionalProperty> -->
               <f:optionalBlock field="block" title="${%Block until the triggered projects finish their builds}" checked="${instance.block!=null}">
                 <j:set var="descriptor" value="${app.getDescriptorOrDie(descriptor.getPropertyType(field).clazz)}" />
            
            Show
            javerous Julien-Pierre Avérous added a comment - Here a git diff with a little bit cleaner implementation, with a check box in the UI to activate / deactivate this functionality. diff --git a/src/main/java/hudson/plugins/parameterizedtrigger/BlockableBuildTriggerConfig.java b/src/main/java/hudson/plugins/parameterizedtrigger/BlockableBuildTriggerConfig.java index d955f4c..304337d 100644 --- a/src/main/java/hudson/plugins/parameterizedtrigger/BlockableBuildTriggerConfig.java +++ b/src/main/java/hudson/plugins/parameterizedtrigger/BlockableBuildTriggerConfig.java @@ -12,6 +12,11 @@ import hudson.model.Node; import hudson.model.Run; import org.kohsuke.stapler.DataBoundConstructor; + import hudson.scm.SCM; + import hudson.scm.PollingResult; + import hudson.util.LogTaskListener; + import static hudson.scm.PollingResult.*; + import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; @@ -27,22 +32,56 @@ import java.util.concurrent.Future; */ public class BlockableBuildTriggerConfig extends BuildTriggerConfig { private final BlockingBehaviour block; + private final boolean buildScm; + public boolean buildAllNodesWithLabel; - public BlockableBuildTriggerConfig( String projects, BlockingBehaviour block, List<AbstractBuildParameters> configs) { + public BlockableBuildTriggerConfig( String projects, BlockingBehaviour block, boolean buildScm, List<AbstractBuildParameters> configs) { super (projects, ResultCondition.ALWAYS, false , configs); this .block = block; + this .buildScm = buildScm; } @DataBoundConstructor - public BlockableBuildTriggerConfig( String projects, BlockingBehaviour block, List<AbstractBuildParameterFactory> configFactories,List<AbstractBuildParameters> configs) { + public BlockableBuildTriggerConfig( String projects, BlockingBehaviour block, boolean buildScm, List<AbstractBuildParameterFactory> configFactories,List<AbstractBuildParameters> configs) { super (projects, ResultCondition.ALWAYS, false , configFactories, configs); this .block = block; + this .buildScm = buildScm; } public BlockingBehaviour getBlock() { return block; } + + public boolean getBuildScm() { + return buildScm; + } + + @Override + public boolean needRebuild(AbstractProject project) + { + if (getBuildScm() == false ) + return true ; + + SCM scm = project.getScm(); + + if (scm != null ) + { + // Check that we don't have change in SCM + PollingResult res = project.poll(LogTaskListener.NULL); + + if (res == NO_CHANGES) + { + // Check that we have a sucessfull build + Run success = project.getLastSuccessfulBuild(); + + if (success != null ) + return false ; + } + } + + return true ; + } @Override public List<Future<AbstractBuild>> perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { diff --git a/src/main/java/hudson/plugins/parameterizedtrigger/BuildTriggerConfig.java b/src/main/java/hudson/plugins/parameterizedtrigger/BuildTriggerConfig.java index d5144a7..c6f52be 100644 --- a/src/main/java/hudson/plugins/parameterizedtrigger/BuildTriggerConfig.java +++ b/src/main/java/hudson/plugins/parameterizedtrigger/BuildTriggerConfig.java @@ -31,6 +31,8 @@ import hudson.plugins.parameterizedtrigger.AbstractBuildParameters.DontTriggerEx import hudson.tasks.Messages; import hudson.util.FormValidation; + import hudson.console.HyperlinkNote; + import jenkins.model.Jenkins; import org.apache.commons.lang.StringUtils; import org.kohsuke.stapler.AncestorInPath; @@ -201,6 +203,11 @@ public class BuildTriggerConfig implements Describable<BuildTriggerConfig> { } return actions; } + + public boolean needRebuild(AbstractProject project) + { + return true ; + } /** * Note that with Hudson 1.341, trigger should be using @@ -222,7 +229,10 @@ public class BuildTriggerConfig implements Describable<BuildTriggerConfig> { for (AbstractProject project : getProjectList(build.getProject().getParent(),env)) { List<Action> list = getBuildActions(actions, project); - futures.add(schedule(build, project, list)); + if (needRebuild(project)) + futures.add(schedule(build, project, list)); + else + listener.getLogger().println( "Skipping " + HyperlinkNote.encodeTo( '/' + project.getUrl(), project.getFullDisplayName()) + ". Don't need to rebuild." ); } } @@ -247,7 +257,10 @@ public class BuildTriggerConfig implements Describable<BuildTriggerConfig> { for (AbstractProject project : getProjectList(build.getProject().getParent(),env)) { List<Action> list = getBuildActions(actions, project); - futures.put(project, schedule(build, project, list)); + if (needRebuild(project)) + futures.put(project, schedule(build, project, list)); + else + listener.getLogger().println( "Skipping " + HyperlinkNote.encodeTo( '/' + project.getUrl(), project.getFullDisplayName()) + ". Don't need to rebuild." ); } } return futures; diff --git a/src/main/java/hudson/plugins/parameterizedtrigger/TriggerBuilder.java b/src/main/java/hudson/plugins/parameterizedtrigger/TriggerBuilder.java index b5b4262..fb6b100 100644 --- a/src/main/java/hudson/plugins/parameterizedtrigger/TriggerBuilder.java +++ b/src/main/java/hudson/plugins/parameterizedtrigger/TriggerBuilder.java @@ -99,7 +99,7 @@ public class TriggerBuilder extends Builder implements DependecyDeclarer { if (!projectList.isEmpty()){ //handle non-blocking configs if (futures.isEmpty()){ - listener.getLogger().println( "Triggering projects: " + getProjectListAsString(projectList)); + listener.getLogger().println( "Triggering or skipped projects: " + getProjectListAsString(projectList)); continue ; } //handle blocking configs diff --git a/src/main/resources/hudson/plugins/parameterizedtrigger/BlockableBuildTriggerConfig/config.jelly b/src/main/resources/hudson/plugins/parameterizedtrigger/BlockableBuildTriggerConfig/config.jelly index 1c49bbd..a279ef5 100644 --- a/src/main/resources/hudson/plugins/parameterizedtrigger/BlockableBuildTriggerConfig/config.jelly +++ b/src/main/resources/hudson/plugins/parameterizedtrigger/BlockableBuildTriggerConfig/config.jelly @@ -22,9 +22,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> <j:jelly xmlns:j= "jelly:core" xmlns:st= "jelly:stapler" xmlns:d= "jelly:define" xmlns:l= "/lib/layout" xmlns:t= "/lib/hudson" xmlns:f= "/lib/form" > + <f:entry title= "${%Projects to build}" field= "projects" > <f:textbox /> </f:entry> + + <f:block> + <f:checkbox title= "${%Build triggered projects only if there is SCM changes}" field= "buildScm" checked= "${instance.buildScm== true }" /> + </f:block> + <!-- TODO: replace with <f:optionalProperty> --> <f:optionalBlock field= "block" title= "${%Block until the triggered projects finish their builds}" checked= "${instance.block!= null }" > <j:set var = "descriptor" value= "${app.getDescriptorOrDie(descriptor.getPropertyType(field).clazz)}" />
            Hide
            atef_101 Atef GHOULEM added a comment -

            Hello,
            Does this bug is planned for a next version?

            Show
            atef_101 Atef GHOULEM added a comment - Hello, Does this bug is planned for a next version?
            Hide
            tfields Thomas Fields added a comment -

            Hi,

            This bug is assigned to huybrechts yet that user seems inactive in the Jenkins community. Can the issue be reassigned and the above patch integrated into the next release?

            Tom

            Show
            tfields Thomas Fields added a comment - Hi, This bug is assigned to huybrechts yet that user seems inactive in the Jenkins community. Can the issue be reassigned and the above patch integrated into the next release? Tom
            Hide
            cjo9900 cjo9900 added a comment - - edited

            As this has popped to the top of the list and I am trying to look at all of these issues, I can see that this issue could be resolved when the Run condition branch is added.

            In this case you could create a run condition that could poll a project for changes before triggering other builds, and this then keeps the changes needed separate from this plugin. As in most cases this is not a requirement for triggering a downstream build.

            Note: I have requested reviews on the pending pull requests, and will look at getting a new release done soon.

            Show
            cjo9900 cjo9900 added a comment - - edited As this has popped to the top of the list and I am trying to look at all of these issues, I can see that this issue could be resolved when the Run condition branch is added. In this case you could create a run condition that could poll a project for changes before triggering other builds, and this then keeps the changes needed separate from this plugin. As in most cases this is not a requirement for triggering a downstream build. Note: I have requested reviews on the pending pull requests, and will look at getting a new release done soon.
            cjo9900 cjo9900 made changes -
            Link This issue depends on JENKINS-9209 [ JENKINS-9209 ]
            cjo9900 cjo9900 made changes -
            Assignee huybrechts [ huybrechts ] cjo9900 [ cjo9900 ]
            Hide
            tfields Thomas Fields added a comment -

            Are we any closer to getting this released?

            Show
            tfields Thomas Fields added a comment - Are we any closer to getting this released?
            Hide
            tfields Thomas Fields added a comment -

            Are we any closer to getting this released?

            Show
            tfields Thomas Fields added a comment - Are we any closer to getting this released?
            Hide
            tfields Thomas Fields added a comment -

            Can the fix for the issue be rolled into the main release please?

            Show
            tfields Thomas Fields added a comment - Can the fix for the issue be rolled into the main release please?
            Hide
            lacot5 Ladislav Toldy added a comment -

            Polling feature would be nice to have..

            Show
            lacot5 Ladislav Toldy added a comment - Polling feature would be nice to have..
            Hide
            smokay2k3 Timothy Pharo added a comment -

            This would make such a big difference as it would allow for a single project to be built and the project itself could check that all its dependencies are up to date instead of just always building the dependencies again and again.... Please can this be placed in a release soon as it seems to be the missing piece of the puzzle. Much appreciated

            Show
            smokay2k3 Timothy Pharo added a comment - This would make such a big difference as it would allow for a single project to be built and the project itself could check that all its dependencies are up to date instead of just always building the dependencies again and again.... Please can this be placed in a release soon as it seems to be the missing piece of the puzzle. Much appreciated
            Hide
            cjones Charles Jones added a comment -

            I too would find this useful.

            Show
            cjones Charles Jones added a comment - I too would find this useful.
            Hide
            pavelsaab Pavel Saab added a comment -

            Has there been any development on getting this feature added to the plugin?

            Show
            pavelsaab Pavel Saab added a comment - Has there been any development on getting this feature added to the plugin?
            rtyler R. Tyler Croy made changes -
            Workflow JNJira [ 140335 ] JNJira + In-Review [ 175250 ]
            rk R K made changes -
            Labels scm
            rk R K made changes -
            Priority Minor [ 4 ] Major [ 3 ]

              People

              • Assignee:
                cjo9900 cjo9900
                Reporter:
                ganncamp G. Ann Campbell
              • Votes:
                10 Vote for this issue
                Watchers:
                14 Start watching this issue

                Dates

                • Created:
                  Updated: