うさぎ組

ソフトウェア開発、チームによる製品開発、アジャイル、ソフトウェアテスト

JenkinsでRedmineプラグインつくってみた(公開は来年になりそう) #jenkinsja

JenkinsAdventCalendar2011 の 19日目です。

Jenkins Advent Calendar jp 2011 : ATND


以前に作っていたRedmineプラグインを公開しようと思うので、その前説的な位置づけでこの記事を書きました。
プラグインの概要は

  1. このプラグインはpushされたことを検知して起動するジョブであることが前提になっている
  2. ビルドの失敗でチケットを作成する
    1. Redmineにチケットを作成する
    2. 作成したチケットの内容にVCSのコミットコメントやリビジョン番号などを含める
    3. 対象のpushをリジェクトする
  3. ビルドの成功でコミットコメントに含まれるチケットをクローズする


って感じです。
2.2, 2.3が不完全なのでまだリリース出来ない感じ。

JenkinsとRedmineを連携させる方法

JenkinsプラグインJavaで書く事が多いと思います。
Redmineとの連携にはRedmineRESTAPIのJavaライブラリラッパーを使いました。
http://code.google.com/p/redmine-java-api/
RedmineRESTAPIは便利なので、もっと拡張してほしいです><


使ったクラス

ビルド後の通知なのでNotifierクラスを継承しました。
なんとなく次の感じ。

    @Override
    public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) {
        RedmineManager mgr = new RedmineManager(redmineHost, apiAccessKey);
        List<String> ids = new ArrayList<String>();
        if (build.getResult().isBetterOrEqualTo(Result.SUCCESS)) {
            Pattern pattern = Pattern.compile(".*(close\\s+refs\\s+)#(\\d+)");
            for (Entry change : build.getChangeSet()) {
                Matcher matcher = pattern.matcher(change.getMsg());
                if (matcher.find()) {
                    ids.add(matcher.group(2));
                }
            }
            for (String id : ids) {
                Issue issue = new Issue();
                issue.setId(Integer.valueOf(id));
                issue.setDoneRatio(100);
                try {
                    mgr.updateIssue(issue);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return true;
        }
        Issue issue = new Issue();
        StringBuilder sb = new StringBuilder();
        for (Entry change : build.getChangeSet()) {
            sb.append(change.getMsg() + "\n");
        }
        issue.setSubject("Jenkins Build is FAILURE : " + build.getNumber());
        issue.setDescription(build.getUrl() + "\n" + sb.toString());
        try {
            mgr.createIssue(projectKey, issue);
            ScmType.reject(build, launcher, listener);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

SCMTypeっていうenumを同じクラス内で作っていて、MercurialかGitかBazaarのリポジトリでpushされたものをリジェクトする感じです。
でも、もう少し設定を柔軟に出来るようにして、リジェクトはオプションのほうがいいかも。

JenkinsによるRedmineチケット作成について

以前はシステムテスト専用ジョブにのみ設定していたのですが、どちらかというと、静的解析やカバレッジ率などの専用ジョブを作成して設定するほうが運用的にいいかもしれません。(プロダクトの振る舞いには問題がないレベルでの自動チケット作成がいいかもしれない)

まとめ(はや

JenkinsのプラグインMaven2.xとJava系のIDEがあれば作れます。
あとはここらへんJenkins main module 1.594 API
にまとまっているクラスを継承すればそのクラスの役割のタイミングでサブクラスにしたプラグインを実行できます。