Получить экземпляр cpsscript в отличном коде workflow-cps?

В настоящее время пишу много отличного для очень специфических сценариев Дженкинса.

Проблема в том, что мне нужно отслеживать текущий экземпляр CpsScript для контекста (получение свойств, среды и т. д.) И его invokeMethod (шаги рабочего процесса и тому подобное).

В настоящее время это означает, что я передаю this в конвейерном Groovy-скрипте моему входному классу, а оттуда он передается каждому классу отдельно, то есть очень назойливый.

Экземпляр сценария создается CpsFlowExecution и сохраняется в экземпляре Continuable и CpsThreadGroup, ни один из которых не позволяет вам его получить.

Кажется, расширения, производные от GlobalVariable, получают его, так что у них есть контекст, но в настоящее время я недостаточно осведомлен, чтобы написать собственное расширение, чтобы использовать это.

Итак, вопрос:

Кто-нибудь знает способ отслеживать экземпляр CpsScript, который не требует, чтобы я передавал его каждому новому классу, который я создаю? (Или, как вариант: получить его откуда угодно - неужели это должно быть так сложно?)

2
0
653
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Продолжил поиск способов добиться этого. Даже написал плагин jenkins, который предоставляет глобальную переменную cpsScript. К сожалению, вам нужен экземпляр для предоставления контекста для этого вызова, поэтому он бесполезен.

Итак, в качестве «наименее плохого решения» (тм) я создал класс, названный мной ScriptContext, который я могу использовать в качестве базового класса для моих классов конвейера (он реализует Serializable).

Когда вы пишете свой сценарий конвейера, вы либо один раз передаете ему CpsScript статически:

ScriptContext.script = this

Или, если вы получили его (не забудьте вызвать в super()):

new MyPipeline(this) 

Если ваш класс является производным от ScriptContext, ваша работа сделана. Все будет работать так, как если бы вы не создавали класс, а просто использовали автоматическое преобразование. Если вы используете какие-либо функции уровня CpsScript помимо println, вы можете добавить их сюда.

В любом другом месте вы можете просто вызвать ScriptContext.script, чтобы получить экземпляр скрипта.

Код класса (удалено большинство комментариев, чтобы он был как можно короче):

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()
            }
        }
    }
}

Удалось ли вам обойти тот факт, что плагин безопасности сценария не позволяет вам вызывать invokeMethod() или propertyMissing(), или вы не используете класс ScriptContext в качестве базового класса для чего-либо, определенного в Jenkinsfile или загружаемого с помощью шага загрузки?

Joerg S 25.02.2019 20:55

Я решил работать с глобальной библиотекой вместо библиотеки папок. Базовый код содержит класс на основе ScriptContext для каждого конвейера. Поскольку глобальная библиотека является надежной, песочница не применяется. Именно поэтому я так и поступил.

Blizz 26.02.2019 10:03

Другие вопросы по теме