プロジェクトでJenkinsを使ってますが、勉強も兼ねてJenkinsのプラグインを作ってみようと思いました。 まずは Plugin tutorial - 日本語 - Jenkins Wiki に従って、Jenkinsのプラグイン開発を体験してみたいと思います。 やってみる †環境は Macに Mac OS X に maven3 (3.0.5) をインストールする手順 | OSCALOG をつかってMavenなどをインストール済みです。*1 事前の設定 †# view ~/.m2/settings.xml 下記のように作成しておきます。 # cat ~/.m2/settings.xml <settings> <pluginGroups> <pluginGroup>org.jenkins-ci.tools</pluginGroup> </pluginGroups> <profiles> <!-- Give access to Jenkins plugins --> <profile> <id>jenkins</id> <activation> <activeByDefault>true</activeByDefault> <!-- change this to false, if you don't like to have it on per default --> </activation> <repositories> <repository> <id>repo.jenkins-ci.org</id> <url>http://repo.jenkins-ci.org/public/</url> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>repo.jenkins-ci.org</id> <url>http://repo.jenkins-ci.org/public/</url> </pluginRepository> </pluginRepositories> </profile> </profiles> </settings> プロジェクトの作成 †# mvn -cpu hpi:create プロジェクト名などを聞かれる。 groupId: nu.mine.kino.jenkins.plugins artifactId: project-management こうなるように答えました。 # cd project-management/ # mvn -DdownloadSources=true -DdownloadJavadocs=true eclipse:eclipse Eclipseで利用可能になりました。このDownloadのオプションですが、結構な時間がかかりますので、場合によってはオプションを指定しない方がよさそうです。。 # mvn package /project-management/target/project-management.hpi というファイルができました。これがプラグインの実体になります。 ローカルのリポジトリにインストール †# mvn install 動かしてみる。 †# export MAVEN_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n" # mvn hpi:run Windowsでは set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n ローカルでJenkinsが起動します。http://localhost:8080/jenkins/ からアクセス可能! Hello World的なプラグインがインストールされているのが分かります。 プラグイン全体に関する設定画面 にHello World Builderというプラグインが。 各プラグインの画面にも設定が追加されている。 ビルドを実行した結果でプラグインが動いているのが分かる。 プロジェクトの構成 †プロジェクトの構成はこんな感じになっています。 HelloWorldBuilder? †HelloWorldBuilder? は Builderを拡張しているクラスで、Jenkinsのプロジェクトの「設定 > ビルド」の「ビルド手順の追加」に表示されます。 それで追加するとビルド時にこのクラスのメソッドが呼び出されるようになっています。 実際呼び出されるメソッドは、 @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) { // This is where you 'build' the project. // Since this is a dummy, we just say 'hello world' and call that a build. // This also shows how you can consult the global configuration of the builder if (getDescriptor().getUseFrench()) listener.getLogger().println("Bonjour, "+name+"!"); else listener.getLogger().println("Hello, "+name+"!"); return true; } これです。 config.jelly †config.jelly は ビルド に追加したときに画面に表示されるUIを制御します。 <j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form"> <!-- This jelly script is used for per-project configuration. See global.jelly for a general discussion about jelly script. --> <!-- Creates a text field that shows the value of the "name" property. When submitted, it will be passed to the corresponding constructor parameter. --> <f:entry title="Name" field="name"> <f:textbox /> </f:entry> </j:jelly> ここでセットされた値は HelloWorldBuilder? のコンストラクタ // Fields in config.jelly must match the parameter names in the "DataBoundConstructor" @DataBoundConstructor public HelloWorldBuilder(String name) { this.name = name; } に渡されるようになっています。 global.jelly †global.jelly は 「Jenkinsの管理 > システムの設定」に表示されるUIを制御します。config.jelly と同じようにxmlでUIを定義します。 <j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form"> <!-- This Jelly script is used to produce the global configuration option. Jenkins uses a set of tag libraries to provide uniformity in forms. To determine where this tag is defined, first check the namespace URI, and then look under $JENKINS/views/. For example, <f:section> is defined in $JENKINS/views/lib/form/section.jelly. It's also often useful to just check other similar scripts to see what tags they use. Views are always organized according to its owner class, so it should be straightforward to find them. --> <f:section title="Hello World Builder"> <f:entry title="French" field="useFrench" description="Check if we should say hello in French"> <f:checkbox /> </f:entry> </f:section> </j:jelly> ここでセットされた値は、自動生成された @Extension // This indicates to Jenkins that this is an implementation of an extension point. public static final class DescriptorImpl extends BuildStepDescriptor<Builder> { @Override public boolean configure(StaplerRequest req, JSONObject formData) throws FormException { // To persist global configuration information, // set that to properties and call save(). useFrench = formData.getBoolean("useFrench"); // ^Can also use req.bindJSON(this, formData); // (easier when there are many fields; need set* methods for this, like setUseFrench) save(); return super.configure(req,formData); } } ここからアクセス可能なようです。 いじってみる †システムの設定画面に、テキストボックスを追加してみる。 †システムの設定に表示される設定画面に、新たにテキストボックスを追加してみます。追加するUIを制御しているのは global.jelly でしたので、そこを下記のように追加します。 <j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form"> <f:section title="Hello World Builder"> <f:entry title="French" field="useFrench" description="Check if we should say hello in French"> <f:checkbox /> </f:entry> <!-- 追加 --> <f:entry title="Text Data" field="textData"> <f:textbox /> </f:entry> <!-- 追加 --> </f:section> </j:jelly> Jenkinsを再起動したところ、、、、、 追加されました!!! さて、この設定画面に追加されたテキストボックスの値ですが、画面で保存ボタンをクリックしたときに private String text; public boolean configure(StaplerRequest req, JSONObject formData) throws FormException { text = formData.getString("textData"); save(); return super.configure(req,formData); } などとアクセス可能なのでした。また、設定画面を開いた際には、global.jelly ファイルの field="textData" より public String getTextData(){ return text; } がコールされ、textの情報が画面に反映されます。 まとめると †まとめると、画面( global.jelly )に「field="textData"」というデータを定義した際は、 formData.getString("textData"); で画面上のデータにアクセスし(してデータをsaveしておいて)、画面を開く際は public String getTextData(){ return text; } という名前でさっき保存したデータを返すようにしておく、というのが定石のようです。*2 そしてジョブからそのデータを使用する場合は、プログラム上から @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) { listener.getLogger().print( getDescriptor().getTextData() + ":" + name + "!"); return true; } などと指定すればOKですね。 ジョブの設定画面に、テキストボックスを追加してみる。 †次は、各ジョブごとの設定画面に、テキストボックス(テキストエリア)を追加します。追加するUIを制御しているのは config.jelly でしたので、そこに下記のように追加します。 <?jelly escape-by-default='true'?> <j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form"> <f:entry title="Name" field="name"> <f:textbox /> </f:entry> <!-- 追加 --> <f:entry title="List" field="dataList"> <f:textarea /> </f:entry> <!-- 追加 --> </j:jelly> Jenkinsを再起動したところ、、、、、 追加されました!!! ちなみにこの*.jellyに書くタグは Jelly Taglib references などにリファレンスがあったりします。 さてこの追加された画面の情報をどのようにプラグインが保存するかですが、画面の入力情報は、 @DataBoundConstructor public HelloWorldBuilder(String name) { this.name = name; } このアノテーションされたコンストラクタに渡されるのでした。なのでこのコンストラクタを以下のように書き換えます。 @DataBoundConstructor public HelloWorldBuilder(String name, String dataList) { this.name = name; this.dataList = dataList; } private final String name; private final String dataList; また global.jelly 同様、画面を開いた際に field="dataList" よりgetterがコールされます。すなわち以下のgetterを追加します。 public String getDataList() { return dataList; } 以上で、ジョブの設定画面の情報はJenkinsによってストアされ、必要に応じて @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) { listener.getLogger().print(dataList); return true; } とアクセス可能です。 関連リンク †
この記事は
現在のアクセス:9927 |