2018/06/18
Googleスプレッドシートでメッセージ管理してGitHubへの更新を自動化した話
目次
はじめに
こんにちは、会員管理システムSMOOSYの開発と運用を担当している大橋です。
エンジニアの主な仕事は、システムやサービスを作ることです。そしてどのシステムでもたくさんの文言が使われます。小規模なシステムなら使われる文言を画面や機能ごとのソース(定数クラスなど)の中で定義することもありますが、規模の大きいシステムであれば、それら全てを外部のプロパティファイルにまとめるという管理方法がよく使われています。アトラスもこの方法を使ってメッセージを管理しています。
一般的なメッセージ管理の仕組み
今時のシステム開発はGitHubなどを使ってバージョン管理をしているケースが多く、システム自体が多言語に対応することもあります。例えば、日本語と英語に対応している場合、message_ja.properties
とmessage_en.properties
の2つのファイルを用意する必要があります。さらに中国語やスペイン語などに対応しようとすると、その分プロパティファイルが増えます。そうなると、たった1つのメッセージプロパティを変更するだけでも、対応言語分のプロパティファイルを修正しなければいけません。
※ Gitの知識が必要になるので、Gitについて詳しくない方はまずこちらをご覧ください。
これを全部手動でやると、効率が悪い上にミスや修正漏れも発生しやすくなります。また、開発者だけではなく、プロマネや翻訳担当もメッセージを確認・編集したいという要望もありました。複数のプロパティファイルを一元的に管理・自動更新でき、色々な人がメッセージを編集できる仕組みが必要です。
アトラスのメッセージ管理の仕組み
というわけで、今回はアトラス流のメッセージ管理の仕組みをご紹介します。
アトラスのシステム開発では、GitHubでバージョンを管理し、Google Appsでドキュメントを作成・管理しています。その前提でGoogleスプレッドシートを使ってメッセージプロパティを一括管理し、Google Apps Scriptで更新を自動化する方法を考えました。流れは下図のとおりです。
※ Google Apps Scriptについては過去の記事をご覧ください。
「メッセージ修正」は全てスプレッドシートで行い、「リモートブランチへ反映」の部分をGoogle Apps Scriptで自動化します。マージまで全自動にすることもできますが、人の目による確認を入れた方が良いという理由で、自動化はプルリクエスト作成までとしています。
スプレッドシートの構成は大きく2つのパーツに分かれます。
スプレッドシートからメッセージプロパティを更新できるように、カスタムメニューを追加しています。これはGoogle Apps Scriptによって実現できます。この「メッセージプロパティ更新」をクリックするだけで、自動でGitHubのプルリクエスト作成まで実行してくれます。
メッセージ更新を自動化するためのGoogle Apps Script
メニューバーのツール -> スクリプトエディタを開き、5つのステップに分けてこの機能を作っていきます。
1. スプレッドシートからメッセージプロパティを取得
- シートの中の範囲を指定し、値を加工します。ちなみにJavaのプロパティファイルの場合、文字コードはUTF-8ではないので変換する必要があります。
- 加工した値を変数に格納し返却します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/********************************************************************* * プロパティシートの内容を取得し、プロパティファイルの内容を生成して返す * @param {Sheet} sheet プロパティシート * @param {number} col 取得したいプロパティの列 * @return {string} プロパティファイルの内容 *********************************************************************/ function createMessage(sheet, col) { // 指定した行 + 4行目から最後までのセルの値を取得 var message = getRange(4, col, sheet.getLastRow() - 4 + 1, 1).getValues(); for(var i = 0; i < message.length; i++) { // 文字列前後の空白を削除 message[i] = message[i][0].trim(); } return message.join("\n"); } |
2. メッセージプロパティファイル更新の関数を作成
- リポジトリ上のメッセージプロパティファイルのURLを定義し、ファイルのSHAを取得します。
- 引数
message
をJSON式のデータに加えます。 - APIを呼び出してファイルを更新します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
/******************************************************************* * GitHubリポジトリの指定したパスのファイルを更新 * https://developer.github.com/v3/repos/contents/#update-a-file * @param {String} message 対象スプレッドシートの内容 * @param {String} path プロパティファイルのパス ********************************************************************/ function update2GitHub(message, path) { // 更新対象ファイルのURL(定数は別途で設定) var url = REPOSITORY_PATH + path + '?access_token=' + ACCESS_TOKEN; // 更新対象ファイルのSHAを取得 var res1 = UrlFetchApp.fetch(url); // レスポンスのSHAを取得 var data = JSON.parse(res1.getContentText()); var sha = data.sha; // ファイルを更新 var stringifiedPayload = JSON.stringify({ message: COMMIT_MESSAGE + "(" + path + ")", committer: {name: COMMITER_NAME, email: COMMITER_EMAIL}, content: Utilities.base64Encode(message), sha: sha, branch: WORK_BRANCH }); // ファイル更新API呼出 var res2 = UrlFetchApp.fetch(url, { method: 'PUT', muteHttpExceptions: true, contentType: 'application/json', payload: stringifiedPayload }); return res2.getResponseCode(); } |
3. プルリクエストを作成するメソッド
- プルリクエストに必要なパラメータを定義します。(
title
,head
,base
,body
) - パラメータが入ったJSON式のデータを作成します。
- プルリクエストを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/******************************************************************* * プロパティをプッシュしたブランチからdevelopへプルリクエストを作成 * https://developer.github.com/v3/pulls/#create-a-pull-request ******************************************************************/ function pullRequest() { var url = REPOSITORY_PATH + '/pulls?access_token=' + ACCESS_TOKEN; // PullRequestパラメータ var stringifiedPayload = JSON.stringify({ title: COMMIT_MESSAGE, head: WORK_BRANCH, base: PULL_REQUEST_BRANCH, body: 'メッセージプロパティを更新しました。(ブランチは削除しないでください。)' }); // PullRequest登録 var res1 = UrlFetchApp.fetch(url, { method: 'POST', muteHttpExceptions: true, contentType: 'application/json', payload: stringifiedPayload }); } |
4. 関数を呼び出して実行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/******************************************************************* * メッセージプロパティファイル更新(日英共に)後にプルリクエスト作成 ******************************************************************/ function updateProperties() { // シート名を指定してシートを取得 var sheet = SpreadsheetApp.getActive().getSheetByName(SHEET_NAME); sheet.getRange("G1").setValue('プロパティ(日)更新中'); // メッセージプロパティ(日)ファイル更新 update2GitHub(createMessage(sheet, 14), MP_JA); sheet.getRange('G1').setValue('プロパティ(英)更新中'); // メッセージプロパティ(英)ファイル更新 update2GitHub(createMessage(sheet, 15),MP_EN); sheet.getRange('G1').setValue('プロパティ更新完了'); // プルリクエストを作成 pullRequest(); } |
5. メニューバーにカスタムメニューを追加
1 2 3 4 5 6 7 8 9 10 11 |
/********************************************************************* * スプレットシートのメニューバーにカスタムメニューを追加 ********************************************************************/ function onOpen() { var spreadsheet = SpreadsheetApp.getActiveSpreadsheet(); var entries = [{ name: "メッセージプロパティ更新(全ての環境)", // メニューリストの名前 functionName: "updateAllWithPullRequest" // 押した時に実行する関数 }]; spreadsheet.addMenu("プロパティ更新", entries); }; |
スクリプトの作成に少し時間が掛かるかもしれませんが、 一度作ればどのプロジェクトでも使いまわせます。もしメッセージプロパティの管理に困っているのであれば、是非作ってみてください。