Python Tips: Python のプロジェクトで GitHub Actions を使いたい

GitHub Actions

今回は Python のプロジェクトで GitHub Actions を導入する方法をご紹介します。実際に動くかんたんなサンプルを使って説明します。

追記 2020/07/23:

Poetry をインストールするアクション dschep/install-poetry-action を使う方法を紹介していましたが、こちらはメンテナンスされなくなっているようなので、使わない形での説明に変更しました。

GitHub Actions とは

最初に GitHub Actions についてかんたんに説明します。

GitHub Actions とは GitHub 公式のワークフロー自動化ツールです。

2018 年 10 月にパブリックベータ版が公開され、 2019 年の 11 月に一般公開されました。それまで GitHub で CI/CD を行うには外部のサービスを利用する必要がありましたが、 GitHub Actions が導入されたことでコード管理と CI/CD を GitHub 内で一元的に行えるようになりました。

GitHub Actions は、 GitHub で管理されているリポジトリにディレクトリ .github/workflows/ を作成してその下に自動化したい処理を記述した YAML 形式の設定ファイルを置けばすぐに利用し始めることができます。処理を実行するプラットフォームは Linux / macOS / Windows の中からひとつ(または複数)選ぶことができます。

GitHub Actions の特徴のひとつに、 GitHub や他の人が作成し GitHub 上に公開したアクションを利用できる点があります。たとえば、次の内容を設定ファイルに記述すると、 actions/checkoutactions/setup-python というアクションをかんたんに利用することができます。

name: pytest

on:
  push:

jobs:
  pytest:
    name: Run tests with pytest
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set up Python 3.7
        uses: actions/setup-python@v1
        with:
          python-version: 3.7

汎用度の高いアクションは誰かがオープンソースとして公開してくれていたりもするので、必ずしもすべての手順を自分でゼロから書く必要はありません。 CI/CD の経験があまり無い方やプログラミング初心者の方にも始めやすいかと思います。

Python プロジェクトでの GitHub Actions の使い方

Python プロジェクトでの GitHub Actions の使い方を説明します。

といっても、公式のドキュメントを読めば大体のことは書かれているので、スラスラと読んで理解できる方は公式のドキュメントを読むのがいちばんです。ここでは動くサンプルを使ってさわりの部分だけ説明します。

お話の前提として、 GitHub にアカウントを持っていて Python プロジェクトのリポジトリを置いているものとします。

GitHub Actions を使い始める方法は 2 つあります。

  • ブラウザで Actions のページを開く
  • ファイル .github/workflows/xxx.yml をコミットする

ブラウザで Actions のページを開くにはリポジトリの「 Actions 」タブをクリックします。ファイル .github/workflows/xxx.yml をコミットする場合は、手元のテキストエディタとターミナルをそのまま使います。どちらの形を選んでも最終的にできることは同じです。

以下、テストとスタイルチェックを行うかんたんなサンプルを使って説明します。次のツールを使用します。

  • poetry: 依存パッケージを管理する
  • pytest: テストを実行する
  • black: コーディングスタイルのチェックを行う

最初に GitHub 上に空のリポジトリを作成して、次の内容のファイル hello.py をコミットします。

hello.py:

"""関数 `hello()` を提供する"""

def hello(name: str = "world") -> None:
    """`Hello, xxx.` のメッセージを出力する"""
    print(f"Hello, {name}.")

続いて、テストファイルを作成します。 tests/test_hello.py あたりに作るのがよいでしょうか。

tests/test_hello.py:

from hello import hello

def test_hello_default(capsys):
    hello()
    out, err = capsys.readouterr()
    assert out == "Hello, world.\n"

def test_hello_with_name(capsys):
    hello("サザエ")
    hello("カツオ")
    out, err = capsys.readouterr()
    assert out == "Hello, サザエ.\n" "Hello, カツオ.\n"

これは pytest 用に作ったテストなので pytest をインストールします。私は Python のパッケージには poetry をよく使いますがここは pip でもそれ以外のものでもかまいません。

poetry add --dev pytest

pytest が無事にインストールできたら、 setup.py を作成してからテストを実行します。

setup.py:

from setuptools import setup, find_packages

setup(name="hello-github-actions", version="1.0", packages=find_packages())
poetry run pytest tests/test_hello.py
============================= test session starts ---===========================
platform linux -- Python 3.7.4, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /app
collected 2 items

tests/test_hello.py ..                                                   [100%]

============================== 2 passed in 0.13s ---============================

成功することが確認できました。

続いて、このテストを GitHub Actions で実行するように設定ファイルを書きます。

リポジトリのルートに .github/workflows/ci.yml というファイルを作成し以下の内容で保存します。

.github/worflows/ci.yml:

name: pytest

on:
  push:
  pull_request:

jobs:
  pytest:
    name: Run tests with pytest
    # 実行環境として `ubuntu-latest` という名前のものを選ぶ
    runs-on: ubuntu-latest
    # 複数の Python のバージョンでテストするために `strategy.matrix` を設定する
    strategy:
      matrix:
        python-version: [3.7, 3.8]
    steps:
      # リポジトリをチェックアウトする
      # See: https://github.com/actions/checkout
      - name: Checkout
        uses: actions/checkout@v2
      # Python のランタイムをセットアップする
      # バージョンは `strategy.matrix` に並べたものを指定する
      # See: https://github.com/actions/setup-python
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v1
        with:
          python-version: ${{ matrix.python-version }}
      # Poetry そのものをインストールする
      - name: Install Poetry
        run: |
          curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
      # Poetry へのパスを通す
      - name: Add path for Poetry
        run: echo "::add-path::$HOME/.poetry/bin"
      # インストールした Poetry を使って必要な Python パッケージをインストールする
      - name: Install Dependencies
        run: poetry install --no-interaction
      # pytest を実行する
      - name: Run Tests
        run: poetry run pytest tests/

メインは jobs.pytest.steps の部分です。ここに指定したアクションが上から順に実行されます。

Python プロジェクトで GitHub Actions を使う場合はおそらく最初の 2 ステップ(チェックアウトと Python ランタイムのセットアップ)はほぼ共通になると思います。

各アクションがどういうことをしているかについてはインラインのコメントを見てください。

ちなみに、ディレクトリ .github/worflows/ はそのままこの名前にする必要がありますが、 ci.yml はこの名前でないといけないわけではありません。適当にわかりやすい名前を付けるとよいと思います。

ファイルが作成できたらコミットします。 poetry を使っている場合は pyproject.tomlpoetry.lock を、 pip を使っている場合は requirements.txt も忘れずにコミットしましょう。

コミットができたら GitHub に push します。すると、リポジトリの Actions のページに yaml ファイルで設定したワークフローが追加されていてテスト用のタスクが実行されるはずです。

これがうまく行ったら、おまけで black を使ったスタイルチェックも追加します。 poetry add をして、先ほどの .github/workflows/ci.yml を編集します。

poetry add --dev black

ファイルの末尾に以下の内容を追加します( black: の行が jobs の下に来るようにします)。インデントがおかしいと正しく動かないので注意してください。

  black:
    name: Check code style with Black
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set up Python 3.7
        uses: actions/setup-python@v1
        with:
          python-version: 3.7
      - name: Install Poetry
        uses: dschep/install-poetry-action@v1.3
      - name: Install Dependencies
        run: poetry install --no-interaction
      - name: Check code style with Black
        run: poetry run black --check --diff .

コードに問題がなければ、このワークフローも GitHub Actions で実行され、結果が success として報告されるはずです。

ということで、かんたんではありましたが、 Python プロジェクトでの GitHub Actions の使い方についてでした。 GitHub Actions について深く知りたい方は公式のドキュメントその他を確認していただければと思います。

今回使ったサンプルを少し整理して GitHub にあげているので、興味のある方は参考にしてみてください:

この記事を書いている時点で GitHub Actions は無料で利用できますが、金額等は時間が経つと変わると思うので、ここには載せません。 GitHub 公式の情報を確認してみてください。

参考リンク