Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Allow build-step plugin to be run more than once

I'm create a plugin for Jenkins which adds a new type of post build step (a Publisher). When I try to create a new job, I'm only able to add my new step once (afer that, it is grayed out in the post-build-step menu). I'd like to be able to add it any number of times to the same job, with different configuration for each one (i.e., different instances of my Publisher subclass). How can this be done, and what's telling Jenkins to only allow it to be added once?

Update

I looks like this is somehow related to the <f:repeatable> jelly element, but I can't figure out how to use it, and can't find any information on it. I tried to follow the HTML Publisher plugin, but kept getting errors. If anyone can explain how to use this, or point to a reference, that would be great!

like image 261
brianmearns Avatar asked Nov 01 '22 21:11

brianmearns


1 Answers

Finally able to figure it out after much trial and error, based on the HTML Publisher plugin.

The build step I'm creating is repeatable, meaning you can only add it once to each job, but you can effectively add multiple "instances" of it. Each instance has three properties: name, file, and height. My config.jelly file looks like this:

<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>
        <f:repeatable field='targets'>
            <f:textbox field='name' default='Report' />
            <f:textbox field='file' default='report.html' />
            <f:number field='height' default='300' /> px
            <f:repeatableDeleteButton value='Delete report' />
        </f:repeatable>
    </f:entry>
</j:jelly>

This produces something like the following in the project-config screen:

Build Step Config

This is after having manually added and edited the two "instances" on this particular page.

The key is that each "instance" of the repeatable needs to be built into some kind of object. This works just like normally instantiating a build step from the form, except it isn't the build-step itself, it's a subclass of AbstractDescribablyImpl. Mine looks like this:

public static class Target extends AbstractDescribableImpl<Target>
{
    public String name;
    public String file;
    public int height;

    // Fields in config.jelly must match the parameter names in the "DataBoundConstructor"
    @DataBoundConstructor
    public Target(String name, String file, int height) {
        this.name = name;
        this.file = file;
        this.height = height;
        if(this.name == null) {
            throw new RuntimeException("Name is NULL!");
        }
    }

    public String getName() {
        return this.name;
    }

    public String getFile() {
        return this.file;
    }

    public int getHeight() {
        return this.height;
    }

    @Extension
    public static class DescriptorImpl extends Descriptor<Target> {
        @Override
        public String getDisplayName() {
            return "";
        }
    }
}

That's pretty simple, it's basically just an Object wrapper around the fields.

So then to actually instantiate the BuildStep itself, you have to accept a list of that type you just created to represent each "instance" of the step (in my case, the Target class from above, which was an inner class of my build step). So it looks something like this:

public class EmbedReportPublisher extends Publisher
{
    private List<Target> targets;

    public static class Target extends AbstractDescribableImpl<Target>
    {
        // ... shown above ...
    }

    @DataBoundConstructor
    public EmbedReportPublisher(List<Target> targets) {
        if (targets == null) {
            this.targets = new ArrayList<Target>(0);
        }
        else {
            this.targets = new ArrayList<Target>(targets);
        }
    }
}

And that's about it. Now in the perform method, and things like getProjectActions, you can iterate over this.targets, for instance, or whatever you need to do.

like image 95
brianmearns Avatar answered Nov 11 '22 10:11

brianmearns