GitHub Actionsでワークフローを別ファイルに分割して順番に起動する方法

# 概要
**GitHub Actions**において、すべての処理を単一のワークフローファイルに記述する方法は、ファイルの肥大化を招き、保守性や可読性の低下を引き起こす要因となります。
本記事では、ワークフローを複数のファイルに分割し、[workflow_dispatch](https://docs.github.com/ja/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_dispatch)を用いて順次起動する手法について記載します。


# 構築手順
## ディレクトリー構成
```sh
.
├── .github/
│   └── workflows/
│       ├── actions_workflow1.yml
│       ├── actions_workflow2.yml
│       └── actions_workflow3.yml
└── README.md
```

# 設定の事前準備
## 設定手順
- [**Settings**] → [**Actions**] → [**General**]に、**Workflow permissions**がある為、その画面を開く
- `Read and write permissions`にチェックをした後、[**save**]をする

![actions_workflow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664659/6c9f0484-887d-4243-bdec-8640ca1f518e.png)

- 上記の画面の設定を行う事で、メインのワークフローファイルから、別のワークフローファイルを起動する事が出来る

## 翻訳
> **ワークフローパーミッション**
このリポジトリでワークフローを実行する際に、GITHUB_TOKENに付与されるデフォルトの権限を選択してください。
YAMLファイル内で、より細かい権限設定を行うこともできます。
権限管理について詳しくは、「Managing permissions（権限管理について）」をご覧ください。

>⚪︎ 読み取りおよび書き込み権限
ワークフローには、すべてのスコープに対して、リポジトリの読み取りおよび書き込み権限が与えられます。

>⚪︎ リポジトリコンテンツおよびパッケージの読み取り権限**
ワークフローには、コンテンツおよびパッケージスコープに対する読み取り権限のみが与えられます。

>GitHub Actionsがプルリクエストを作成・承認できるかどうかを選択してください。
◻︎ GitHub Actionsにプルリクエストの作成と承認を許可する

## 補足
- `Read and write permissions`をONにしない場合は、下記の設定を入れる
- 本記事では、記述したコードを記載
```yml
permissions:
  actions: write
```

# 処理フロー概要
この3つの`GitHub Actions`ワークフローは、段階的に別のワークフローをトリガーする構成になっており、以下のような流れで動作する

## 各ワークフローの役割

| ワークフロー名 | ファイル名 | 主な役割 |
| :-: | :-: | - |
| Workflow 1 | `actions_workflow1.yml` | 実行トリガーと環境セット処理、次のWorkflow2を起動 |
| Workflow 2 | `actions_workflow2.yml` | Workflow1から環境とブランチ名を受け取り、Workflow3を起動 |
| Workflow 3 | `actions_workflow3.yml` | Workflow2から情報を受け取り、最終的な処理を実行 |

## 実行トリガー
Workflow1は、以下の2つの条件で実行される
- `main` ブランチへの `push`された際に処理が実行される
- `workflow_dispatch`（手動実行）時に 環境指定（production） を入力して `Run workflow`行うとActionsが動作する


# 構成ファイル
## actions_workflow1

1. 実行トリガーを受け付ける（`push` または `workflow_dispatch`）
2. 環境変数 `environment_value` を設定（`workflow_dispatch` ならユーザー入力、それ以外は `production` 固定）
3. 実行ブランチが `main` でなければエラー終了
4. 次の `actions_workflow2.yml` をトリガーする（`branch` 名と環境名を渡す）

```actions_workflow1.yml
name: Actions Workflow 1
run-name: |
  Workflow triggered by ${{ github.actor }} 🚀

on:
  workflow_dispatch:
    inputs:
      environment_target:
        description: 'Environment target'
        required: true
        type: choice
        options:
          - production

  push:
    branches:
      - main

permissions:
  actions: write      
    
jobs:
  environment-set-and-show-message:
    runs-on: ubuntu-latest
    outputs:
      environment_value: ${{ steps.set-env.outputs.environment_value }}
    
    steps:
      - name: Show workflow triggered message
        id: set-env
        run: |
          if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
            echo "environment_value=${{ github.event.inputs.environment_target }}" >> $GITHUB_ENV
            echo "environment_value=${{ github.event.inputs.environment_target }}" >> $GITHUB_OUTPUT
          else
            echo "environment_value=production" >> $GITHUB_ENV
            echo "environment_value=production" >> $GITHUB_OUTPUT
          fi

      - name: Print info
        run: |
          echo "actions_workflow1.yml が動作しました"
          echo "現在のブランチ: ${{ github.ref_name }}"
          echo "現在の環境: $environment_value"
  
      - name: Validate branch is main
        run: |
          echo "バリデーション開始..."
          BRANCH_NAME="${{ github.ref_name }}"
          
          if [ "$BRANCH_NAME" != "main" ]; then
            echo "エラー: ブランチ '$BRANCH_NAME' は許可されていません。mainブランチのみ許可されています。"
            exit 1
          fi
          echo "ブランチ検証通過"

  trigger-actions-workflow:
    name: Trigger Build Workflow1
    needs: environment-set-and-show-message
    runs-on: ubuntu-latest

    steps:
      - name: Trigger Build
        uses: actions/github-script@v7
        with:
          script: |
            const environment_value = '${{ needs.environment-set-and-show-message.outputs.environment_value }}';
            console.log('ENV_NAME:', environment_value);

            await github.rest.actions.createWorkflowDispatch({
              owner: context.repo.owner,
              repo: context.repo.repo,
              workflow_id: 'actions_workflow2.yml',
              ref: context.ref,
              inputs: {
                branch_name: context.ref.replace('refs/heads/', ''),
                environment_name: environment_value
              }
            })

```

## actions_workflow2

1. `workflow_dispatch` で受け取った入力（ブランチ名、環境名）を表示する
2. 次の `actions_workflow3.yml` をトリガー（同じくブランチ名、環境名を渡す）

```actions_workflow2.yml
name: Actions Workflow 2
run-name: |
  Workflow triggered by ${{ github.actor }} 🚀

on:
  workflow_dispatch:
    inputs:
      branch_name:
        description: 'Branch name'
        required: true
        type: choice
        options:
          - main 

      environment_name:
        description: 'Deployment environment'
        required: true
        type: choice
        options:
          - production

jobs:
  show-received-message:
    runs-on: ubuntu-latest
    steps:
      - name: Show workflow triggered message
        run: |
          echo "actions_workflow2.yml が動作しました"
          echo "受け取ったブランチ名: ${{ github.event.inputs.branch_name }}"
          echo "受け取った環境名: ${{ github.event.inputs.environment_name }}"


  trigger-actions-workflow:
    name: Trigger Build Workflow2
    runs-on: ubuntu-latest

    steps:
      - name: Trigger Build
        uses: actions/github-script@v7
        with:
          script: |
            await github.rest.actions.createWorkflowDispatch({
              owner: context.repo.owner,
              repo: context.repo.repo,
              workflow_id: 'actions_workflow3.yml',
              ref: context.ref,
              inputs: {
                branch_name: '${{ github.event.inputs.branch_name }}',
                environment_name: '${{ github.event.inputs.environment_name }}'
              }
            })     

```


## actions_workflow3
1. 入力されたブランチ名と環境名を表示する
2. ここで処理は完了する

```actions_workflow3.yml
name: Actions Workflow 3
run-name: |
  Workflow triggered by ${{ github.actor }} 🚀

on:
  workflow_dispatch:
    inputs:
      branch_name:
        description: 'Branch name'
        required: true
        type: choice
        options:
          - main 

      environment_name:
        description: 'Deployment environment'
        required: true
        type: choice
        options:
          - production

jobs:
  show-received-message:
    runs-on: ubuntu-latest
    steps:
      - name: Show workflow triggered message
        run: |
          echo "actions_workflow3.yml が動作しました"
          echo "受け取ったブランチ名: ${{ github.event.inputs.branch_name }}"
          echo "受け取った環境名: ${{ github.event.inputs.environment_name }}"      

```

## メソッド・コマンド名と説明

| メソッド・コマンド名 | 説明 |
| :-: | - |
| `echo` | 標準出力に文字列を表示する |
| `>> $GITHUB_ENV` | 環境変数を設定して、以降のステップで使えるようにする |
| `>> $GITHUB_OUTPUT` | ステップの出力値として値を設定する |
| `${{ github.actor }}` | ワークフローを実行したユーザーの `GitHub` アカウント名を取得する |
| `${{ github.event_name }}` | トリガーイベントの種類（`push`、`workflow_dispatch`など）を取得する |
| `${{ github.event.inputs.<input_name> }}` | `workflow_dispatch` で指定された入力値を取得する |
| `${{ github.ref_name }}` | 実行されたブランチ名を取得する |
| `exit 1` | スクリプトをエラーとして終了させる（以降の処理を中断する） |
| `context.repo.owner` | リポジトリの所有者名（ユーザーまたは`Organization` (組織アカウント)）を取得する |
| `context.repo.repo` | リポジトリ名を取得する |
| `context.ref` | 実行中のリファレンス（例: refs/heads/main）を取得する |
| `github.rest.actions.createWorkflowDispatch({...})` | 別のワークフローを指定して手動トリガーする |
| `uses: actions/github-script@v7` | `JavaScript`コードを `GitHub Actions` 上で実行する公式アクションを使う |
| `run:` | シェルスクリプトとしてコマンドを実行するステップを定義する |


# GitHub

https://github.com/kengo-sk8/github_actions_work_flow_test1


# 参考資料
## 公式
- [[GitHub] github-script](https://github.com/actions/github-script?tab=readme-ov-file)
- [Controlling permissions for GITHUB_TOKEN](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token)


## 非公式
- [GitHubの更新をActionsで楽にする公式Actionのgithub-scriptへ入門してみる](https://dev.classmethod.jp/articles/github-script-first-contact/)
- [[GitHub Actions] Unhandled error: HttpError: Resource not accessible by integrationエラーを解決する](https://qiita.com/nakamasato/items/6ce8ae18617b4c82b83b)

# 感想
 複数のワークフローファイルに処理を分割し、順番に実行される構成を作成しました。実用性はそれほど高くないかもしれませんが、ワークフローを分割して構成する方法を学べたのは良い経験でした。今後も引き続き `GitHub Actions` を学び、より良い `CI/CD` パイプラインを構築できるよう精進していきたいと思います。