📆

GoogleカレンダーとGASを使ってテスト環境の利用調整をスマートにした

2024/12/20に公開

はじめに

弊社ではAWS上にテスト用の環境を用意しています。
テスト環境を検証などで占有したい場合にはプロダクトに関わるメンバーにその旨の連絡や調整が必要です。
この記事では、テスト環境利用調整の運用フローを見直したことについて書きたいと思います。

これまでの運用

Slackの専用チャンネルに、目的と利用したい日時を投稿するのみでした。

↓イメージ↓

【利用調整】
xxxの動作確認のため
開始:2024/12/22 13:00
終了:2024/12/22 15:00

課題感

いつ利用調整されているのかがわかりづらく、
特に複数の日時で利用調整が入っていると、
Slackの投稿を遡りながらテキストで書かれた日時を頼りに空いているところを探す長い旅に出かけることになります。。。

結果

Googleカレンダーで予約状況が見れるようになり、
空いている日時が一瞬で見つけられるようになりました!

また、Slackへ通知しているのでちょっと変わって欲しいなどの調整も、
スレッドに返信することですぐにできます。

やったこと

1.予約用のGoogleカレンダーを作成する(以下、共有カレンダー)

はじめに、Googleカレンダーの設定画面から新しいカレンダーを作成します。

2.カレンダー共有の設定をする

作成したカレンダーに必要なアカウントを共有設定します。

3.カレンダーIDを控える

作成したカレンダーIDをメモなどしておきます。
(後でGASに設定するため)

4.GASのコードを作成する

  1. マニフェストファイルを作成する
    ※マニフェストファイルの表示・編集方法は参考サイトを参照
// appscript.json
{
  "oauthScopes": [
  "https://www.googleapis.com/auth/contacts",
  "https://www.googleapis.com/auth/spreadsheets",
  "https://www.googleapis.com/auth/userinfo.profile",
  "https://www.googleapis.com/auth/calendar.events.readonly",
  "https://www.googleapis.com/auth/directory.readonly",
  "https://www.googleapis.com/auth/script.external_request"
  ],
  "timeZone": "Asia/Tokyo",
  "dependencies": {
    "enabledAdvancedServices": [
      {
        "userSymbol": "Calendar",
        "version": "v3",
        "serviceId": "calendar"
      }
    ]
  },
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8"
}
  1. 通知用のコードを作成する
// sample.gs

/**
 * カレンダーが更新されたらSlackへ通知します
 */
let envMap = new Map();
envMap.set({カレンダーID}, {SlackのWebhookURL});


function onUpdatedEvent(event) {
    const calendarId = event.calendarId;
    try {
        const newestEvent = getUpdatedNewestEvent_(calendarId);
        notifySlack_(calendarId, createMessage_(newestEvent));
    }
    catch (e) {
        console.error(e);
        throw e;
    }
}


function createMessage_(event) {
    const startDateTime = new Date(event.start.dateTime).toLocaleString("ja-JP", { timeZone: event.start.timeZone });
    const endDateTime = new Date(event.end.dateTime).toLocaleString("ja-JP", { timeZone: event.end.timeZone });
    
    return `
カレンダーの予定が${judgeStatusDetail_(event)}されました。

> タイトル:${event.summary}
> 開始日時:${startDateTime}
> 終了日時:${endDateTime}
> 説明:${event.description ?? "" }
> 作成者:${event.creator.email}
`
}


function judgeStatusDetail_(event) {
    if (event.status === "cancelled") {
      return "削除";
    }

    const diffSecond = Math.floor((new Date(event.updated) - new Date(event.created)) / (1000));

    // 2秒以内は登録とみなす
    return (diffSecond <= 2) ? "登録" : "更新";

}


function getUpdatedNewestEvent_(calendarId) {
    const options = {
      maxResults: 100,
      showDeleted: true ,
      orderBy : 'updated' ,
      updatedMin: getRelativeDate_().toISOString()
    };

    if (!Calendar.Events) {
      return null;
    }

    const events = Calendar.Events.list(calendarId, options);
    if (!events) {
      return null;
    }

    return events.items.pop();
}


function getRelativeDate_() {
    const offsetMinute = 1;
    const relativeDateUnix = new Date().getTime() - (offsetMinute * 60 * 1000); //ミリ秒なので(xx秒*1000)

    return new Date(relativeDateUnix);
}


function notifySlack_(calendarId, message) {
    const options = {
      method: 'post',
      payload: JSON.stringify({ 'username': 'テスト環境利用調整', 'text': message }),
      muteHttpExceptions: true
    };
    
    UrlFetchApp.fetch(envMap.get(calendarId), options);
    return;
}

※Slackへの通知を行うためのWebhookURLは、こちらからアプリケーションを作成し取得してください

5.トリガーを設定する

作成したコードにトリガーを設定する。
カレンダーのオーナーのメールアドレスには、
先ほどメモしたカレンダーIDを設定する。

おわりに

めちゃくちゃ困ってはないけど地味にめんどうなことって以外と多いので、
そういったものはGASに限らず効率化して開発に使える時間を増やしていきたいと思います。

BABY JOB  テックブログ

Discussion