背景・状況
現チームでは、日常的なスクラムイベントで利用するコンフルページが1スプリントで新規作成する。
イメージ的には、こいう感じです。
前スプリントのページをコピーし、タイトルを当日の日付を書き換えるという作業だった。
上記手順は定形作業であるが地味にめんどくさい作業だった。
固定作業となっているコンフルの作成タスクを軽減する目的で、自動化ソースが公開してくれていたため、この場で共有させてください。
できること
基本的には下記のGASを定期実行しています。
コードを読んでもらうのが早いですが、やっているところは
- 日時でGASを実行(トリガー)
- 営業日かどうか判断してAPI投げるかを判断
- コンフルAPIを投げて、作成したいページの前回のコンフルページを検索(本文とタイトルを取得)
- 作成したい当日のコンフルページを作成。作成の際にbodyに本文やタイトルを入れてページを作成
簡単に言うと、翌週のMTG用ページを実行週のページをコピーする形で作成
例:
- 2023年2月20日の夜にGasのMain関数が動く
- 営業日なので、コンフルページ作成用のコードを動かす
- 今週分である「2023-02-20週PO/SMデイリー」のページを検索し本文とタイトルを取得
- 日付をインクリメントして「2023-02-27週PO/SMデイリー」というページを作成するAPIを投げる
起動時間の登録は画面左側の時計のアイコン”トリガー”より設定が可能
// 指定された日が営業日か(営業日 = 「土日でない」「祝日カレンダーに予定がない」)
// 営業日 = true
function isWorkday (targetDate) {
// targetDate の曜日を確認、月曜以外は休む (false)
var rest_or_work = ["REST","mon","REST","REST","REST","REST","REST"]; // 日〜土
var youbi_num = targetDate.getDay() //取得した日付の曜日が0~6の数字で返却される
if ( rest_or_work [youbi_num] == "REST" ) { //rest_or_workのリストは月曜日以外はRESTとしている
console.log("実行しません")
return false;
};
// // 祝日カレンダーを確認する
// var calJpHolidayUrl = "ja.japanese#holiday@group.v.calendar.google.com";
// var calJpHoliday = CalendarApp.getCalendarById (calJpHolidayUrl);
// if (calJpHoliday.getEventsForDay (targetDate).length != 0) {
// // その日に予定がなにか入っている = 祝祭日 = 営業日じゃない (false)
// return false;
// } ;
// 全て当てはまらなければ営業日 (True)
return true;
}
// main
function main () {
var today = new Date ();
// 実行日であれば実行
if (isWorkday (today) == true) {
post_content();
console.log("実行します")
}
}
const API_BASE_URL = "https://API_BASE_URL.atlassian.net/wiki";
// // API情報を定義
// // APIで表示及び更新したいコンフルのワークスペース
var user_id = {Googleアカウント};
var token = {Google Token};
// コンテンツ作成
function post_content() {
var page_title = "週 PO/SMデイリー"
var stringtoday = getToday().toString();
var next_monday = getSevenDaysLater();
var id = get_contentid(page_title,stringtoday);
console.log("コピー元ページのid", id);
var body = get_contentbody(page_title,stringtoday);
var response = create_contents(id,next_monday,page_title,body);
return;
}
// コンテンツID取得
function get_contentid(page_title,stringtoday) {
var options = {
'headers': create_headers(user_id, token),
'method': 'get',
'muteHttpExceptions': true,
};
var title = "\"" + stringtoday + page_title + "\"";
console.log(title);
var space = "\"AUTHRESTORED\"";
var api_url = "https://spacename.atlassian.net/wiki/rest/api/content/search?expand=ancestors&cql=space="+space+ "+and+title=";
var urlEncoded = encodeURI(api_url)+encodeURIComponent(title);
var response = UrlFetchApp.fetch(urlEncoded, options).getContentText('UTF-8');
//console.log(response);
var content_json = JSON.parse(response);
var length = Object.keys(content_json.results[0].ancestors).length;
console.log(content_json.results[0].ancestors[length - 1].id)
return content_json.results[0].ancestors[length - 1].id;
}
// コンテンツボディ取得
function get_contentbody(page_title,stringtoday) {
var options = {
'headers': create_headers(user_id, token),
'method': 'get',
'muteHttpExceptions': true,
};
var sprint = "SP#";
var title = "\"" + stringtoday + page_title + "\"";
console.log("取得したページタイトル", title)
var space = “\”{コンフル該当スペース名}\””;
var api_url = "https://spacename.atlassian.net/wiki/rest/api/content/search?expand=body.storage&cql=space="+space+ "+and+title=";
var urlEncoded = encodeURI(api_url)+encodeURIComponent(title)+encodeURI("&?expand=body.storage");
var response = UrlFetchApp.fetch(urlEncoded, options).getContentText('UTF-8');
console.log(api_url+title+"&?expand=body.storage");
console.log(urlEncoded);
console.log(response);
var content_json = JSON.parse(response);
console.log(content_json.results[0]);
return content_json.results[0].body;
}
//コンテンツ作成
function create_contents(id,next_monday,page_title,body){
var payload = {
'type': 'page',
'space': { 'key': "コンフル該当スペース名" },
'ancestors': [{ 'id': id }],
'title': next_monday + page_title,
'body': body,
"metadata": {
"properties": {
"editor": {
"key": "editor",
"value": "v2"
}
}
}
};
payload = JSON.stringify(payload);
var options = {
'headers': create_headers(user_id, token),
'payload': payload,
'muteHttpExceptions': true,
'method': 'post'
};
var expand_string = "body.storage";
var api_url = API_BASE_URL + '/rest/api/content/' + '?expand=' + expand_string;
console.log(api_url);
var response = UrlFetchApp.fetch(api_url, options).getContentText('UTF-8');
content_json = JSON.parse(response);
return content_json;
}
/* 認証ヘッダー作成関数 */
function create_headers(user_id, token) {
return {
'content-type': 'application/json',
'Authorization': 'Basic ' + Utilities.base64Encode(user_id + ':' + token)
};
}
// 日付取得関数
function getToday() {
var dt = new Date();
var d1 = Utilities.formatDate(dt, 'Asia/Tokyo', 'yyyy-MM-dd');
return d1;
}
// 一週間後の日付を取得(週初めの日付取得なので来週月曜日の日付を取得)
function getSevenDaysLater() {
var dt = new Date();
dt.setDate(dt.getDate() + 7);
var d2 = Utilities.formatDate(dt, 'Asia/Tokyo', 'yyyy-MM-dd');
return d2
}