Poetryで管理しているPythonパッケージのテスト
Poetryで管理しているPythonパッケージで、
testsディレクトリにテストがありpytest
でテストを行うようなものを考えます。
ルートディレクトリで、
1
2
| poetry install
poetry run pytest
|
とすればテストを行うことが出来る状態。
Poetryで環境を作りテストを行う
以下のような.github/workflows/test.ymlを作成します。
.github/workflows/test.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| ---
name: test
on: push
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Make poetry environment
run: |
pip install poetry
poetry install
- name: Run pytest
run: poetry run pytest
|
これでpush
されたときにpoetry
で環境を作ってpytest
を実行することが出来ます。
ちなみにこの辺のPytestはほとんどの場所で共通して使ってるので
下にあるようなactionを作って共通化して使ってます。
Docker環境で共通のテストを行う
Dockerfileの準備
でやったPoetryで管理しているプロジェクトの環境構築のDockerfileを使います。
pyrproject.tomlは上のものに加え、テスト用のpytest
を
dev
のグループに追加しておきます。
pyproject.toml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| [tool.poetry]
name = "myproject"
version = "0.0.1"
description = ""
authors = ["rcmdnk <[email protected]>"]
[tool.poetry.dependencies]
python = "^3.11"
[tool.poetry.group.dev.dependencies]
pytest = "^8.0.0"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.poetry.scripts]
hello = "myproject:main"
|
これに対応するDockerfileは以下のようになります。
Dockefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| FROM python:3.12-slim-bookworm as builder
ENV PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
VIRTUAL_ENV=/app/.venv
WORKDIR /app
RUN pip install poetry-plugin-export
COPY pyproject.toml poetry.lock src ./
RUN poetry export --with dev --without-hashes --format=requirements.txt > requirements.txt
RUN echo "./" >> requirements.txt
RUN python -m venv "$VIRTUAL_ENV"
RUN . "$VIRTUAL_ENV/bin/activate" && pip install -r requirements.txt
#########
FROM python:3.12-slim-bookworm as runtime
ENV VIRTUAL_ENV=/app/.venv \
PATH="/app/.venv/bin:$PATH" \
USER_NAME=appuser
COPY --from=builder $VIRTUAL_ENV $VIRTUAL_ENV
WORKDIR /app
RUN useradd -r -u 1000 $USER_NAME
RUN chown -R $USER_NAME:$USER_NAME /app
USER $USER_NAME
|
変えたのは
Dockefile
1
| RUN poetry export --with dev --without-hashes --format=requirements.txt > requirements.txt
|
の部分だけで、--with dev
が追加されています。
これでdev
のグループに含まれるpytest
もインストールされます。
テスト部分の共通化
共通のテストにするため、テスト実行部分を別途actionsとして作成します。
.github/actions/test/action.yml
1
2
3
4
5
6
7
8
9
| name: test
description: Run tests
runs:
using: 'composite'
steps:
- name: pytest
shell: bash
run: pytest
|
こんな感じでpytest
を実行するだけのcomposite actionを作っておきます。
必要であればここで色々と実行するコマンドを追加しておきます。
これでレポジトリをcheckoutした後なら
1
| - uses: ./.github/actions/test
|
と指定するとpytest
が実行されます。
Poetry用Actionsファイル
上のactionを使って、Poetry用のactionを作ります。
.github/workflows/poetry-test.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| ---
name: poetry test
on: push
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Make poetry environment
run: |
pip install poetry
poetry install
echo "$(poetry show -v 2>/dev/null|grep 'Using virtualenv:'|awk '{print $3}')/bin" >> $GITHUB_PATH
- uses: ./.github/actions/test
|
最初の場合は最後にpoetry run
でpytest
を実行することで仮想環境下での実行を行っていましたが、
この場合ではtest actionの中ではpoetryを使ってません。
test actionの引数としてpoetry run
を使うかどうか、を指定しても良いかもしれませんが、
ごちゃごちゃするので、ここでは全体の環境のPATH
に
poetryの仮想環境のbin
ディレクトリを追加しています。
あとは最後の
最後のpytest
部分をactionに置き換えるだけです。
Docker用Actionsファイル
.github/workflows/docker-test.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| ---
name: docker test
on: push
jobs:
docker-build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: $
password: $
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: ghcr.io/$/test-image:$
docker-test:
needs: docker-build
runs-on: ubuntu-latest
container:
image: ghcr.io/$/test-image:$
credentials:
username: $
password: $
options: --user root
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/test
|
こんな感じ。
まず、docker-build
ジョブでイメージをビルドしています。
GitHubでは
GitHub Packages
でContainer registoryが提供されていて、
ghcr.ioでアクセス出来るレジストリで
Dockerイメージを保存したり公開したりすることが出来ます。
コンテナレジストリの利用 - GitHub Docs
それを使うため、
login-actionでログインし、build-push-actionでイメージをビルドしてpushしています。
setup-buildx-actionはDocker Buildxを使うためのもので、
今回の例では無理に使う必要はないかもしれませんが入れておきました。
これでレポジトリの環境をDockerイメージとしてビルドし、
Container registoryに登録されます。
次にdocker-test
ジョブで
docker-build
ジョブでビルドしたイメージを使ってテストを行います。
container
で作ったイメージを指定して
後はレポジトリをcheckoutしてテストを実行するだけです。
ここで、イメージ名など共通なのでenv
とかで変数化したいところですが、
steps
内では使えるもののこの上のcontainer
などの階層部分では
Unrecognized named-value: 'env'.
なエラーになってしまいます。
レポジトリの設定の
Actions secrets and variablesで設定した変数であれば
vars.<変数名>
で使え、これはcontainer
の中でも使えるので
それを設定すればよりきれいに書くことは出来ます。
イメージが複数になるような場合にはそのようなことをした方が良いかもしれません。
テストのステップに関してはまず
actionsやtestsディレクトリを取得するために
レポジトリをcheckoutしています。
もしこのDockerfileがGitHub Actions専用であればDockerfileの中で
Dockefile
1
2
3
| RUN mkdir -p .github
COPY .github/actions ./.github/
COPY tests ./
|
のようにしておけば
docker-test
側のcheckout
は不要になります。
今回はなんらか別に使うものでそのテストも兼ねるということで上のような形でイメージに余計なものを入れないようにしています。
containerの部分で--user root
を指定していますが、
これはGitHub Actionsでcheckout
を行う際、
root
権限でないとcheckoutできないためです。
今回のDockefileではUSER
を指定しているため、
そのままだと
1
| Error: EACCES: permission denied, open '/__w/_temp/_runner_file_commands/save_state_XXXXXXXX-XXXX-XXXX-XXXX-XXXX[XX](https://github.com/SensoftInc/xxxxxxxxxxxx/actions/runs/xxxxxxxxxx/jobs/xxxxxxxxxx#step:x:xx)xxxxxx'
|
というエラーが出てしまいます。
Error: EACCES: permission denied in container on self hosted Linux runner · Issue #1014 · actions/checkout
これに関しては上のIssueで
上のように--user root
を指定するか、
中で/__wを作って実行するユーザー(もしくは全員)に権限をもたせる方法が
紹介されていますが、上のIssueにあるような
をしても同じエラーになりました。
Dockefile
1
2
| RUN mkdir /__w
RUN chown -R $USER_NAME:$USER_NAME /__w
|
みたいなのもうまくいきません。
何かおまじないがあるのか…
というわけで、ちょっと環境変えてしまうことにもなってしまいますが
一旦--user root
で対応しています。
実行するコマンドによってはユーザーが誰か、で結果が変わるようなこともあると思うので、
そういった場合は最初からDockerfileの定義でUSER
を指定せずに
rootで実行するようにして正しく動作するように設定したが方が良いです。
push時にはpoetryで、手動テストでDocker環境も使えるようにする
.github/workflows/test.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
| name: test
on:
push:
workflow_dispatch:
inputs:
exe_env:
description: "Execution environment."
type: choice
required: false
default: "docker"
options:
- "docker"
- "poetry"
jobs:
docker-build:
if: ${{ (github.event_name == 'workflow_dispatch' && github.event.inputs.exe_env == 'docker') }}
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: ghcr.io/${{ github.repository }}/test-image:${{ github.sha }}
docker-test:
if: ${{ (github.event_name == 'workflow_dispatch' && github.event.inputs.exe_env == 'docker') }}
needs: docker-build
runs-on: ubuntu-latest
container:
image: ghcr.io/${{ github.repository }}/test-image:${{ github.sha }}
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
options: --user root
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/test
poetry-test:
if: ${{ (github.event_name == 'push') || (github.event_name == 'workflow_dispatch' && github.event.inputs.exe_env == 'poetry') }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: '3.12'
- name: setup poetry
run: |
pip install poetry
poetry install
echo "$(dirname $(poetry run which python))" >> $GITHUB_PATH
- uses: ./.github/actions/test
|
こんな感じのGitHub Actionsを作成しておけば、
push
時にはpoetryでテスト
- 手動で実行するときには
docker
かpoetry
を選択して実行
を行うことが出来ます。
まあこのように手動でテスト出来るようにしておく意味があるかどうかはわかりませんが、
テストがてら作るときに便利かな、と思ってこうしてみただけです。
以下のレポジトリはこのテストを実際にやってみたもの。