Jiraの未完了課題をSlackに毎朝投稿する

Google App Script

やりたいこと

毎日決まった時間にJiraの未完了課題をSlackの各チャンネルに投稿します。
未完了課題の確認漏れを無くします。

全体の流れ

  1. Jira APIを使ってJiraから未完了の課題データを取得します。
  2. Slack APIを使ってのSlackの各チャンネルに投稿します。

手順

Jira APIトークンを作成

まずはJiraのAPIトークンを取得します。

下記リンクへログインします。
https://id.atlassian.com/manage/api-tokens
「API トークンの作成」をクリックします。

ダイアログが表示されるので「Label」欄に簡単なラベル名を入力して「作成」をクリックしてください。

APIトークンが発行されますのでコピーしてから「閉じる」を押してください。

一度しか表示されませんので必ずコピーして大切に保管してください。

Jira APIの作成は以上です。

SlackでIncoming Webhook URLを取得

次にSlackで課題を投稿したいチャンネルのIncoming Webhook URLを取得します。

アプリの作成

Slackアプリが必要ですので下記リンクから作成します。
https://api.slack.com/apps/new
「Create a Slack App」ダイアログが表示させますのでApp Nameにアプリ名を記入し、「Development Slack Workspace」で課題を投稿したいワークスペースを選択して「Create App」をクリックします。

アプリの設定

作成したアプリの設定をします。

OAuth & Permissionsの設定

左のメニューから[OAuth & Permissions]をクリックする。

Scopeの設定をします。「Scopes」>「Bot Token Scopes」のAdd an OAuth Scopeをクリックして「chat:write」、「incoming-webhook」を追加します。

ページ上部の「Install to Workspace」をクリックします。

投稿先のチャンネルを選択し、「許可する」をクリックします。

Bot User OAuth Access Tokenの欄にトークンが表示されれば成功です。

OAuth & Permissionsの設定は以上です。

Incoming Webhooksを設定

次に左のメニューから「Incoming Webhooks」をクリックして「Active Incoming Webhooks」をOnになっていることを確認します。なっていなければOnにしてください。

ページ下部にWebhook URLとChannelが追加されています。
このWebhook URLは後ほど使います。
投稿するチャンネルを増やす場合は「Add New Webhook to Workspace」で追加できます。

これでSlackでチャンネルのWebhook URLを取得できました!

プログラムを作成

今回はGoogle AppScriptでプログラムを書いていきます。

Jiraからデータを取得

まずはJiraからプロジェクト毎の未完了タスクを取得する処理を書きます。

const EMAIL = "[YOUR_EMAIL]";
const JIRA_API_TOKEN = "[JIRAのAPIトークン]";
const BASE_URL = 'https://[Jiraドメイン]';
const SEARCH_URL = BASE_URL + '/rest/api/2/search?';
const ISSUE_URL = BASE_URL + '/rest/api/2/issue/';
const PROJECTS = [{key:"プロジェクトKEY",name:"プロジェクト名", url:"投稿先チャンネルのWebhook URL"},
                  {key:"プロジェクトKEY",name:"プロジェクト名", url:"投稿先チャンネルのWebhook URL"}];


function get_project_issues(project_key){
  let issues = serach_project_issues(project_key);
 //project_keyをキーにして検索します。
  let array = [];
  add_objects(issues,array);
 //プロジェクトの二次元配列を作ります。
  return array;
};


function serach_project_issues(project_key) {
  let status = 'Done, 完了';
  let query = "&jql=project[key]=" + project_key + " AND status NOT IN(" + status + ") ORDER BY duedate asc";
  //未完了のissueを期日が近い順に取得するクエリ。
  let issues = search(query);
  return issues;
};

function add_objects(issues,array) {
  issues.forEach(function(issue){ 
    obj = {};
    obj["key"] = issue.key;
    obj["summary"] = issue.fields.summary;
    obj["status"] = issue.fields.status.name;
    obj["priority"] = issue.fields.priority.name;
    obj["duedate"] = issue.fields.duedate?issue.fields.duedate: '期日未定';
    obj["assignee"] = issue.fields.assignee?issue.fields.assignee.displayName: '未割当';
    array.push(obj); 
  });
};

function search(query) {
  let sort = "&fields=self,issuetype,summary,status,priority,assignee,duedate";
  let url = SEARCH_URL + sort + query;
  let data = get_data(url);
  let decoded = decode(data);
 //帰ってきたJSONデータをデコードする。
  let issues = decoded["issues"];
  return issues;
};

function get_data(url) {
  let token = Utilities.base64Encode(EMAIL + ":" + JIRA_API_TOKEN);
  let headers = {
    "Content-Type": "application/json",
    'Authorization': 'Basic ' + token,
  };
  //EMAILとJiraのAPIトークンで認証する。
  let options = {
    "method": "get",
    "headers" : headers,
  };
  let response = UrlFetchApp.fetch(url, options);
  return response;
};

function decode(data) {
  let json = JSON.parse(data.getContentText());
  return json;
};

function run_project_issues(){
  let projects = PROJECTS;
  projects.forEach(project => {
    let issue_keys = get_project_issues(project["key"]);
    //Jiraから課題データ取得

    send_to_project(project,issue_keys);
    //Slackに投稿
  });
}
Slackに投稿

次にSlackに投稿する処理を書きます。

function send_to_project(project, issues){
  let text = "*" + project["name"]+ "の未完了タスクです。*\n";
  let number = 0;
  issues.forEach( issue => {
    let url = "https://[Jiraドメイン]/browse/" + issue["key"];
    number = number +1;
    text = make_text(number,text,issue,url);
  });
  Logger.log(text);
  send_to_slack(project["url"], text);
};

function make_text(number,text,issue,url) {
  text = text + "\n" + number + ". " + issue["assignee"] + " "+ issue["duedate"] +  " " +
  issue["priority"] + " " + issue["status"] +"<" + url + "|" + issue["summary"] + "> "  ; 
  return text;
 //担当者、期日、優先度、ステータス、URLをテキストに追加
};

function send_to_slack(webhook_url, text) {
  let json_data = {
    "text" : text,
  };
  let payload = JSON.stringify(json_data);
  var options = {
    "method" : "post",
    "contentType" : "application/json",
    "payload" : payload,
  };
  UrlFetchApp.fetch(webhook_url, options);
};

コードは完成です。

ウェブアプリケーションとして導入

コードが書けたら次はウェブアプリケーションとして導入します。
上部のメニューから「公開」をクリックします。

モーダルが表示されたら各項目を設定して「デプロイ」します。
今回は
Execute the app as : User accessing the web app(アクセスユーザーが実行ユーザー)
Who has access to the app : Anyone within [ドメイン名](G Suiteに登録している{ドメイン名}のアカウントでログインしていればアクセス可能)

これでウェブアプリケーションとして公開できました。

トリガーを設定

次に決まった時間にアプリケーションを実行するようトリガーを設定します。

上部メニューの時計マークをクリックしてトリガー作成ページを開きます。

ページ右下の「+ トリガーを追加」から新規トリガーを作成します。

今回は毎朝9時〜10時にrun_project_issues関数を実行したいので、以下のように設定します。
設定が完了したら「保存」して完成です。

これで以下のように毎朝SlackのチャンネルにJiraの未完了課題が投稿されます。

コメント

タイトルとURLをコピーしました