困ったこと
業務でAWS SES(Simple Email Service)のemailテンプレートを利用していて、便利なんだけど変更に弱いのがビミョーだった。
テンプレートを変更するためにコマンド打って既存テンプレートを取得して、jsonファイル作って変更してまたテンプレート変更のコマンドを打たなければならない。面倒な上にミスに気付きにくい・管理しにくいと言うデメリットがあった。
んでワークフローに組み込もうと思って調べても記事が少なかったので備忘録にする。
実現したいこと
本番環境を管理するブランチ(prd)にメールテンプレートを管理するjsonファイルの変更(追加・削除)がマージ(もしくは直push)された時、本番環境のSESのテンプレートを変更する処理を走らせるようにする。
書くこと
- Github Actionsのyaml記載に関して
- 特定のファイルの差分の取り方について
書かないこと
- SESの設定方法に関して
- github actionsの初期設定に関して
作戦
ほんで作戦を立てたわけだが、だいたい以下の作戦通りに実装が進んだ。
- 対象となるリポジトリにメールテンプレートのjsonファイルを管理するためのフォルダである
mail_templates
を作成し、SESのテンプレート形式に則ったjsonファイルを配置 - github actionsの設定を行う
- prdブランチに変更がpushされた時かつ
mail_templates
配下のjsonファイルに変更があった時に処理が走るようにする - pushしたPRとpush先のbaseブランチ(prd)との差分を取得する
- 差分の種類を判別する(追加・変更・削除)
- githubaction処理内にてSESの権限を持つIAMユーザーでAWSにログインし、差分を元にテンプレート変更のコマンドを実行する
- prdブランチに変更がpushされた時かつ
やっていく
mail_templatesフォルダを作成する。
プロジェクトのrootにmail_templatesフォルダを作成し、その下にjsonファイルを配置する
mail_templates
├ uho.json
├ uha.json
└ oho.json
一応これでgit管理ができる形になる。
jsonの中身の書き方に関してはこの記事では詳細を記載しないが、json名と中身のテンプレート名はテンプレート削除の際に整合性がとれるように同じにしておいてほしい
github actionsの設定を行う
※ githubactonsを動くようにする方法は記載してないので動く状態になってる程で話を進めてますので他で調べていただけると!
以下の感じでyamlファイルを作成しておく(ことになると思う)
.github/workflows/modify_ses_templates.yml
以下、yamlを記述していく
prdブランチに変更がpushされた時かつmail_templates
配下のファイルに変更があった時に処理が走るようにする
PRがprdブランチにmergeされた時に発火して欲しかったのですが、
prdブランチにmergeされる ≒ prdブランチにpushされる
なので条件は以下の書き方でOKっぽい。
on:
push:
branches:
- prd
paths:
- "mail_templates/**"
翻訳すると、
prdブランチにpushされた時かつmail_templates配下に変更があった時
みたいなことを表現している(らしい)
変数をセットしておく
env:
base_branch: prd # gitコマンドで使う
region: ap-northeast-1 # AWSの設定で使う
pushしたPRとpush先のbaseブランチ(prd)との差分を取得する
※ 意外とここが鬼門だったりする
こっからjobを書いていくのでjobs:
と記載してから処理を書いていく
jobs:
get-diff-files:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Get template diffs
run: |
changes=$(git diff -M100% --name-only ${{ github.event.before }} origin/${base_branch} --diff-filter=M --relative mail_templates)
adds=$(git diff -M100% --name-only ${{ github.event.before }} origin/${base_branch} --diff-filter=A --relative mail_templates)
deletes=$(git diff -M100% --name-only ${{ github.event.before }} origin/${base_branch} --diff-filter=D --relative=mail_templates)
echo changes=$changes >> $GITHUB_ENV
echo adds=$adds >> $GITHUB_ENV
echo deletes=$deletes >> $GITHUB_ENV
最新のubuntuで処理は実行していくので
runs-on: ubuntu-latest
の記載
Checkoutの処理
uses: actions/checkout@v3
を記述することによりプライベートリポジトリをcheckoutしてくれて、
fetch-depth: 0
を指定してあげることにより、全タグ・全ブランチ・全履歴を取得するようになるらしいのでこれで差分とか取るための準備ができてるぽい。
この辺はちょっと概念の理解がむずかしいのでふーんと思いながら分かったふりをして記述した。
Get template diffs
ほんでここでスクリプトを実行しているのだが、gitコマンドのオプションに癖があるのでその解説と、変数の扱いに関しての解説をする
gitコマンドのオプションについて
SESの話に戻るのだが、テンプレートは 変更・追加・削除 のそれぞれのパターンによって実行するコマンドが違う。なので、prdブランチにpushされるものの差分を取得すると言っても変更・追加・削除で分けて取得する必要がある。
そこで役にたつオプションが以下だ。
—-name-only
# 名前のまんまのオプション。余計なものを取得しないように。
--diff-filter
# ファイルの変更の種類を識別するために。
# M: 変更ファイル取得
# A: 追加ファイル取得
# D: 削除ファイル取得
-M100%
# 削除と追加が同一コミット内で行われた際に、デフォルトでは類似性が50%以上だとadd/deleteではなく、renameとして扱われるため、その閾値を変更した。
--relative: # 変更を取得したい対象のpathを指定するのだが、"="の有無で挙動が違ったので使い分けた
--relative mail_templates # 絶対パスを取得してくれる
--relative=mail_templates # ファイル名のみを取得してくれるので、deleteのコマンドを実行する時にテンプレート名を作り易いかなと思ってdeleteのみ"="ありで指定
これはオプションじゃないけど…
github.event.before
# こいつのおかげでpush(merge)前後の差分を取ることができる。
# 逆にして "origin/${base_branch} ${{ github.event.before }}"としちゃうと取得されるdeleteとaddが逆になるので注意
変数の取り扱いを工夫する
それぞれのstep間というか、次のstepでも取得したdiff情報を持つ変数を使いたいので、以下のように記載することで環境ファイルに変数を書き込む。
echo changes=$changes >> $GITHUB_ENV
echo adds=$adds >> $GITHUB_ENV
echo deletes=$deletes >> $GITHUB_ENV
AWS SESのコマンドを実行する(これはどっかのサイトをもろ参考にした)
普通に自分のAWSアカウントとか別で使ってるIAMユーザーとか使ってもいいけど、SES権限を持つIAMを作ってそのアカウントでAWSにログインできるといいかもねということで自分はそうした。
IAMユーザーの作り方・ロールのアタッチ方法はググってくれると。
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1-node16
with:
aws-access-key-id: ${{ secrets.ACCESS_KEY }}
aws-secret-access-key: ${{ secrets.SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
アクセスキーとシークレットアクセスキーの直書きは怖いので一応githubのsecretsにACCESS_KEY
とSECRET_ACCESS_KEY
格納し、それを利用する(secretsの作成方法に関してはググってね)
テンプレート更新コマンドを走らせる
AWSにログインできてる状態になったのでテンプレート更新コマンドを走らせ、テンプレートを更新
コマンドは以下なので、
# 変更
aws ses update-template --cli-input-json file://ファイルpath --region リージョン名
# 追加
aws ses create-template --cli-input-json file://ファイルpath --region リージョン名
# 削除 ここだけテンプレート名なのでdiffのオプションで工夫した--relativeのかきかたを有効活用できる
aws ses delete-template --template-name テンプレート名 --region リージョン名
取得したファイル一覧の値を利用して以下のような感じになる。
- name: Update Templates
run: |
if [ -n "$changes" ]; then
for change in $changes; do
echo "変更対象ファイル: ${change}";
aws ses update-template --cli-input-json file://${change} --region ${region}
done
fi
if [ -n "$adds" ]; then
for add in $adds; do
echo "追加対象ファイル: ${add}";
aws ses create-template --cli-input-json file://${add} --region ${region}
done
fi
if [ -n "$deletes" ]; then
for delete in $deletes; do
template_name=$(basename $delete .json) # ここでファイル名からテンプレート名に変換をしている
echo "削除対象テンプレート: ${template_name}";
aws ses delete-template --template-name ${template_name} --region ${region}
done
fi
結果的に出来上がったファイル
name: Modify ses templates
on:
push:
branches:
- prd
paths:
- "mail_templates/**"
env:
base_branch: prd
region: ap-northeast-1
jobs:
get-diff-files:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Get template diffs
run: |
changes=$(git diff -M100% --name-only ${{ github.event.before }} origin/${base_branch} --diff-filter=M --relative mail_templates)
adds=$(git diff -M100% --name-only ${{ github.event.before }} origin/${base_branch} --diff-filter=A --relative mail_templates)
deletes=$(git diff -M100% --name-only ${{ github.event.before }} origin/${base_branch} --diff-filter=D --relative=mail_templates)
echo changes=$changes >> $GITHUB_ENV
echo adds=$adds >> $GITHUB_ENV
echo deletes=$deletes >> $GITHUB_ENV
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1-node16
with:
aws-access-key-id: ${{ secrets.ACCESS_KEY }}
aws-secret-access-key: ${{ secrets.SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Update Templates
run: |
if [ -n "$changes" ]; then
for change in $changes; do
echo "変更対象ファイル: ${change}";
aws ses update-template --cli-input-json file://${change} --region ${region}
done
fi
if [ -n "$adds" ]; then
for add in $adds; do
echo "追加対象ファイル: ${add}";
aws ses create-template --cli-input-json file://${add} --region ${region}
done
fi
if [ -n "$deletes" ]; then
for delete in $deletes; do
template_name=$(basename $delete .json)
echo "削除対象テンプレート: ${template_name}";
aws ses delete-template --template-name ${template_name} --region ${region}
done
fi
以上、めでたしめでたし。