Dropdownlist from ui-samples applied to BuildStep

18 views
Skip to first unread message

Ivan Martinez

unread,
Mar 5, 2021, 10:14:26 AM3/5/21
to Jenkins Developers
Hi,

I am developing a plugin in which I want to create a BuildStep. From UI perspective, the user should be able to select a certain script to run (A,B,C). The scripts have some common parameters (i.e: debug mode, version to use, etc...) and then some specific ones.

I have seen the ui-samples-plugin, in particular the DropdownList example, which has a base class Fruit and then some child classes with particular configurable parameters (Apple, Banana), which fits exactly my use case.

However, I am struggling to implement this same behavior when it comes to my plugin. I am starting from the HelloWorldBuilder archetype. I added to the HelloWorldBuilder class the definition of the Fruit, Apple, and Banana classes, as well as the FruitDescriptor.

The first issue that I am facing is that in the config.jelly associated to the HelloWorldBuilder, the "${it}" object, is not an instance of the the HelloWorldBuilder class, instead, it is an instance of the FreeStyleProject class.


I have seen that a different type of object can be referenced, which is the ${instance}. I have tried by modifying the references to ${it} and replace them by ${instance}. In this case, it does refer to the HelloWorldBuilder class, but, this object is null when adding the build step into a job for the first time. Once I save the job and re-configure, the drop-down list is populated, since the instance is created. But then again, I face another problem, the data does not seem to be persisted, I have debugged and indeed the DataBoundConstructor for HelloWorldBuilder is invoked and the Fruit object is passed to it, but in further re-configurations of the job step, it is not persisted.

I wonder if someone can provide some guidance here. I have tried to search for other plugins that may implement similar patterns but couldn't really found simple examples of it that I could somehow re-use as part of this plugin. The most similar scenario I have seen is the warnings-ng-plugin. But it is quite complex and I haven't been able to fully understand it.

Thanks anyways for the community help & support.
BRs
/Iván

Jesse Glick

unread,
Mar 5, 2021, 3:02:23 PM3/5/21
to Jenkins Dev
On Fri, Mar 5, 2021 at 10:14 AM Ivan Martinez <ivan.sa...@gmail.com> wrote:
I have seen that a different type of object can be referenced, which is the ${instance}. I have tried by modifying the references to ${it} and replace them by ${instance}. In this case, it does refer to the HelloWorldBuilder class, but, this object is null when adding the build step into a job for the first time. Once I save the job and re-configure, the drop-down list is populated, since the instance is created.

Right, `instance` is set only during reconfiguration. `descriptor` is always set.

If you are using high-level form controls, you should normally need to pay attention to `it` and `instance`. `descriptor` would be used for example to let you load a list of options from Java (your `DescriptorImpl`).

the data does not seem to be persisted, I have debugged and indeed the DataBoundConstructor for HelloWorldBuilder is invoked and the Fruit object is passed to it, but in further re-configurations of the job step, it is not persisted.

Check whether the actual `config.xml` is saved correctly.

I think your issue is that you are looking at the `DropdownList` example, which is using low-level form controls. For the purposes of typical plugins, you can ignore all that. The `HeteroList` example is more relevant (specifically the objects inside it starting with `Config`). Basically use controls which have a `field` attribute.

Ivan Martinez

unread,
Mar 9, 2021, 6:57:21 AM3/9/21
to Jenkins Developers
Hi Jesse,

Thanks for the suggestion. I have adapted my code to follow the HeteroList approach. However, I am still facing some issues when I try to use a base class to wrap some common parameters (i.e: debug mode) while delegating to child classes the specific ones. I was trying to adapt first the HeteroList example to see how could I achieve it. I have modified the Entry class as follows:


public static class Entry extends AbstractDescribableImpl<Entry> {
private Boolean debug;

@DataBoundConstructor
public Entry(){}

public Boolean getDebug() {
return debug;
}

@DataBoundSetter
public void setDebug(Boolean debug) {
this.debug = debug;
}

I added within the resources/jenkins/plugins/ui_samples/HeteroList/ a folder named Entry with the following config.jelly:

<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<f:entry title="">
<f:checkbox field="debug" title="Debug mode?"/>
</f:entry>
</j:jelly>

I was expecting that these changes would allow me to add the debug parameter to all 3 child classes of the Entry class (using the DataBoundConstructor associated to the parent class). I am not sure if this is possible, or what approach should I take. Any guidance or example would be appreciated.

Thanks again for your time and help
BRs
/Iván

Jesse Glick

unread,
Mar 9, 2021, 9:04:12 AM3/9/21
to Jenkins Dev
On Tue, Mar 9, 2021 at 6:57 AM Ivan Martinez <ivan.sa...@gmail.com> wrote:
I was expecting that these changes would allow me to add the debug parameter to all 3 child classes of the Entry class (using the DataBoundConstructor associated to the parent class). I am not sure if this is possible

While Jelly views are inherited, if the child provides its own `config.jelly`, that will override the parent’s. It is possible to pick up fragments from a parent, for example:


In your example, `Entry` should be `abstract`, and should have a `protected` constructor which is not marked `@DataBoundConstructor` (that annotation is only allowed on concrete types).

We probably need to expand `ui-samples` to include more varied idioms, and clearly fence off the examples of low-level controls. 
Reply all
Reply to author
Forward
0 new messages