Corredor

ウェブ、プログラミングの勉強メモ。

Redmine を API 経由で操作する node-redmine

普段 Redmine を利用しているが、似たようなチケットをまとめて一括作成したり、チケット情報を抽出・整形したりしたい時に、GUI では限界があったので、何か良いやり方がないか調べてみた。

すると、Redmine も API が用意されており、JSON をぶん投げれば Issue の登録やら何やらができるみたいだった。

JSON を使うなら、シェルスクリプトで curl したりするよりは、Node.js スクリプトで書いた方がオブジェクトとして扱いやすいかな…と思い、もう少し調べてみると、node-redmine という npm モジュールが公開されていた。

コードの中身を見ると、create_issue() とか update_issue() とかいったメソッドが用意されていて、内部で Redmine API 向けの URL に変換している、簡単な作り。でもコレがかなり助かる。

実際に使ってみよう。

最もシンプルにチケット一覧を取得するまで

まずは適当な作業ディレクトリを作り、node-redmine をインストールしておく。

$ mkdir practice-redmine-api/ && cd $_
$ npm init -y
$ npm install -S node-redmine

$ touch list-issues.js

次に、list-issues.js を以下のようにコーディングしていく。

const Redmine = require('node-redmine');

const hostName = 'http://my-redmine.com/';  // Redmine の URL
const config = {
  apiKey: '【API キー】'
};
const redmine = new Redmine(hostName, config);

// Issue を5件取得する
redmine.issues({
  limit: 5
}, (error, data) => {
  if(error) throw error;
  
  // JSON を2スペースで整形して表示する
  data.issues.forEach((issue) => {
    console.log(JSON.stringify(issue, null, '  '));
  });
});

コレを実行すると以下のようになる。

$ node ./list-issues.js
{
  "id": 99,
  "project": {
    "id": 1,
    "name": "オレオレ Redmine"
  },
  // 中略……
  "assigned_to": {
    "id": 1,
    "name": "Neo"
  },
  "subject": "あの問題を解決する",
  "description": "h1. ほげほげ\r\nふがふが",
  "start_date": "2018-01-01",
  "due_date": "2018-12-31",
  "created_on": "2018-01-01T00:00:00Z",
  "updated_on": "2018-01-01T00:00:00Z"
}
{
  // 2件目の Issue…
}
// 以下略…

こりゃ簡単だ!

API 認証部分を共通化する

Issue が取得できたので、Issue を登録したり更新したりする、別のスクリプトを書いてみようと思う。

ただその前に、先程のスクリプトの冒頭に書いた、API 認証部分を共通化しようと思う。

redmine-api-base.js というファイルを作り、以下のように書く。

const Redmine = require('node-redmine');

const hostName = 'http://my-redmine.com/';  // Redmine の URL
const config = {
  apiKey: '【API キー】'
};
const redmine = new Redmine(hostName, config);

module.exports = redmine;

先程の list-issues.js は以下のように直す。

const redmine = require('./redmine-api-base');

redmine.issues({
  limit: 5
}, (error, data) => {  // 以下略…

このスクリプトのように1回しか使わないなら、イチイチ変数化しないで以下のように書いてしまっても良い。

require('./redmine-api-base').issues({
  limit: 5
}, (error, data) => {  // 以下略…

今後はこのノリで、やりたいことに合わせたスクリプトを作ってみる。

試してみた API

試しに使ってみた API は以下のとおり。callback は、全て (error, data) => { } という2つの仮引数を渡してくれる。

  • redmine.issues({ 【検索条件など】 }, callback)
  • redmine.get_issue_by_id(【Issue ID】, {}, callback)
  • redmine.create_issue({ 'issue': 【Issue オブジェクト】 }, callback)
  • redmine.update_issue(【Issue ID】, { 'issue': 【更新したいフィールドのみ書いた Issue オブジェクト】, callback)
  • redmine.get_user_by_id(【User ID】, {}, callback)

他にもあるので、ソースを見ながら使ってみよう。

複数チケットを一括登録する

複数のチケットを一括登録するには、API への POST 通信を順次実行するのが良いかと思う。色々試行錯誤して、以下のような bulk-create-issues.js というスクリプトを作った。

const redmine = require('./redmine-api-base');

// 登録データの配列
const issues = [
  {
    'project_id'    : 1,             // プロジェクト ID
    'tracker_id'    : 10,            // トラッカー ID
    'subject'       : 'ある課題 1',  // チケット名
    'description'   : '説明',        // 説明 : 改行は「\r\n\」で書ける
    'assigned_to_id': 14,            // 担当者 ID
    'start_date'    : '2018-05-01',  // 開始日 : 文字列 'YYYY-MM-DD'
    'due_date'      : '2018-09-30'   // 期日   : 文字列 'YYYY-MM-DD'
  },
  {
    'project_id'    : 1,
    'tracker_id'    : 10,
    'subject'       : 'ある課題 2',
    'description'   : '似たような説明',
    'assigned_to_id': 18,
    'start_date'    : '2018-05-01',
    'due_date'      : '2018-09-30'
  }
];

// 1件ずつ登録していく
issues.reduce((prevPromise, issue) => {
  return prevPromise
    .then(() => {
      return new Promise((resolve, reject) => {
        redmine.create_issue({
          'issue': issue
        }, (error, data) => {
          if(error) {
            console.error('登録失敗 : ', error);
            return reject(error);
          }
          
          console.log('登録成功', data);
          resolve();
        });
      });
    });
}, Promise.resolve());

以前紹介した、配列データを直列で順次実行する Promise チェーンを作った。

実際は、登録データ (issues) を作る方が大変。Redmine プロジェクトの設定に合わせて、色々指定しておかないといけないプロパティが多い。ココらへんは、既に作ってある Issue を issues()get_issue_by_id() で取得してみて、「この項目はこの値にしておこう」というモノを控えておくと良い。

元データを Excel などで作ってあれば、CSV 形式で吐き出しておいて、CSV ファイルを読み込んだら JSON 形式の配列に変換する、という風にやれば良さそう。

以上

Redmine の一括操作もコレで楽チン!

Redmine実践ガイド 理論と実践、事例で学ぶ新しいプロジェクトマネジメント

Redmine実践ガイド 理論と実践、事例で学ぶ新しいプロジェクトマネジメント

入門Redmine 第5版

入門Redmine 第5版