株式会社スマレジの開発部でスマレジのサーバサイドを作っています

Redmine APIをGASで実行して、ガントチャートを同期する(1)


こんにちは!株式会社スマレジ、開発部のmasaです。 今回は前回に続けて、Redmine APIを使ったツールづくりを実施します。 前回のブログ↓

masa2019.hatenablog.com

ボリュームがありそうなので、何回か分けようかと思ってます。

こういう使い方を想定

スプレッドシートのテンプレートの中に、下記のようなガントチャートがあります。

f:id:masa2019:20200301232414p:plain
Redmineガントチャート

今回はRedmine APIをつかってRedmine上のガントチャートスプレッドシートガントチャートを同期させることを目指します。 「全部Redmineでええやん?」と思われる方もいると思いますが、前のブログで書いたように、Redmineで多くのタスクを管理するのはかなり面倒なのです。 また、プロジェクトのスケジュール調整の打ち合わせの時にいちいちredmineのチケットを更新しながらなんて、とてもじゃないですができません。 その点、スプレッドシートであれば、編集がスムーズにできるので、進捗などの更新には向いているんです。

具体的には、

  • プロジェクト開始時

    1. スプレッドシートガントチャートをうめる。
    2. 「チケット作成」GASを実行して、スプレッドシートに対応するチケットを作成する。(説明欄は空っぽ)
    3. 説明欄をredmineのチケットに追記する。
    4. 「説明欄のサマリー」GASを実行して、スプレッドシート側に取り込む(努力目標)
  • プロジェクト進行中

    1. 作業する
    2. 作業終わりやその日の帰りにスプレッドシートに進捗を記載
    3. Redmineと同期」GASを実行することでスプレッドシートの進捗ベースでredmineのチケットが更新される
  • プロジェクト完了時

    1. クローズしていないチケットをスプレッドシート上で確認。
    2. 「チェックのついたチケットを削除する」GASを実行して、不要なチケットを削除する。
    3. 「チェックのついたチケットのバージョンを変更する」GASを実行して、チケットのバージョンを変更する。(努力目標)

こんな感じで使う想定です。

Redmineと同期GASを作る(1)

今回は、「とりあえず、Redmineの参照APIを使って、スプレッドシートの各タスクにチケット情報入れたれ」くらいのものです。 チケットの親子等は一切見ていませんし、チケットも全部取ってきちゃっています。 下記はチケットIDとチケットタイトルだけ対応セルに入れる例です。 一応、チケットIDはチケットのハイパーリンクにしてあります。

function createTaskFromRedmine() {

    //検索条件(とりあえず固定)
  var conditions = {"project_id" : 1};

    //header情報
    var headers = { 'X-Redmine-API-Key' : '<APIのアクセスキー>' };

    //urlfetchappのオプション情報
    var options = {
        "method" : "GET",
        "headers" : headers,     //header情報を追加
        "muteHttpExceptions" : true,
        "validateHttpsCertificates" : false //SSLエラー回避
    };
    var url = 'https://redmineのドメイン/issues.json?';
    
    Object.keys(conditions).forEach( function(value) {
      url = url + value + '=' + this[value] ;
    }, conditions)
  
    var chicketUrl = 'https://49.212.209.129/issues/';
    try {
        //外部へアクセスさせる
        var resStr = UrlFetchApp.fetch(url, options).getContentText();
        if (resStr.length === 0) {
            throw new Error("受信データがありませんでした。");
        }
        var resJson = JSON.parse(resStr);
        if (isset(resJson.errors)) {
            throw new Error("取得条件が不正です。");
        }
        var currentIssue = "";
        var sheet = SpreadsheetApp.getActiveSheet();      
        for (var i = 0; i < resJson.issues.length; i++) {
            currentIssue = resJson.issues[i];
            Logger.log(currentIssue.id);
            sheet.getRange(i + 11, 2).setFormula('=HYPERLINK("' + chicketUrl + currentIssue.id + '", "' + currentIssue.id + '")');
            sheet.getRange(i + 11, 3).setValue(currentIssue.subject);
        }

    } catch(e) {
        Browser.msgBox("エラー:" + e);
    }
}

f:id:masa2019:20200301235806p:plain
実行例(スプレッドシート
f:id:masa2019:20200301235851p:plain
実行時のRedmineのチケット

タイトルとIDが対応して入っていることがわかると思います。 ただ、チケットの親子関係を見ていないので、入っている場所はめちゃめちゃです。 次回はこれを手直ししていきます。

ちなみに、途中にあるisset()関数は

qiita.com

こちらからお借りしました。