😸

[Python]pipenv + Github ActionsでDevOps

2022/02/01に公開

Pythonでネタコマンドラインツールを作ったのですが、pipenv + Github Actions を交えて、(ネタツールにしては)堅牢にDevOpsをしたので、ハマったポイント等を覚書します。

https://github.com/prs-watch/hof

pipenv

https://pipenv-ja.readthedocs.io/ja/translate-ja/index.html

Pythonのパッケージマネージャー。Pythonバージョンの npm なイメージですが、virtualenv の様にPythonの仮想環境をアクティベート出来るので、プロジェクトに閉じたオンリーワンな環境をあっさりと作り上げることが可。

Github Actions

https://github.co.jp/features/actions

Githubがサポートしているワークフローサービス。YAML を上手く書くと、ビルド環境を立てて、テストやリリース等を行える。パブリックにされている汎用アクションの様な物を用いると、リポジトリのチェックアウトやパッケージリリース等も楽に実現可と、とても便利。

pipenv 覚書

仮想環境のセットアップ

$ pipenv --python 3

pipenv で依存管理を行うファイル Pipfile が作られます。

パッケージインストール

$ pipenv install pybaseball

テストやビルド、フォーマット等に必要なパッケージを入れる場合は、--dev オプションを入れて、dev-packages としてインストールします。

$ pipenv install --dev twine wheel

これらのパッケージはPythonの「仮想環境」にインストールされているので、ローカルマシンはクリーンなままです。仮想環境の中の pip にパッケージが入っているため、プロジェクトに閉じたオンリーワンな環境に Python とパッケージが詰まっている、そんな状況です。

Pipfile.lock

pipenv install でパッケージを入れると、インストールしたパッケージのバージョンを保持する Pipfile.lock が作られます。npm で言う package-lock.json と同等。

ただし、このファイルに人力で手を入れることは無いので、「お、あるなー」ぐらいなテンションで良いです。

スクリプト実行

pipenv run

npm と同じく、pipenv もスクリプトを定義の上、実行が出来ます。
&& でつないで複数コマンドを実行する場合は、bash -c でパスしてあげる必要がある様です。

Pipfile
...
[scripts]
test = "bash -c 'python -m pip install -e . && pytest tests'"
build = "bash -c 'python setup.py sdist && python setup.py bdist_wheel'"

と書き、例えば「あー、テストでもするかー」との気分になれば

$ pipenv run test

で実行。

仮想環境の中でコマンド実行

$ pipenv shell

で、仮想環境の中に入ります。docker exec の様なイメージ。
この中では、仮想環境の中の Python pip にアクセス出来るため、自作パッケージのローカルインストールやテストをラフに書くことが可。

Github Actions 覚書

主に pipenv を利用しながらのフロー作り、との観点で。とは言え、基本は YAML にコマンドをステップ毎に書く形なので、あんまりハマるポイントは無かったです。

pipenv 環境の再現

PipfilePipfile.lock が存在する場合は、pipenv sync --dev で開発用パッケージも入れたインストールが可。

Warning: Python 3.10 was not found on your system...

が、、Pipfile の中にPythonバージョンが 3.10 とされていましたが、ワークフロー環境上に無いため、エラーになってしまった様です。
Github Actions 側の環境がどうなっているかは分からんので、pipenv のドキュメントにオススメされる形で管理を直します。

https://pipenv-ja.readthedocs.io/ja/translate-ja/basics.html

複数バージョンのPythonを対象とする場合は、 Pipfile.lock はバージョン管理に含めないでください。

この上で、

# Pipfile.lockを生成
$ pipenv lock

# syncする
$ pipenv sync --dev

ワークフロー全体

テスト

test.yml
name: test

on:
  push:
    branches:
      - main

jobs:
  test:
    runs-on: ubuntu-20.04
    steps:
      - name: checkout
        uses: actions/checkout@v2

      - name: install pipenv
        run: |
          python -m pip install --upgrade pip
          python -m pip install pipenv
      
      - name: lock package version
        run: pipenv lock
      
      - name: install packages
        run: pipenv sync --dev
      
      - name: run test
        run: pipenv run test

リリース

release.yml
name: release

on:
  workflow_dispatch:

jobs:
  release:
    runs-on: ubuntu-20.04
    steps:
      - name: checkout
        uses: actions/checkout@v2

      - name: install pipenv
        run: |
          python -m pip install --upgrade pip
          python -m pip install pipenv
      
      - name: lock package version
        run: pipenv lock
      
      - name: install packages
        run: pipenv sync --dev

      - name: build
        run: pipenv run build

      - name: release
        uses: pypa/gh-action-pypi-publish@master
        with: 
          user: __token__
          password: ${{ secrets.PYPI_API_TOKEN }}

まとめ

クリーンに環境を作りつつ、テストやリリースも楽にぐるぐる回せて、とても良かったです。ネタコマンドラインツールにはリッチすぎるぐらい、、

Pythonの場合はほとんどこのスクリプトを流用出来る気がするので、これからはDevOpsが楽に実現出来そうです!
Github Actions のデバッグが辛かったなー、との気はするので、今度は act をテストしてみよう、、

https://dev.classmethod.jp/articles/act-for-github-actions-local-execution-tool/

Discussion