1on1とかのFBをGitHubで管理してみた話

# この記事は？
1on1とかでもらったFBをうまいこと管理したい！と思い、githubのボードで管理してみた話です。
![スクリーンショット 2024-12-18 152754.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3735304/7a84070b-1ce6-ce81-24a4-1825c385e0cc.png)




# どうだった？
### 便利！
けっこう便利です🎉

やっぱり視覚的にステータス管理ができるので、今なにに取り掛かっているのか？がわかりやすくていい感じでした。
issueテンプレートにやるべきことを書いておけば、何も考えずに書き進めるだけでいい感じの振り返りができるので楽ちんです。

![スクリーンショット 2024-12-18 163225.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3735304/3ba88357-7506-d4be-94a4-bf07a61861c1.png)

### FB以外も管理できる！

FBのボード管理がいい感じだったので、現在はFB以外の学習タスクなどを放り込むボードも作成して同じように管理しています。

![スクリーンショット 2024-12-18 171616.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3735304/1157a7c6-b413-a157-3bf3-2e71eecd8292.png)


学習タスクなどは最初、PBIとSBIのように「なんかこんな感じになりたいという大きいissue」と「それを実現するための細かいissue」という構成になっていました。
なのですが、issueが多いとなんだか萎えてしまうのと、PBIレベルに細かく分けてもissue自体に書き込む内容はそんなにない…ことがわかったため今は↓のようにしています👀

![スクリーンショット 2024-12-18 165436.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3735304/c9a7fbe3-61d5-9551-d40f-075ad8779826.png)


↑「なにをする」でリンクになっているのはコメントURLを貼り付けています。
大量にメモしておくことがない限りはコメントをSBI扱いして運用します。
あとはSBIレベルのタスクを完了したらまとめNotionを貼り付けたり、軽微であればまとめコメントをしたりします。

# それだけ？
### カレンダーに予定として追加！
これだけだとさみしい記事になってしまうので、Googleカレンダーに予定を追加するブックマークレットについてもお話します。

![スクリーンショット 2024-12-18 170951.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3735304/257dda63-f5b8-7a8c-e6d9-427bc2114e3f.png)

### 手動はめんどい
私は普段、あらゆるタスクをGoogleカレンダーで管理しています。
なのでgithubでInProgresにしたissueをカレンダーに予定として組み込む必要がありました。

「そんなん手動でやればええやん」とお思いかもしれませんが、これがずっとやっていると結構めんどくさくなってくるんですよね…
１タスクが１終日予定で完了するなら許容できたかもしれないのですが、実際は1,2時間の予定を何回か経てやっと１タスクが完了するので「何回やるねん」という気持ちになっていました。


![スクリーンショット 2024-12-18 170833.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3735304/3c106618-4742-c86a-d0c6-0722c1e0e30f.png)

### ポチっと追加！楽ちん！

そこでポチッと押したらカレンダーに1時間枠の予定が作成されるブックマークレットを作りました。
拡張機能でない理由はそこまでリッチにしなくていいかなと思ったからです。
ただ今後もちょっとずつ改良していきたいと思っています！
いずれは画面のボタンを押すとカレンダーに連携される拡張機能とかにできたら嬉しいです。

### ポチ！の構成の概要！
使ったもの👇️

- GitHub(個人向けアカウント)
- GAS
- GCP Apps Script API(OAuth 2.0認証)

構成の概要👇️

🔖ブックマークレット
- 別タブを開いてGASにGETリクエスト

🪛GAS
- GitHub issueの取得
- カレンダーのイベント(予定)を作成

☁GCP
- GASの認証(よくわかってない)


📖参考にした主な記事📖

- https://ten-snapon.com/archives/2131
- https://qiita.com/sunymaeno/items/700399063d2a407d8f57
- https://www.sejuku.net/blog/61639
- GitHubなどの公式ドキュメント

余談ですが、コードを書くのは1年ぶりくらいでした。
調べつつやってみたら動くものが出来上がったのでネットの便利さにちょっと驚いています。

### ポチ！のコードの中身！

まずはブックマークレットです。
CORS回避のため別タブを開く形でリクエストしています。

GASをウェブアプリとしてデプロイするとHTTPSのURLがもらえるので、それをopenしています。
クエリパラメータにブックマークレットを押したときに開いているURLを渡しています。

```
javascript: (function issuepost() {
    const UrlAtThisPage = location.href; 
    open(`https://script.google.com/XXXXXX/exec?issueurl=${UrlAtThisPage}`);
})();
```

こちらがGASのコードです。

やっていることとしては、次のような処理です。
1. GitHub issueのURLであればURLからissueのIDを切り出す
1. GitHub REST APIを使って切り出したissue IDのissue情報を取得する
1. 今日の日付から今週土曜日のDateを算出する
1. 今週土曜日にissueタイトル、issue URLを記載したカレンダーイベントを追加する

```
function doGet (prm) {
  const token = PropertiesService.getScriptProperties().getProperty("ACCESS_TOKEN");
  const user = PropertiesService.getScriptProperties().getProperty("USER_NAME");
  const repository = PropertiesService.getScriptProperties().getProperty("REPOSITORY");


  try {
    // ブックマークレットが送ってくるクエリパラメータ(issueのURL)を格納
    const url = prm.queryString;

    // リポジトリのissueページ または Projectのissueサイドパネル 判定
    const isIssuePageUrl = url.indexOf(`/${user}/${repository}/issues/`);
    const isIssuePageUrlOfProjectBoard = url.indexOf(`/${user}/projects/`) ? url.indexOf(`issue=${user}%7C${repository}`) : -1;

    if (isIssuePageUrl || isIssuePageUrlOfProjectBoard) {
      // ProjectのURL向けにパラメータの｜を/に変換
      const replased_url = url.replaceAll("%7C", "/");
      // スラッシュ区切りで分割
      const issueUrl_array = replased_url.split("/");
      const arrayLength = issueUrl_array.length;
      
      // GitHub issue のIDを取り出し
      let issueId_num = -1;
      if (arrayLength > 0) {
        const lastWordOfArray = issueUrl_array[arrayLength-1];
        issueId_num = Number(lastWordOfArray);
      }
      
      // GitHub REST APIでissueの情報を取得
      let issueTitle = "";
      let issueHtmlUrl = "";
      if (!isNaN(issueId_num) && Number.isInteger(issueId_num)) {
        const issue_url = `https://api.github.com/repos/${user}/${repository}/issues/${issueId_num}`;

        try {
          const responce = UrlFetchApp.fetch(`${issue_url}`, {
            method: "GET",
            headers: {
              'Content-Type': 'application/json',
              'Authorization': `Bearer ${token}`
            }
          });

          const responceContentText = responce.getContentText();
          const responceContent = JSON.parse(responceContentText);

          issueTitle = responceContent.title;
          issueHtmlUrl = responceContent.html_url;
        } catch (error) {
          Logger.log("ERROR! : " + error);
        }
      }

      // Googleカレンダーにイベント(予定)を追加
      if (issueTitle.length > 0 && issueHtmlUrl.length > 0) {
        //イベント日時をDate型で作成
        const today_date = new Date();
        const todayYoubi_num = today_date.getDay();
        const saturday_num = 6;
        const eventDate = new Date();
        eventDate.setDate(today_date.getDate() + (saturday_num - todayYoubi_num));// イベントは土曜日に追加したい
        const eventStartDate = new Date(`${eventDate.getFullYear()}-${eventDate.getMonth()+1}-${eventDate.getDate()}T10:00:00`);//いったん開始は10時固定
        const eventEndDate = new Date(`${eventDate.getFullYear()}-${eventDate.getMonth()+1}-${eventDate.getDate()}T11:00:00`);//いったん終了は11時固定

        // カレンダーの取得
        const defaultCalender = CalendarApp.getDefaultCalendar();
        // カレンダーのイベントを作成
        const event = defaultCalender.createEvent(
          issueTitle,
          eventStartDate,
          eventEndDate,
          {description: issueHtmlUrl}
        );

        // responeceとして作成したカレンダーイベントのIDを返す
        const payload = JSON.stringify({
          eventId: event.getId()
        });
        return ContentService.createTextOutput(payload).setMimeType(ContentService.MimeType.JSON);
      }
    }
  } catch (error) {
    const payload = JSON.stringify({
      result: error
    });
    return ContentService.createTextOutput(payload).setMimeType(ContentService.MimeType.JSON);
  }
}
```

### さいごに！
久しぶりに手を動かしてものを作ったのですが、とても楽しかったです。
ブックマークレットは今後も改良を続けて、画面上にボタンを表示したり、GitHub ProjectのstartAtにあわせて予定を追加したりできるようにしたいです。
あとずっとコーディングをしているとトリップ状態みたいになるのはなんなのでしょうね…？
似た経験がある人はぜひいいね♥をお願いします！

それでは最後まで読んでいただきありがとうございました✨️