Azure Pipelines で Python の自作パッケージのテスト&ビルド自動化
読む前の注意
自動化において Azure Pipelines を使用するが、初めて利用する場合、Microsoft がホストしているサーバーでパイプラインを動かすには以下のフォームから利用申請を送る必要がある。(無料枠の場合)
このリクエストの回答・承認が2-3営業日後とのことなので Azure Pipelines がすぐに使えるわけではないので注意。
もし、この申請前にパイプラインを動かそうとすると、以下のエラーがでてパイプラインが失敗する。
##[error]No hosted parallelism has been purchased or granted. To request a free parallelism grant, please fill out the following form https://aka.ms/azpipelines-parallelism-request
はじめに
これは以下の記事の続きである。本記事は以下の記事のcatlib
という自作パッケージについて、テストやビルドを自動化するものである。
やりたいこと
-
main
ブランチへのマージ時に自作 Python パッケージのテストを自動的に行う - タグを切ったときに Azure Artifacts へのデプロイを自動的に行う
テスト自動化
パイプラインの準備
ローカル環境のリポジトリ直下から.azure-pipelines/test.yml
でファイルを作り、以下のパイプラインを記述する。なお、pytest
およびpytest-cov
が導入済みであることを前提に書いている。
trigger:
branches:
include:
- main
pool:
vmImage: "ubuntu-latest"
jobs:
- job: "Test"
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: "3.12"
displayName: "Install Python"
- script: |
pip install poetry
poetry --version
displayName: "Install Poetry"
- script: |
poetry install
poetry add pytest-azurepipelines --dev
displayName: "Install Dependencies"
- script: poetry run pytest tests --doctest-modules --junitxml=junit/test-results.xml --cov=./catlib --cov-report=xml
displayName: "Test"
- task: PublishTestResults@2
condition: succeededOrFailed()
inputs:
testResultsFiles: "**/test-*.xml"
testRunTitle: "Publish test results for Python $(python.version)"
displayName: "Publish Test Results"
- task: PublishCodeCoverageResults@1
inputs:
codeCoverageTool: Cobertura
summaryFileLocation: "$(System.DefaultWorkingDirectory)/**/coverage.xml"
displayName: "Publish Code Coverage Results"
基本的な流れは以下のようである。
-
main
ブランチにマージされたタイミングで発火する。 - Ubuntu 仮想環境を用意する。
- そこに Python と Poetry をインストール。
-
poetry install
コマンドでpyproject.toml
にある依存関係をインストールする。poetry add pytest-azurepipelines --dev
というのがあるが、公式ドキュメントにそのような記述があり、おそらくpytest
の出力フォーマットに必要なのだろうと思われる。(未調査) - テストを実行し、テスト結果とコードカバレッジ結果を
xml
形式で吐き出す。 -
PublishTestResults@2
タスクでテスト結果を Azure Pipelines の UI 上で見れるようにする。 -
PublishCodeCoverageResults@1
タスクでコードカバレッジ結果を Azure Pipelines の UI 上で見れるようにする。
ちなみに VSCode で作業している場合は、MicroSoft 公式の拡張があるので、導入することをオススメする。
Azure Pipelines に登録する
.azure-pipelines/test.yml
のファイルをmain
ブランチにマージしてみると、実はパイプラインが発火しない。これは Azure Pipelines にこのファイルを登録してからでないと動作しないからである。なので、今回作成したファイルを登録する。
Azure DevOps のプロジェクトに入り、右のサービスリストから [Pipelines] > [Pipelines] のページを開く。
そのページにはおそらく [Create Pipeline] というのが表示されており、そのボタンを押す。
-
Connect
What is your code?
と聞かれるので [Azure Repos Git] を選択する。 -
Select
Select a repository
で自作パッケージのリポジトリ(catlib
)を選択する。 -
Configure
Configure your pipeline
ではすでにあるパイプラインを参照するので [Existing Azure Pipelines YAML file] を選択し、Path を.azure-pipelines/test.yml
にする。 -
Review
[Run] を押して実行するか、[Run] の隣にマークがあり、それを押すと [Save] があるので、セーブするだけでもよい。
実行
どこか適当にファイルを編集しmain
ブランチに Push するときに発火する。あるいは Azure Pipelines からパイプラインを選ぶとその中に [Run Pipeline] のボタンがあるのでそれを押せば実行される。
しばらくたつとパイプラインの処理が終了し、結果が見れる状態になる。一つの実行結果を見るとテストやカバレッジの結果が見られるようになっていることがわかる。
Azure Artifacts へのデプロイ自動化
パイプラインの準備
次に.azure-pipelines/deploy.yml
を作成し、以下のようなパイプラインを記述する。
trigger:
tags:
include:
- "v*"
pool:
vmImage: "ubuntu-latest"
jobs:
- job: "Release"
variables:
PROJECT: $(System.TeamProject) # 組織スコープの場合不要
FEED: catlib
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: "3.12"
displayName: "Install Python"
- script: |
pip install twine
twine --version
displayName: "Install Twine"
- script: |
pip install poetry
poetry --version
displayName: "Install Poetry"
- script: |
poetry install --no-dev
displayName: "Install Dependencies"
- script: |
poetry build -f wheel
displayName: "Build"
- task: TwineAuthenticate@1
inputs:
artifactFeed: $(PROJECT)/$(FEED) # 組織スコープの場合 $(PROJECT)/ が不要
- script: |
twine upload -r $(FEED) --config-file $(PYPIRC_PATH) dist/*.whl
displayName: "Publish to $(PROJECT)/$(FEED)"
-
v
から始まるタグ(想定はv1.0.0
など)が作られたタイミングで発火する。 - Ubuntu 仮想環境を用意する。
- そこに Python, Twine, Poetry をインストール。
-
poetry install
コマンドでpyproject.toml
にある依存関係をインストールする。--no-dev
オプションで開発用のライブラリについてはインストールしないようにしている。 -
wheel
形式でビルドする。 -
TwineAuthenticate@1
タスクによってtwine
で Azure Artifacts へデプロイするための認証を行う。(このとき認証情報が書かれた.pypirc
ファイルが配置され、そのパスがPYPIRC_PATH
変数に入っている。) -
twine
により Azure Artifacts にデプロイする。
前回の記事での手動デプロイではpoetry publish
を利用したが、そのときに PAT (Personal Access Token) を使っていた。しかし Azure DevOps ではこの PAT に必ず有効期限があるため、メンテナンスをしなくてはならなくなる。それを回避するためにはTwineAuthenticate@1
タスクを使う必要があった。そのためデプロイにはpoetry
ではなく、twine
というツールを使う。
ちなみに PAT をシークレット変数(GitHub でいうsecrets
)として登録しpoetry publish
するパイプラインは以下に載せておく。
Twine を使わない場合のパイプライン
以下のドキュメントを参考にcatlib-release
変数グループを作成し、AZURE_PAT
として PAT の値を入力した。
trigger:
tags:
include:
- "v*"
variables:
- group: catlib-release
pool:
vmImage: "ubuntu-latest"
jobs:
- job: "Release"
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: "3.12"
displayName: "Install Python"
- script: |
pip install poetry
poetry --version
displayName: "Install Poetry"
- script: |
poetry install --no-dev
displayName: "Install Dependencies"
- script: |
poetry build -f wheel
displayName: "Build"
- script: |
poetry publish -r azure
env:
POETRY_REPOSITORIES_AZURE_URL: <フィードのアップロード用URL>
POETRY_HTTP_BASIC_AZURE_USERNAME: "auto-deployer"
POETRY_HTTP_BASIC_AZURE_PASSWORD: $(AZURE_PAT)
displayName: "Publish to Azure Artifacts Feed"
poetry publish -r azure
のところで環境変数がでてくるが、poetry
の config は環境変数から与えることもできる。
Azure Pipelines に登録する
.azure-pipelines/test.yml
の時と同じように [New Pipeline] ボタンから登録する。
ちなみにそれぞれのパイプラインの名前は [Pipelines] のページから変更できるのでわかりやすい名前に変えておくとよい。
Azure Artifacts に Azure Pipelines からデプロイできるようにする
これで実行してみたいところだが、このまま実行しても実はうまくいかない。これは Azure Pipelines の実行系にフィードに対しての write 権限がないためである。
フィードの<プロジェクト名> Build Service (<組織ID>)
に対してContributor
のロールを付与することで解決できる。
以下の公式ドキュメントを参考にして設定すればよいが、少しわかりにくいのが [Permissions] のところで、すでにリストにある User/Group でも [Add users/groups] からロールを変えることである。
実行
pyproject.toml
ファイルのversion
の値を変更してから、パイプラインの実行を行う。もしその値が変わってなければデプロイに失敗するので注意。
Azure Artifacts 上のフィード内のバージョンが変更されていれば成功である。
今後の課題
タグを切ったときのバージョンの値とpyproject.toml
で記載したバージョンの値が一致するか検証してからデプロイしたい。
pr
タグで Pull Request 時に発火するトリガーがあるのでこれも試してみたい。たとえばそのタイミングでテストを行うとか。
Discussion