JIRA APIでissueの変更履歴を取得する
の発展形で、実行を自動化したときに書いたコードです。
やりたいこと
JIRAのissue keyをA列に取得しておいて
それらのステータスの最終変更日時を取得してシートに書き出したい。
ということをやるときに以下の点も考慮しました。
- 対象のissue keyが多いとGASの6分の実行制限にかかるので
- 1課題1秒くらいとして1分間に余裕持って50課題の履歴を取得する
- 1分ごとのトリガーを用意して
- ヘッダにstatus_last_changed, from, toの列を自動追加して
- 次回実行はstatus_last_changedの列で値が入力されている次の行から
- 前回の実行が終わっていなければもう1分待つ
- 最後の実行時に残りが50課題も無ければあるだけ実行して
- トリガーを自動で削除する
コードは長くなりましたが、以下の4つの変数を設定すれば動くように書きました。
- ISSUE_URL
- ss_url
- rownums
- issue_key_col
事前準備
- JIRAのissue keyをA列に書き出しておく
- スクリプトのプロパティにtokenという名でbasic認証用の文字列を入れておく
関連記事
JIRA APIでissueの変更履歴を取得する
JIRA APIでissueの変更履歴を取得する2
JIRA APIでissueの変更履歴を取得する3
コード.gs
var ISSUE_URL = 'https://SITENAME.atlassian.net/rest/api/2/issue/';
var ss_url = "https://docs.google.com/spreadsheets/d/SPREADSHEET_ID/edit#gid=0";
var rownums = 50;
var issue_key_col = 1;// A列にissue keyがある想定で1列目
/************************************
初回実行でトリガーを登録する
************************************/
function initialize() {
create_header_values();
console.log('トリガーを登録します' + new Date());
set_property('running', false);
createTriggerEvery1Minutes();
}
function create_header_values() {
var sheet = get_sheet();
var valeus = [
"status_last_changed",
"from",
"to"
];
set_header(sheet, valeus);
}
/************************************
トリガーを作成する
************************************/
function createTriggerEvery1Minutes() {
ScriptApp.newTrigger('run')
.timeBased()
.everyMinutes(1)
.create();
}
/************************************
run 1分ごとに実行される
************************************/
function run() {
if(getProps('running') === 'true') {
console.log('前の処理が終わっていないので次の1分を待つ' + new Date())
} else {
console.log('前の処理が終わっているので実行する' + new Date())
set_property('running', true);
get_last_status_change_date();
}
}
/************************************
runで判定後に実行される
シートを取得して
シートからJIRAのissue keyを取得して
最終ステータスの日時と何から何へを取得して
シートに書き込む
************************************/
function get_last_status_change_date() {
var sheet = get_sheet();
var keys = get_keys(sheet);// ["KT-6", "KT-7"];// 列で値が入っている最終行の下から50行分取得して1分おきにトリガーセットして完了したらトリガー削除
var last_statuses = get_last_statuses(keys);
var values = create_value(last_statuses, sheet);
set_values(values, sheet);
set_property('running', false);
}
/************************************
指定したss_urlのシートの0番目のシートを取得して返す
************************************/
function get_sheet() {
var ss = SpreadsheetApp.openByUrl(ss_url);
var sheet = ss.getSheets()[0];
return sheet;
}
/************************************
シート内のA列の2行目から入力されているissue keyを取得して
二次元配列で取得されるので一次元配列にして返す
************************************/
function get_keys(sheet) {
//var col = 2; // B列
var col = getProps("start_col");
var last_row = get_last_row(sheet, col);
var rangeA = sheet.getRange(last_row + 1, issue_key_col, rownums, 1);
var valuesA = rangeA.getValues();
var keys = array_push_apply(valuesA);
Logger.log(keys);
return keys;
}
/************************************
二次元配列を一次元配列にして返す
************************************/
function array_push_apply(arrays){
for(var i = 1; i < arrays.length; i++){
Array.prototype.push.apply(arrays[0], arrays[i]);
}
return arrays[0];
}
/************************************
issue keyの最後のステータス変更を取得して
last_statuses配列に入れて返す
************************************/
function get_last_statuses(keys) {
var last_statuses = [];
for(var i = 0; i < keys.length; i++) {
var key = keys[i];
if(key === '') {// keyがなくなれば
console.log('トリガーを削除します' + new Date())
deleteTrigger("run");// トリガーを削除する
break;
} else { // keyがあれば
var latest_status = get_latest_status(key);
last_statuses.push(latest_status);
}
}
return last_statuses;
}
/************************************
issue keyの最後のステータス変更の履歴を取得して返す
************************************/
function get_latest_status(key) {
var histories = get_issue_histories(key);
var arrays = get_status(histories);
var latest_status = arrays[0];// descにした配列の先頭がlatest
return latest_status;
}
/************************************
issueの情報からchangelogのhistoriesを取得して返す
************************************/
function get_issue_histories(key) {
var response = get_issue(key);
var jobj = JSON.parse(response);
var histories = jobj["changelog"]["histories"];
return histories;
}
/************************************
issueの情報を?expand=changelog付けて取得して返す
************************************/
function get_issue(key) {
var token = getProp("token");
var options = {
contentType: "application/json",
headers: {"Authorization": " Basic " + token}
};
var url = ISSUE_URL + key + "?expand=changelog";
var response = UrlFetchApp.fetch(url, options);
return response;
}
/************************************
histories(履歴)の数だけ繰り返す
さらに履歴の中のitemsの数だけ繰り返す
fieldがstatusならcreatedとfromとtoのオブジェクトを作って
arrays配列に入れて
descending_arrayで日時を基準に降順にして返す
************************************/
function get_status(histories) {
var arrays = [];
for(var i = 0; i < histories.length; i++) {
var history = histories[i];
var created = format_date(history["created"]);
var items = history["items"];
for(var j = 0; j < items.length; j++) {
var item = items[j];
var field = item["field"];
if(field === "status") {
var obj = {};
obj["created"] = created;
obj["from"] = item["fromString"];
obj["to"] = item["toString"];
arrays.push(obj);
}
}
}
var desc = descending_array(arrays);
return desc;
}
/************************************
シートに入れる値を作って入れる
************************************/
function create_value(last_statuses, sheet) {
var values = [];
for(var i = 0; i < last_statuses.length; i++) {
var latest_status = last_statuses[i];
if(latest_status === undefined) {
values.push(["-", "-", "-"]);// statusの変更履歴がなければ-にする→しないとlatest_status["created"]などがエラーになるのでここで回避
//set_values([["-", "-", "-"]], sheet)
} else {
var created = latest_status["created"];
var from = latest_status["from"];
var to = latest_status["to"];
values.push([created, from, to]);
//set_values([[created, from, to]], sheet)
}
}
return values;
}
/************************************
シートに値を入れる
************************************/
function set_values(array, sheet){
//var start_col = 2;
var start_col = getProps("start_col");
var last_row = get_last_row(sheet, start_col);
var start_row = last_row + 1;
var num_rows = array.length;
var num_cols = array[0].length;
var range = sheet.getRange(start_row, start_col, num_rows, num_cols);
range.setValues(array);
}
/************************************
指定したcol(列)の値が入っている最終行を取得して返す
************************************/
function get_last_row(sheet, col) {
var start_row = 1;
var num_cols = 1;
var sh_last_row = sheet.getLastRow();
var values = sheet.getRange(start_row, col, sh_last_row, num_cols).getValues();
for (var i = values.length - 1; i >= 0; i--) {
if (values[i] != "") {
break;
}
}
var last_row = i + 1;
return last_row;
}
/************************************
受け取ったkeyの値をスクリプトのプロパティから返す
************************************/
function getProp(key) {
return PropertiesService.getScriptProperties().getProperty(key);
}
/************************************
日時をフォーマットして返す
************************************/
function format_date(date) {
return Utilities.formatDate(new Date(date), "asia/tokyo", "yyyy-MM-dd HH:mm:ss");
}
/************************************
日時を降順にした配列を返す
************************************/
function descending_array(array) {
var descending = array.sort(sorting_desc);
return descending;
}
/************************************
array配列内の日時を降順にする
************************************/
function sorting_desc(a, b){
if(a[0] > b[0]){
return -1;
}else if(a[0] < b[0] ){
return 1;
}else{
return 0;
}
}
/************************************
トリガーを削除する
************************************/
function deleteTrigger(functionName) {
var allTriggers = ScriptApp.getProjectTriggers();
for (var i = 0; i < allTriggers.length; i++) {
if (allTriggers[i].getHandlerFunction() == functionName) {
ScriptApp.deleteTrigger(allTriggers[i]);
break;
}
}
}
/************************************
スクリプトのプロパティを読み書きする
************************************/
var ScriptProperties = PropertiesService.getScriptProperties();
function getProps(id) {
return ScriptProperties.getProperty(id)
}
function set_property(key, value){
ScriptProperties.setProperty(key, value);
}
/************************************
1行目に自動入力する
************************************/
function set_header(sheet, values){
var start_col = sheet.getLastColumn() + 1;
set_property("start_col", start_col);
var start_row = 1;
var num_rows = 1;
var num_cols = values.length;
var range = sheet.getRange(start_row, start_col, num_rows, num_cols);
range.setValues([values]);
}
|