背景
今年 Redmine REST API
を使って下記のようなことをする機会がありました。
- 進捗管理をExcelからRedmineにmigration
- CIのリグレッションテストでFailしたテストケースをRedmineに自動起票
目的
今まで Redmine REST API
は使ったことがなく、実装しながら学んでいきました。その中でハマったことを中心に皆さんに共有して、僕のはハマった罠を回避して頂きたいと思います。
前提
- javaをそこそこ理解している
- Redmineの機能をそこそこ理解している
環境
Environment:
Redmine version 3.4.6.stable
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)
<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
を使うことで「この条件」を表現できます。
Params().add("set_filter", "1")
.add("f[]", "subject")
.add("op[subject]", "=")
.add("v[subject][]", actual.getFileName());
ハマったことは下記3点です。
題名以外(例:担当者)ときのキー値は?
ドキュメントを見つけられなかったので、力技で特定してました。チケット一覧のフィルタで希望の条件を設定するとURLのパラメータとしてフィルタ条件が表示されます。パラメータをデコードするとキーの値を特定できます。
一致以外(例:一致しない、含む)のときは?
上の方法で解析。
チケット全部取得したいから条件なしで取得したら500件しか取得できない
現状不明。方法をご存じの方がいたらご教示ください。
4. 既存チケットのカスタムフィールドを更新するときは一度clearする
一度既存チケットのカスタムフィールドを取得して、値を更新する。そのあとに既存チケットのカスタムフィールドを clearCustomFields
してから追加しないとうまく更新されませんでした。
// この処理で既存チケットからカスタムフィールドを取得して更新して、返却している
Collection<CustomField> customFieldCollection = setEachCustomField(issue, fetchedIssue);
issue.clearCustomFields();
issue.addCustomFields(customFieldCollection);
5. 日付型のカスタムフィールドに値を設定するときのフォーマット
yyyy-MM-dd
一択です。これ以外はparseエラーになります。
以上(思いついたら追加していきます。)