Googleスプレッドシートの仕様書のバックアップを定期的に行ないGitHub Pull Requestで誰でも検知できるようにした話

こんにちは、ROUTE06でソフトウェアエンジニアをしている @ohteru です。

この記事ではROUTE06の普段の業務内容を紹介したいと思います。

概要

僕が現在携わらせていただいてるプロジェクトは仕様書をGoogleスプレッドシートで管理しています。

スプレッドシートを選んだ理由はビジネス要件として下記のものがあったからです。

  • 外部会社に共有しやすい形式である必要がある
  • 共同で編集できる必要がある

ですがもちろん運用するにあたりいくつかの課題もあがりました。

  • 変更した際に関係者全員に周知することは大変
  • バージョン管理の機能はあるが差分がわかりづらい

当初はこの課題の対応として変更があった部分のテキストの色を変え、変更があれば自動で通知されるといった通知の部分だけをシステム化しようと思っていました。

どのような方針で課題を解決するか

色々と調査していく中で一つの記事を見つけ、それを参考にGoogle Sheets APIを使ったスクリプトをGitHub Actionsで定期的に実行するという方針にしました。

参考記事

実装内容は参考させていただいた記事とほぼ同じですが、少しカスタマイズしています。

シート一枚に対して記載している量も多く、Pull Requestの差分から何列の何行目かをわかりやすくする必要があったのでオブジェクトの一つ目にLineとそれぞれのデータにはキーとしてA列などを表示するようにしました。

{
    "Line": 7,
    "A": "",
    "B": "",
    "C": "情報",
    "D": "",
    "E": "",
    "F": "",
    "G": "",
    "H": "",
    "I": "",
    "J": "CRUD",
    "K": "",
  },

これによってスプレッドシート内のどこを見ればいいかすぐにわかるようになりました。

スプレッドシートのファイル名とJSONのファイル名は同じになるようにしているのでファイルはそこから辿っています。

下記にシートの情報を吐き出しているスクリプトのおおまかな流れを実際に動かしているコードから抜粋して記載させていただきます。

const range = `${sheetName}!A1:ZZ`;
const { data } = await sheets.spreadsheets.values.get({
  spreadsheetId,
  range,
});

const rows = data.values;
if (rows && rows.length) {
  const jsonData = rows.map((row, colIndex) =>
    row.reduce(
      (obj, value, index) => ({
        ...obj,
        Line: colIndex + 1,
        [String.fromCharCode(65 + index)]: value,
      }),
      {}
    )
  );

  const exportFileName = `${path}/${fileName}__${sheetName}.json`;
  fs.writeFileSync(exportFileName, JSON.stringify(jsonData, null, 2));
  console.log(`Sheet "${sheetName}" has been exported to ${exportFileName}`);
}

上記のスクリプトを紹介させていただいたZennの記事を参考に実装したGitHub Actionsで実行しています。

GitHub Actionsの方は以下のようなコードです。

name: specification-backup

on:
  workflow_dispatch:
  schedule:
    - cron: '0 21 * * sun-thu' # 月-金 6時 JST に実行

defaults:
  run:
    working-directory: tools/specification_backup

permissions:
  contents: write
  pull-requests: write

jobs:
  specification_backup:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version-file: tools/specification_backup/.node-version
          cache: 'yarn'
          cache-dependency-path: 'tools/specification_backup/yarn.lock'

      - name: Get current date
        env:
          TZ: 'Asia/Tokyo'
        id: date
        run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT

      - name: Authenticate to Google Cloud
        uses: google-github-actions/auth@v1
        with:
          credentials_json: '${{ secrets.GCLOUD_CERTS }}'

      - name: Install dependencies
        run: yarn install --frozen-lockfile --prefer-offline

      - name: Run script
        run: node index.js
        env:
          SPREAD_SHEET_IDS: ${{ secrets.SPREAD_SHEET_IDS }}

      - name: Create Pull Request
        uses: peter-evans/create-pull-request@v5.0.0
        with:
          branch-suffix: timestamp
          title: Specification Backup(${{ steps.date.outputs.date }})
          body: '@organization/team-name 確認してください。'
          author: github-actions[bot]
          commit-message: Backup specification
          labels: |
            specification,documentation
          delete-branch: true

運用してみての感想と今後の改修予定

ROUTE06ではGitHubをワークスペースとして選択していることもあり、様々な情報がGitHubに集められています。

スプレッドシートで管理しているコンテンツもGitHubで管理できるようになり、1日の始まりにPull Requestを確認をすれば前日の変更を確実にキャッチアップできるのでとても重宝しています。

ただ、少し課題も残っておりJSON形式なのでパッと見てもデータがわかりづらく、最終的にスプレッドシートを見に行かねばなりません。

これはコストなのでJSONデータをChatGPTに食わせて見やすくしてもらうなどの案があり、スプレッドシートを確認しにいく必要を無くしたいよね。という話も出ています。

ここまでお読みいただきありがとうございました。

今回はROUTE06での普段の業務を紹介させていただきました。