GitHub ActionsのIssueの内容をパラメータファイルにしてプログラムを起動する
こんにちは。Kaneyasuです。
私の周りでは楽をするために作った小さいプログラムが多数あります。
それらは便利ではあるのですが、CLI止まりなので属人性が高いのが悩みです。
画面を作ればベストですが、そこまでの力は注げません。
そこで、GitHub ActionsとIssueでプログラムの実行を若干楽にできないかと考えてみました。
本記事の目標は、Issueの起票をトリガーに、Issueの内容を引数にプログラムを起動することとしています。
本記事では、起動するプログラムをPythonで書いたAWS Lambda関数としています。
ワークフローで起動するプログラムはAWS Lambda関数である必要はありません。
本記事が元々はAPI用に作っていたコードを流用したのと、Lambda関数は引数をJSONで渡せるのがサンプルとしてちょうどいいのでそのままとしました。
みなさんが動かすものはLambda関数ではないかもしれませんが、パラメータをファイルで渡す手法は広く使われています。
従って、私が行ったIssueをファイル化してプログラムに渡す流れが参考になるのではと思います。
ワークフローの流れ
- Issueの起票をトリガーに、GitHub Actionsのワークフローを起動
- PythonとAWS SAMをインストール(ここは説明を省略します)
- Issueの本文をJSONファイル化してパラメータファイルとする
- パラメータファイルを渡しながらLambda関数を起動
Issueの起票をトリガーに、GitHub Actionsのワークフローを起動
リポジトリの.github/workflows
にYAMLファイルを置くと、なんらかのイベントをトリガーにYAMLに応じたワークフローを起動することができます。
トリガーにできるイベントは様々で、Issueの作成をトリガーにすることもできます。
今回はこれを利用します。
Issueの作成をトリガーにするとこのような記述になります。
name: Issue Triggered Workflow
on:
issues:
types:
- opened
Issueの本文をJSONファイル化してパラメータファイルとする
Issueのフォーマットを決める
Issueのフォーマットを下記のように決めます。
コードブロックでJSONを書いてもらう形式で、JSONの部分がLambda関数に渡す引数となります。
上側は説明ブロックです。
JSONはコメントが書けないので、上側に説明を持ってきました。
コードブロックはトリプルバッククォートではなく、「~~~」で括っています。
「```」ですると、この後に出てくるファイル出力で各行がコマンドと認識されてしまうのでその回避策です。
| プロパティ | 内容 |
| --- | --- |
| column1 | column1の説明 |
| column2 | column2の説明 |
| column3 | column3の説明 |
~~~json
{
"body": {
"column1": "100",
"column2": "200",
"column3": "300",
}
}
Issueのテンプレート
Issueはテンプレートを作れます。
実際に動かすときは上記フォーマットをテンプレートにしました。
JSONファイル化してパラメータファイルとする
GitHub Actionsのワークフローの途中に、Issueのファイル化、そして不要な部分をカットしてJSON化するコマンドを仕込みます。
このようにしてみました。
- name: Export issue contents to file
run: |
cat <<EOF > issue_body.md
${{ github.event.issue.body }}
EOF
cat issue_body.md
sed -n '/~~~json/,/~~~/p' issue_body.md | sed '1d;$d' > issue_body.json
cat issue_body.json
ワークフローが実際に動くと、${{ github.event.issue.body }}
の部分がIssueの本文に置き換わります。
これをcat
コマンド+リダイレクトでファイル出力します。
この時、Issueの本文にトリプルバッククォートがあると、「cat <<EOF > issue_body.md」から「EOF」の間にトリプルバッククォートが入り込み、正常に動作しなくなります。
前述のIssueのフォーマットで、コードブロックを「~~~」としているのはこのためです。
次にsed
コマンドを用いて、「~json」から「~」までを切り取っています。
これをまたリダイレクトによるファイル出力でJSONファイルを作っています。
できあがったJSONファイルをパラメータファイルとします。
パラメータファイルを渡しながらLambda関数を起動
Lambda関数をローカル実行するコマンドで、パラメータファイル=出力したJSONファイルを指定します。
これでLambda関数にパラメータが渡ります。
- name: Invoke Lambda
run: sam local invoke "SampleFunction" --event issue_body.json
リポジトリの構成変数のJSONファイル化
前項までで、Lambda関数にパラメータを渡せました。
Lambda関数をローカル実行するコマンドでは、JSONファイルを指定することで環境変数も渡せます。
DBのテーブル名など、固定値的なものは環境変数で渡すことが多いので、ついでにこれもやってみます。
GitHubにはリポジトリ単位で設定できる構成変数があるので、ついでにこれを環境変数の設定場所に活用してみます。
構成変数には「Secrets」と「Variables」があります。
APIキーの秘密情報は「Secrets」、それ以外を「Variables」で設定すると使い分けることにします。
- name: Create env.json file
run: |
cat << EOF > env.json
{
"Parameters": {
"SAMPLE_API_KEY": "${{ secrets.SAMPLE_API_KEY }}",
"SAMPLE_VAR": "${{ vars.SAMPLE_VAR }}"
}
}
EOF
cat env.json
これで、構成変数をJSONファイル化できます。
構成変数の「Secrets」の値はsecrets
で取れます。
「Variables」の値はvars
で取れます。
構成変数から作ったJSONファイルもLambda関数をローカル実行するコマンドで指定します。
これでLambda関数にリポジトリの構成変数が環境変数として渡ります。
- name: Invoke Lambda
run: sam local invoke "SampleFunction" --event issue_body.json --env-vars env.json
全文
ここまでを踏まえた、ワークフローの全文です。
name: Issue Triggered Workflow
on:
issues:
types:
- opened
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Python 3.11.x
uses: actions/setup-python@v5
with:
python-version: '3.11.6'
cache: 'pipenv'
- name: Install pipenv
run: |
python -m pip install --upgrade pip
python -m pip install pipenv
- name: Install dependencies
run: |
pipenv install
- name: install AWS SAM
uses: aws-actions/setup-sam@v2
with:
use-installer: true
- name: Create env.json file
run: |
cat << EOF > env.json
{
"Parameters": {
"SAMPLE_API_KEY": "${{ secrets.SAMPLE_API_KEY }}",
"SAMPLE_VAR": "${{ vars.SAMPLE_VAR }}"
}
}
EOF
cat env.json
- name: Export issue contents to file
run: |
cat <<EOF > issue_body.md
${{ github.event.issue.body }}
EOF
cat issue_body.md
sed -n '/~~~json/,/~~~/p' issue_body.md | sed '1d;$d' > issue_body.json
cat issue_body.json
- name: Build
run: pipenv requirements > requirements_layer/requirements.txt; sam build
- name: Invoke Lambda
run: sam local invoke "SampleFunction" --event issue_body.json --env-vars env.json
何か他にいい方法があれば教えていただけると幸いです。
Discussion