はじめに

新しい技術を身につけるためには、実際に使うことが一番です。

最近流行りのGraphQLを学ぶために、実際にコードを書いてみました。

ついでに得意なSlack連携で、Githubのレポジトリのブランチごとのコミット数を習慣で集計するChatOps化します。

その週にコミットがあった全てのブランチを取得できるので、「知らない間に新しいブランチが切られている」ことや、「masterブランチへのマージ忘れ」を発見できるなど、思った以上に役に立ちました。

Slackに連携した状態

GithubのマスコットOctocatが毎週コミット数を教えてくれる形にしました。

準備するもの

  • Githubアカウント
  • Googleのアカウント
  • Slackのアカウントとワークスペース

手順

大まかな手順を列挙します。

  1. GraphQLのクエリを書く
  • GASのダッシュボードからプロジェクトを作成する
  • GASのコードを書く
  • トリガーを設定し、送信時間を決める

GraphQLのクエリと返却されるJSON

query{
  repo_name: repository(owner: "owner_name", name: "repo_name") {
    ...RepoFragment
  }
}

fragment RepoFragment on Repository {
  refs(first: 100, refPrefix:"refs/heads/") {
    edges {
      node {
        name
      }
    }
    nodes {
        target {
      ... on Commit {
        history(first: 0, since: "2018-08-01T09:00:00.000+09:00\"  ) {
          totalCount
        }
       }
     }
   }
 }
}

repo_nameはレポジトリの名前、owner_nameはレポジトリの所有者を入れてください。

また、histroy項目内のsinceはGASでトリガーの1週間前の日付が入るように調節します。

実際にテストしてみたい方は上記項目を変更した後、Github DeveloperのGraphQL API Explorerで上記クエリを実行してみてください。

Githubから下記のようなJSONが返却されます。

{
  "data": {
    "emma": {
      "refs": {
        "edges": [
          {
            "node": {
              "name": "PHP_UNIT"
            }
          },
          {
            "node": {
              "name": "develop"
            }
          },
          {
            "node": {
              "name": "feature/SAMPLE_PROJECT"
            }
          },
          {
            "node": {
              "name": "master"
            }
          },
          {
            "node": {
              "name": "release_0820"
            }
          }
        ],
        "nodes": [
          {
            "target": {
              "history": {
                "totalCount": 8
              }
            }
          },
          {
            "target": {
              "history": {
                "totalCount": 44
              }
            }
          },
          {
            "target": {
              "history": {
                "totalCount": 19
              }
            }
          },
          {
            "target": {
              "history": {
                "totalCount": 2
              }
            }
          },
          {
            "target": {
              "history": {
                "totalCount": 11
              }
            }
          }
        ]
      }
    }
  }
}

nodeのname:“ブランチ名”とtargetのtotalCount:“数字”が順番に対応しています。

これを整理すると、2018-08-01以降、2018-08-24 22:00(クエリを飛ばした時点)のコミット数がわかります。

ブランチ名コミット数
PHP_UNIT8
develop44
feature/SAMPLE_PROJECT19
master2
release_082011

ブランチのマージ先のコミット数は、その週にマージされたブランチのコミット数が加算さます。なので、developブランチはコミット数が多くなりがちです。

コード全体の紹介

repositoryのowner名をpanda_program、プロジェクト名をgasとします。

function createMessage() {
  // GithubのAPIを叩く
  const json  = fetchCommitTotal();
  const repos = [json.data.gas];
  const branch = {
    "gas" : repos[0].refs.edges
  };
  const total = {
    "gas" : repos[0].refs.nodes
  };

  // JSONを整形し、プロジェクト毎のブランチとコミット数を取得
  const gas = prepareInfo(branch.gas, total.gas);
  const projectName = ['Gas'];
  const project     = [gas];

  const today         = formatDate(0);
  const oneWeekBefore = formatDate(-7);
  const time = new Date();
  const hour = time.getHours();
  const triggerTime = hour + ':00:00';

  // メッセージの作成
  var message = '今週もお疲れ様でした😊\n';
  message += '今週のプロジェクト毎のコミット数を集計しました。\n';
  message += '(集計期間 ' + oneWeekBefore + ' ' + triggerTime + ' ~ ' + today + ' ' + triggerTime + ')\n\n';

  for (i = 0, len = project.length; i < len; ++i) {
    message += 'プロジェクト名: *' + projectName[i];
    message += '* \n ```' + project[i] + '```\n\n';
  }

  // Slackに送る
  const to = PropertiesService.getScriptProperties().getProperty("TO");
  sendToSlack(message, to);
}

function prepareInfo(branch, total) {
  const branchName  = [];
  const commitTotal = [];
  const data        = [];

  for (var i = 0, len = branch.length; i < len; ++i) {
    // コミット数が0のブランチを除外
    if(parseInt(total[i].target.history.totalCount) === 0) {
      continue;
    }

    // 配列にオブジェクトを格納
    data.push({
      "branchName"  : branch[i].node.name,
      "commitTotal" : total[i].target.history.totalCount
    });
  }

  var info = '';
  var sum = 0;

  for (var i = 0, len = data.length; i < len; ++i) {
    info += data[i].branchName + ' のコミット数は ' + data[i].commitTotal + '件' + '\n';
    sum += data[i].commitTotal;
  }

  info += '合計' + sum + '件です。';

  return info;
}

function fetchCommitTotal() {
  const url   = 'https://api.github.com/graphql';
  const token = PropertiesService.getScriptProperties().getProperty("TOKEN");
  const oneWeekBefore = formatDate(-7);

  const graphql = ' \
{ \
  gas: repository(owner: "panda_program", name: "gas") {\
    ...RepoFragment\
  }\
}\
fragment RepoFragment on Repository {\
  refs(first: 100, refPrefix:"refs/heads/") {\
    edges {\
      node {\
        name\
      }\
    }\
    nodes {\
        target {\
      ... on Commit {\
        history(first: 0, since: "'
         + oneWeekBefore +
        'T09:00:00.000+09:00\"  ) {\
          totalCount\
        }\
       }\
     }\
   }\
 }\
}\
';

  const options = {
    'method' : 'post',
    'contentType' : 'application/json',
    'headers' : {
      'Authorization' : 'Bearer ' +  token
     },
    'payload' : JSON.stringify({ query : graphql })
  };

  const response = UrlFetchApp.fetch(url, options);
  const json     = JSON.parse(response.getContentText());

  return json;
}

/** 日付をフォーマットする
 *  @param  {int} days
 */ @return {string} YYYY-MM-DD
function formatDate(days) {
  const now = new Date;
  const oneWeekBefore = new Date(now.getFullYear(), now.getMonth(), now.getDate() + days);
  const year    = oneWeekBefore.getFullYear();
  const month   = ('0' + (oneWeekBefore.getMonth() + 1)).slice(-2);
  const date    = ('0' + oneWeekBefore.getDate()).slice(-2);
  const format  = year+ '-' + month + '-' + date;

  return format;
}

function sendToSlack(body, channel) {
  const url = PropertiesService.getScriptProperties().getProperty("WEBHOOK_URL");

  // Slackに通知する際の名前、色、画像を決定する
  const data = {
    'channel' : channel,
    'username' : 'Octocat',
    'attachments': [{
      'color': '#fc166a',
      'text' : body,
    }],
    'icon_url' : 'https://assets-cdn.github.com/images/modules/logos_page/Octocat.png'
  };

  const payload = JSON.stringify(data);
  const options = {
    'method' : 'POST',
    'contentType' : 'application/json',
    'payload' : payload
  };

  UrlFetchApp.fetch(url, options);
}
  • createMessageでSlackの本文を作成します。
  • prepareInfoでGraphQLから返却されたJSONの整形します。
  • fetchCommitTotalでGraphQLにクエリを飛ばす。
  • formatDateで日付をYYYY-MM-DDの形にフォーマットします。
  • sendToSlackでSlackに通知します。

1つの関数に1つの動作をさせることでコードをシンプルに保っています(KISS原則)。

プロパティとトリガーを設定する

プロパティの設定

下記の情報をGASの「スクリプトのプロパティ」に書き込む(方法は「GoogleAppsScript スクリプトのプロパティの超簡単な使い方」を参照)。

プロパティ
Slackの通知先(チャンネル or ユーザー名)TO(*1)
SlackのWebhook URLWEBHOOK_URL (*2)
GithubのPersonal access tokensTOKEN (*3)

*1 チャンネルは「#チャンネル名」、ユーザーは「@ユーザー名」 *2 「SlackのWebhook URL取得手順」を参照 *3「GitHub「Personal access tokens」の設定方法」を参照

トリガーの設定

[編集 > 全てのトリガー]で関数を実行するタイミングを設定します。 GASはFaaSなので、関数ごとに実行を選択する事ができます。

定期実行する関数はcreateMessage、一週間に一度に集計するため週タイマーを選択します。

GASのトリガー設定画面

複数のレポジトリのコミットを取得する

このシステムは複数レポジトリがある前提で作成しました。gas, nodejs, javascriptというレポジトリからコミット数を取得すると仮定します。

その場合、GraphQLのクエリとcreateMessageを書き換えます。

GraphQLのクエリにレポジトリを追加する

下記のようにレポジトリを追加してください。

{
  gas: repository(owner: "panda_program", name: "gas") {
    ...RepoFragment
  }
  nodejs: repository(owner: "panda_program", name: "nodejs") {
    ...RepoFragment
  }
  javascript: repository(owner: "panda_program", name: "javascript") {
    ...RepoFragment
  }
}

JSONの整形箇所を変更する

createMessageの一部を下記のように書き換えてください。

const json  = fetchCommitTotal();
const repos = [json.data.gas, json.data.nodejs, json.data.javascript];
const branch = {
  "gs" : repos[0].refs.edges,
  "node" : repos[1].refs.edges,
  "js" : repos[2].refs.edges
};
const total = {
  "gs" : repos[0].refs.nodes,
  "node" : repos[1].refs.nodes,
  "js" : repos[2].refs.nodes
};

// JSONを整形し、プロジェクト毎のブランチとコミット数を取得
const gs = prepareInfo(branch.gs, total.gs);
const node = prepareInfo(branch.node, total.node);
const js = prepareInfo(branch.js, total.js);
const projectName = ['gas', 'nodejs', 'javascript'];
const project     = [gs, node, js];

Slackの通知の表示方法を変更する

sendToSlackのoptionを変更することで、表示名やアイコン画像を変更することができます。

実行環境としてGoogle Apps Scriptを選択した理由

  • GASはファンクションを書くだけで利用できるFaaS(サーバレス)であるため管理コストが小さい
  • 会社で使用しているGithubのトークンを掲載するため、セキュリティの観点から外部サーバーにファイルを置かず、会社用Google Driveに格納したかった
  • Slackへの連携が容易だから

備忘

  • const graphqlの箇所で\で改行をエスケープしないとエラーが出ます。何かいい方法はありそう。
  • レポジトリ数が増えるとconst branchconst totalはfor文を使う方がベター。
Google Apps ScriptGraphQL
プログラミングをするパンダ
プログラミングをするパンダ (@Panda_Program)
Software Engineer

簡単に開発環境を整えることができるDocker。ベースイメージにAlpineを使うと簡単に環境を構築できる。

イメージのサイズ比較

イメージが超軽量なのでpullする時間が短い。 参考にgcc, ubuntuのイメージとサイズを比較。

REPOSITORY   TAG      IMAGE ID       CREATED       SIZE
gcc          8.2.0   1d6ec261d687   2 weeks ago   1.68GB
ubuntu       18.04   cd6d8154f1e1   2 weeks ago   84.1MB
alpine       3.8     196d12cf6ab1   12 days ago   4.41MB

gccは1.68G、ubuntuは84.1MBなのに対して、alpineは4.41MBと圧倒的に軽い。 docker pullする時間が一瞬なのでストレスフリー。

Dockerfileの構成

C言語のファイルをgccでコンパイルする場合、DockerfileはこれだけでOK。

FROM alpine:3.8

RUN apk add --no-cache gcc libc-dev

C言語で書いたローカルファイルをコンテナに置くためには、 DockerfileにCOPYコマンドを追加する、或いはdocker run時に-vオプションでディレクトリをマウントする。

コンテナ作成&コンパイル例

「Hello World」を出力するファイルをコンパイルする。

#include <stdio.h>

int main(){
	printf("Hello World\n");
}

ディレクトリ構成は以下のようにする。

├── Dockerfile
└── sample_program
    └── hello.c

イメージをbuildし、コンテナを立ち上げる。その後、コンテナに入りgccコマンドでコンパイルする。

$ docker build -t alpine:exec-c .
$ docker run -v "$PWD"/sample_program:/home --rm -ti alpine:exec-c
6a333c246e82:# cd /home
6a333c246e82:# gcc hello.c
6a333c246e82:# ./a.out
Hello world

簡単にC言語の環境構築ができました!

C langDocker
プログラミングをするパンダ
プログラミングをするパンダ (@Panda_Program)
Software Engineer

LINEの通知画面

LINEでサプライズメッセージを送ろう!

毎月の月記念日にLINEでメッセージが自動的に送られてくるプログラムを書きました!

これで「俺たちが付き合ったのっていつからだっけ?」と忘れることも無くなります! (なし崩し的に付き合い、記念日がわからないケースは非対応です)

既婚者の方なら「結婚記念日」、独り身の方でも「新しい挑戦を始めた日」など発想一つで応用が効くと思います。

また、非エンジニアにとって、「LINEにメッセージを送れる」というだけですごいエンジニアに思えるようです。うちの親がそう言ってました。意外ですよね。API叩くだけなのでコスパ最強です。

実際に送ってみよう!

コードの構成はこのようになっています!

①LINE NotifyのAPIキーを設定 ②文面を作成 ③curlを使ってLINE NotifyのエンドポイントにHTTPリクエストを飛ばす

スタンプはランダムで選ばれるようにしています。 スタンプの番号はLINEの公式ページに書かれています。

ちなみに、毎年の記念日には、文面がちょこっと変わります。

LINE NotifyのAPIキーを取得

トークルームごとにAPIキーが発行されます。こちらから取得しに行きましょう。

(注)相手と自分の二人きりのトークルームには送信することができません。 LINE Notifyをトークルームに招待することで、新しいトークルームが作成されます。 そのトークルームのAPIキーを取得しましょう!

<?php
date_default_timezone_set('Asia/Tokyo');

// トークルームを指定
$url = 'https://notify-api.line.me/api/notify';
$token = '取得したAPIキーを設定';
// 記念日を入力
$start = strtotime('0000-00-00');
// 今日の日付
$date = new Datetime();
$today = strtotime($date->format('Y-m-d'));

// 日数計算
$diff = (($today - $start) / 86400);
$year = floor( $diff / 365);
$date = $diff % 365;

// スタンプの番号を指定
$stamps = array(
	'608', // プレゼントボックス
	'301', // カクテル
	'269', // ハート
	'268', // 虹
);
// スタンプをランダムに選択
$stamp_key = array_rand($stamps, 1);

if($date !== 0){

	$message = PHP_EOL
			. '🎉おめでとう🎉' . PHP_EOL
			.'二人が付き合ってから' . PHP_EOL
			. $diff .'日が経ちました😍' . PHP_EOL
			. '今日で' . $year . '年と' . $date . '日です💕' . PHP_EOL
			. 'これからもよろしくね😘';

} else {

	$message = PHP_EOL
			. '🎉おめでとう🎉' . PHP_EOL
			.'二人が付き合ってから' . $diff .'日が経ちました💕';

	$message .= PHP_EOL
			. $year . '年も続くなんてすごい!' . PHP_EOL
			. 'これからもよろしくね😘';

}

// 送信情報を設定する
$data = array('message' => $message, 'stickerPackageId' => 4, 'stickerId' => $stamps[$stamp_key]);
$data = http_build_query($data);
$header = array(
        'Content-Type: application/x-www-form-urlencoded',
        'Authorization: Bearer ' . $token,
);

// curlでLINE NotifyのエンドポイントにHTTPリクエストを送る
$ch = curl_init($url);
$options = array(
    CURLOPT_RETURNTRANSFER  => true,
    CURLOPT_POST            => true,
    CURLOPT_HTTPHEADER      => $header,
    CURLOPT_POSTFIELDS      => $data,
);
curl_setopt_array($ch, $options);

$info = curl_getinfo($ch);
$response =  curl_exec($ch);

curl_close($ch);

cronを設定

0 0 記念日 * * cronは左から分 時 日 月 曜日です。 これで12時ちょうど、日付が記念日に変わった瞬間にLINEが届きます。 cronの設定についてはcronの設定方法をご参照ください。

ただし、相手の生活リズムに合わせて時間を変更しましょう。 思いやりも大切です。

実行した結果

イラストや

彼女が喜んでくれました(笑)

自分でもこれが送られてくるのを忘れていて12時前に寝たため、翌朝起きてビックリしたことがあります。

(今では当時の彼女は奥さんになりました)

それでは楽しいLINE lifeを!

以上、プログラミングをするパンダ(@Panda_Program)でした。

Google Apps ScriptLINE
プログラミングをするパンダ
プログラミングをするパンダ (@Panda_Program)
Software Engineer

弊社(2018時点の前職)では、毎週月曜日に朝礼と掃除があります。 毎週イントラネットの掲示板の当番スレッドを見に行かねばならず、 煩雑だったので会社全体のSlackに通知するようにしました。

実現すること

毎週月曜日の朝に、朝礼の担当者と掃除のグループをSlackで通知する

仕様

朝礼担当

  • その日の担当者と、翌週の担当者の名前を通知する
  • 3ヶ月先まで、予定日と担当者は決まっている
  • 朝礼は2人1組である
  • 一度担当したメンバーは、リストから除外する

掃除グループ

  • チーム分け、チームメンバー、掃除場所を通知する
  • 掃除場所は、毎週ローテーションする

その他

  • 月曜日が祝日なら通知しない

なぜGoogle Apps Scriptを選択したか

  • 朝礼担当者はイントラの掲示板で管理
  • 掃除チーム、掃除場所はスプレッドシートで管理

→ スプレッドシートで一元管理したかったから

成果物

Slackの通知画面

準備すること

シート「朝礼当番」「掃除チーム」を作成

今回はGoogle Apps Scriptのコード内でシートを指定するので、それぞれシート名をつけます。

SpreadSheetの画面

SpreadSheetの画面

コード

Google Apps Scriptはサーバー不要で関数だけ書けば済むFaaSなので、作成した関数ごとに解説します。今回作成した関数は5つです。

notifyMondayMorningInfo()       // Slackに送る本文をまとめる
fetchMCs()                      // 「朝礼当番」シートから朝礼担当者の名前を取得する
fetchCleaningAreasAndMembers()  // 「掃除チーム」シートから掃除チームと掃除場所を取得する
rotateCleaningTeam(sheet)       // 掃除場所をローテーションする
setForSlack(body, channel)      // SlackのWebhook URLにHTTPリクエストを送る

順番にみていきましょう。

Slackに送る本文をまとめる

function notifyMondayMorningInfo() {

  //祝日なら実行しない
  var currentDate = new Date();
  var calendar = CalendarApp.getCalendarById('ja.japanese#holiday@group.v.calendar.google.com');

  if (calendar.getEventsForDay(currentDate, {max: 1}).length > 0) {
    return;
  }

  // 朝礼当番と掃除当番の本文を合わせる
  messageBody = fetchMCs() + '\n\n' + fetchCleaningAreasAndMembers();

  // Slackのチャンネルを指定する
  setForSlack(messageBody, '#slack連携のテスト');
}

毎週月曜日のトリガーで実行する関数はこれです。トリガーについては「Google Apps Script で毎日決まった時刻にスクリプトを実行するトリガー設定」を参照。

「朝礼当番」シートから朝礼担当者の名前を取得する

function fetchMCs() {

  // メンバーのデータをスプレッドシートから取得
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('朝礼当番');

  // 本日と来週の担当メンバーを取得
  var data = sheet.getRange('B1:C2').getValues();

  // 来週のメンバーが書き込まれてるか否かでメッセージを変更する
  if (data[1][1] == '') {

    // 来週のメンバーが記入されていない場合はこちらの文章を送る
    var mcBody =
       '本日の朝礼担当は ' + data[0][0] + 'さん と ' + data[0][1] + 'さん です。' + '\n'
        + 'なお、次回の朝礼当番はまだ記入されていません😅' + '\n'
        + '当番決めをお願いします!' + '\n'
        + 'https://docs.google.com/spreadsheets/d/Spreadsheetのハッシュ値/';
  } else {

  // 普段の文章
  var mcBody =
      '本日の朝礼担当は ' + data[0][0] + 'さん と ' + data[0][1] + 'さん です。' + '\n'
       + '来週は ' + data[1][0] + 'さん と ' + data[1][1] + 'さん です。' + '\n'
       + 'よろしくお願いします😆';
  }

    // 順番が来た朝礼当番の名前を削除。
    // 1行目が削除される
    sheet.deleteRow(1);

    return mcBody;
}

「朝礼当番」シート

SpreadSheetの画面

getRange関数で範囲を指定し、getValues関数で値を取得します。

Logger.log(data)で変数dataの中身を出力すると、多次元配列になっています。

GASのログ画面

変数mcBodyでは、この多次元配列から値を一つずつ取り出しています。

なお、sheet.deleteRow(1)を実行すると、このようにシートの1行目が削除されます。

SpreadSheetの画面

「掃除チーム」シートから掃除チームと掃除場所を取得する

SpreadSheetの画面

function fetchCleaningAreasAndMembers() {

  // メンバーのデータをスプレッドシートから取得
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('掃除チーム');

  // 本日と来週の担当メンバーを取得
  var data = sheet.getRange('A1:C4').getValues();

  // 場所とメンバーを文字列にまとめる
  var AreasAndMembers = '';
  data.forEach(function(value){
        AreasAndMembers += value[0] + ' : ' + value[1] + '\n' + '                    ' + value[2] + '\n\n';
  });

  var cleaningBody =
        '本日の掃除場所' + '\n'
        + AreasAndMembers
         + '詳細はこちら' + '\n'
         + 'https://docs.google.com/spreadsheets/d/Spreadsheetのハッシュ値/'
         ;
  // 掃除場所をローテーションさせる
  rotateCleaningTeam(sheet)

  return cleaningBody;
}

Logger.log(data)で変数dataの中身を出力すると、このようになります。

GASのログ画面

これでは扱いづらいので、文字列にして変数AreasAndMembersにまとめて入れてしまいます。ちなみに、forEach内のvalue[1]とvalue[2]の間でスペースを入れているのは、Slackに通知した時に見やすくするためです。

変数AreasAndMembersの中身はこのようになります。

GASのログ画面

掃除場所をローテーションする

function rotateCleaningTeam(sheet) {

  // 掃除場所のレンジオブジェクトを取得
  var areaRange = sheet.getRange('B1:B4');

  var areas = areaRange.getValues();

  // 配列の銭湯の要素を一番最後に移動させる
  areas.push(areas.shift());

  // シートにローテーション結果を記入する
  areaRange.setValues(areas);
}

ここでは配列の操作をしています。

shift()の返り値が配列areasの先頭の要素なので、それをpush()で配列の一番最後に持っていきます。その配列をスプレッドシートに記入すると、ローテーションの完成です。

(実行前) SpreadSheetの画面

(実行後) SpreadSheetの画面

B列がローテーションしているのがわかります。

なお、同じGoogle Apps Script内で何度もSpreadsheetを呼び出すと関数の実行速度が遅くなります。このため、関数の引数にsheetを取ることにより、「掃除チーム」シートの呼び出しを1回で済むようにしています(Google Apps Scriptでは関数の実行に5分以上かかると動作が停止します)。

SlackのWebhook URLにHTTPリクエストを送る

function setForSlack(body, channel) {
  var url = 'https://hooks.slack.com/services/ハッシュ値';

  // Slackに通知する際の名前、色、画像を決定する
  var data = {
    'channel' : channel,
    'username' : '朝礼・清掃当番教える君',
    'attachments': [{
      'color': '#008000',
      'text' : body,
    }],
    'icon_url' : 'https://2.bp.blogspot.com/-pFOv6JJOGbc/Wb8gR79McsI/AAAAAAABGwk/X4rTOgVBt206izOmKKUpVGV49o4NDxAYACLcBGAs/s800/group_young_people.png'
  };

  var payload = JSON.stringify(data);
  var options = {
    'method' : 'POST',
    'contentType' : 'application/json',
    'payload' : payload
  };

  UrlFetchApp.fetch(url, options);
}

この関数ではSlackに通知するときの表示名、アイコンなどを設定し、POSTでHTTPリクエストを送ります。

コードの検討

notifyMondayMorningInfo()

◆ 月曜日の日付

そもそもA列のカラムで祝日を避けた日付を記入しているので、A1セルの日付を使ってif文を作り、「今日がA1セルの日であれば、以下の動作を行う」というコードを、この関数の一番頭に持ってくることもできます。

一方、人の手で祝日を避けた月曜日の日付を入力すると、仮にミスがあった場合、slackに通知されてしまいます。実際に、別箇所に記載されている朝礼担当のリストには本来祝日である7/16が記載されていました。なので、できるだけ人の手は避けるべきと思っています。

ただ、それは自分がカレンダーをみながら修正すればいいので、単なる好みの問題だと思います。しかし、カレンダーではお盆休みは反映されませんし、一長一短ですね。

fetchMCs()

◆ スプレッドシートの担当者

例えば、一つのセルに「Aさん、 Bさん」と入れると、変数dataは多次元配列にならずに済みます。

ただ、新しく担当者リストを作成する際、名前を記入する人が面倒だと思うのでやめました。

なお、翌週の担当者が記入されていない場合は、Slackの文言が変わります。

Slackの通知

あとがき

エンジニアになって半年が経ったので何か残そうと思ったのと、Google Apps Scriptを使ってみたかったのでSlack連携のコードを書いてみました。会社でも好評なので作ってよかったです。皆様の参考になればと思います。

以上、プログラミングをするパンダ(@panda_program)でした。

その他参照

掃除当番の割当を Google Apps Script で自動化して Slack の BOT として通知

Google Apps Script
プログラミングをするパンダ
プログラミングをするパンダ (@Panda_Program)
Software Engineer

このエントリは、下記の記事のコードをGuzzleを使って書き換えたものです。

LINE Notifyを使って、PHPとcurlでLINEに通知を送る

コード

notifyを利用します

<?php
require_once 'vendor/autoload.php';

use GuzzleHttp\Client;

$token = 'トークン';
$message = 'Guzzleを使ってLINEに通知します';

$client = new Client(['base_uri' => 'https://notify-api.line.me/api/']);

$client->post('notify', [
	'headers' => [
		'Content-Type'	=>	'application/x-www-form-urlencoded',
		'Authorization'	=>	'Bearer ' . $token
	],
	'form_params' => [
		'message'	=>	$message
	]
]);

post('notify', 'リクエスト内容')request('POST', 'notify', 'リクエスト内容')に書き換えることができます。

statusを利用します

<?php
require_once 'vendor/autoload.php';

use GuzzleHttp\Client;

$token = 'トークン';

$client = new Client(['base_uri' => 'https://notify-api.line.me/api/']);

$response = $client->get('status',
	['headers' => ['Authorization' => 'Bearer ' . $token]]);

var_dump($response);

上記と同様、 get('notify', 'リクエスト内容')request('GET', 'notify', 'リクエスト内容')に書き換えることもできます。

revokeを利用します

<?php
require_once 'vendor/autoload.php';

use GuzzleHttp\Client;

$token = 'トークン';

$client = new Client(['base_uri' => 'https://notify-api.line.me/api/']);

$client->post('revoke', [
	'headers' => [
		'Content-Type'	=>	'application/x-www-form-urlencoded',
		'Authorization'	=>	'Bearer ' . $token
	]
]);

これもpost('revoke', 'リクエスト内容')request('POST', 'revoke', 'リクエスト内容')に書き換えることができます。

参照した記事

LaravelでLineNotifyの認証からやってみる

PHPLINEGuzzle
プログラミングをするパンダ
プログラミングをするパンダ (@Panda_Program)
Software Engineer