4
4

More than 3 years have passed since last update.

Redmine REST APIでハマったこと

Last updated at Posted at 2019-12-15

背景

今年 Redmine REST API を使って下記のようなことをする機会がありました。

  • 進捗管理をExcelからRedmineにmigration
  • CIのリグレッションテストでFailしたテストケースをRedmineに自動起票

目的

今まで Redmine REST API は使ったことがなく、実装しながら学んでいきました。その中でハマったことを中心に皆さんに共有して、僕のはハマった罠を回避して頂きたいと思います。

前提

  • javaをそこそこ理解している
  • Redmineの機能をそこそこ理解している

環境

Redmine Version
Environment:
  Redmine version                3.4.6.stable
java Version
java version "1.8.0_221"
Java(TM) SE Runtime Environment (build 1.8.0_221-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode)
pom.xml
        <dependency>
            <groupId>com.taskadapter</groupId>
            <artifactId>redmine-java-api</artifactId>
            <version>4.0.0.preview.1</version>
        </dependency>

ハマったこと

1. ユーザーに付与された権限にAPIの機能も制限される

Redmine REST APIを使うために最初に RedmineManagerクラスを生成します。このときに API KEYというものを使用します。

RedmineManager manager = RedmineManagerFactory.createWithApiKey(REDMINE_URL, API_KEY);

この API KEYはRedmineのユーザー一人一人に付与されます。当時、自分のユーザー権限は管理者権限ではありませんでした。APIのメソッドによってはRedmineのシステム管理者権限が必要なものがあります。

全ユーザーを取得
    /**
     * Load list of users from the server.
     * <p><strong>This operation requires "Redmine Administrator" permission.</strong>
     * <p>
     * This method calls Redmine with "include = memberships,groups" parameter.
     *
     * @return list of User objects
     * @throws RedmineAuthenticationException invalid or no API access key is used with the server, which
     *                                 requires authorization. Check the constructor arguments.
     * @throws NotFoundException
     * @throws RedmineException
     */
    public List<User> getUsers() throws RedmineException {
        return transport.getObjectsList(User.class, new BasicNameValuePair(
                "include", "memberships,groups"));
    }

柔軟に利用したい場合、システム管理者権限になることをお勧めします。

2. Transport が必要

redmine-java-apiのversion4以降から取り込まれた概念のようです。RedmineManagerクラスから取得できます。

RedmineManager redmineManager = RedmineManagerFactory.createWithApiKey(REDMINE_URL, API_KEY);
Transport transport = redmineManager.getTransport();

Transportがないとチケット作成・更新時に「Transportが未設定だぞ!」という例外がスローされます。なので作成・更新前に Issueのインスタンスに Transportを設定してあげてください。

新規チケット作成
// Transportをセット
Issue issue = new Issue(manager.getTransport());
// (中略)
issue = issue.create();
既存チケット更新
Issue issue = manager.getIssueManager().getIssueById(fetchedIssue.getTicketId());
// Transportをセット
issue.setTransport(manager.getTransport());
// (中略)
issue.update();

3. Paramsの使い方

既存チケットに更新をかけるとき、「この条件にあったチケット」を取得したいときがあります。そのときは Params を使うことで「この条件」を表現できます。

チケットの題名が"actual.getFileName"に一致するという条件
Params().add("set_filter", "1")
        .add("f[]", "subject")
        .add("op[subject]", "=")
        .add("v[subject][]", actual.getFileName());

ハマったことは下記3点です。

題名以外(例:担当者)ときのキー値は?

ドキュメントを見つけられなかったので、力技で特定してました。チケット一覧のフィルタで希望の条件を設定するとURLのパラメータとしてフィルタ条件が表示されます。パラメータをデコードするとキーの値を特定できます。
flow.png

一致以外(例:一致しない、含む)のときは?

上の方法で解析。

チケット全部取得したいから条件なしで取得したら500件しか取得できない

現状不明。方法をご存じの方がいたらご教示ください。

4. 既存チケットのカスタムフィールドを更新するときは一度clearする

一度既存チケットのカスタムフィールドを取得して、値を更新する。そのあとに既存チケットのカスタムフィールドを clearCustomFields してから追加しないとうまく更新されませんでした。

// この処理で既存チケットからカスタムフィールドを取得して更新して、返却している
Collection<CustomField> customFieldCollection = setEachCustomField(issue, fetchedIssue);
issue.clearCustomFields();
issue.addCustomFields(customFieldCollection);

5. 日付型のカスタムフィールドに値を設定するときのフォーマット

yyyy-MM-dd一択です。これ以外はparseエラーになります。

以上(思いついたら追加していきます。)

参考

4
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4