GitHub ActionsのReusable workflowsをMolecule + Dockerのテスト環境で採用してみる

## Reusable workflowsとは

GitHub Actionsのworkflowを外部ファイルにして登録、GitHub Actionsの実行ファイル部分で呼び出す仕組みです。

### resusable workflows導入前

```yaml:.github/workflows/build.yml
---
name: build
on: [deployment, push]

jobs:
  ansible-lint:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: '3.9'

      - name: Install ansible-lint
        run: |
          pip install "ansible-lint[community,yamllint]"

      - name: Install galaxy roles
        run: |
          ansible-galaxy install git+https://github.com/${{ github.repository }},${{ github.sha }}

      - name: Execulte ansible-lint
        run: |
          ansible-lint

      - name: Show ansible-lint version
        run: |
          pip list | grep ansible \
          | GREP_COLORS='mt=01;34' egrep --color=always '[[:digit:]]' \
          | GREP_COLORS='mt=01;34' egrep --color=always '\.' \
          | GREP_COLORS='mt=01;33' egrep --color=always 'ansible.* '
          ansible-lint --version
```

### reusable workflows導入後

```yaml:.github/workflows/build.yml
---
name: build
on: [deployment, push]

jobs:
  ansible-lint:
    uses: org/repo/.github/workflows/workflows.yml@main
```

このように短い記述で済むようになります。またansible-lintを実行するファイル部分は外部のPublicリポジトリに

```yaml:.github/workflows/workflows.yml
name: Ansible lint execution workflow

on:
  workflow_call

jobs:
  ansible-lint:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: '3.x'

      - name: Install ansible-lint
        run: |
          pip install "ansible-lint[community,yamllint]"

      - name: Install galaxy roles
        run: |
          if [ -f 'roles/requirements.yml' ]; then
            ansible-galaxy install -r roles/requirements.yml
          else
            ansible-galaxy install git+https://github.com/${{ github.repository }},${{ github.sha }}
          fi

      - name: Execulte ansible-lint
        run: |
          ansible-lint

      - name: Show ansible-lint version
        run: |
          pip list | grep ansible \
          | GREP_COLORS='mt=01;34' egrep --color=always '[[:digit:]]' \
          | GREP_COLORS='mt=01;34' egrep --color=always '\.' \
          | GREP_COLORS='mt=01;33' egrep --color=always 'ansible.* '
          ansible-lint --version
```

のように記述し公開設定にしておきます。

## 今回作成したReusable workflows

```yaml:.github/workflows/workflows.yml
name: Ansible Molecule execution workflow

on:
  workflow_call:
    inputs:
      molecule-image:
        description: 'Molecule image. ex:centos:7,public.ecr.aws/owner/image:tag,ghcr.io/org/repo/image:tag'
        default: 'centos:7'
        type: string
      molecule-scenario:
        description: 'Molecule scenario name.'
        default: 'default'
        type: string
      pip-requirements-file:
        description: 'Path of Pip requirements file'
        default: 'molecule/requirements.txt'
        type: string
      python-version:
        description: 'Python version'
        default: 3
        type: string

jobs:
  molecule:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2

      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: "${{ inputs.python-version }}"

      - name: Install Pip requirements
        run: |
          pip install -r ${{ inputs.pip-requirements-file }}

      - name: Test with molecule
        run: |
          molecule test --scenario-name ${{ inputs.molecule-scenario }}
        env:
          ANSIBLE_FORCE_COLOR: '1'
          MOLECULE_IMAGE: ${{ inputs.molecule-image }}
          MOLECULE_NO_LOG: False
          PROFILE_TASKS_SORT_ORDER: 'none'
          PROFILE_TASKS_TASK_OUTPUT_LIMIT: '100'
          PY_COLORS: '1'
          TZ: 'Asia/Tokyo'

      - name: Show Ansible version
        run: |
          pip list | grep ansible \
          | GREP_COLORS='mt=01;34' egrep --color=always '[[:digit:]]' \
          | GREP_COLORS='mt=01;34' egrep --color=always '\.' \
          | GREP_COLORS='mt=01;33' egrep --color=always 'ansible.* '
          ansible --version

      - name: Show molecule version
        run: |
          molecule --version
        env:
          PY_COLORS: '1'
```

### 導入してみて良かった点

* GitHub Actionsの設定ファイルへ記述するコードの量が減った
* 処理を一箇所にまとめたのでメンテナンス、変更が容易になった

### 導入してみて気が付いた点

* Reusable workflowsが何らかの原因で呼び出されなかった時のエラーメッセージが非常に分かりにくい
* Reusable workflowsでMatrix buildは利用出来るがMatrix buildのパラメーターが外部から変更できないため場合によってはコードが冗長になる

```yaml:.github/workflows/workflows.yml
name: Ansible Molecule execution workflow

on:
  workflow_call:
    inputs:
      molecule-scenario:
        description: 'Molecule scenario name.'
        default: 'default'
        type: string
      pip-requirements-file:
        description: 'Path of Pip requirements file'
        default: 'molecule/requirements.txt'
        type: string
      python-version:
        description: 'Python version'
        default: 3
        type: string

jobs:
  molecule:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        molecule-image:
          - centos:7
          - centos:8

    steps:
      - uses: actions/checkout@v2

      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: "${{ inputs.python-version }}"

      - name: Install Pip requirements
        run: |
          pip install -r ${{ inputs.pip-requirements-file }}

      - name: Test with molecule
        run: |
          molecule test --scenario-name ${{ inputs.molecule-scenario }}
        env:
          ANSIBLE_FORCE_COLOR: '1'
          MOLECULE_IMAGE: ${{ matrix.molecule-image }}
          MOLECULE_NO_LOG: False
          PROFILE_TASKS_SORT_ORDER: 'none'
          PROFILE_TASKS_TASK_OUTPUT_LIMIT: '100'
          PY_COLORS: '1'
          TZ: 'Asia/Tokyo'

      - name: Show Ansible version
        run: |
          pip list | grep ansible \
          | GREP_COLORS='mt=01;34' egrep --color=always '[[:digit:]]' \
          | GREP_COLORS='mt=01;34' egrep --color=always '\.' \
          | GREP_COLORS='mt=01;33' egrep --color=always 'ansible.* '
          ansible --version

      - name: Show molecule version
        run: |
          molecule --version
        env:
          PY_COLORS: '1'
```

このようにDockerイメージの指定部分をmatrixに変更して並列にJobを実行するような処理も書けるのですが **matrix** の値が固定になってしまい変更できません。そのためコードは冗長になりますが、Matrix buildを使わないでひとつひとつパラメーターを指定した方が柔軟性は高くなります。

```yaml:.github/workflows/build.yml
---
name: build
on: [deployment, push]

jobs:
  molecule-centos6:
    uses: org/repo/.github/workflows/workflows.yml@main
    with:
      molecule-image: ghcr.io/org/repo/centos7:latest

  molecule-centos6jp:
    uses: org/repo/.github/workflows/workflows.yml@main
    with:
      molecule-image: ghcr.io/org/repo/centos7jp:latest

  molecule-centos7:
    uses: org/repo/.github/workflows/workflows.yml@main
    with:
      molecule-image: ghcr.io/org/repo/centos7:latest

  molecule-centos7jp:
    uses: org/repo/.github/workflows/workflows.yml@main
    with:
      molecule-image: ghcr.io/org/repo/centos7jp:latest

  molecule-centos8:
    uses: org/repo/.github/workflows/workflows.yml@main
    with:
      molecule-image: ghcr.io/org/repo/centos8:latest

  molecule-centos8jp:
    uses: org/repo/.github/workflows/workflows.yml@main
    with:
      molecule-image: ghcr.io/org/repo/centos8jp:latest
```






## 参考サイト

Reusable workflowsとは？

* [Reusing workflows - GitHub Docs](https://docs.github.com/ja/actions/learn-github-actions/reusing-workflows)

今回のサンプルリポジトリ

* [github-actions-reusable-workflows/molecule-docker | GitHub](https://github.com/github-actions-reusable-workflows/molecule-docker)

今回紹介したReusable workflowsを採用したコード

* [ansible-roles-mamono210/sl | GitHub](https://github.com/ansible-roles-mamono210/sl)