Finally, you can understand this after much trial and error based on the HTML Publisher plugin.
, , , , , "". : name, file height. config.jelly :
<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>
- - :

, "" .
, "" - . , , , , , , AbstractDescribablyImpl. :
public static class Target extends AbstractDescribableImpl<Target>
{
public String name;
public String file;
public int height;
@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 "";
}
}
}
, .
, BuildStep, , , "" ( Target , ). , :
public class EmbedReportPublisher extends Publisher
{
private List<Target> targets;
public static class Target extends AbstractDescribableImpl<Target>
{
}
@DataBoundConstructor
public EmbedReportPublisher(List<Target> targets) {
if (targets == null) {
this.targets = new ArrayList<Target>(0);
}
else {
this.targets = new ArrayList<Target>(targets);
}
}
}
. perform , getProjectActions, , , this.targets - , .