とりゅふの森

GCPデータエンジニアとして生きる

【Atlassian Trello】APIでカードを操作する【Google Apps Script】

f:id:true-fly:20210811222646p:plain

おはようございます。以前の記事で、カンバンボードサービス、Atlassian Trelloを使って、ブログの運用タスクを管理している事例についてご紹介しましたが、今回はこのTrelloを、APIで操作する方法についてご紹介します。

www.true-fly.com

上記記事の通り、Trelloのカード、リストを使って記事の公開タスクも管理しているのですが、毎回カードを移動したりするのがやはり手間で、いつか力尽きてしまいそうなので・・・早めにプログラムを作成して自動化を図ろうと思います。

今回はGoogle Apps Scriptを用いて、本ブログに公開された記事に対応するTrelloのカードを、TrelloAPIで自動処理する例について、Trello APIのKey,Tokenの取得と、実際のソースコードを交えてご紹介します。
ブログの運用に限らず、Trelloによるタスク管理全般に応用できるので、参考にしていただければ幸いです。

今回作るもの

Google Apps Scriptで以下の機能を作成してみます。

  • 自分のブログに新規投稿された記事タイトルをRSSから取得する
  • Trelloの「予約投稿」リストにある同名のカードを、「公開済み」リストに移動する
  • Trelloカードの日付を実際の記事の公開日時に設定し、完了のチェックを入れる
  • 毎日4回自動実行する

Trelloには以下のように、「予約投稿」リストと、「公開済み」リストがあり、実際に予約投稿した記事は、同じタイトルで「予約投稿」リストにカードとしても作ってある前提とします。

f:id:true-fly:20210809004057p:plain

Trello API KeyとToken取得

まずはTrelloAPIを利用するために、API KeyとTokenの取得をします。
以下にアクセスします。

https://trello.com/app-key

Keyがいきなり取得できます。こちらを控えておきましょう。次はTokenを発行しましょう。[トークン]をクリックします。

f:id:true-fly:20210804225116p:plain

以下の画面に遷移します。内容を読んで、画面下部の[許可]をクリックします。

f:id:true-fly:20210804225524p:plain

以下のようにTokenが取得できれば準備完了です!Tokenも控えておきましょう。

f:id:true-fly:20210804225824p:plain

合わせて、TrelloのユーザIDも確認します。プロフィールページにアクセスし、@以下のユーザIDを確認しましょう。

Trello APIを試してみる

先程取得したKeyとTokenを用いて、Trello APIが実行できることを確認しましょう。
今回はGoogle Apps Scriptで実行してみます。

ボード一覧取得API

自分のアカウントが利用しているボードの一覧を取得するコードです。以下のmain()を実行してみましょう。

const TRELLO_API_URL = 'https://api.trello.com/';
const TRELLO_USER_ID = 'ここにユーザIDを入力';
const TRELLO_KEY = 'ここにKeyを入力';
const TRELLO_TOKEN = 'ここにTokenを入力';

function main() {
  Logger.log('ボード一覧');
  let boards = getBoards()
  for (let i = 0; i < boards.length; i++){
    Logger.log(boards[i].id);
    Logger.log(boards[i].name);
  }
}

function getBoards() {
  let params = {
    'method': 'GET',
    'headers': {'ContentType': 'application/json'},
  };
  let url = TRELLO_API_URL + '1/members/' + TRELLO_USER_ID + '/boards'
          + '?key=' + TRELLO_KEY
          + '&token=' + TRELLO_TOKEN;
  let result = UrlFetchApp.fetch(url, params).getContentText();
  return JSON.parse(result);
}

私のアカウントではボードが3つあるので、以下のように3つのID、名前が取得できました。グレーの部分はIDになります。

f:id:true-fly:20210809223929p:plain

リスト一覧取得API

次はボード内のリストの一覧を取得してみます。先程取得したボードIDを入力し、以下のmain()を実行してみましょう。

const TRELLO_API_URL = 'https://api.trello.com/';
const TRELLO_KEY = 'ここにKeyを入力';
const TRELLO_TOKEN = 'ここにTokenを入力';
const BOARD_ID = 'ここに先程取得したボードIDを入力'


function main() {
  // リスト取得
  Logger.log('リスト一覧');
  let lists = getLists(BOARD_ID)
  for (let i = 0; i < lists.length; i++){
    Logger.log(lists[i].id);
    Logger.log(lists[i].name);
  }
}

function getLists(boardId) {
  let params = {
    'method': 'GET',
    'headers': {'ContentType': 'application/json'},
  };
  let url = TRELLO_API_URL + '1/boards/' + boardId + '/lists'
          + '?key=' + TRELLO_KEY
          + '&token=' + TRELLO_TOKEN;
  let result = UrlFetchApp.fetch(url, params).getContentText();
  return JSON.parse(result);
}

以下のようにリスト一覧が取得できます。グレーの部分はIDになります。

f:id:true-fly:20210809223932p:plain

カード一覧取得API

次はリスト内のカードの一覧を取得してみます。先程取得したリストIDを入力し、以下のmain()を実行してみましょう。

const TRELLO_API_URL = 'https://api.trello.com/';
const TRELLO_KEY = 'ここにKeyを入力';
const TRELLO_TOKEN = 'ここにTokenを入力';
const LIST_ID= 'ここに先程取得したリストIDを入力'


function main() {
  Logger.log('カード一覧');
  let cards = getCards(LIST_ID)
  for (let i = 0; i < cards.length; i++){
    Logger.log(cards[i].id);
    Logger.log(cards[i].name);
  }  
}

function getCards(listId) {
  let params = {
    'method': 'GET',
    'headers': {'ContentType': 'application/json'},
  };
  let url = TRELLO_API_URL + '1/lists/' + listId + '/cards'
          + '?key=' + TRELLO_KEY
          + '&token=' + TRELLO_TOKEN;
  let result = UrlFetchApp.fetch(url, params).getContentText();
  return JSON.parse(result);
}

以下のようにカード一覧が取得できます。グレーの部分はIDになります。

f:id:true-fly:20210809223936p:plain

その他Trello API

以上、3つだけAPIの機能紹介しましたが、詳細は以下の公式ドキュメントをご参照ください。
APIの使用のみでなく、cURL、Node.js、Java、Python、PHPのプログラムサンプルがあるので、初めてでもわかりやすいドキュメントかと思います。

developer.atlassian.com

はてなブログのRSSから最新の投稿を取得する

はてなブログのRSSは、ブログURLの後ろに/rssとつければ取得できます。当ブログの場合は、

https://www.true-fly.com/rss

です。このURLから、過去の記事を参考に最新の投稿を取得しようと思います。

www.true-fly.com

以下のソースを実行してみましょう。

//function getLatestEntry() {
const BLOG_URL ='https://www.true-fly.com/rss';

function getRssData() {
  // XMLデータ取得
  let xml = UrlFetchApp.fetch(BLOG_URL, {'ContentType': 'text/xml;charset=utf-8'}).getContentText();
  let docs = XmlService.parse(xml);
  let entries = docs.getRootElement().getChildren('channel')[0].getChildren('item');

  // RSSから取得したデータを整形
  Logger.log(entries[0].getChildText('title'))
  Logger.log(entries[0].getChildText('link'));
  Logger.log(Utilities.formatDate(new Date(entries[0].getChildText('pubDate')),'JST', 'yyyy-MM-dd HH:mm:ss'));
}

結果は以下の通りです。今回はタイトル、URL、投稿日時のみを出力しています。

f:id:true-fly:20210809235952p:plain

これでTrelloAPIの利用方法、はてなブログの最新記事の取得方法が試せたので、いよいよ本題のコードを書いてみましょう。

最新の記事を取得し、Trelloカードを移動させる

ソースコード

以下のmain()を実行してみましょう。最新記事が「予約投稿」リストにあった場合は、「公開済み」リストに移動されます。 移動はmoveCard()で実行しています。

/* 自分ブログの最新投稿を取得し、
Trelloの予約投稿リストにある同名のカードを、
Trelloの公開済みリストに移動する。
*/
const TRELLO_API_URL = 'https://api.trello.com/';
const TRELLO_KEY = 'ここにKeyを入力';
const TRELLO_TOKEN = 'ここにTokenを入力';
const TRELLO_TARGET_BOARD_ID = 'ここにボードIDを入力';
const TRELLO_BEFORE_LIST_ID = 'ここに予約投稿リストIDを入力'; // 
const TRELLO_AFTER_LIST_ID = 'ここに公開済みリストIDを入力'; // 
const BLOG_URL ='ここに自分のブログのRSS URLを入力';

function main() {
  // ブログの最新記事取得
  entry = getLatestEntry()

  // 予約投稿ボード下にあるカード取得
  let cards = getCards(TRELLO_BEFORE_LIST_ID)
  
  // 最新記事と一致するタイトルのカードを探す
  let cardId = '';
  for (let i = 0; i < cards.length; i++){
    if (entry.title == cards[i].name){
      cardId = cards[i].id;
      break;
    }
  }
  if (cardId == ''){
    Logger.log('対象カードがないため、処理を終了');
    return;
  }
  // カードの移動
  moveCard(cardId, entry)
}


function getApi(apiurl) { 
  let params = {
    'method': 'GET',
    'headers': {'ContentType': 'application/json'},
  };
  let url = apiurl + '?key=' + TRELLO_KEY + '&token=' + TRELLO_TOKEN;
  let result = UrlFetchApp.fetch(url, params).getContentText();
  return JSON.parse(result);
}


function getCards(listId) {
  let apiurl = TRELLO_API_URL + '1/lists/' + listId + '/cards';
  return getApi(apiurl);
}


function moveCard(cardId, entry) {
  let params = {
    'method': 'PUT',
    'headers': {'ContentType': 'application/json'},
    'payload': {
      'due': entry.published_at, // 日付に投稿日時を設定
      'dueComplete': 'true', // 日付にチェックをつける
       'pos': 'top' // リストの一番上
    }
  };
  Logger.log('カードを公開済みリストに移動させます');
  let url = TRELLO_API_URL + '1/cards/' + cardId + '?idList=' + TRELLO_AFTER_LIST_ID
          + '&key=' + TRELLO_KEY
          + '&token=' + TRELLO_TOKEN;
  let result = UrlFetchApp.fetch(url, params).getContentText();
  Logger.log(result);
}


function getLatestEntry() {
  // XMLデータ取得
  let xml = UrlFetchApp.fetch(BLOG_URL, {'ContentType': 'text/xml;charset=utf-8'}).getContentText();
  let docs = XmlService.parse(xml);
  let entries = docs.getRootElement().getChildren('channel')[0].getChildren('item');

  // RSSから取得したデータを整形
  return {
    'title': entries[0].getChildText('title'),
    'published_at': Utilities.formatDate(new Date(entries[0].getChildText('pubDate')),'JST', 'yyyy-MM-dd HH:mm:ss') + '+0900',
  }
}

トリガー設定

これをトリガー設定します。今回は1日4回動かしたいので、「時間ベースのタイマー」で、「6時間おき」で設定します。

f:id:true-fly:20210811221004p:plain

これ設定完了です!投稿されたら「予約投稿」リストにある関連カードが、「公開済み」リストに自動的に移動されるようになりました!

まとめ

以上、今回はTrelloのタスク管理をAPIで自動化する方法についてご紹介しました。今回は本ブログの運用の一部として、カードの移動と日付の付与、チェックのみを実装しました。TrelloAPIはできることも多く、かつAPIリファレンスも非常に見やすいので、Trelloで運用している面倒な作業はどんどんプロジェクトで自動化していきましょう!
Google Apps Scriptであれば簡単にトリガー実行する環境を作ることができるのでおすすめです!