Jenkins
             プラグイン開発
                メモ
                @kiy0taka




13年4月5日金曜日
自己紹介
             •奥清隆(おく きよたか)
             •id:kiy0taka、@kiy0taka
               ※ 「0」は数字のゼロ

             •株式会社ニューキャスト所属
             •日本Grails/Groovyユーザーグループ
             •関西Javaエンジニアの会
13年4月5日金曜日
プラグイン開発歴(公式)

             •Terminal
             •jQuery
             •jQueryUI
             •MongoDB
             •TEPCO
             •Groovy Remote Control
13年4月5日金曜日
プラグイン開発歴(非公式)

             •Backup
             •GCrawler
             •go-con
             •Xmas
             •irof
13年4月5日金曜日
多分書きます




             http://beta.mybetabook.com/b/kiy0taka/Building+Jenkins+plugin+with+Groovy

13年4月5日金曜日
プラグインを作る

             •Apache Jelly
             •Stapler
             •Extension Point
              •http://wiki.jenkins-ci.org/display/
                JENKINS/Extension+points


13年4月5日金曜日
前準備


             •JDK 1.6以上
             •Maven 3.0.4以上が望ましい
             •好きなIDE


13年4月5日金曜日
Maven設定


             • /.m2/settings.xmlに設定を追記
             •参考:                   850703
                   https://gist.github.com/kiy0taka/




13年4月5日金曜日
settings.xml
             <settings>
               [...]
               <pluginGroups>
                 <pluginGroup>org.jenkins-ci.tools</pluginGroup>
               </pluginGroups>
               <profiles>
                 [...]
                 <profile>
                   <id>jenkins</id>
                   <pluginRepositories>
                     <pluginRepository>
                        <id>m.g.o-public</id>
                        <url>http://maven.glassfish.org/content/groups/public/</url>
                     </pluginRepository>
                   </pluginRepositories>
                   <repositories>
                     <repository>
                        <id>m.g.o-public</id>
                        <url>http://maven.glassfish.org/content/groups/public/</url>
                        </repository>
                     </repositories>
                 </profile>
               </profiles>
               [...]
             </settings>
                                              ※ profileを分けなくても良い
13年4月5日金曜日
Maven Jenkins Plugin

             •プロジェクト作成
              •mvn hpi:create -P jenkins
             •実行
              •mvn hpi:run
             •パッケージ、リリースなどは通常のターゲ
              ットで。(package, release:prepare)


13年4月5日金曜日
Describable/Descriptor


             •Describableインターフェースを実装する
              クラスにはDescriptorの実装が必要

             •Descriptorはシングルトン、Describable
              なインスタンスはDescriptorから作られ
              る



13年4月5日金曜日
HelloWorldBuilder
  public class HelloWorldBuilder extends Builder {

         @Override
         public DescriptorImpl getDescriptor() {
             return (DescriptorImpl)super.getDescriptor();
         }

         @Extension
         public static final class DescriptorImpl
             extends BuildStepDescriptor<Builder> {
         }
  }



13年4月5日金曜日
13年4月5日金曜日
13年4月5日金曜日
Stapler
         •JenkinsのオブジェクトとURLをマッピング
         •/descriptorByName/
             org.jenkinsci.plugins.sample.HelloWorldB
             uilder/checkName?value=Hello

         •Jenkins.getInstance().getDescriptorByNa
             me("org.jenkinsci.plugins.sample.HelloWo
             rldBuilder")).doCheckName("Hello")


13年4月5日金曜日
Builder#perform()
             •AbstractBuild
              •実行中のビルド
             •Launcher
              •ノード上でコマンドを実行する
             •BuildListener
              •ログ出力したり
13年4月5日金曜日
プロセス実行

   // コマンド
   ArgumentListBuilder args = new ArgumentListBuilder("ls", "-la");

   // 実行
   launcher.launch()
     .cmds(args)                     // コマンド設定
     .stdout(listener.getLogger())   // 標準出力をビルドのログに出力
     .join();                        // 実行して待つ




13年4月5日金曜日
プロセス実行

   // コマンド
   ArgumentListBuilder args = new ArgumentListBuilder("ls", "-la");

   // 実行
   launcher.launch()
     .cmds(args)                     // コマンド設定
     .stdout(listener.getLogger())   // 標準出力をビルドのログに出力
     .join();                        // 実行して待つ




13年4月5日金曜日
ノード上で処理
     // リモート上で実行する処理
     static class MyTask implements Callable<String, Exception> {
         public String call() throws Exception {
             return "hello";
         }
     }

     public boolean perform(...) {
         // 処理実行
             launcher.getChannel().call(new MyTask());
     }




13年4月5日金曜日
ノード上で処理

   public boolean perform(...) {

         // callの引数はシリアライズされてリモートノード上で実行される
         // BuilderはSerializableではないのでこれはダメ
         launcher.getChannel().call(new Callable<String, Exception> {
             public String call() throws Exception {
                 return "hello";
             }
         });
   }




13年4月5日金曜日
Jelly

             •JenkinsのViewを書く
             •Groovyスクリプトでも記述可能
             •書き方についてはUI Samplesを参照
             •どのjellyファイルを書かないといけないか
              は各ExtensionのJavadoc等を参照



13年4月5日金曜日
マイグレーション



13年4月5日金曜日
13年4月5日金曜日
マイグレーション

             •モデルのプロパティを変更した場合、古い
             データも変更する必要がある

             •プラグインのバージョンを上げてジョブの
             設定が飛んだとかならないように

             •バージョンを下げても動くように

13年4月5日金曜日
マイグレーション

             // private final String name;
             private final String username;

             // Initializerを使って対象のデータが読み込まれる前に
             @Initializer(before = InitMilestone.JOB_LOADED)
             public static void migration() {
                 Items.XSTREAM2.aliasAttribute(
                     HelloWorldBuilder.class,
                     "username",
                     "name");
             }




13年4月5日金曜日
テスト



13年4月5日金曜日
Jenkinsとの結合テスト


             •extens HudsonTestCase
             •@Rule JenkinsRule


13年4月5日金曜日
@Rule
   public JenkinsRule rule = new JenkinsRule();

   @Test
   public void test() throws Exception {

         FreeStyleProject myJob = rule.createFreeStyleProject();
         HelloWorldBuilder builder = new HelloWorldBuilder("World");
         myJob.getBuildersList().add(builder);
         myJob.save();

         FreeStyleBuild build = myJob.scheduleBuild2(0).get();

         assertEquals(build.getResult(), Result.SUCCESS);
         assertTrue(readFileToString(build.getLogFile())
             .contains("Hello, World!"));
   }




13年4月5日金曜日
src/test/resources/org/jenkinsci/plugins/sample/
             HelloWorldBuilderTest/test以下にテスト用の
                     JENKINS_HOMEを作っておく

        @Test
        @LocalData
        public void test() throws Exception {

             FreeStyleProject myJob = (FreeStyleProject)
                 rule.jenkins.getItem("myJob");
             FreeStyleBuild build = myJob.scheduleBuild2(0).get();

             assertEquals(build.getResult(), Result.SUCCESS);
             assertTrue(readFileToString(build.getLogFile())
                  .contains("Hello, World!"));
        }



13年4月5日金曜日
@Recipe
             •LocalData
             •PresetData
             •WithPlugin
             •WithPluginManager
             •WithTimeout

13年4月5日金曜日

Jenkins plugin memo

  • 1.
    Jenkins プラグイン開発 メモ @kiy0taka 13年4月5日金曜日
  • 2.
    自己紹介 •奥清隆(おく きよたか) •id:kiy0taka、@kiy0taka ※ 「0」は数字のゼロ •株式会社ニューキャスト所属 •日本Grails/Groovyユーザーグループ •関西Javaエンジニアの会 13年4月5日金曜日
  • 3.
    プラグイン開発歴(公式) •Terminal •jQuery •jQueryUI •MongoDB •TEPCO •Groovy Remote Control 13年4月5日金曜日
  • 4.
    プラグイン開発歴(非公式) •Backup •GCrawler •go-con •Xmas •irof 13年4月5日金曜日
  • 5.
    多分書きます http://beta.mybetabook.com/b/kiy0taka/Building+Jenkins+plugin+with+Groovy 13年4月5日金曜日
  • 6.
    プラグインを作る •Apache Jelly •Stapler •Extension Point •http://wiki.jenkins-ci.org/display/ JENKINS/Extension+points 13年4月5日金曜日
  • 7.
    前準備 •JDK 1.6以上 •Maven 3.0.4以上が望ましい •好きなIDE 13年4月5日金曜日
  • 8.
    Maven設定 • /.m2/settings.xmlに設定を追記 •参考: 850703 https://gist.github.com/kiy0taka/ 13年4月5日金曜日
  • 9.
    settings.xml <settings> [...] <pluginGroups> <pluginGroup>org.jenkins-ci.tools</pluginGroup> </pluginGroups> <profiles> [...] <profile> <id>jenkins</id> <pluginRepositories> <pluginRepository> <id>m.g.o-public</id> <url>http://maven.glassfish.org/content/groups/public/</url> </pluginRepository> </pluginRepositories> <repositories> <repository> <id>m.g.o-public</id> <url>http://maven.glassfish.org/content/groups/public/</url> </repository> </repositories> </profile> </profiles> [...] </settings> ※ profileを分けなくても良い 13年4月5日金曜日
  • 10.
    Maven Jenkins Plugin •プロジェクト作成 •mvn hpi:create -P jenkins •実行 •mvn hpi:run •パッケージ、リリースなどは通常のターゲ ットで。(package, release:prepare) 13年4月5日金曜日
  • 11.
    Describable/Descriptor •Describableインターフェースを実装する クラスにはDescriptorの実装が必要 •Descriptorはシングルトン、Describable なインスタンスはDescriptorから作られ る 13年4月5日金曜日
  • 12.
    HelloWorldBuilder publicclass HelloWorldBuilder extends Builder { @Override public DescriptorImpl getDescriptor() { return (DescriptorImpl)super.getDescriptor(); } @Extension public static final class DescriptorImpl extends BuildStepDescriptor<Builder> { } } 13年4月5日金曜日
  • 13.
  • 14.
  • 15.
    Stapler •JenkinsのオブジェクトとURLをマッピング •/descriptorByName/ org.jenkinsci.plugins.sample.HelloWorldB uilder/checkName?value=Hello •Jenkins.getInstance().getDescriptorByNa me("org.jenkinsci.plugins.sample.HelloWo rldBuilder")).doCheckName("Hello") 13年4月5日金曜日
  • 16.
    Builder#perform() •AbstractBuild •実行中のビルド •Launcher •ノード上でコマンドを実行する •BuildListener •ログ出力したり 13年4月5日金曜日
  • 17.
    プロセス実行 // コマンド ArgumentListBuilder args = new ArgumentListBuilder("ls", "-la"); // 実行 launcher.launch() .cmds(args) // コマンド設定 .stdout(listener.getLogger()) // 標準出力をビルドのログに出力 .join(); // 実行して待つ 13年4月5日金曜日
  • 18.
    プロセス実行 // コマンド ArgumentListBuilder args = new ArgumentListBuilder("ls", "-la"); // 実行 launcher.launch() .cmds(args) // コマンド設定 .stdout(listener.getLogger()) // 標準出力をビルドのログに出力 .join(); // 実行して待つ 13年4月5日金曜日
  • 19.
    ノード上で処理 // リモート上で実行する処理 static class MyTask implements Callable<String, Exception> { public String call() throws Exception { return "hello"; } } public boolean perform(...) { // 処理実行 launcher.getChannel().call(new MyTask()); } 13年4月5日金曜日
  • 20.
    ノード上で処理 public boolean perform(...) { // callの引数はシリアライズされてリモートノード上で実行される // BuilderはSerializableではないのでこれはダメ launcher.getChannel().call(new Callable<String, Exception> { public String call() throws Exception { return "hello"; } }); } 13年4月5日金曜日
  • 21.
    Jelly •JenkinsのViewを書く •Groovyスクリプトでも記述可能 •書き方についてはUI Samplesを参照 •どのjellyファイルを書かないといけないか は各ExtensionのJavadoc等を参照 13年4月5日金曜日
  • 22.
  • 23.
  • 24.
    マイグレーション •モデルのプロパティを変更した場合、古い データも変更する必要がある •プラグインのバージョンを上げてジョブの 設定が飛んだとかならないように •バージョンを下げても動くように 13年4月5日金曜日
  • 25.
    マイグレーション // private final String name; private final String username; // Initializerを使って対象のデータが読み込まれる前に @Initializer(before = InitMilestone.JOB_LOADED) public static void migration() { Items.XSTREAM2.aliasAttribute( HelloWorldBuilder.class, "username", "name"); } 13年4月5日金曜日
  • 26.
  • 27.
    Jenkinsとの結合テスト •extens HudsonTestCase •@Rule JenkinsRule 13年4月5日金曜日
  • 28.
    @Rule public JenkinsRule rule = new JenkinsRule(); @Test public void test() throws Exception { FreeStyleProject myJob = rule.createFreeStyleProject(); HelloWorldBuilder builder = new HelloWorldBuilder("World"); myJob.getBuildersList().add(builder); myJob.save(); FreeStyleBuild build = myJob.scheduleBuild2(0).get(); assertEquals(build.getResult(), Result.SUCCESS); assertTrue(readFileToString(build.getLogFile()) .contains("Hello, World!")); } 13年4月5日金曜日
  • 29.
    src/test/resources/org/jenkinsci/plugins/sample/ HelloWorldBuilderTest/test以下にテスト用の JENKINS_HOMEを作っておく @Test @LocalData public void test() throws Exception { FreeStyleProject myJob = (FreeStyleProject) rule.jenkins.getItem("myJob"); FreeStyleBuild build = myJob.scheduleBuild2(0).get(); assertEquals(build.getResult(), Result.SUCCESS); assertTrue(readFileToString(build.getLogFile()) .contains("Hello, World!")); } 13年4月5日金曜日
  • 30.
    @Recipe •LocalData •PresetData •WithPlugin •WithPluginManager •WithTimeout 13年4月5日金曜日