📝

GitHub Actionsを学ぶ#2

2024/09/18に公開

GitHub Actionsを学ぶ#1 の続きです。

今回も以下の書籍を参考にさせていただきました。
・参考書籍
GitHub CI/CD実践ガイド―持続可能なソフトウェア開発を支えるGitHub Actionsの設計と運用

Contexts

実行時の情報やジョブの実行結果などを保持するオブジェクト
https://docs.github.com/ja/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs

オブジェクトの値を使うには、${{ 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やアーキテクチャに応じて使うコマンドとかが変わるので、それをカバーできそうです。

環境変数

envvariables があるようです。
環境変数には文字列だけでなく先ほど記載したコンテキストも指定でき、ワークフロー・ジョブ・ステップの各レベルで設定が可能です。

コンテキストの中には特殊文字を含むものがあり、シェルコマンドに直接指定すると想定外の挙動を起こす可能性があります。そのため以下のようにするとよいみたいです。

  1. コンテキストは環境変数を経由してシェルコマンドで使う
  2. 環境変数はすべてダブルクォーテーションで囲む

使い分け

https://docs.github.com/ja/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#about-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の登録

https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-deployments/managing-environments-for-deployment

今回は「staging」で登録しました

  • Deployment protection rules
    この環境へのデプロイメントを続行する前に通過する必要があるレビュー担当者、タイマー、およびカスタムルールを設定できます。
    • Required reviewers
      ワークフローの実行を承認できる人またはチームを指定できる
    • Wait timer
      デプロイメントの続行を許可するまでの待機時間を設定できる
  • Allow administrators to bypass configured protection rules
    管理者が設定された保護ルールを省略?する
    本番環境ではチェックを外しておいた方が良さそうですね...。
  • Deployment branches and tags
    ルールまたは命名パターンに基づいて、この環境にデプロイできるブランチとタグを制限します
    • No restriction
      制限なし
    • Protected branches only
      ブランチ保護ルールが有効になっているブランチのみが環境にデプロイ可能
      ※リポジトリ内のどのブランチにもブランチ保護ルールが定義されていない場合は、すべてのブランチをデプロイ可能
    • Selected branches and tags
      指定した名前パターンに一致するブランチとタグのみが環境にデプロイ可能
  • Environment secrets
    secretsを管理する
  • Environment variables
    varialbesを管理する
CLIで登録と確認
$ 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の登録を参照)

CLIで登録
# Repositoryの場合
$ gh {variable|secret} set {Key} --body {Value}

# Environmentの場合
$ gh {variable|secret} set {Key} --env {Environment} --body {Value}

変数の参照

変数の参照
# Variablesの場合
${{ vars.変数名 }}

# Secretsの場合
${{ secrets.変数名 }}
ワークフローで確認

変数は別途追加したものを使います。

Variablesと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」が出力されています。

https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions

式の一部として以下が使えます

  • 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なことを確認してからマージするみたいな感じにすれば障害が発生しにくくなるって感じかな...?
まだ使い勝手わかってないのでここではスルーします。

オブジェクトフィルター

アスタリスク(*)を使用してフィルターを適用し、コレクション内に一致する項目を取得できます

公式サンプル fruits
[
  { "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> }} # 通常の環境変数として参照する
ワークフローで確認
GITHUB_OUTPUTとGITHUB_ENV
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

https://docs.github.com/en/rest/actions?apiVersion=2022-11-28
GitHub ActionsからGitHubのAPIを使うことができます。

GITHUB_TOKEN

APIを実行するために認証が必要なんですが、GitHub Actionsが実行時のみ使える一時的なクレデンシャルを発行してくれます。

以下のように設定しておけばいい感じにやってくれるようです

環境変数に設定
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

パーミッション

GITHUB_TOKENの権限をジョブレベル及びワークフローレベルで制御できるようです。
以下のような感じで設定が可能です。

パーミッション
    permissions:
      pull-requests: write
      contens: read

設定できる値は公式を確認すると良いでしょう。
https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token

おわりに

ちょっとずつ使い方が分かってきましたが、まだまだ奥が深そうな感じがしてます。
業務で使っているわけじゃないので学習スピードが遅いですが少しずつ理解していこうと思います。

Discussion