GitHub Actions まとめ

(今後ちょくちょく触りそうなので、自分用にまとめている。随時メンテしていく)

# GitHub Actions とは
CI/CDパイプラインを実現するCI/CDツールの一つ。
GitHub Actions では、GitHub リポジトリへの様々なイベントをトリガーに、設定された工程にしたがってリポジトリの clone 、プロジェクトのビルド、テスト、デプロイを実行する。

---
**CI**  
continuous integration 継続的インテグレーション。
コードの変更を自動的にテストするプロセス。  

---

**CD**  
continuous delivery 継続的デリバリー
CI のテストを通過したコードを自動的にデプロイするプロセス。  

---

## 競合するクラウドサービス
一番は CircleCI だろう。

[自分のまとめ記事](https://qiita.com/WisteriaWave/items/7fc7b02455cf206609cd)

CircleCI では、GitHub に限らず様々な Git ホスティングサービスと連携して CI/CD パイプラインを構築できる。
しかし、GitHub と連携させる場合は、GitHub Actions の方が GitHub に特化している分、機能面では優位な印象。
設定ファイルの書き方もお互いに似ているが、細かい面で色々と仕様の違いはある。

例. 
- CircleCI: 1ファイルに全 workflow を記述する。
- GitHub: ファイルごとに workflow を記述する。

# GitHub Actions での CI/CD パイプラインの設定
![GitHubActions-簡単な概念図 (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59542/e6476be7-71af-5377-1450-4b4e6a943005.jpeg)



## workflow
workflow は、複数の job の並びで構成されるものである。
workflow の設定は、 `<プロジェクトルート>/.github/workflows/xxx.yml` に記述する。
1つのリポジトリに複数の workflow を定義できる。

GitHub Actions は、workflow ごとに設定可能な実行トリガー条件(以下)が満たされた時、条件が満たされた全ての workflow を並列に実行しようとする。
- 対象のリポジトリのブランチに push されたとき
- スケジュールされた日時になったとき
- GitHub の Web アプリの UI から手動実行したとき
- GitHub CLI の wrokflow run サブコマンドを実行したとき
- 直接 GitHub Actions の API を実行したとき
- その他、対象のリポジトリに関する様々なイベントが発生したとき(トリガー条件として設定可能なものは、[Webhook events and payloads
](https://docs.github.com/en/webhooks/webhook-events-and-payloads#branch_protection_rule)を参照)


ちなみに、CirclecI では以下の形であった。
- GitHub Actions と同様に、1つのリポジトリに複数の workflow を定義できる(全 workflow は、pipeline という単位で束ねられる) 
- GitHub Actions とは異なり、`.circleci/config.yml` という1ファイル内で workflows というブロックに各 workflow の定義を記述する。
- GitHub Actions とは異なり、workflow の実行トリガーの設定は(以下3パターン)だった。
    - CircleCI と連携する Git ホスティングサービス上のリポジトリのブランチに PUSH されたとき(最も基本的なトリガー)
    - CircleCI の Web アプリの UI から手動実行したとき
    - 直接 CircleCI の API を実行したとき

## job
job は、「一連の step 群」または「別の workflow」である。
各 job の実行条件としては以下が設定できる
- 並列実行、順次実行 (その job を実行する前に実行されているべき他の job を指定するという形で設定できる)
- 手動承認 (その job をレビュー必須にするという形で設定できる)

## step
step は、「単純なコマンドの実行」または「action の実行」である。

# 設定ファイル
## .github/workflows/xxx.yml
GitHub Actions の各 workflow は、.github/workflows/xxx.yml で設定する。第一階層は以下のようなブロックで構成する。


```workflows/xxx.yml
name: workflow 名
run-name: workflow 実行名(その workflow の実行結果として一覧表示されるもの)
on: workflow のトリガー条件
permissions: job を実行するにあたって付与する GitHub上 での操作権限
env: 全 jobの 全 step に適用する環境変数群
defaults: 全てまたは特定の job に適用するデフォルト設定
concurrency: workflow の並列実行の制御
jobs: workflow で実行する一連の job 群。
```

jobs には、実行する一連の処理(以下のもの)を列挙できる。
- 単純なコマンド実行
- action の実行
- 別ワークフローの実行

## name
workflow の名前を指定する。
GitHub の Web アプリケーション上で GitHub Actions のページを開いた際に、左のサイドメニューに一覧表示されるものでもある。

省略すると、リポジトリルートからのファイルパスになる。


## run-name
workflow の実行名を指定する。
GitHub Actions で対象の workflow 名を選択した際に、その workflow の過去の実行結果が一覧表示されるが、各実行結果の表示名である。

省略すると、後述の on の種類に応じた値がセットされる。

## on
workflow を自動でトリガーするためのイベントの種類を指定する。

例. 
```.github/workflows/xxx.yaml
on:
  push:
    # master ブランチに commit が push されたとき(マージされたとき含む)
    branches: [master]
  pull_request:
    # Pull Request が作成されたとき
    # Pull Request でマージしようとしているブランチの HEAD が更新されたとき
    types: [opened, synchronize] 
    # 手動実行がトリガーされたとき(※デフォルトブランチのみ)
  workflow_dispatch:
    # 毎日 UTC 時刻で 9:00 になったとき
  schedule: 
    - cron: '0 9 * * *'
```

on に設定可能なイベントは、[ワークフローをトリガーするイベント](https://docs.github.com/ja/actions/using-workflows/events-that-trigger-workflows)に記載されている(以下例) 

### on.push
コミットが push されたとき。
Pull Request がマージされたときも push 扱いになる。ブランチ A を ブランチ B にマージしようとする場合だとブランチ B に対する workflow がトリガーされる)

### on.pull_request
Pull Request 関連の操作がなされたとき。操作の種別は、`types` で指定する。
指定できる`types` の一覧は、[pull_request](https://docs.github.com/ja/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request) で確認できる。

`types` のデフォルト設定は、以下3つになっている。
- `opened`: PR が新規にオープンされた時
- `synchronize`: PR のヘッドブランチに新しいコミットが追加された時
- `reopened`: PR が再度オープンされた 時

:::note
**pull_request と pull_request_target**

pull_request:
ヘッドブランチ側のコンテキスト。
checkout action で chekout されるものは ヘッドブランチのものに。
fork してるリポジトリのブランチからの PR である場合、
fork 元リポジトリのシークレットにアクセス不可能。
ただし、`secrets.GITHUB_TOKEN` にはアクセスできるため注意。
これは、前もってリポジトリに登録するものではなく、workflow の 各 job の開始時に発行されるものである。
- [About the GITHUB_TOKEN secret](https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication#about-the-github_token-secret)
- [Workflows in forked repositories](https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflows-in-forked-repositories)

pull_request_target:
ベースブランチ側のコンテキスト。checkout action で chekout されるものは ベースブランチのものに。fork してるリポジトリのブランチからの PR である場合、fork 元リポジトリのシークレットにアクセス可能。


:::

### [on.pull_request_review](https://docs.github.com/ja/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request_review)

PR のレビューを[提出](https://docs.github.com/ja/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/reviewing-proposed-changes-in-a-pull-request#submitting-your-review), [編集](), [却下](https://docs.github.com/ja/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/dismissing-a-pull-request-review)したとき。
一部に制限したい場合は types で指定する。
- `submitted`: 提出
- `edited`: 編集
- `dismissed`: 却下


### [on.schedule](https://docs.github.com/ja/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#schedule)

指定した日時に達したとき。日時は cron で複数指定できる。

```sample.yml
on:
  schedule:
    - clon: '0/20 0-2 * * 1-5'
```

### on.workflow_dispatch
手動実行の要求があったとき。
手動実行できるのは、デフォルトブランチのみである。

inputs で外部からの入力を受けつけるプロパティを設定でき、workflow 内部で `input.<input_name>` で参照できる。


### on.workflow_run
別の workflow に対する状態変化があったとき。この キー/バリュー 配下にセットする キー workflows で状態変化を検知する別の workflow 名を、types で状態変化の種類を指定する。

### on.workflow_call
別の workflow の job として呼び出されたとき。

inputs で外部からの入力を受けつけるプロパティを設定でき、workflow 内部で `input.<input_name>` で参照できる。

---

イベントの種類によっては、ブランチ名・タグ名・ファイル名 もあわせて指定して、workflow のトリガー条件をさらに細かく設定できる(以下例)。

### `on.*.branches`
指定した名前の(パターンの)ブランチに、workflow のトリガーを限定する。
push, pull_request, pull_request_target, workflow_run イベント限定で指定できる。

### `on.*.branches_ignore`
指定した名前の(パターンの)ブランチで、workflow のトリガーをさせないようにする。
push, pull_request, pull_request_target, workflow_run イベント限定で指定できる。

### `on.*.tags`
指定した名前の(パターンの)タグに、workflow のトリガーを限定する。
push イベント限定で指定できる。

### `on.*.tags_ignore`
指定した名前の(パターンの)タグで、workflow のトリガーをさせないようにする。
push イベント限定で指定できる。

### `on.*.pashs`
指定した名前の(パターンの)ファイル名が変更された場合に、workflow のトリガーを限定する。
push, pull_request イベント限定で指定できる。

### `on.pashs_ignore`
指定した名前の(パターンの)ファイル名が変更された場合に、workflow のトリガーをさせないようにする。
push, pull_request イベント限定で指定できる。

---

## permissions
シークレット `GITHUB_TOKEN` (後述) のパーミッションを明示的に制御したい場合に使う。
設定できるパーミッション項目の一覧は [permissions](https://docs.github.com/ja/actions/writing-workflows/workflow-syntax-for-github-actions#permissions) を参照。

アクセス権限の種類の例: 
- contents: リポジトリの内容を操作. read だと、コミット一覧の表示を許可
- id-token: write を設定することで OIDC を取得できる。

各項目について、read / write / none で指定できる。write は read を兼ねる。
まったく指定しなかった場合、デフォルトのパーミッションが使用される。

デフォルト設定や MAX で設定可能なものについては [Permissions for the GITHUB_TOKEN](https://docs.github.com/ja/actions/security-for-github-actions/security-guides/automatic-token-authentication#permissions-for-the-github_token) の一覧の通り。

一覧上 permissive, restrict が存在するが、これは [Setting the permissions of the GITHUB_TOKEN for your organization](https://docs.github.com/en/organizations/managing-organization-settings/disabling-or-limiting-github-actions-for-your-organization#setting-the-permissions-of-the-github_token-for-your-organization)で語られている通り organization や リポジトリの設定で GITHUB_TOKEN のデフォルトのパーミッションとして設定した方に依存する。


### GITHUB_TOKEN と 独自 GitHub App の IAT
GitHub Actions 側で用意されるシークレット。
中身は、GitHub Actions を有効化したときに GitHub リポジトリにインストールされる [GitHub App](https://qiita.com/WisteriaWave/private/32afca27c8b58d85f28a) の [GitHub App インストールアクセストークン(IAT)](https://qiita.com/WisteriaWave/private/32afca27c8b58d85f28a#:~:text=%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E3%81%A7-,GitHub,-App%20%E8%AA%8D%E8%A8%BC%E3%81%A8)。
GitHub は各 job の開始前にこの IAT を取得しにいく。
`secret.GITHUB_TOKEN` でなく、コンテキスト `github.token` でも利用可能。
workflow を実行するリポジトリのみに有効で、有効期間は最大 24 時間となっている。
パーミッションについては `permissions` に記述した通り。
公式の action では、デフォルトのトークンを `GITHUB_TOKEN` に設定しているものが多い(印象)。

なお GITHUB_TOKEN は、設定可能な最大のパーミッションが IAT として本来設定可能な最大のパーミッションに比べてかなり限定的である。
GITHUB_TOKEN のパーミッションでは足りない操作(= GitHub API の利用)をしたい場合は、独自にパーミッションを設定した GitHub App を作成、操作対象のリポジトリにインストール、秘密鍵 と ID をリポジトリにsecret, variable として登録した上で [create-github-app-token](https://github.com/actions/create-github-app-token) で独自 GitHub App の IAT を払い出すということをする必要がある。

## env
workflow 内の全ての job の step に適用する環境変数。

```workflows/xxx.yaml
env: 
  GCP_PROJECT_ID: "test"
  GCP_SPANNER_INSTANCE_ID: "test"
  GCP_SPANNER_DATABASE_ID: "test"
```

job または step で定義した環境変数と同名のものがあれば、そちら側で上書きされる。


## defaults
workflow 内の全ての job の step に適用する「使用するシェル」と「カレントディレクトリ」の設定。

```workflows/xxx.yaml
defaults:
  run:
    shell: bash
    working-directory: ./test
```

それぞれについて、job または step で設定がある場合は、そちら側で上書きされる。


## concurrency
concurrency.group, concurrency.cancel-in-progress を設定することで、workflow, job の並列実行を制御できる。設定パターンがある。

**並列実行を完全に許容:**
concurrency を何も設定しない

**新たな workflow がトリガーされた場合、古い workflow の実行をキャンセル**

```.github/workflows/xxx.yaml
concurrency:
  group: group1
  cancel-in-progress: true  
```
group1 である workflow が先に実行されている場合、同じく group1 である workflow がトリガーされると、先に実行されていた group1 の workflow はキャンセルされる

**新たな workflow がトリガーされた場合、古い workflow が実行中であってもキャンセルせず待機**

```.github/workflows/xxx.yaml
concurrency:
  group: group1
```

group1 である workflow が先に実行されている場合、同じく group1 である workflow がトリガーされると、先に実行されていた group1 の workflow はキャンセルされない。あとからトリガーされた workflow はキューに入れられ「pending」状態になり、先に実行されている workflow の実行完了を待つ。ただし、キューに入れられる workflow は1つだけである。ある workflow が「pending」状態でさらに別の group1 である workflow がトリガーされた場合、先に pending になっていた workflow は取り消され、あとからトリガーされた workflow が キューに入れられる。

---
所感: 
`cancel-in-progress: true` にするパターンとして、
[例: 現在のワークフローで進行中のジョブまたは実行のみを取り消します](例: 現在のワークフローで進行中のジョブまたは実行のみを取り消します)で挙げられている

```
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true
```

は、これを設定したい場面が想像できる。
同一ブランチに対して最後にトリガーされた workflow の結果を知りたいことが大半であり、その他は無駄(なんならデプロイを伴うものであれば、競合してしまい結果が不安定になる)であるため、古い workflow は実行をキャンセルしたいと思うだろうからだ。

`cancel-in-progress: false` にするパターンは、今実行しているデプロイを伴う workflow は完遂したい(対象のサーバーを利用しているテスターやユーザーがいて、中途半端な状態でデプロイ処理が停止してしまうと、無駄に問い合わせが来てしまうとか)場合に有効そうである。
その例として、「特定の preffix を持つブランチでは完遂、それ以外は即時キャンセルする」設定が
[例: 特定のブランチで進行中のジョブのみを取り消す](https://docs.github.com/ja/actions/writing-workflows/choosing-what-your-workflow-does/control-the-concurrency-of-workflows-and-jobs#%E4%BE%8B-%E7%89%B9%E5%AE%9A%E3%81%AE%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E3%81%A7%E9%80%B2%E8%A1%8C%E4%B8%AD%E3%81%AE%E3%82%B8%E3%83%A7%E3%83%96%E3%81%AE%E3%81%BF%E3%82%92%E5%8F%96%E3%82%8A%E6%B6%88%E3%81%99)に挙げられている。うまい設定だ・・・

```
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ !contains(github.ref, 'release/')}}
```

同一の concurrency.group が workflow と job に設定されている場合に、同じレベルで制御されるのかが気になる・・・

workflow1 と workflow2.job1 で 同じ group 名で、ともに cancel-in-progress: true を設定していた場合、workflow1 の実行中に workflow2.job1 が走ったらworkflow1 は停止してしまうのだろうか・・・

## jobs
対象の workflow で実行する一連の job を一意の識別子である job_id を設定して列挙する。
各 job は、その job の runs-on で指定した環境で実行される。
以下、各 job_id 配下で設定するキー。

## `jobs.<job_id>.name`
GitHub の Web アプリ上で表示される実行結果上の job の表示名

## `jobs.<job_id>.permissions`
workflow レベルの persmission と異なり、job 個別に設定できるアクセス許可権限。

※workflow と job で同時に設定されている場合の挙動についての仕様は見当たらなかったが、上書きされる形になる？指定されなかった分はどうなる？

## `jobs.<job_id>.needs`
対象の job の前に正常完了している必要がある job を設定する。これにより、job の順次の実行を設定することができる(設定がない場合は並列実行)。

```.github/workflows/xxx.yaml

jobs:
  job1:
    ...
  job2:
    needs: job1
    ...
```

CircleCI の requires キーに相当する。CircleCI の requires では指定した job が必ず正常に完了している必要があったが、GitHub Actions の needs では、`if ${{ 
 always() }}` を設定することで、失敗していても完了していれば OK という形に緩和することができる。

```.github/workflows/xxx.yaml

jobs:
  job1:
    ...
  job2:
    if: ${{ always() }}
    needs: job1
    ...
```

## `jobs.<job_id>.if`
対象の job を実行できる条件を式で設定する。
式の評価値が true である場合、その job が実行される。
false の場合は 実行されない。
CircleCI の when に相当するキーである。

式は、`${{ <式> }}` という形で記述する。
論理式 や 便利な関数が使える。

式については、[Evaluate expressions in workflows and actions](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions)を参照。


## `jobs.<job_id>.runs-on`
対象の job を実行する仮想マシンの種類をラベルで設定する。

例.
```.github/workflows/xxx.yaml
jobs:
  job1:
    runs-on: ubuntu-latest
```

ubuntu-xx は、GitHub 側で用意してくれている標準のLinux の仮想マシン。他のLinux ディストリビューションは存在しない。

設定できる仮想マシンの種類の一覧は、[GitHub ホステッド ランナーの選択](https://docs.github.com/ja/actions/writing-workflows/workflow-syntax-for-github-actions#github-%E3%83%9B%E3%82%B9%E3%83%86%E3%83%83%E3%83%89-%E3%83%A9%E3%83%B3%E3%83%8A%E3%83%BC%E3%81%AE%E9%81%B8%E6%8A%9E)を参照。

注意: GitHub 側で用意してくれている標準の仮想マシンは、パブリックリポジトリ、プライベートリポジトリでスペックが異なる


## `jobs.<job_id>.environment`
あらかじめ、GitHub の Web アプリケーション上で作成しておいた「環境」を対象の job に設定する。

**環境:**
特定の job に以下のような制限、シークレット、変数を反映するために GitHub の Web アプリケーション上であらかじめ作成しておくもの(詳細は、[デプロイに環境の使用](https://docs.github.com/ja/actions/managing-workflow-runs-and-deployments/managing-deployments/managing-environments-for-deployment)を参照)。

- デプロイ保護ルール
    - 対象の job を実行するにはレビュアーによる承認が必要(6 ユーザーまでリストアップできて、その中 1 人の承認でOK)
        - job を開始したユーザー自身が承認できないようにするオプションもある

    - 対象の job を実行するには、job がトリガーされてから指定の時間(分)の間待つ必要がある
    - デプロイできるブランチとタグを制限
    - 管理者によるブランチ保護ルールのスルーを許可しない
- 環境固有のシークレット(`{{ secret.<シークレット名> }}` で、.yaml 内で展開可能)
- 環境固有の変数(`{{ vars.<変数名> }}` で、.yaml 内で展開可能)

## `jobs.<job_id>.concurrency`
(workflow の concurrency を参照)

## `jobs.<job_id>.outputs`
対象の job の実行終了時に評価される値で、下流の job から `needs.<親の job-id>.outputs.<output名>`で参照できるもの。上流 job から 下流 job へデータを受け渡す際に使える。
受け渡し方になかなかクセがある。
[例: ジョブの出力の定義](https://docs.github.com/ja/actions/writing-workflows/workflow-syntax-for-github-actions#%E4%BE%8B-%E3%82%B8%E3%83%A7%E3%83%96%E3%81%AE%E5%87%BA%E5%8A%9B%E3%81%AE%E5%AE%9A%E7%BE%A9)を参照。

## `jobs.<job_id>.env`
対象の job に含まれる全ての step で適用される環境変数。workflow レベルで設定した env と同名である場合、job レベルの env の値で上書きされる。

## `jobs.<job_id>.defaults.run`
使用する shell と 作業ディレクトリ working-directory を設定できる。env と同様に、workflow レベルのものより job レベルの defaults.run が優先される

## `jobs.<job_id>.steps`
対象の job 上で実行する一連処理を記述する。
コマンド、ローカルディレクトリ、GitHubリポジトリ、Dockerレジストリで公開されている Action を実行できる。環境変数の変更は、step 間では反映されない。

## `jobs.<job_id>.steps[*].if`
TODO

## `jobs.<job_id>.steps[*].name`
step の名。GitHub Actions の Webアプリで確認できる実行結果上の step の表示名。

## `jobs.<job_id>.steps[*].uses`
step として実行する Action を指定。一部の Action では、 with キーワードで入力値を与える必要がある。Actions が JavaScript の場合は仮想マシン上で実行されるが、Docker の場合は 仮想マシン上の Docker コンテナ上で実行される

**public な GitHub リポジトリで公開されている Action の使用:**
`<リポジトリのオーナー>/<リポジトリ名>@<ref>`
ref には、ブランチ名だったりタグ名だったりを設定可能。

例.[actions/checkout](https://github.com/actions/checkout)

```.github/workflows/xxx.yaml
jobs:
  job1:
    steps:
      - name: Checkout
        uses: actions/checkout@v4.2.0
```

**workflow と同じリポジトリにある Action の使用:**
リポジトリルートからのパスで action.yaml が配置されているディレクトリを指定する。

例. `.github/actions/xxx-action/action.yaml`

```.github/workflows/xxx.yaml
jobs:
  job1:
    steps:
      - name: Checkout
        uses: ./actions/xxx-action

```

## `jobs.<job_id>.steps[*].run`
step として実行するコマンドを指定

## `jobs.<job_id>.steps[*].working-directory`
run で指定したコマンドを実行するディレクトリ

## `jobs.<job_id>.steps[*].shell`
run で指定したコマンドを実行するshell

## `jobs.<job_id>.steps[*].with`
uses で指定した Action に与える環境変数。

## `jobs.<job_id>.steps[*].env`
対象の step で適用される環境変数。workflow レベルで設定した env や job レベルで設定した env と同名である場合、step レベルの env の値で上書きされる。

## `jobs.<job_id>.steps[*].continue-on-error`
true に設定した場合、対象の step が失敗しても成功扱いにする。

## `jobs.<job_id>.steps[*].timeout-minutes`
対象の step のタイムアウト時間(分)。

## `jobs.<job_id>.uses`
対象の job を workflow として実行する場合、 その workflow を指定する。
同じリポジトリ内の workflow の場合、
`./.github/workflows/<workflow ファイル名(.yamlまで)>`で設定。

## `jobs.<job_id>.with`
対象の job を uses で workflow として実行する場合に workflow に与える入力値。

## `jobs.<job_id>.secrets`
対象の job を uses で workflow として実行する場合に workflow に与えるシークレット。

## `jobs.<job_id>.strategy`
同じjob を内部パラメータを変えて複数回に実行したいときに設定する。
以下の制御ができる。

- 各job の内部パラメータのパターン: matrix
- job を直列実行するか並列実行するか: max-parallel
- 1つの job が失敗した場合、他の job の実行を停止させるか: fail-fast

内の実行時に使う値を配列で列挙して

## `jobs.<job_id>.strategy.matrix`
対象 job の内部パラメータのパターンを map (バリューは配列)で定義。
値は `${{ matrix.<キー> }}` で展開できる。

```.github/workflows/xxx.yaml
jobs:
  job1:
    strategy:
      matrix:
        param1: ["a", "b"]
        param2: ["x", "y"]
    runs-on: ubuntu-latest
    steps:
      - run: echo "${{ matrix.param1 }}, ${{ matrix.param2 }}"
```

## `jobs.<job_id>.strategy.matrix.include`
所感: 意味不明


[jobs.<job_id>.strategy.matrix.include](https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrixinclude)

を何度読んでも

```
strategy:
  matrix:
    fruit: [apple, pear]
    animal: [cat, dog]
    include:
      - color: green
      - color: pink
        animal: cat
      - fruit: apple
        shape: circle
      - fruit: banana
      - fruit: banana
        animal: cat
```

が

```
{fruit: apple, animal: cat, color: pink, shape: circle}
{fruit: apple, animal: dog, color: green, shape: circle}
{fruit: pear, animal: cat, color: pink}
{fruit: pear, animal: dog, color: green}
{fruit: banana}
{fruit: banana, animal: cat}
```

というパターンになるのがわからない・・・

## `jobs.<job_id>.strategy.matrix.exclude`
matrix で設定したパターン群のうち、特定のパターンを除外する。

```.github/workflows/xxx.yaml
jobs:
  job1:
    strategy:
      matrix:
        param1: ["a", "b"]
        param2: ["x", "y"]
      # (a, x), (b, x), (b, y) のパターンで実行される
      exclude:
        - param1: "a"
          param2: "y" 
    runs-on: ubuntu-latest
    steps:
      - run: echo "${{ matrix.param1 }}, ${{ matrix.param2 }}"
```

## `jobs.<job_id>.strategy.matrix.fail-fast`
true に設定すると、設定したパターンのうち 1 つでも実行に失敗したら他の job を停止させる


```.github/workflows/xxx.yaml
jobs:
  job1:
    fail-fast: true
    strategy:
      matrix:
        param1: ["a", "b"]
        param2: ["x", "y"]
    runs-on: ubuntu-latest
    steps:
      - run: echo "${{ matrix.param1 }}, ${{ matrix.param2 }}"
```

## `jobs.<job_id>.strategy.matrix.max-parallel`
設定したパターンの job の実行で、並列実行できる最大数を設定する。
未設定の場合、そのランナーが並列実行できる最大数で実行しようとする。

```.github/workflows/xxx.yaml
jobs:
  job1:
    strategy:
      # 直列実行
      max-parallel: 1
      matrix:
        param1: ["a", "b"]
        param2: ["x", "y"]
    runs-on: ubuntu-latest
    steps:
      - run: echo "${{ matrix.param1 }}, ${{ matrix.param2 }}"
```


## `jobs.<job_id>.timeout-minutes`
対象の job のタイムアウト時間(分)。デフォルト360分。


# 処理の再利用性
GitHub Actions では、再利用できるものとして以下の要素がある。

**workflow:** 
1つ以上の job 群を、別の workflow で1つの job として利用できる。外から再利用してもらう workflow には、 `on: workflow_call` を記述しておく必要あり (Circle CI では、これに相当するものはない)

**action:**
以下3種類について、別のリポジトリ、ローカルディレクトリで外部定義できる。
- JavaScript アクション: JavaScript ファイルの実行
- Docker コンテナアクション: Docker コンテナの実行
- 複合アクション: 一連の step 群の実行

action は、1つの step として利用できる。
複合アクションについては、CicleCI でいうところの 自身で定義する Command, Orb の Command に相当する。


---
対して、CircleCIでは、再利用できるものとして以下の要素がある。

**executor:**
 各 job の実行環境を事前定義しておくものであり、全 job でその executor 名を指定する形で利用できる (GitHub Actions では、これに相当するものはない)

**job:**
事前定義しておくものであり、全 workflow でその job 名を指定する形で利用できる。
(GitHub Actions では、各workflow ごとに job の定義も同時にする形になっており、別のworkflow で job 単位の再利用はできないが、1 job のみの workflow を作っておけば同じ効果を得ることができる)

**command:**
一連の step 群を事前定義しておくものであり、全 job でその command 名を指定する形で、step として利用できる (GitHub Actions の Action に相当する)

**orb:**
CircleCI Orb レジストリで公開されているものであり、一般利用として便利な executor, job, command を利用できる。(command 部分に限っていえば、GitHub Actions ではpublicリポジトリで公開されている Action に相当する)

# action.yml
action を定義するメタデータファイル。

## 同一リポジトリ内で定義する場合
workflow と同一リポジトリ内で action を定義する場合は、以下のように action.yaml を配置する。

`リポジトリルート/<任意のパス>/<action名>/action.yaml`

参考: 

https://docs.github.com/ja/actions/writing-workflows/workflow-syntax-for-github-actions#example-using-an-action-in-the-same-repository-as-the-workflow

## 複合アクションの記述

例. 
```.github/actions/sample-action/action.yaml
name: "sample action"
author: "anonymous"

inputs:
  input1:
    description: "input1 description"
    default: "default value"
    
outputs:
  output1:
    description: "output1 description"
    value: ${{ steps.step1.outputs.output1 }}
    
runs:
  using: "composite"
  steps:
    - id: "step1"
      run: "echo "output1=outputValue" >> $GITHUB_OUTPUT
```

### name
[必須]action 名。

### author
[任意]atcion の著者。

### description
[必須]action の説明

### inputs
[任意]action に渡すプロパティの定義。

例. 
```.github/workflows/test-action/action.yaml
inputs:
  prop1:
    # 必須 prop1 プロパティの説明
    description: "prop1 value"
    # 任意 指定必須のプロパティか
    required: true
    # 任意 prop1 プロパティのデフォルト値
    default: "test"
    # 任意 prop1 が渡されたときにログに出力する非推奨を意味する警告メッセージ。
    deprecationMessage: "prop1 is deprecated"

```

### outputs
[任意]action で返すプロパティの定義

例. 
```.github/workflows/test-action/action.yaml
outputs:
  output1:
    # 必須 output1 プロパティの説明
    description: "output1 description"
    # 必須 マッピングするコンテキストの式
    value: ${{ steps.step1.outputs.output1 }}

runs:
  using: "composite"
  steps:
    - id: step1
      run: echo "output1=1" >> $GITHUB_OUTPUT
```


### runs
#### runs.using
無条件に "composite" を設定。

#### runs.steps
workflow の steps と同じように設定する。

参考: 

https://docs.github.com/ja/actions/sharing-automations/creating-actions/creating-a-composite-action

https://docs.github.com/ja/actions/sharing-automations/creating-actions/metadata-syntax-for-github-actions#runs-for-composite-actions




# step の成否判定
処理の成否は終了コードで判定されており、「終了コードが 0: 成功、0 以外: 失敗」 と判断される。

https://docs.github.com/ja/actions/sharing-automations/creating-actions/setting-exit-codes-for-actions

(ちなみにCircleCI も同様である)

# GitHub Actions 公式の Action
## [actions/checkout](https://github.com/actions/checkout)

対象のリポジトリを checkout するときに使う Action。
以下、 action の input。

**repository**
オーナー名を伴うリポジトリ名。
デフォルト値は、コンテキスト `github.repository`。

**ref**
checkout するブランチ or tag or SHA を指定する。
デフォルト値は、repository が workflow のトリガーとなったリポジトリである場合は、そのイベントの ref or SHA。そうでない場合は デフォルトブランチを使う。

**token**
リポジトリを checkout するのに使う アクセストークンを指定する。
デフォルト値は、コンテキスト `github.token`。 

**ssh-key**
TODO

**ssh-key**
TODO

**ssh-known-hosts**
TODO

**ssh-strict**
TODO

**ssh-user**
TODO

**persist-credentials**
TODO

**path**
TODO

**clean**
TODO

**filter**
TODO

**sparse-checkout**
TODO

**sparse-checkout-cone-mode**
TODO

**fetch-depth**
fetch するコミット番号。
0 は全ての history, ブランチ, タグを指す。
デフォルト値は 1。

**fetch-tags**
TODO

**show-progress**
TODO

**lfs**
TODO

**submodules**
TODO

**set-safe-directory**
TODO

**github-server-url**
TODO

## [actions/upload-artifact](https://github.com/actions/upload-artifact)
GitHub Actions へ Artifact として成果物をアップロードする Action。

以下 action の input。

**name:**  
[任意]アップロードするアーティファクトの名前。
デフォルトは'artifact'

**path:**
[必須]アップロードするもののパス

**if-no-files-found:**
[任意] path で設定したパスにファイルがなかった場合の挙動を設定( 'warn' / 'error' / 'ignore' )。デフォルトは 'warn'。

**retention-days:**
[任意]アーティファクトが期限切れになるまでの日数。デフォルトはリポジトリの設定。

**compression-level:**
[任意]zlib での 圧縮レベルを 0 〜 9 で指定。デフォルトは 6 。

**overwrite:**
[任意]アーティファクト名がマッチする場合、true ならば前のものを削除して上書き。false なら失敗。

**include-hidden-files**
[任意] path で設定したパスに隠しファイルがあった場合、true ならば隠しファイルも含めて成果物としてアップロード。false ならば隠しファイルをアップロードしない

## [actions/cache](https://github.com/actions/cache)
workflow 実行を改善するための依存関係やビルド出力のキャッシュをする。

**path:**
キャッシュ、リストアするファイル・ディレクトリ・ワイルドカードパターンのリスト。

**key:**
キャッシュエントリのための明示的なキー

**restore-keys:**
プレフィックスがマッチしたキーの一覧。キャッシュがキーにヒットしなかった場合に、古いキャッシュからリストアする場合に使用。

**fail-on-cache-miss**
キャッシュエントリが見つからない場合に workflow を失敗にする。デフォルトは false 。

**lookup-only:**
true の場合、キャッシュエントリが存在するかだけをチェックし、ダウンロードをスキップする。保存キャッシュの挙動は変更しない。デフォルトは false 。


## [actions/setup-go](https://github.com/actions/setup-go)

Go をセットアップする。
利用可能な input は以下の通り。

**go-version:**
[任意]ダウンロードして利用する Go のバージョン。
セマンティックバージョン使用と範囲をサポートしている。
必ず一重引用符で囲んで値を指定する必要あり。

**go-version-file:**
[任意]go.mod or go.work ファイルを指定。

**check-latest:**
[任意]デフォルトは false。 true にすると、バージョン仕様を満たす最新の利用可能なバージョンをチェックする。

**token:**
[任意]go-version から Go ディストリビューションを取得するために使用されるトークン。
github.com でこのアクションを実行する場合は、デフォルト値で十分で、通常はユーザーがこれを指定することはない。
GitHub Enterprise Server(オンプレの GitHub )で実行しているときにレート制限が発生している場合は、github.com の個人のアクセストークンをこの input にセットして回避できる。

**cache:**
[任意]true に設定するとキャッシュを有効化できる。
デフォルトで true。

**cache-dependency-path:**
[任意]go.sum のパスを指定。

**architecture:**
[任意]Go が使用するCPUアーキテクチャ。例: x86、x64。デフォルトでシステムのCPUアーキテクチャを使用する。

(どの CPU アーキテクチャ向けの Go をインストールするか、ということだろうか・・・)


## [actions/setup-node](https://github.com/actions/setup-node)
Node.js をセットアップする。

利用可能な input は以下の通り

**always-auth:**
[任意].npmrc の always-auth の値。
デフォルトは false

**node-version:**
[任意]セマンティックバージョン表記で、使用するバージョンの仕様を指定する
lts/*、latest、nightly、canary ビルドなどのエイリアスでもOK。
例: 12.x, 10.15.1, >=10.15.0, lts/Hydrogen, 16-nightly, latest, node

**node-version-file:**
[任意]使用するバージョンのバージョン仕様を含むファイル。
例: package.json、.nvmrc、.node-version、.tool-versions

node-version と node-version-file の両方が指定されている場合、node-version のバージョンが優先される。

**architecture:**
Node が使用するターゲットアーキテクチャ。
例: x86、x64。
デフォルトでシステムのCPUアーキテクチャを使用する。

**check-latest:**
[任意]バージョン仕様を満たす最新の利用可能なバージョンをチェックする場合に設定。
デフォルトは false。

**registry-url:**
[任意]認証のために設定するオプションのレジストリ。
プロジェクトレベルの .npmrc と .yarnrc ファイルにレジストリを設定し、env.NODE_AUTH_TOKEN から読むように認証設定する。

**scope:**
[任意]スコープされたレジストリに対して認証するためのオプションのスコープ。
GitHub パッケージレジストリ (https://npm.pkg.github.com/) を使用する場合は、リポジトリのオーナーにフォールバックします。

**token:**
node-version から node ディストリビューションを取得するために使用される。
github.com でこのアクションを実行する場合は、デフォルト値で十分で、通常はユーザーがこれを指定することはない。
GitHub Enterprise Server(オンプレの GitHub )で実行しているときにレート制限が発生している場合は、github.com の個人のアクセストークンをこの input にセットして回避できる。

**cache:**
[任意]デフォルトのディレクトリにキャッシュするパッケージマネージャーを指定。(サポートされている値: npm, yarn, pnpm)

**cache-dependency-path:**
依存関係ファイル(package-lock.json, yarn.lock など)へのパスを指定するために使用される。
複数の依存関係をキャッシュするためのワイルドカードまたはファイル名のリストをサポートする。


## [actions/create-github-app-token](https://github.com/actions/create-github-app-token)

GitHub Actions では、GitHub Actions を有効化したリポジトリに対して裏でインストールされる GitHub App があって、そのインストールトークン が GITHUB_TOKEN として利用できる。
そのパーミッション項目は、なかなかに制限されている。
workflow 実行時に叩きたい GitHub API に必要なパーミッションが GITHUB_TOKEN ではどうしても足りない場合は、パーミッション多めに作成した独自 GitHub App の IAT を使うことになる。
workflow 上での独自 GitHub App の IAT 取得には、[actions/create-github-app-token](https://github.com/actions/create-github-app-token) という便利な 公式の Action が用意されている。

input と output は以下の通り。

---

### input

**app-id**
[任意] GitHub App の ID
デフォルト値: なし

**private-key**
[任意] GitHub App の 秘密鍵
デフォルト値: なし

**private_key**
[任意] GitHub App の 秘密鍵 (非推奨。将来削除予定)
デフォルト値: なし

**owner**
[任意] GitHub App インストールのオーナー (デフォルトは現在のリポジトリのオーナー)
デフォルト値: なし

**repositories**
[任意] GitHub App をインストールするリポジトリのカンマまたは改行区切りリスト (オーナーが未設定の場合、デフォルトは現在のリポジトリ)
デフォルト値: なし

**skip-token-revoke**
[任意] true の場合、現在の job が完了してもトークンは無効化されない
デフォルト値: なし

**github-api-url**
[任意] GitHub REST API の URL。
デフォルト値: ${{ github.api_url }}

---

### output

**token**
[任意] GitHub App インストールアクセストークン
デフォルト値: なし

**installation-id**
[任意] GitHub App インストール ID
デフォルト値: なし

**app-slug**
[任意] GitHub App のスラッグ名
デフォルト値: なし

---

# サードパーティ製の Action (ツール公式のもの)
## [google-github-actions/auth](https://github.com/google-github-actions/auth)
Google Cloud へ認証する action。
JSON 形式のサービスアカウントキーでの認証 と Workload Identity 連携での認証をサポートする。

前提条件
※ actions/checkout@v4 はこの action の前に実行すること。
* Node 20 を使用するため、ランナーがこれ以降のバージョンをサポートしていること。

**project_id:**
GCP のプロジェクトID

**workload_identity_provider:**
プロジェクトID、workload identity プール名、プロバイダ名を含む、ID プロバイダの完全な識別子。 


## [google-github-actions/setup-gcloud](https://github.com/google-github-actions/setup-gcloud)
Google Cloud SDK を設定する。
Google Cloud SDK は、gcloud, gsutil 双方のバイナリを含む。

利用可能な input は以下の通り。

**version:**
[任意]インストールする gcloud のバージョンまたはバージョン制約を表す文字列。デフォルトは latest。


**project_id:**
[任意]gcloud が使用するデフォルトの GCP プロジェクト ID。

**install_components:**
[任意]追加でインストールする gcloud components。

**skip_install:**
gcloud をインストールせず、システム(=ランナー？)が提供するバージョンを使用する。
指定した場合、`version` は無視される。

## dependabot/fetch-metadata

https://qiita.com/WisteriaWave/items/b37be9c3ebf1de37da0f#dependabot-%E3%81%8C%E4%BD%9C%E6%88%90%E3%81%97%E3%81%9F-pr-%E3%81%AB%E9%96%A2%E3%81%99%E3%82%8B%E6%83%85%E5%A0%B1%E3%82%92%E5%8F%96%E5%BE%97

を参照。


# コンテキスト
workflow, job, step, 環境変数, 構成変数, シークレット, ランナー など workflow 実行時の情報を含むオブジェクト。

コンテキストやそのプロパティ値は 
`${{ <コンテキスト(のプロパティ)> }}` 
という GitHub Actions における「式」の構文で展開できる。

workflow の特定のキーでは、特定のコンテキストを取得できないことがある([Context availability](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#context-availability)を参照)

特に使い勝手がよさそうなコンテキストのプロパティを独以下に列挙する。

**github.action:**
step の ID もしくは action 名。

**github.action_path:**
action.yaml が配置されているパス。
複合アクションでのみサポートされている。

**github.actor:**
workflow を(元々)トリガーしたユーザー名。トリガーを再実行しても変わらない。
後述の github.triggered_actor も併せて参照してほしい。

**github.event_name:**
workflow をトリガーしたイベント名。

**github.event:**  
workflow をトリガーしたイベントに関する情報が詰まったオブジェクト。
`github.event` 以下参照できる情報は、それぞれの イベントの [Webhook ペイロード オブジェクト](https://docs.github.com/ja/webhooks/webhook-events-and-payloads#pull_request_review) の仕様による。

例えば、[`on: pull_request`](https://docs.github.com/ja/webhooks/webhook-events-and-payloads#pull_request) でトリガーしたのであれば、
`github.event.action`, `github.event.assignee` etc. が参照できる。
[`on: pull_request_review`](https://docs.github.com/ja/webhooks/webhook-events-and-payloads?actionType=submitted#pull_request_review) でトリガーしたのであれば、
`github.event.action`, `github.event.enterprise` etc. が参照できる。

GitHub Actions タブから workflow を re-run できるが、re-run したときも初回トリガー時のイベントの情報がそのまま使われる模様。

**github.job:**
現在の job の ID 。step 内でのみ利用可能で、それ以外の場面では NULL になる。

**github.ref:**
ワークフローの実行のトリガーとなったブランチ or タグの完全形式の参照。
- ブランチの場合: refs/heads/<ブランチ名>
- Pull Request の場合: refs/pull/<Pull Request番号>/merge
- タグの場合: refs/tags/<タグ名>

**github.run_id:**
リポジトリ内の workflow 実行 ID。全 workflow を通してユニーク。

**github.run_number:**
リポジトリ内の各 workflow について、workflow 実行時に発行される連番。

**github.sha:**
workflow をトリガーしたコミットハッシュ。

**github.token:**
環境変数 GITHUB_TOKEN の値。secrets.GITHUB_TOKEN も同値。step 内でのみ利用可能で、それ以外の場面では NULL になる。

**github.triggering_actor:**
workflow をトリガーしたユーザー名。トリガーを再実行した場合はそのユーザー名。
先述の github.actor も併せて参照してほしい。

**github.workflow:**
workflow 名。

**github.workspace:**
各 step におけるデフォルトの作業ディレクトリ。要するに、`working-directory` 未適用時の作業ディレクトリ。リポジトリルートのパスと捉えてよさそう。

**`env.<環境変数名>`:**
workflow, job, step レベルで env キーでセットされた環境変数の値。

**`vars.<構成変数名>`:**
組織, リポジトリ, 環境 レベルでセットされた構成変数の値。

**job.status:**
job の現在のステータス( success / failure / cancelled )。

**`jobs.<job_id>.result`:**
再利用可能な workflow 内の指定した ID の job の結果( success / failure / skipped )。

**`jobs.<job_id>.outputs.<output_name>`:**
再利用可能な workflow 内の指定した ID の job の 出力値。

**`steps.<step_id>.conclusion`:**
指定した ID の step の結果( `"success" / "failure" / "cancelled" / "skipped"` )。`continue-on-error` によるステータス補正「後」の値。

**`steps.<step_id>.outcome`:**
指定した ID の step の結果( `"success" / "failure" / "cancelled" / "skipped"` )。`continue-on-error` によるステータス補正「前」の値。

**`steps.<step_id>.outputs.<output_name>`:**
指定した ID の step の出力値。

**runner.os:**
job を実行するランナーのOS( Linux / Windows / macOS )。

**runner.arch:**
job を実行するランナーの CPU アーキテクチャ( x86 / x64 / ARM / ARM64 )

**secrets.GITHUB_TOKEN:**
各 workflow 実行時に、自動で生成されるトークンの値。

**`secrets.<secret_name>`:**
指定した名前のシークレット値。

**strategy.fail-test:**
matrix 内の job の1つが失敗した場合、実行中の job をキャンセルする設定か( true / false )。

**strategy.job-index:**
matrix 内の現在の job のインデックス。最初の job はインデックス 0 。

**strategy.job-total:**
matrix 内の job の総数。

**strategy.max-parallel:**
実行可能な job の 最大数。

**`matrix.<property_name>`:**
指定した matrix プロパティの値。

**`needs.<job_id>.outputs.<output_name>`:**
ID で指定した依存 job の出力値

**`needs.<job_id>.result`:**
ID で指定した依存 job の実行結果( success / failure / cancelled / skipped )。

**`inputs.<name>`:**
action, 再利用可能な workflow, 手動でトリガーされた workflow に与えられた input プロパティ値。

参考:

https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs

# その他気をつけた方がよいこと
(先輩から教えてもらったこと)

## 信頼できる Action を利用する
シークレットの情報を渡して何かしらの処理してもらうものが多いため、悪用を警戒して信頼性が低いものはなるべく使わない。

基本的に以下の Action のみを使う。
- GitHub Actions 公式のもの
- verified (Marketplace で ✓ がついているもの)なサードパーティ製のもの
- ツール公式 のサードパーティ製のもの

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59542/927be17d-121d-2db8-778a-9b9f2547ee3d.png)

どうしても使いたいサードパーティ製の Action があるならば、その実装を参考に、自前のローカルな Action として実装して使う。