How to extract pipeline dsl in the pipeline plugin with the Java?

142 Views Asked by At

I am developing a Jenkins pipeline plugin for CNB(buildpacks). I need to get the variables ​​in the pipeline script with Java but I still can't succeed.

This is the my pipeline script.

buildpacks {
    builder = "some/builder"
}

And I can access these variables(like builder variable) ​​with Groovy language in the buildpacks.groovy

package dsl

// The call(body) method in any file in workflowLibs.git/vars is exposed as a
// method with the same name as the file.
def call(body) {
    def config = [:]
    body.resolveStrategy = Closure.DELEGATE_FIRST
    body.delegate = config
    body()
    try {
    
        echo "${config.builder}"

    } catch (Exception rethrow) {
        throw rethrow
    }

}

But as i said i need to get these variables in Java. Below is my class that I inherited from the GlobalVariable class.

public abstract class PipelineDSLGlobal extends GlobalVariable {

public abstract String getFunctionName();

@Override
public String getName() {
    return getFunctionName();
}

@Override
public Object getValue(CpsScript script) throws Exception {
    Binding binding = script.getBinding();

    CpsThread c = CpsThread.current();
    if (c == null)
        throw new IllegalStateException("Expected to be called from CpsThread");

    ClassLoader cl = getClass().getClassLoader();

    String scriptPath = "dsl/" + getFunctionName() + ".groovy";
    Reader r = new InputStreamReader(cl.getResourceAsStream(scriptPath), "UTF-8");

    GroovyCodeSource gsc = new GroovyCodeSource(r, getFunctionName() + ".groovy", cl.getResource(scriptPath).getFile());
    gsc.setCachable(true);
    System.out.println(gsc.toString());

    Object pipelineDSL = c.getExecution()
            .getShell()
            .getClassLoader()
            .parseClass(gsc)
            .getDeclaredConstructor()
            .newInstance();
    binding.setVariable(getName(), pipelineDSL);
    r.close();

    System.out.println("test");
    
    return pipelineDSL;
}

}

And below is my class that i created for my buildpacksdsl.

package io.jenkins.plugins.buildpacks;

import hudson.Extension;
import io.jenkins.plugins.pipelinedsl.PipelineDSLGlobal;
import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.ProxyWhitelist;
import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.StaticWhitelist;

import java.io.IOException;

@Extension
public class BuildpacksDSL extends PipelineDSLGlobal {

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

@Extension
public static class MiscWhitelist extends ProxyWhitelist {
    public MiscWhitelist() throws IOException {
        super(new StaticWhitelist(
                "method java.util.Map$Entry getKey",
                "method java.util.Map$Entry getValue"
        ));
    }
}

}

If you want to see the structure in more detail, you can take a look at the repository.

Can someone help me ? Thanks.

1

There are 1 best solutions below

0
On

We found a little solution.

We created an instance of a class using compatibility between Groovy and Java. And since we can already get values ​​with Groovy, we can pass parameters directly in the constructor method.

There is probably a more efficient method. But now it's working.

// Buildpacks.groovy
...


import io.jenkins.plugins.buildpacks.pipeline.BuildpacksDSL.BuildpacksPipelineDSL

class Buildpacks implements Serializable {

    // first executed method is similar to main method in java
    public void call(final Closure body) {

        // the config array is the array that holds the variables.
        def config = [:]
        body.resolveStrategy = Closure.DELEGATE_FIRST
        body.delegate = config
        body()

        // creating a new instance, when we give the 'config' array in the constructor, the variables is transferred.
        BuildpacksPipelineDSL pipeline = new BuildpacksPipelineDSL(config)
        pipeline.build()

    }

}

...
// BuildpacksDSL.java

...


 public static class BuildpacksPipelineDSL {

        public BuildpacksPipelineDSL() {
        }

        /**
         * This constructor takes dsl parameters, logger and envs from Jenkins and
         * extracts them to local variables.
         * 
         * @param c
         * @throws Exception
         */
        public BuildpacksPipelineDSL(LinkedHashMap<String, Object> c)
                throws Exception {
            
        // codes...

        }
}

...