GeekFactory

int128.hatenablog.com

Jenkins Workflow PluginのDSLを拡張する試み

Jenkins Workflow PluginのDSLを拡張する仕組みを調べたのでメモします.

Workflow basic stepsを参考にする

Workflow Pluginはbasic stepsという基礎的な命令セットと一緒にリリースされています.basic stepsには下記が含まれます.

ここではEchoStepの実装を参考にします.echoという名前は下記のDescriptorクラスで定義されています.

    @Extension
    public static class DescriptorImpl extends AbstractStepDescriptorImpl {
        public DescriptorImpl() {
            super(Execution.class);
        }
        @Override
        public String getFunctionName() {
            return "echo";
        }
    }

Workflowスクリプトechoを実行した場合,コンストラクタが実行されます.echoの引数はコンストラクタに渡されます.

    @DataBoundConstructor
    public EchoStep(String message) {
        this.message = message;
    }

そして,Executionクラスのrun()メソッドが実行されます.

    public static class Execution extends AbstractSynchronousStepExecution<Void> {
        @Override protected Void run() throws Exception {
            listener.getLogger().println(step.getMessage());
            return null;
        }
    }

おおまかな処理の流れが分かったところで,プラグインを実装してみましょう.

プラグインでStepを実装する

Stepの定義をプラグインに書いて,Workflowの動作を確認します.

Jenkinsプラグインの作り方は Plugin tutorial - Jenkins - Jenkins Wiki を参考にします.ここでは,Archetypeで自動生成されたコードを使います.なお,自動生成されたコードはIntelliJ IDEAで読み込めます.

まず,pom.xmlにWorkflow Step APIの依存関係を追加します.

    <dependencies>
        <dependency>
            <groupId>org.jenkins-ci.plugins.workflow</groupId>
            <artifactId>workflow-step-api</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>org.jenkins-ci.plugins.workflow</groupId>
            <artifactId>workflow-step-api</artifactId>
            <version>1.2</version>
            <classifier>tests</classifier>
            <scope>test</scope>
        </dependency>
    </dependencies>

次に,EchoStepのコードをそのまま貼り付けて,名前をカスタマイズします.

    @Extension
    public static class DescriptorImpl extends AbstractStepDescriptorImpl {
        public DescriptorImpl() {
            super(Execution.class);
        }
        @Override
        public String getFunctionName() {
            return "something";
        }
    }

コンストラクタはあらゆる引数を受け取れるようにしてみます.

    @DataBoundConstructor
    public EchoStep(Object arg) {
        this.arg = arg;
    }

Executionクラスのrun()メソッドでは,引数をtoString()したものを出力してみます.

    public static class Execution extends AbstractSynchronousStepExecution<Void> {
        @Override protected Void run() throws Exception {
            listener.getLogger().println(step.getArg().toString());
            return null;
        }
    }

コードを書いたら実際に動作させてみましょう.下記のコマンドでプラグインが組み込まれたJenkinsが起動します.

mvn hpi:run

初期状態ではプラグインが足りないため,追加でWorkflow: Aggregateプラグインをインストールします.

新しいWorkflowジョブを作成して実行してみましょう.Workflowスクリプトは下記とします.

something 'D・S・L!!'

ジョブを実行したら引数が表示されると思います.また,somethingの引数をクロージャなどに変えたらクラス名が表示されるはずです.

まとめ

本エントリでは,WorkflowのDSLを拡張する基礎的な方法を説明しました.この仕組みを応用することで,既存のプラグインをWorkflowに対応させたり,新しい語彙をDSLに追加したりすることが可能です.

参考文献: