Adding pipeline compatabilty to jenkins plugin

629 views
Skip to first unread message

fkp...@gmail.com

unread,
Aug 28, 2016, 11:40:32 AM8/28/16
to Jenkins Developers
Hi,
I followed the nice guide on refactoring my Jenkins plugin to pipeline compatibility given at Jenkins.io.
I've stumbled on a strange issue - the snippet generator creates the groovy syntax but without parenthesis and without brackets, which is ok since groovy does support it.

But once i paste in at my job DSL he writes "Unexpected token: "one of the tags" ", if i add the brackets manually - it works!

another small issue i've noticed while debugging is that it calls the Class extending "AbstractStepImpl" twice - but I'm not sure it's related...

the code is here:
https://github.com/YafimK/hp-application-automation-tools-plugin/tree/LoadRunnerPipelineStep/src/main/java/com/hp/application/automation/tools/pipelineSteps

that's my current dependency list:
<dependency>
 
<groupId>org.jenkins-ci.plugins.workflow</groupId>
 
<artifactId>workflow-step-api</artifactId>
 
<version>${workflow.version}</version>
</dependency>
<dependency> <!-- Test framework -->
 
<groupId>org.jenkins-ci.plugins.workflow</groupId>
 
<artifactId>workflow-step-api</artifactId>
 
<version>${workflow.version}</version>
 
<classifier>tests</classifier>
 
<scope>test</scope>
</dependency>
<dependency>
 
<groupId>org.jenkins-ci.plugins.workflow</groupId>
 
<artifactId>workflow-aggregator</artifactId>
 
<version>${workflow.version}</version>
 
<scope>test</scope>
</dependency>
<dependency>
 
<groupId>org.jenkins-ci.plugins.workflow</groupId>
 
<artifactId>workflow-cps</artifactId>
 
<version>${workflow.version}</version>
</dependency>

and I'm building with 1.642.4 as baseline and parent POM...

Is there any known issue or any solution that i've missed (i tried to look at HTML publisher, junit archiver and artifict archiver as reference) ?

Thanks ahead,
Fima.
 

fkp...@gmail.com

unread,
Aug 29, 2016, 4:15:28 AM8/29/16
to Jenkins Developers
Solved by following https://wiki.jenkins-ci.org/display/JENKINS/Structs+plugin and changing the order of variables in the Constructor.

Jesse Glick

unread,
Aug 29, 2016, 2:49:13 PM8/29/16
to Jenkins Dev
On Mon, Aug 29, 2016 at 4:15 AM, <fkp...@gmail.com> wrote:
> Solved by following
> https://wiki.jenkins-ci.org/display/JENKINS/Structs+plugin and changing the
> order of variables in the Constructor.

Order of variables in a constructor should not matter, so perhaps you
are doing something else wrong. Without a self-contained code example
it is hard to say.

fkp...@gmail.com

unread,
Aug 30, 2016, 2:29:36 AM8/30/16
to Jenkins Developers
Thanks,
You're right, it didn't sound right but it worked.I've checked it again and probably something else? maybe just adding the structs dependency solved it? e
[added the code -  just a trial and error experience ]

public class LrScenarioLoadStep extends AbstractStepImpl {

    public String getArchiveRunTestResultsMode() {
//        return archiveRunTestResultsMode;
        return ResultsPublisherModel.CreateHtmlReportResults.toString();
    }

    public boolean isPublishResults() {
//        return publishResults;
        return true;
    }

    public String getIgnoreErrorStrings() {
        return ignoreErrorStrings;
    }

    public String getPerScenarioRunTimeOut() {
        return perScenarioRunTimeOut;
    }

    public String getControllerRunPollingInterval() {
        return controllerRunPollingInterval;
    }

    public String getRunTimeout() {
        return runTimeout;
    }

    public String getTestPaths() {
        return testPaths;
    }

    private final  String archiveRunTestResultsMode;
   private final  boolean publishResults;
    private final  String ignoreErrorStrings;
    private final  String perScenarioRunTimeOut;
    private final  String controllerRunPollingInterval;
    private final  String runTimeout;
    private final  String testPaths;



    @DataBoundConstructor
    public LrScenarioLoadStep( String runTimeout, String ignoreErrorStrings, String perScenarioRunTimeOut, String controllerRunPollingInterval, String testPaths)
    {
        this.testPaths = testPaths;
        this.runTimeout = runTimeout;
        this.controllerRunPollingInterval = controllerRunPollingInterval;
        this.perScenarioRunTimeOut = perScenarioRunTimeOut;
        this.ignoreErrorStrings = ignoreErrorStrings;
    }

    @Extension @Symbol("LrScenarioLoad")
    public static class DescriptorImpl extends AbstractStepDescriptorImpl {
        public DescriptorImpl() { super(LrScenarioLoadStepExecution.class); }

        @Override
        public String getFunctionName() {
            return "lrScenarioLoad";
        }

        @Nonnull
        @Override
        public String getDisplayName() {
            return "Run LoadRunner scenario";
        }

        public List<EnumDescription> getReportArchiveModes() {

            return ResultsPublisherModel.archiveModes;
        }


    }

}

and the executor:
public class LrScenarioLoadStepExecution extends AbstractSynchronousNonBlockingStepExecution<Void> {

@Inject
private transient LrScenarioLoadStep step;

@StepContextParameter
private transient TaskListener listener;

@StepContextParameter
private transient FilePath ws;

@StepContextParameter
private transient Run build;

@StepContextParameter
private transient Launcher launcher;



@Override
protected Void run() throws Exception {

RunFromFileBuilder runFromFileBuilder = new RunFromFileBuilder(step.getTestPaths(), step.getRunTimeout(), step.getControllerRunPollingInterval(), step.getPerScenarioRunTimeOut(), step.getIgnoreErrorStrings(), "", "", "", "", "", "", "", "", "", "", "", "", "", null, false);
RunResultRecorder runResultRecorder = new RunResultRecorder(step.isPublishResults(), step.getArchiveRunTestResultsMode());
runFromFileBuilder.perform(build, ws, launcher, listener);

HashMap<String,String> resultFilename = new HashMap<String, String>(0);
resultFilename.put(RunFromFileBuilder.class.getName(), runFromFileBuilder.getRunResultsFileName());

runResultRecorder.pipelinePerform(build, ws, launcher, listener, resultFilename);

return null;
}

private static final long serialVersionUID = 1L;
}

Jesse Glick

unread,
Aug 30, 2016, 4:26:38 AM8/30/16
to Jenkins Dev

Not clear why you are writing a `Step` at all. From a quick glance, you could just implement `SimpleBuildStep` on an existing `Builder` or `Publisher` and share more code with freestyle. Assuming there is a `@Symbol`, the result will look just like a true `Step`.

A `@Symbol` should start with a lowercase letter.

Use `@DataBoundSetter` for optional parameters.

fkp...@gmail.com

unread,
Aug 31, 2016, 8:59:06 AM8/31/16
to Jenkins Developers
hmmm ...
as i've understood from the posted refactoring guide on Jenkins.io, it's better to separate it - especially when you have a builder and recorder in one plugin and you'd like to make it a one step in pipeline.
I've also looked at HtmlPublisher that separated too.

In what cases it's advised to separate? and not share code? i.e. create diffrent module to support pipeline that launches modules of freestyle job..?

Jesse Glick

unread,
Aug 31, 2016, 10:23:26 AM8/31/16
to Jenkins Dev
On Wed, Aug 31, 2016 at 8:59 AM, <fkp...@gmail.com> wrote:
> it's
> better to separate it - especially when you have a builder and recorder in
> one plugin and you'd like to make it a one step in pipeline.

If there is a reason for these to be separate in a freestyle project,
why should a Pipeline script be obliged to run both in conjunction?

> In what cases it's advised to separate? and not share code?

· you need to write an asynchronous step
· you need to use some more advanced Pipeline APIs (e.g., adding an
`Action` to a `FlowNode`)
· there is no way the current `SimpleBuildStep`/`SimpleBuildWrapper`
databinding could work sensibly in a Pipeline script

fkp...@gmail.com

unread,
Sep 1, 2016, 1:47:41 AM9/1/16
to Jenkins Developers

1. Well, your points might lead to tedious refactoring of old code and design :)
 but in short, the removal of the possibility (in the new Project-job model) to check the list of previous builders used is the main issue which led for this.

Since it's not convenient to start looking for which files were created during the builders run. for example if four different builders of my plugin ran and each have created it's result, I'd have to look for each possible result file and parse it - instead of simply "pulling" it from the builder - which is much simpler.

2. I will look into that. I've been thinking on the need to shift for the asyncrhonous due to step length concern mainly.

3. Where can I read the DOC on the advanced API (such as the one you mentioned...) - other then looking straight at the code (which is cool, but is there something else? )

Thanks again! 

Jesse Glick

unread,
Sep 1, 2016, 6:54:08 AM9/1/16
to Jenkins Dev
Message has been deleted

Fima

unread,
Sep 1, 2016, 8:53:45 AM9/1/16
to Jenkins Developers
Saw that, but I couldn't find what you've said about the Flow Node...
I guess I'll look at the code.


On Thu, Sep 1, 2016 at 1:54 PM, Jesse Glick <jgl...@cloudbees.com> wrote:

--
You received this message because you are subscribed to a topic in the Google Groups "Jenkins Developers" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/jenkinsci-dev/34AKdC0SARM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to jenkinsci-dev+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/CANfRfr3c_mY3enmY6jJNFMAiTsOwX55PKxLO6E2vR0Bo4Csf3Q%40mail.gmail.com.

For more options, visit https://groups.google.com/d/optout.

Cédric Cousseran

unread,
Sep 26, 2016, 9:13:54 AM9/26/16
to Jenkins Developers
Hi,

I've encountered the same issue with my plugin, the syntax of the snippet generator is not supported.
I've tried the solutions you mentioned, without success.
Do you have a more precise idea of what caused your issue?

Thanks,
Cédric Cousseran



Le jeudi 1 septembre 2016 14:53:45 UTC+2, Fima a écrit :
Saw that, but I couldn't find what you've said about the Flow Node...
I guess I'll look at the code.

On Thu, Sep 1, 2016 at 1:54 PM, Jesse Glick <jgl...@cloudbees.com> wrote:

--
You received this message because you are subscribed to a topic in the Google Groups "Jenkins Developers" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/jenkinsci-dev/34AKdC0SARM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to jenkinsci-de...@googlegroups.com.

fkp...@gmail.com

unread,
Sep 26, 2016, 9:53:48 AM9/26/16
to Jenkins Developers
If you'd publish some link to your code - I could take a look and see if there's any fix i made that can be relevant for your plugin.

You can also compare here to see if you spot any differences (it's in ongoing work following the comments I got from Jesse but it works)
https://github.com/YafimK/hp-application-automation-tools-plugin/tree/LoadRunnerPipelineStep/src/main/java/com/hp/application/automation/tools/pipelineSteps

Cédric Cousseran

unread,
Sep 26, 2016, 11:38:55 AM9/26/16
to Jenkins Developers
Thanks for the response,

I took a look at your code, but I've not been able to notice any noticeable difference.

Here is my code, if you have any idea what's wrong in it:

public class CustomStepExecution extends AbstractSynchronousNonBlockingStepExecution<Void> {


    private static final long serialVersionUID = 1L;

    @StepContextParameter
    private transient TaskListener listener;

    @StepContextParameter
    private transient FilePath ws;

    @StepContextParameter
    private transient Run build;

    @StepContextParameter
    private transient Launcher launcher;

    @Inject
    private transient CustomStep step;

    @Override
    protected Void run() {
//work
        return null;
    }
}


public class CustomStep extends AbstractStepImpl {

    private final String string;

    public String getString() {
        return string;
    }

    @DataBoundConstructor
    public CustomStep(@Nonnull String string) {
        this.string = string
    }

    @Extension
    public static class DescriptorImpl extends AbstractStepDescriptorImpl {

        public DescriptorImpl() {
            super(CustomStepExecution.class);
        }

        @Override
        public String getFunctionName() {
            return "CustomStep";
        }

        @Nonnull
        @Override
        public String getDisplayName() {
            return "Launch Step";
        }       
    }
}

fkp...@gmail.com

unread,
Sep 26, 2016, 12:02:36 PM9/26/16
to Jenkins Developers
could you please post the stack trace from the console?

Cédric Cousseran

unread,
Sep 27, 2016, 3:39:21 AM9/27/16
to Jenkins Developers
Sure, here is the stack trace:

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 3: unexpected token: dd3afb84-7f74-4a47-b9da-1cd5ed1cfc59 @ line 3, column 34.
       
CustomStep 'dd3afb84-7f74-4a47-b9da-1cd5ed1cfc59'
                                   
^

1 error

        at org
.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:310)
        at org
.codehaus.groovy.control.ErrorCollector.addFatalError(ErrorCollector.java:150)
        at org
.codehaus.groovy.control.ErrorCollector.addError(ErrorCollector.java:120)
        at org
.codehaus.groovy.control.ErrorCollector.addError(ErrorCollector.java:132)
        at org
.codehaus.groovy.control.SourceUnit.addError(SourceUnit.java:360)
        at org
.codehaus.groovy.antlr.AntlrParserPlugin.transformCSTIntoAST(AntlrParserPlugin.java:145)
        at org
.codehaus.groovy.antlr.AntlrParserPlugin.parseCST(AntlrParserPlugin.java:111)
        at org
.codehaus.groovy.control.SourceUnit.parse(SourceUnit.java:237)
        at org
.codehaus.groovy.control.CompilationUnit$1.call(CompilationUnit.java:167)
        at org
.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:931)
        at org
.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:593)
        at org
.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:569)
        at org
.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:546)
        at groovy
.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
        at groovy
.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
        at groovy
.lang.GroovyShell.parseClass(GroovyShell.java:688)
        at groovy
.lang.GroovyShell.parse(GroovyShell.java:700)
        at org
.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:67)
        at org
.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:410)
        at org
.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:373)
        at org
.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:213)
        at hudson
.model.ResourceController.execute(ResourceController.java:98)
        at hudson
.model.Executor.run(Executor.java:410)
Finished: FAILURE

Jesse Glick

unread,
Sep 27, 2016, 10:04:35 AM9/27/16
to Jenkins Dev
Should not matter, but as a matter of convention, function names

fkp...@gmail.com

unread,
Sep 27, 2016, 10:21:40 AM9/27/16
to Jenkins Developers
Please also add the pipeline script you used...

Can be due to the fact you use string as the variable name and when it been serached it has some issues?

Could you please upload your jelly view for this ....

(If you have a github account to ease this - it will be great..)

Cédric Cousseran

unread,
Sep 27, 2016, 10:56:21 AM9/27/16
to Jenkins Developers
Using a lowercase letter at the start of the function name did the trick:
@Override
public String getFunctionName() {
    return "customStep";
}

Thank you for your help

Jesse Glick

unread,
Sep 27, 2016, 1:20:14 PM9/27/16
to Jenkins Dev
On Tue, Sep 27, 2016 at 10:56 AM, Cédric Cousseran
<cedric.c...@gmail.com> wrote:
> Using a lowercase letter at the start of the function name did the trick

Hmm, perhaps the Groovy parser uses letter case to disambiguate class
names from function names in some cases. Never heard of that before.
In any event, I will update the Javadoc accordingly.
Reply all
Reply to author
Forward
0 new messages