Blizz
Blizz

Reputation: 8408

Obtain CpsScript instance in workflow-cps groovy code?

Currently coding a lot of groovy for very specific jenkins scenarios.

The problem is that I have to keep track of the current CpsScript-instance for the context (getting properties, the environment and so on) and its invokeMethod (workflow steps and the likes).

Currently this means I pass this in the pipeline groovy script onto my entry class and from there it's passed on to every class separately, which is very annoying.

The script instance is created by the CpsFlowExecution and stored within the Continuable-instance and the CpsThreadGroup, neither of which allow you to retrieve it.

Seems that GlobalVariable derived extensions receive it so that they have a context but I'm currently not knowledgeable enough to write my own extension to leverage that.

So the question is:

Does anyone know of a way to keep track of the CpsScript-instance that doesn't require me to pass it on to every new class I create? (Or alternatively: obtain it from anywhere - does this really need to be so hard?)

Upvotes: 3

Views: 1473

Answers (1)

Blizz
Blizz

Reputation: 8408

Continued looking into ways to accomplish this. Even wrote a jenkins plugin that provides an cpsScript global variable. Unfortunately you need the instance to provide a context for that call, so it's useless.

So as the "least bad solution"(tm) I created a class I called ScriptContext that I can use as a base class for my pipeline classes (It implements Serializable).

When you write your pipeline script you either pass it the CpsScript statically once:

ScriptContext.script = this

Or, if you derived from it (make sure to call super()):

new MyPipeline(this) 

If your class is derived from the ScriptContext your work is done. Everything will work as though you didn't create a class but just used the automagic conversion. If you use any CpsScript-level functions besides println, you might want to add these in here as well.

Anywhere else you can just call ScriptContext.script to get the script instance.

The class code (removed most of the comments to keep it as short as possible):

package ...

import org.jenkinsci.plugins.workflow.cps.*

class ScriptContext implements Serializable {
    protected static CpsScript _script = null

    ScriptContext(CpsScript script = null) {
        if (!_script && script) {
            _script = script
        }
    }

    ScriptContext withScript(CpsScript script) {
        setScript(script)
        this
    }

    static void setScript(CpsScript script) {
        if (!_script && script) {
            _script = script
        }
    }

    static CpsScript getScript()
    {
        _script
    }

    // functions defined in CpsScript itself are not automatically found
    void println(what) {
        _script.println(what)
    }

    /**
     * For derived classes we provide missing method functionality by trying to 
     * invoke the method in script context
     */
    def methodMissing(String name, args) {
        if (!_script) {
            throw new GroovyRuntimeException('ScriptContext: No script instance available.')
        }
        return _script.invokeMethod(name, args)
    }

    /**
     * For derived classes we provide missing property functionality.
     * Note: Since it's sometimes unclear whether a property is an actual property or
     * just a function name without brackets, use evaluate for this instead of getProperty.
     * @param name
     * @param args
     * @return
     */
    def propertyMissing(String name) {
        if (!_script) {
            throw new GroovyRuntimeException('ScriptContext: No script instance available.')
        }
        _script.evaluate(name)
    }

    /**
     * Wrap in node if needed
     * @param body
     * @return
     */
    protected <V> V node(Closure<V> body) {
        if (_script.env.NODE_NAME != null) {
            // Already inside a node block.
            body()
        } else {
            _script.node {
                body()
            }
        }
    }
}

Upvotes: 1

Related Questions