GitHub Actionsを学ぶ#2
GitHub Actionsを学ぶ#1 の続きです。
今回も以下の書籍を参考にさせていただきました。
・参考書籍
GitHub CI/CD実践ガイド―持続可能なソフトウェア開発を支えるGitHub Actionsの設計と運用
Contexts
実行時の情報やジョブの実行結果などを保持するオブジェクト
オブジェクトの値を使うには、${{ github.actor }}
のように指定することでアクセスできます。
(前回の記事で既に使っていました)
name: CI
on: push
jobs:
prod-check:
if: ${{ github.ref == 'refs/heads/main' }}
runs-on: ubuntu-latest
steps:
- run: echo "Deploying to production server on branch $GITHUB_REF"
github
ワークフロー実行時の情報やイベントの情報を保持(参照)できる
runner
ジョブ実行時のランナー情報を保持(参照)できる
基本的にマネージドのやつなら事足りる気がしますが、OSやアーキテクチャに応じて使うコマンドとかが変わるので、それをカバーできそうです。
環境変数
env
と variables
があるようです。
環境変数には文字列だけでなく先ほど記載したコンテキストも指定でき、ワークフロー・ジョブ・ステップの各レベルで設定が可能です。
コンテキストの中には特殊文字を含むものがあり、シェルコマンドに直接指定すると想定外の挙動を起こす可能性があります。そのため以下のようにするとよいみたいです。
- コンテキストは環境変数を経由してシェルコマンドで使う
- 環境変数はすべてダブルクォーテーションで囲む
使い分け
公式に記載されている通りですが、以下の通りです。
- env
単一のワークフローで使用する環境変数を定義する場合 - variables
複数のワークフローにわたって構成変数を定義する場合
具体的な設定方法は次を参照ください。
env
name: Greeting on variable day
on:
workflow_dispatch
env:
DAY_OF_WEEK: Monday
jobs:
greeting_job:
runs-on: ubuntu-latest
env:
Greeting: Hello
steps:
- name: "Say Hello Mona it's Monday"
run: echo "$Greeting $First_Name. Today is $DAY_OF_WEEK!"
env:
First_Name: Mona
Variables(Secrets)
パスワードのような機密情報を登録する場合は「Secrets」に登録し、それ以外は「Variables」に登録するでいいと思います。
(Secretsの場合は暗号化されたりログ出力時にマスクされたりします)
さらにスコープが以下に分かれているのでこちらも用途に応じて使い分けると良さそうです。
- Repository
リポジトリ内の全てのワークフローから参照可能 - Environment
リポジトリ内の全てのワークフローが特定環境用に実行される際に参照可能
GUIで登録
リポジトリページにある「Settings」から以下の順にアクセスすることで、登録画面にいけます。
Environmentsを使う場合は事前に登録が必要です。
Environmentsの登録
今回は「staging」で登録しました
- Deployment protection rules
この環境へのデプロイメントを続行する前に通過する必要があるレビュー担当者、タイマー、およびカスタムルールを設定できます。- Required reviewers
ワークフローの実行を承認できる人またはチームを指定できる - Wait timer
デプロイメントの続行を許可するまでの待機時間を設定できる
- Required reviewers
- Allow administrators to bypass configured protection rules
管理者が設定された保護ルールを省略?する
本番環境ではチェックを外しておいた方が良さそうですね...。 - Deployment branches and tags
ルールまたは命名パターンに基づいて、この環境にデプロイできるブランチとタグを制限します- No restriction
制限なし - Protected branches only
ブランチ保護ルールが有効になっているブランチのみが環境にデプロイ可能
※リポジトリ内のどのブランチにもブランチ保護ルールが定義されていない場合は、すべてのブランチをデプロイ可能 - Selected branches and tags
指定した名前パターンに一致するブランチとタグのみが環境にデプロイ可能
- No restriction
- Environment secrets
secretsを管理する - Environment variables
varialbesを管理する
$ gh variable set NAME --body 'hoge' --env staging
$ gh secret set NAME --body 'hoge' --env staging
$ gh variable list --env staging
NAME VALUE UPDATED
NAME hoge about 2 minutes ago
$ gh secret list --env staging
NAME UPDATED
NAME less than a minute ago
secretはVALUEが出力されていないことを確認できました。
GUI上からも確認できます。
CLIで登録
下記コマンドは「Repository」に登録されます。
※Environmentは事前に登録しておく必要があります(Environmentsの登録を参照)
# Repositoryの場合
$ gh {variable|secret} set {Key} --body {Value}
# Environmentの場合
$ gh {variable|secret} set {Key} --env {Environment} --body {Value}
変数の参照
# Variablesの場合
${{ vars.変数名 }}
# Secretsの場合
${{ secrets.変数名 }}
ワークフローで確認
変数は別途追加したものを使います。
name: Variables and Secrets
on: push
jobs:
output:
runs-on: ubuntu-latest
env:
PASSWORD: ${{ secrets.PASSW0RD }}
VARIABLE: ${{ vars.VAR_01 }}
steps:
- name: Output secrets
run: echo "${PASSWORD}"
- name: Output variables
run: echo "${VARIABLE}"
ちょっと画像だとみにくいですが、
secretsはマスクされているため「***」が出力されていて、
variablesは「hoge」が出力されています。
式
式の一部として以下が使えます
- boolean
- null
- number
- string
それぞれの設定方法は以下のようです。
env:
myNull: ${{ null }}
myBoolean: ${{ false }}
myIntegerNumber: ${{ 711 }}
myFloatNumber: ${{ -9.2 }}
myHexNumber: ${{ 0xff }}
myExponentialNumber: ${{ -2.99e-2 }}
myString: Mona the Octocat
myStringInBraces: ${{ 'It''s open source!' }}
演算子
比較演算子や論理演算子が使えるようで、対応している演算子は以下のようです。
- 論理演算子
-
!
&&
||
-
- 比較演算子
-
==
!=
>=
<=
>
<
-
- グループ化
()
- インデックス
[]
- プロパティの逆参照
.
組み込み関数
よくある組み込み関数です。
- contains( search, item )
- 検索に項目が含まれる場合は true を返す(searchは文字列や配列を指定できる)
- startsWith( searchString, searchValue )
- searchString が searchValue で始まる場合に true を返す
- endsWith( searchString, searchValue )
- searchString が searchValue で終わる場合は true を返す
- format( string, replaceValue0, replaceValue1, ..., replaceValueN)
- 文字列内の値を変数 replaceValueN に置き換える
- 文字列内の変数は、{N} 構文を使用して指定し、N は整数で指定する
- join( array, optionalSeparator )
- array には配列または文字列を指定でき、配列内のすべての値が文字列に連結される
- OptionalSeparator を指定すると、連結された値の間に挿入される
- toJSON(value)
- 引数の値をJSON形式で返す
- fromJSON(value)
- 引数の値をJSONオブジェクトまたはJSONデータ型で返す
- hashFiles(path)
- パスに指定されたファイルのハッシュ値(SHA-256)を返す(パスはカンマ区切りで複数可能)
- パスはGITHUB_WORKSPACEディレクトリに対する相対パスであり、GITHUB_WORKSPACE内のファイルのみを含めることができる
ステータスチェック関数
if条件の式として使用できる関数が用意されていて、ジョブやステップの結果に応じて返す値が変わります。
- success()
- 前のステップがすべて成功した場合は true を返す
- always()
- ステップを常に実行し、キャンセルされた場合でも true を返す
- cancelled()
- ワークフローがキャンセルされた場合は true を返す
- failure()
- ジョブの前のステップが失敗した場合に true を返す
通知ぐらいにしか使えないかな...と思って調べていたら、この関数とGitHubのブランチ保護を組み合わせる例がありました。
CIテストを行うワークフローを準備して、実行結果から全てOKなことを確認してからマージするみたいな感じにすれば障害が発生しにくくなるって感じかな...?
まだ使い勝手わかってないのでここではスルーします。
オブジェクトフィルター
アスタリスク(*)を使用してフィルターを適用し、コレクション内に一致する項目を取得できます
[
{ "name": "apple", "quantity": 1 },
{ "name": "orange", "quantity": 2 },
{ "name": "pear", "quantity": 1 }
]
fruits.*.name
を指定すると、[ "apple", "orange", "pear" ]
が返ってきます。
*
とname
の位置を逆に書きそうですね...。
ステップ間のデータ共有
結果に応じた値を変数にセットして、次の処理でその値を使うみたいなことってよくあると思いますが、
それをやる場合は専用の環境変数にセットする必要があるようです。
用途に応じて使い分けると良さそうですね。
やり方は2パターン
- GITHUB_OUTPUT
ステップIDとキーバリューを使ったやり方で、ステップ間の依存関係がわかりやすい - GITHUB_ENV
キーバリューを使ったやり方で、どのステップからでも参照できる
・GITHUB_OUTPUTの場合
steps:
- id: <ステップID>
run: echo "<key>=<value>" >> "${GITHUB_OUTPUT}"
${{ steps.<ステップID>.outputs.<key> }}
・GITHUB_ENVの場合
steps:
- run: echo "<key>=<value>" >> "${GITHUB_ENV}"
${{ <key> }} # 通常の環境変数として参照する
ワークフローで確認
name: GITHUB_OUTPUT and GITHUB_ENV
on: push
jobs:
var_share:
runs-on: ubuntu-latest
steps:
- name: GITHUB_OUTPUT set step
id: share
run: echo "SHARE_VAR=hogehoge" >> "${GITHUB_OUTPUT}"
- name: GITHUB_OUTPUT output step
env:
RESULT: ${{ steps.share.outputs.SHARE_VAR }}
run: echo "${RESULT}"
- name: GITHUB_ENV set step
run: echo "SHARE_VAR=hogehogehogehoge" >> "${GITHUB_ENV}"
- name: GITHUB_ENV output step
run: echo "${SHARE_VAR}"
GitHub API
GitHub ActionsからGitHubのAPIを使うことができます。
GITHUB_TOKEN
APIを実行するために認証が必要なんですが、GitHub Actionsが実行時のみ使える一時的なクレデンシャルを発行してくれます。
以下のように設定しておけばいい感じにやってくれるようです
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
パーミッション
GITHUB_TOKENの権限をジョブレベル及びワークフローレベルで制御できるようです。
以下のような感じで設定が可能です。
permissions:
pull-requests: write
contens: read
設定できる値は公式を確認すると良いでしょう。
おわりに
ちょっとずつ使い方が分かってきましたが、まだまだ奥が深そうな感じがしてます。
業務で使っているわけじゃないので学習スピードが遅いですが少しずつ理解していこうと思います。
Discussion