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