GitHub Actionsにおける複数ジョブの基本の基本

# 概要
- GithubActionsをいじる機会が多くなってきたが、知見がないため覚書
    - かなり基本的な内容です。もし間違ってたらご指摘ください🙇‍♂
    - 「こんなやり方もあるよー」などのご意見もありましたらぜひいただけると大変嬉しいです🙇‍♂
- この記事の内容
    1. 複数ジョブの並列実行のやり方（ジョブの基本）
    1. 複数ジョブの逐次実行のやり方
    1. 複数ジョブ間のデータ共有のやり方

# ジョブの基本
- 単一のワークフローから、複数のジョブが起動できる
- 複数ジョブを起動すると、**デフォルトでは並列実行**される
    - なので、適切にジョブ分割すると**ワークフロー全体の実行時間を短縮できる**

# ジョブの並列実行

- まず、デフォルトで「複数ジョブは並列実行される」ということを確認

お試し用ワークフローファイルを作成

```yaml
name: Tests Workflow
on: push

jobs:
  job1:
    runs-on: ubuntu-latest
    steps:
      - run: sleep 10 && echo "job1"
  job2:
    runs-on: ubuntu-latest
    steps:
      - run: sleep 10 && echo "job2"
  job3:
    runs-on: ubuntu-latest
    steps:
      - run: sleep 10 && echo "job3"
```

- 【結果】pushしてワークフローを発火させると、以下のように並列で回っていることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990312/89e134ea-3ad1-7aef-2efc-0568c650ba7c.png)

# ジョブの逐次実行

- ジョブ間で依存関係がある場合など、逐次実行したい際は`needs`を使用する
    - `needs: [実行前に終了させたいジョブIDを指定]`
    - `needs`は配列形式で複数指定が可能

```yaml
name: Tests Workflow
on: push

jobs:
  job1: # 最初に実行
    runs-on: ubuntu-latest
    steps:
      - run: sleep 10 && echo "job1"
  job2: # job1が終了した後に実行
    runs-on: ubuntu-latest
    needs: [job1]
    steps:
      - run: sleep 10 && echo "job2"
  job3: # job2が終了した後に実行
    runs-on: ubuntu-latest
    needs: [job2]
    steps:
      - run: sleep 10 && echo "job3"
```

逐次実行されていることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990312/b04e0633-ff58-1293-7c91-9ff40f48e4b5.png)

複数指定した場合

```yaml
name: Tests Workflow
on: push

jobs:
  job1: # 最初に実行
    runs-on: ubuntu-latest
    steps:
      - run: sleep 10 && echo "job1"
  job2: # 最初に実行
    runs-on: ubuntu-latest
    steps:
      - run: sleep 10 && echo "job2"
  job3: # job1とjob2が終了した後に実行
    runs-on: ubuntu-latest
    needs: [job1, job2]
    steps:
      - run: sleep 10 && echo "job3"
```

job1とjob2が終了したあとにjob3が実行されていることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990312/80a7e9b1-e62b-ea59-8114-529dc14dd447.png)

# ジョブ間のデータ共有
- GitHub Actionsでは各ジョブごとに別々のランナー（実行環境）で実行されるので、何かしらの値を別ジョブに渡したいときは少々工夫が必要
- 主に`outputs`・`GITHUB_OUTPUT`を使用する
- 以前は`::save-output`を使用してデータ共有ができたが現在は非推奨
    - `echo “::set-output name={name}::{value}”`　→ `echo “{name}={value}” >> $GITHUB_OUTPUT`

公式が出していた`set-output`のサンプル
```yaml
name: Tests Workflow
on: push

jobs:
  job1:
    runs-on: ubuntu-latest
    # Map a step output to a job output
    outputs:
      output1: ${{ steps.step1.outputs.test }}
      output2: ${{ steps.step2.outputs.test }}
    steps:
    - id: step1
      run: echo "::set-output name=test::hello"
    - id: step2
      run: echo "::set-output name=test::world"
  job2:
    runs-on: ubuntu-latest
    needs: job1
    steps:
    - run: echo ${{needs.job1.outputs.output1}} ${{needs.job1.outputs.output2}}

```

一応まだ使用できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990312/54ea67ae-cf88-f0ab-6d1a-478ca1f92ad0.png)

だがしかしがっつり警告が出ている（ので使用はやめよう）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990312/6b27629e-df51-9189-393c-829b4427352f.png)



## `$GITHUB_OUTPUT`と`outputs`使用して変数の値を受け渡し
- 例として`before_job`と`after_job`という2つのjobを使用する
- 以下が変数を渡す側の基本構文
- 参考記事
    - [ギットハブ　アクション　のワークフロー構文 - GitHub Docs](https://docs.github.com/ja/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idneeds)

```yaml:構文
steps:
  - id: <ステップID>
    run: echo "<key>=<value>" >> "${GITHUB_OUTPUT}
outputs:
  <アウトプット名>: ${{ steps.<ステップID>.outputs.<key> }}
```

ポイント
- 主に使用するコンテキスト
    - `needs`, `id`(ステップID), `outputs`が必要
- 変数の形式
    - `GITHUB_OUTPUT`環境変数へは`key=value`形式で値を書き出す
    - `GITHUB_OUTPUT`は、ステップの出力パラメータの設定に使う**環境ファイル**
        - そのためリダイレクトで追記するという形式になっている
- 別jobに変数の値を渡すまでの流れ
    - ステップ内で`id`を定義し、他のステップや`outputs`キーで`$GITHUB_OUTPUT`内の値が受け取れるようにする(before_jobからafter_jobに渡す)
        - ちなみにbefore_jobに`outputs`キーを定義することで、before_job内の複数ステップ内で値を参照できるようになる(用途としては`GITHUB_ENV`使う時と同様)
            - `${{ steps.<step-id>.outputs.<key> }}`
    - after_job側で`needs`を用いることで、before_jobで定義した`outputs`の値を受け取れるようにできる
        - `${{ needs.<ジョブID>.outputs.<アウトプット名> }}`


```yaml:例
name: Tests Workflow
on: push

jobs:
  before_job: # 最初に実行
    runs-on: ubuntu-latest
    steps:
      - id: generate # ステップID
        run: echo "result=HELLO" >> "${GITHUB_OUTPUT}"
    outputs:
      ghop_result: ${{ steps.generate.outputs.result }} # GITHUB_OUTPUTのresultを参照
  after_job:
    runs-on: ubuntu-latest
    needs: before_job # before_jobが先に終了するように依存関係を作成
    steps:
      - env:
          RESULT: ${{ needs.before_job.outputs.ghop_result }} # 依存関係ジョブのoutputsを参照
        run: echo $RESULT

```
- ちなみに受け取った値を環境変数に入れず、直接`run: echo "${{ needs.before_job.outputs.ghop_result }}"`みたいにするのはアンチパターンのためNG

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990312/1c7e3cbb-5421-43a3-8219-f9ff83859ad0.png)

値がafter_jobに渡っていることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990312/92b57756-df78-c443-1e69-ea1f9002b8b3.png)

# 参考
- [ジョブの出力の定義 - GitHub Docs](https://docs.github.com/ja/actions/using-jobs/defining-outputs-for-jobs)
- [GitHub Actionsはね、後続ステップで参照できるようにあるステップで出力を定義する方法が、ワークフローコマンドから環境ファイルに変わったんだよ - nikkie-ftnextの日記](https://nikkie-ftnext.hatenablog.com/entry/use-github-output-instead-of-set-output)
- [GitHub Actionsで複数Job間でデータを共有する方法 - Job outputs #GitHubActions - Qiita](https://qiita.com/yokawasa/items/dc46ae6936b745af8b80)