ウェブサイト検索

GitHubアクションを使用したPythonの継続的な統合と展開


ソフトウェアを作成することは、祝う価値のある成果です。しかし、ソフトウェアは決して静的ではありません。バグを修正する必要があり、機能を追加する必要があり、セキュリティには定期的な更新が必要です。今日の風景では、アジャイル方法が支配的であるため、進化するコードベースを管理するために堅牢なDevOpsシステムが重要です。そこで、GitHubアクションが輝き、Python開発者がワークフローを自動化し、プロジェクトがシームレスに変化するようにすることを可能にします。

Python 用のGitHub Actions を使用すると、開発者はワークフローを効率的に自動化できます。これにより、チームは絶え間ない変化に適応しながらソフトウェアの品質を維持できます。

継続的な統合と継続的な展開(CI/CD)システムは、十分にテストされた高品質のソフトウェアを生成し、展開を合理化するのに役立ちます。 GitHubアクションにより、CI/CDはすべての人がアクセスでき、リポジトリ内のワークフローの自動化とカスタマイズが可能になります。この無料サービスにより、開発者はソフトウェア開発プロセスを効率的に実行し、生産性とコードの信頼性を向上させることができます。

このチュートリアルでは、次の方法を学習します。

  • githubアクションを使用およびワークフロー
  • Python プロジェクトのリンティング、テスト、 デプロイメントを自動化します。
  • 安全な資格情報自動化に使用されます
  • セキュリティと依存関係の更新を自動化します

このチュートリアルでは、CI/CD パイプラインを作成する開始点として既存のコードベースである Real Python Reader を使用します。 GitHub 上の Real Python Reader コードをフォークして、従うことができます。フォークするときは、必ずmaster ブランチのみをコピーするオプションを選択解除してください。あるいは、必要に応じて、前のチュートリアルを使用して独自の Real Python Reader を構築することもできます。

このチュートリアルを最大限に活用するには、pip、Python パッケージの構築、Git に慣れており、YAML 構文にある程度慣れている必要があります。

Githubアクションを掘り下げる前に、一歩後退してCI/CDの利点について学ぶことが役立つ場合があります。これは、GitHubアクションが解決できる問題の種類を理解するのに役立ちます。

CI/CD の利点を最大限に活用する

一般にCI/CDとして知られる継続的インテグレーション (CI)継続的デプロイメント (CD) は、現代のソフトウェア開発において不可欠な手法です。これらのプラクティスにより、コード変更の統合、テストの実行、アプリケーションのデプロイメントが自動化されます。これにより、チームやオープンソースの貢献者は、信頼性が高く構造化された方法でコード変更をより頻繁に提供できるようになります。

さらに、CI/CDは、オープンソースPythonパッケージを公開するときに、すべてのプルリクエスト(PRS)とパッケージへの貢献により、コードの品質を標準化しながらプロジェクトのニーズを満たすことが保証されます。

コードの変更が小さいため、より頻繁に展開する意図しない壊れた変化のリスクを減らしますより大きく、より複雑なリリースで発生する可能性があります。たとえば、開発者は同じまとめツールとルールを使用してすべてのコードをフォーマットできますが、ポリシーは、コードのテストが合格しない場合、PRSがマージされるのを自動的にブロックできます。

次のセクションでは、GitHubワークフローがGitHubでホストされているリポジトリにCI/CDを実装するのに役立つ方法を学びます。

GitHub ワークフローの探索

GitHub ワークフローは、GitHub Actions の強力な機能です。これらを使用すると、リポジトリのカスタム自動化ワークフローを定義できます。コードをビルド、テスト、デプロイする場合でも、GitHub ワークフローは、リポジトリがパブリックかプライベートかに関係なく、GitHub 上のプロジェクトが無料で使用できる柔軟でカスタマイズ可能なソリューションを提供します。

CI/CD プロバイダーは数多くありますが、GitHub Actions は、その広大なエコシステム、柔軟性、低コストまたは無料のため、GitHub 上のオープンソース プロジェクトのデフォルトとなっています。

ワークフロー ファイルの構造

ワークフローファイルは、ワークフローを正常に実行するために順守する必要がある定義済みの構造を持つYAMLファイルと宣言的に記述されています。 YAMLワークフローファイルは、プロジェクトのルートディレクトリの .github/workflows/フォルダーで保存および定義されています。

ワークフローフォルダーには複数のワークフローファイルがあり、それぞれが特定のタスクを実行します。これらのワークフローファイルを何でも名前にすることができます。ただし、シンプルさと読みやすさのために、 test.yml など、彼らが達成したタスクにちなんで名前を付けるのが一般的な慣行です。

各ファイルには必要な要素がいくつかありますが、オプションの多くの要素があります。 GitHubアクションドキュメントは徹底的でよく書かれているので、このチュートリアルを読んだ後は必ずチェックしてください。

ワークフロー ファイルの大部分を構成する主要な部分は、トリガージョブステップの 3 つです。これらについては次のセクションで説明します。

ワークフロートリガー

トリガーは、ワークフローを実行するイベントです。多くの種類のトリガーがあります。最も一般的なものは、次のことで発生するものです。

  • プルリクエスト
  • デフォルトのブランチにコミットをプッシュしました
  • タグ付きコミット
  • 手動トリガー
  • 別のワークフローによるリクエスト
  • 新しい号がオープン中です

また、特定のブランチまたはファイルのセットに制限することにより、トリガーをさらに制限することもできます。メインブランチへの のプッシュでワークフローを実行するトリガーの簡単な例を次に示します。

on:
  push:
    branches:
      - main

このチュートリアルでは説明されていないトリガーの詳細については、公式ドキュメントをご覧ください。

イベントがワークフローをトリガーする方法がわかったので、ワークフローファイルの次のコンポーネントであるJobsを探索する時が来ました。

ワークフロージョブ

各ワークフローには 1 つの jobs セクションがあり、これがワークフローの中身のコンテナです。ワークフローには、実行する 1 つ以上のジョブを含めることができ、各ジョブには 1 つ以上のステップを含めることができます。

このセクションが手順を省略した場合の例を次に示します。

# ...

jobs:
  my_first_job:
    name: My first job
  my_second_job:
    name: My second job

ジョブを作成するときに最初に行うことは、ジョブの実行に使用するランナーを定義することです。 runner は、ジョブを実行する GitHub でホストされる仮想マシン (VM) です。 GitHub が VM をプロビジョニングおよびプロビジョニング解除するため、CI/CD のインフラストラクチャの維持について心配する必要はありません。

サポートされているオペレーティング システムが複数あります。 GitHub でホストされているランナーの完全なリストはドキュメントにあります。

ランナーを定義するには、YAMLの単一ラインほどほとんど必要となります。

# ...

jobs:
  my_first_job:
    name: My first job
    runs-on: ubuntu-latest
    # ...
  my_second_job:
    name: My second job
    runs-on: windows-latest
    # ...

上記の例では、my_first_job は Ubuntu VM 内で実行され、my_first_job は Windows VM 内で実行されます。この場合、両方とも -latest 接尾辞を使用しますが、サポートされているものであれば、オペレーティング システムの正確なバージョン (たとえば、ubuntu-20.24) を指定することもできます。バージョン。

ワークフローのステップ

ステップは仕事の主要な部分です。おそらく推測したように、ステップは、ワークフローを実行するときに実行する必要があるアクションを宣言します。これには、Pythonのインストール、テストの実行、コードの染色、別のGitHubアクションの使用などのタスクが含まれます。

Pythonコードと同様に、一般的で繰り返し可能なタスクを別々のワークフローに抽象化して再利用できます。これは、Pythonライブラリをインポートする際の方法と同様に、他の人のgithubアクションを独自のワークフローで使用できることを意味し、その機能を再現する時間を節約する必要があります。

次のセクションでは、他のGitHubアクションを使用する方法とそれらを見つける方法を確認します。

Python 用の GitHub アクションの使用

ワークフローはGitHubアクションの一部ですが、ワークフローにはGitHubアクションも含まれています。言い換えれば、ワークフローで他の人や組織の行動を使用できます。実際、それは一般的な慣行であり、ワークフローファイルで既存のGitHubアクションを使用することを強く奨励されています。このプラクティスにより、事前に構築された機能を活用することで時間と労力を節約できます。

達成する特定のタスクがある場合、それを行うために利用できるGithubアクションがおそらくあります。 GitHub Marketplaceで関連するGitHubアクションを見つけることができます。これについては、次に飛び込みます。

Github Marketplaceの探索

GitHub Marketplace は、ユーザーが独自のワークフローで使用できるすべてのアクションのオンライン リポジトリです。 GitHub、サードパーティ ベンダー、および個人は、これらの GitHub アクションを構築および維持します。誰でも GitHub Action テンプレートを使用して独自のアクションを作成し、マーケットプレイスでホストできます。

これにより、ほぼすべての種類のタスクオートメーションが想像できる膨大な数のGitHubアクションが利用可能になりました。 Github Marketplaceのすべてのアクションはオープンソースであり、無料で使用できます。

次のセクションでは、すべてのPythonプロジェクトに使用する2つのGitHubアクションを調べます。

ワークフローにアクションを含める

作成するすべてのPythonベースのワークフローは、現在のリポジトリをワークフロー環境にチェックアウトするだけでなく、Pythonをインストールしてセットアップする必要があります。幸いなことに、GitHubには両方のタスクを支援する公式のGithubアクションがあります。

# ...

jobs:
  my_first_job:
    name: My first job
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.13"
      - run: python -m pip install -r requirements.txt

上の例では、steps の最初のステップが公式の checkout アクションを使用することであることがわかります。このアクションにより、コードがリポジトリから現在の GitHub ワークスペースにチェックアウトされ、ワークフローがアクセスできるようになります。 checkout に続く @4 は、使用するアクションのバージョンを示すバージョン指定子です。現時点での最新バージョンは v4.2.2 なので、この構文を使用して最新のメジャー バージョンを指定して参照できます。

この例の 2 番目のステップでは、環境内に Python をセットアップします。繰り返しますが、この例では、継続的なサポートと開発のため、公式の GitHub Action を使用してこれを実行します。すべてではないにしても、ほとんどのアクションには、ステップに追加できる追加の構成があります。

セットアップPythonアクションドキュメントには、構成の完全なリストが含まれています。今のところ、Pythonをワークフロー環境にインストールする必要がある最小限は、インストールするPythonのバージョンを宣言することです。

例の最後のステップでは、 run コマンドを使用します。このコマンドを使用すると、ステップに使用しているランナーに応じて、 bash または powerShell コマンドを実行できます。この場合、要件ファイルからプロジェクトの依存関係をインストールしています。

うまくいけば、GitHubアクションがどれほど強力かを確認できます。コードと労力がほとんどないため、Pythonプロジェクトの構築、テスト、展開の準備が整った環境をセットアップする再現性のある方法があります。

これで、ワークフロー ファイルの構造と、プロジェクトの最初のワークフローを作成する方法についての基本を理解できました。次のセクションでは、実際の例を使用してこれを実行します。

初めてのワークフローの作成

CI/CDを既存の現実世界のプロジェクトであるReal Python Readerに追加する手順を歩いてみましょう。 このパッケージをテストして展開するためのワークフローを追加する前に、まず糸くずから始めてください。

リンターは、コードを分析し、エラー、スタイルの問題、および疑わしい構成を探すツールです。 lint を使用すると、他の人と共有する前に問題に対処し、コードの品質を向上させることができます。 lint を使用して CI/CD を開始すると、パッケージを PyPI にデプロイする前に、コードがクリーンで読みやすいことを確認できます。

このワークフローでは、Ruffを使用してPythonコードを並べます。ただし、まだお持ちでない場合は、最初にすべてのブランチを含むリポジトリをフォークしてからクローンを作成します。必ず Your-Username をGitHubユーザー名に置き換えてください。

$ git clone git@github.com:your-username/reader.git
$ cd reader/
$ git checkout github-actions-tutorial
$ mkdir -p .github/workflows/

Forked Repositoryをクローンして現在の作業ディレクトリを変更した後、 github-actions-tutorial という名前の既存のブランチに切り替える必要があります。そのようなブランチが利用できない場合、フォーキング時にマスターオプションのみを copy copy を解除するのを忘れてしまう可能性が高いです。そのような場合、フォークを削除し、元のリポジトリに戻り、再度フォークし、今回はすべてのブランチを含めることを確認する必要があります。

正しいブランチに正常に切り替えられたら、ワークフローを保存するフォルダーを作成します。このフォルダーは workflows/ という名前で、.github/ フォルダーのサブディレクトリにする必要があります。

これで、トリガーを定義し、環境をセットアップし、ラフをインストールする最初のワークフローを作成する準備ができました。開始するには、 lint.yml ファイルでトリガーを定義できます。

name: Lint Python Code

on:
  pull_request:
    branches:
      - master
  push:
    branches:
      - master
  workflow_dispatch:

必須ではありませんが、それぞれのワークフローに明確で人間の読み取り可能な名前を与えることはベストプラクティスと見なされます。この名前は、GitHubリポジトリのアクションタブの左列に表示されます。利用可能なワークフローを特定し、以前のワークフローの実行を介してフィルタリングするのに役立ちます。

名前を定義した後、このワークフローのトリガーに焦点を移すことができます。上記のコードには、ワークフローを開始できる3つの異なるトリガーが定義されています。

  1. プルリクエストを開く
  2. ローカルコミットのプッシュ
  3. ワークフローを手動で派遣します

最初の 2 つは、master ブランチ上のプッシュまたはプル リクエスト イベントでワークフローをトリガーします。つまり、コードを変更すると、master に直接プッシュするか、プル リクエストを使用してコードを master ブランチにマージするかに関係なく、このワークフローが実行されます。リポジトリ。

最終トリガーが何をするかは明らかではありません。ドキュメントによると、期限切れのAPIキーなど、コードの変更とは無関係に失敗したワークフローを再実行するために一般的に使用されています。ただし、トリガーは、ワークフローファイルがデフォルトのブランチにある場合にのみ機能します。

トリガーが定義されていると、ジョブを定義し、環境を構成するワークフローファイルを作成する次のステップに進みます。

name: Lint Python Code

on:
  pull_request:
    branches:
      - master
  push:
    branches:
      - master
  workflow_dispatch:

jobs:
  lint: # The name of the job
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.13"
          cache: "pip"

このコードのほとんどは、以前の例からは馴染みがあるはずですが、いくつかの小さな違いがあります。まず、ジョブ lint に名前を付けて、それが何をするかを説明しました。これは単なる名前なので、YAMLの構文に準拠している限り、好きな名前を選択できます。また、このワークフローに使用するランナーを ubuntu-latest として定義しました。

次に、 setup-python アクションが、インストールされているパッケージのPIP依存関係をキャッシュするように構成されていることに気付くでしょう。これにより、パッケージのバージョンが同じ場合、将来の実行でワークフローをスピードアップできます。 Pypiからそれらを引っ張る代わりに、キャッシュバージョンを使用します。

ワークフローにトリガーとランナーが定義され、コードのチェックアウトと Python がインストールされたので、Ruff をインストールして実行してコードを lint します。これを行うには、lint ジョブにさらに 2 つのステップを追加します。

name: Lint Python Code

on:
  pull_request:
    branches:
      - master
  push:
    branches:
      - master
  workflow_dispatch:

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.13"
          cache: "pip"
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          python -m pip install ruff

      - name: Run Ruff
        run: ruff check --output-format=github

lint ジョブの最後の 2 つのステップでは、前に見た run コマンドを使用します。 YAML 構文の一部として、2 行目にパイプ (|) 記号があることに気づくでしょう。これは複数行の文字列を表します。 run コマンドは、次の行を個別のコマンドとして解釈し、順番に実行します。

Ruffをインストールした後、ワークフローはラフを実行して糸くずエラーを探すことで最終的に終了します。このコマンドを使用すると、 github ワークフローでの実行に出力を最適化することを指定できます。

おめでとう!最初のワークフローを完了しました。このワークフローがリポジトリにコミットしてプッシュすると、GitHubはトリガー条件が満たされたときにこの糸くずのワークフローを自動的に実行します。また、GitHub Webサイトでいつでもこのワークフローを手動でトリガーすることもできます。これを行うには、リポジトリの[アクション]タブに移動し、左側から目的のワークフローを選択し、[ワークフローを実行] [/em>]をクリックします。

ベルトの下にワークフローがあり、ワークフローがどのように機能するかを理解したので、今度はReal Pythonリーダーでテストスイートを実行するものを作成する時が来ました。

自動テストワークフローの作成

最初のGitHubワークフローで足を濡らしたので、今度はこのパッケージのすべてのワークフローの中で最も重要なものである自動テストを見る時が来ました。

実際のPythonリーダーは、 pytest をテストフレームワークとして使用します。また、GitHubアクションについてすでに学んだことを考えると、糸くずのワークフローを編集してテストワークフローに変える方法を確認することもできます。結局のところ、同じ手順に従って pytest を実行する準備をします。ソフトウェアパッケージをテストするときは、Pythonのサポートされているすべてのバージョンでテストする必要があることに注意することが重要です。

しかし、最初に、すべてのGitHubワークフローと同様に、テストワークフローのトリガーを宣言する必要があります。

name: Run Tests

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
  workflow_call:
  workflow_dispatch:

上記の多くは、以前の糸くずワークフローと同じですが、1つの違いがあります。現在、新しいトリガーがあります。 workflow_dispatch と同様に、 workflow_call は、他のワークフローをトリガーする事前定義されたトリガーです。

つまり、コードを繰り返す代わりに、テストに合格する必要がある将来のワークフローがある場合、新しいワークフローにこのテストワークフローを使用するように依頼することができます。このワークフローは、このテストワークフローをその手順の1つとしてトリガーし、ジョブの他のステップに進む前に通過することを確認します。したがって、繰り返しはもうありません。また、ワークフローを短くしてポイントに保つことができます。

test.yml ワークフローでこのワークフローの再利用方法を使用することはありませんが、を使用して、ワークフローファイルの他のgithubアクションを呼び出すのと同じ方法でこれを達成します。 キーワード:

# Github-username/repo/path/to/workflow@version
- uses: realpython/reader/.github/workflows/test.yml@master

ここでは、パスのような文字列をにに渡すことで、ワークフローを再利用できることがわかります。 GitHubユーザー名とリポジトリ名から始めて、使用するワークフローファイルへのパスが続きます。 @master 新しいワークフローに、 Master ブランチからテストワークフローのバージョンを使用することを伝えます。そして今、あなたはGithubアクションがどれほど強力かを見ることができます。ワークフローの再利用は、GitHubアクションの大きな利点です。

テスト ワークフローのトリガーを定義したので、次は「複数のバージョンの Python でどのようにテストするのか?」という質問に答えます。次のセクションでは、ステップを一度定義して、異なるバージョンの Python で各実行で複数回実行する方法を説明します。

複数のバージョンの Python でのテスト

lint ワークフローでは、stepssetup-python アクションを使用して、Ubuntu インスタンスに Python 3.13 をセットアップしました。これは次のようになります。

# ...

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.13"
          cache: "pip"
      # ...
# ...

残念ながら、Python バージョンのリストを python-version に追加するだけで完了というわけではありません。必要なのは、複数のバージョンの Python でテストするための strategy マトリックスです。

公式ドキュメントを引用するには:

マトリックス戦略により、単一のジョブ定義で変数を使用して、変数の組み合わせに基づいた複数のジョブ実行を自動的に作成できます。たとえば、マトリックス戦略を使用して、言語の複数のバージョンまたは複数のオペレーティングシステムでコードをテストできます。 (ソース)

要するに、 matrix で定義する変数はすべて、ジョブで同じ手順を実行しますが、それらの変数を使用します。ここでは、Pythonのさまざまなバージョンで実行する必要がありますが、これを使用して、さまざまなオペレーティングシステムでコードを実行または構築することもできます。

戦略を宣言することは比較的簡単です。あなたの手順を定義する前に、しかしあなたの仕事の一部として、あなたはあなたの必要な戦略を定義することができます:

name: Run Tests

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
  workflow_call:
  workflow_dispatch:

jobs:
  testing:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]

ご覧のとおり、バージョン番号の配列である変数 python-version を宣言しています。素晴らしい、これで最初の部分が完了しました。 2 番目の部分では、特別な変数構文を使用して、これらのバージョンを使用することを setup-python アクションに伝えます。

name: Run Tests

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
  workflow_call:
  workflow_dispatch:

jobs:
  testing:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]

    steps:
      - uses: actions/checkout@v4
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
          cache: "pip"

ワークフローのPythonセットアップステップには2つの変更があります。 1つ目は、ステップに追加された名前です。前に学んだように、これは必須ではありませんが、ステップの名前でPythonバージョンを参照することで失敗したPythonバージョンを特定するのに役立ちます。このステップが5つの異なるバージョンのPythonで実行されることを考えると、これは役立ちます。

2番目の変更は、バージョン番号をにハードコーディングする代わりに、python-version setup-python の一部で、 python-を参照できることです。バージョンマトリックスで定義されています。

GitHubには、ワークフローの一部としてアクセスできる特別なコンテキストがいくつかあります。マトリックスはこれらの1つです。マトリックスを戦略の一部として定義することにより、 python-version がマトリックスコンテキストのプロパティになりました。これは、ドット()構文を使用して行列の一部として定義された変数にアクセスできることを意味します。たとえば、 matrix.python-version

これは、実際のPythonリーダーのために行う必要があるものではありませんが、異なるOSバージョンでも同じことができます。例えば:

strategy:
  matrix:
    os: [ubuntu-latest, windows-latest]

次に、同じドット表記を使用して、 matrix.os を使用してマトリックスで定義した os 変数にアクセスできます。

マトリックスを使用して、Python の別のバージョンを使用してステップを宣言的に実行する方法がわかったので、テスト ワークフローを完全に完了します。

テストワークフローの完成

ワークフローを完了するには、あといくつかの手順が必要です。 Python がインストールされたので、ワークフローでは開発者の依存関係をインストールし、最後に pytest を実行する必要があります。

Real Python Reader パッケージは、依存関係を宣言するために pyproject.toml 構成ファイルを使用します。また、pytest を含む、オプションの開発者の依存関係もあります。 run コマンドを使用して、前に Ruff をインストールしたのと同じ方法でインストールできます。

name: Run Tests

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
  workflow_call:
  workflow_dispatch:

jobs:
  testing:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]

    steps:
      - uses: actions/checkout@v4
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
          cache: "pip"

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          python -m pip install .[dev]

この手順は、必要な依存関係をインストールするために必要なすべてです。残りのステップは、 pytest を実行することです。

name: Run Tests

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
  workflow_call:
  workflow_dispatch:

jobs:
  testing:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]

    steps:
      - uses: actions/checkout@v4
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
          cache: "pip"

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          python -m pip install .[dev]

      - name: Run Pytest
        run: pytest

この時点で、マスターでPRまたはプッシュイベントが発生するたびにトリガーされる糸くずとテストのワークフローの両方があります。次に、CI/CDのCD部分に注意を向け、Pypiにパッケージを自動的に公開する方法を学びます。

パッケージを PyPI に自動的に公開する

3 番目のワークフローは、ほとんどの人が最小限の CI/CD パイプラインとみなしているものを完成させます。この 3 番目のワークフローは、パッケージを構築して公開するための再現可能で一貫した方法を提供します。 Real Python Reader パッケージは、広く使用されている Python build ライブラリを利用して Python 配布ファイルを生成し、これを PyPI にデプロイできます。

ワークフローがもう少し複雑になり、複数のステップまたはジョブがある場合は、手順とフローを書き出すことをお勧めします。これにより、すべての手順を正しい順序で取得して、使用するgithubアクションが最初から正しく構成されます。これにより、ビルドワークフローの潜在的なバグを回避するのに役立つことにより、時間を節約できます。

deploy.yml ファイルのワークフロー手順は次のとおりです。

  1. Pythonをインストールして依存関係を構築して環境を設定します
  2. 出力ファイルを dist/フォルダーに配置して、パッケージを作成します
  3. 配布ファイルをPypiに公開します
  4. 正常に公開された場合は、GitHub リリースを作成します。

次のセクションでは、リストの最初の2つの項目に取り組み、ワークフローのかなりの部分を書き込みます。

パッケージのセットアップと構築

過去2つのワークフローと同様に、最初のステップは、ワークフローのトリガーを定義することです。典型的な開発者ワークフローを中心に展開する一般的なトリガーを見てきましたが、新しいPRまたはメインブランチへのプッシュごとに自動的にリリースすることは、実際のPythonリーダーには理想的ではありません。

いくつかのプルリクエスト、バグ修正、または新しい機能を追加した後、パッケージのバージョンをパッケージのバージョンにぶつける方が理にかなっています。バージョンバンプの後にこのようなリリースをトリガーする最新の方法は、開発者の親友であるGitを使用することです。

GITを使用すると、ソフトウェアの開発における顕著な時点を示すためにコミットにタグを付けることができます。これは、多くの場合、新しいリリースを定義するための選択ツールです。 githubアクションには、タグキーワードをトリガーするgitタグを使用するための組み込みサポートがあります。

name: Publish to PyPI
on:
  push:
    tags:
      - "*.*.*"

ここでわかるように、トリガーは glob パターンもサポートしています。したがって、アスタリスク (*) はシーケンス内の任意の文字と一致します。上記のパターンは、任意の文字、その後に小数点 (.)、別の文字、別の小数点、そして最後に別の文字と一致します。

これは、1.0.0 は 2.5.60 と同様に有効な一致であることを意味します。これは、Real Python Reader で使用されるセマンティック バージョニングと一致します。必要に応じて、代わりに v*.*.* を使用することもできます。したがって、Git タグは、バージョン を表す v で始まる必要があります。たとえば、v1.0.0 は有効なタグです。

このワークフローをトリガーするには、バージョン名でコミットにタグを付けます。

$ git tag -a "1.0.0" -m "1.0.0"
$ git push --tags

新しいタグを GitHub にプッシュすると、このワークフローがトリガーされます。次に、環境をセットアップし、依存関係をインストールします。

name: Publish to PyPI
on:
  push:
    tags:
      - "*.*.*"

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: "3.13"

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        python -m pip install .[build]

    - name: Build package
      run: python -m build

まず、 publish ジョブを定義し、python 3.13をubuntu VMにインストールします。次のステップでは、実際のPythonリーダーのビルド依存関係をインストールします。最後のステップでは、以前に使用した同じ run コマンドを使用しますが、今回はruffまたは pytest を実行する代わりに、実際のpythonリーダーを構築するパッケージ。デフォルトでは、 build は、分布ファイルを dist というフォルダーに配置します。

素晴らしい!ワークフロー計画の最初の 2 つの主要な部分を実装しました。 PyPI にデプロイする前に、PyPI API トークンを安全に保つ方法を理解しておく必要があります。

秘密を安全に保つ

前に学んだように、ワークフローは matrix などの特別なコンテキストにアクセスできます。すべてのワークフローがアクセスできるもう 1 つのコンテキストは、secrets コンテキストです。機密データをリポジトリ シークレットとして保存することで、API キー、パスワード、その他の認証情報が誤って漏洩することがなくなります。ワークフローは、secrets コンテキストを使用して、これらの機密認証情報にアクセスできます。

GitHub Web サイトでリポジトリにシークレットを追加できます。追加すると、表示したり編集したりすることはできません。それらを新しい値に置き換えることのみが可能です。 GitHub ドキュメントを参照して、GitHub Web サイトにシークレットを追加する方法を確認することをお勧めします。公式ドキュメントは UI の変更に応じて継続的に更新されるため、この GitHub 機能の使用方法を学習するための最良のソースになります。

パッケージを展開します

API キーを GitHub シークレットとして保護したら、ワークフローでアクセスできるようになります。

name: Publish to PyPI
on:
  push:
    tags:
      - "*.*.*"

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: "3.13"

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        python -m pip install .[build]

    - name: Build package
      run: python -m build

    - name: Test publish package
      uses: pypa/gh-action-pypi-publish@release/v1
      with:
        user: __token__
        password: ${{ secrets.PYPI_API_TOKEN }}
        repository-url: https://test.pypi.org/legacy/

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

このステップでは、Pypiを管理するPython Packaging Authority(PYPA)の公式Githubアクションを使用できます。このGitHubアクションはほとんどの作業を行い、Pypi APIトークンへの参照のみが必要です。繰り返しますが、デフォルトでは、アップロードするパッケージの新しいバージョンの dist フォルダーを調べます。

PyPI への認証に従来のユーザー名とパスワードを使用するのではなく、自動リリースにはスコープ指定された API トークンを使用することがベスト プラクティスです。

APIトークンを使用しており、ユーザー名はないため、 __トークン__ を使用して、ユーザー名がGithubアクションにトークン認証が使用されていることを伝えます。以前のMatrix戦略と同様に、 secrets.pypi_api_token のように、DOT表記を使用して秘密のコンテキストにアクセスできます。

Githubに保管されているときの秘密の名前は、それがあなたにとって理にかなっている限り、重要ではありません。 Github Secretの名前は pypi_api_token です。そのため、その名前を使用してワークフロー内で参照します。

パッケージをPYPIに公開する前に、ワークフローにテストステップが含まれていることに気付いたかもしれません。このステップは、公開ステップとほぼ同じです。1つの重要な違いがあります。 repository-url を提供する必要があります。

TestPyPI の使用は、パッケージが正しくビルドされ、バージョン管理されていることを確認する優れた方法です。これにより、メインの PyPI リポジトリに公開するときに問題を引き起こす可能性のある潜在的な問題を特定して対処できます。

リポジトリの独自のフォークに従っていて、バージョンを PyPI にプッシュする場合は、プロジェクトの名前を一意の名前に更新する必要があります。プロジェクト名を更新しない場合、プロジェクトをアップロードしようとすると HTTP 403 エラーが発生します。これは、realpython-reader パッケージを PyPI に公開する権限がないためです。プロジェクト名を更新すると、独自のバージョンを公開できるようになります。

たとえば、プロジェクト名の接頭辞としてユーザー名を追加できます。

[build-system]
requires      = ["setuptools>=61.0.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "username-realpython-reader"
# ...

ワークフローにはもう1つのステップがあります。GitHubリリースを作成してリリースを促進し、直接共有します。これを行う前に、GitHub環境変数について学びます。

GitHub環境変数へのアクセス

GitHubリポジトリにリリースを公開するには、GitHubトークンが必要です。 GitHub APIを使用したことがある場合は、これらを以前に使用したことがあります。ワークフローで個人のGithubトークンを使用するセキュリティリスクを考えると、Githubはデフォルトで秘密のコンテキストで読み取り専用トークンを作成します。これは、必要に応じて常にアクセスできることを意味します。

さらに、すべてのGithubランナーには、デフォルトで便利なGithub CLIが含まれています。これにより、リリースを作成するなど、特定のタスクを実行することができます。 Github CLIには、ユーザーを認証する多くの方法があります。その1つは、 github_token と呼ばれる環境変数を設定することです。

これがどこに向かうのかがわかるかもしれません。提供された GitHub トークンを使用して CLI にアクセスし、最終的には GitHub リリースを作成するシームレスな方法を作成できます。ワークフローでは次のようになります。

name: Publish to PyPI
on:
  push:
    tags:
      - "*.*.*"

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: "3.13"

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        python -m pip install .[build]

    - name: Build package
      run: python -m build

    - name: Test publish package
      uses: pypa/gh-action-pypi-publish@release/v1
      with:
        user: __token__
        password: ${{ secrets.PYPI_API_TOKEN }}
        repository-url: https://test.pypi.org/legacy/

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

    - name: Create GitHub Release
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      run: |
        gh release create ${{ github.ref_name }} ./dist/* --generate-notes

39 行目と 40 行目で、ワークフローが特に GitHub トークンをシークレット コンテキストから GITHUB_TOKEN という環境変数に割り当てていることがわかります。 env に設定されたキー値はすべて、現在のステップの環境変数として設定されます。これは、GitHub CLI (gh) を実行すると、割り当てられた環境変数を通じてトークンにアクセスできることを意味します。 GitHub CLI は、シークレット コンテキスト自体に直接アクセスできません。

Githubでは、 github という特別なコンテキストにアクセスすることもできます。ワークフローは、 github コンテキストの ref_name 属性を参照します。これは、GitHubドキュメントで次のように定義されています。

ワークフローの実行をトリガーしたブランチまたはタグの短いREF名。 (ソース)

したがって、github.ref_name は、ワークフローをトリガーした属性 (この場合は Git タグの名前) に置き換えられます。

上記の gh コマンドは、リリースのトリガーに使用されたタグと同じ名前でリリースを作成し、./dist からすべてのファイルをアップロードし、リリース ノートを自動生成します。これらのリリース ノートには、開発者が前回のリリースを作成してからマージしたすべての PR が含まれており、作成者の貢献に対するリンクとユーザー名を適切にクレジットします。

不足している詳細をリリース ノートに追加することもできます。非推奨の通知などの追加情報を含める必要がある場合は、リリースを作成後に編集できることに注意してください。

おめでとう!これで、自動化された糸くず、テスト、展開が整っています。最新のコミットにタグを付けることができ、最終的な展開ワークフローは正常に実行されるはずです。

Real Python Reader には、将来のコードベースの変更が堅牢であり、読みやすく一貫性のあるコードが使用されることを保証する CI/CD パイプラインが備わっているため、Real Python Reader にワークフローを 1 つ追加できます。いわば、CI/CD ケーキの上のチェリーです。

次のセクションでは、セキュリティと依存関係の更新を自動化するためにDependAbotを構成する方法を学びます。

セキュリティと依存の更新を自動化します

Python コードと同様に、GitHub ワークフローも維持し、最新の状態に保つ必要があります。さらに、Real Python Reader コードが依存するライブラリは常に変更および更新されるため、依存関係を維持して管理するのは困難です。

GitHub やソーシャル メディアでプロジェクトを積極的にフォローしていない場合、依存関係によってリリースされたセキュリティ アップデートに関する最新情報を入手し続けるのは特に困難です。幸いなことに、GitHub には両方の問題を解決する便利なツールがあります。ディペンダボットを入力してください!

Depenabotは、依存関係のセキュリティの脆弱性を通知するだけでなく、構成されている場合、PRを自動的に作成して問題を更新および修正する自動化ツールです。あなたがしなければならないのは、自動化されたPRを確認してマージすることだけです。 Depenabotを使用すると、パッケージを最新の状態に保ち、既知のセキュリティの脆弱性を迅速かつ簡単に保ち、コードを改善したり、新しい機能を追加したりするために使用できる時間を節約できます。

プロジェクトのニーズを満たすように dependabot を構成できます。ここで、Real Python Reader パッケージにはかなり基本的な要件があります。 2 つの目標は次のとおりです。

  1. 利用可能な依存関係の更新があるときに通知を受け取るには。
  2. 他のワークフローを最新の状態に保つため。

これらの要件は、dependabot.yml という構成ファイルで定義されます。他のワークフローとは異なり、dependabot.yml ファイルは、.github/workflowsなく、.github フォルダー自体に存在します。code>。

このファイルの長さはわずか 12 行であり、YAML 構文に慣れてきたので、最終的な dependabot 構成を見てみましょう。

---
version: 2
updates:
  - package-ecosystem: "pip"
    directory: "/"
    schedule:
      interval: "weekly"

  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"

バージョンプロパティは、ファイルの必須部分です。これは、使用するDependAbotのバージョンを定義する場所であり、バージョン2が最新です。別の必須セクションは更新です。これは、構成の大部分が進む場所です。各更新では、チェックするパッケージエコシステムを定義し、どのディレクトリDeparabotが検索すべきか、どの程度の頻度で検索すべきかに関する基本情報を定義します。

最初の更新では、depandabotは、要件など、 pip 依存関係が通常宣言される一般的なファイルを確認します。 。実際のPythonリーダーには、ルートディレクトリに pyproject.toml ファイルがあるため、depandabotは、フォワードスラッシュ( "/" )で示されるように、そこを見るように指示されます。

依存関係の更新を通知したい頻度はあなた次第です。各プロジェクトには独自の要件があります。ただし、YAMLで宣言することは、ケイデンスが多すぎる、または十分でない場合、それが迅速かつ単純な変更であることを意味します。今のところ、 weekly を使用できます。

updates リストの2番目の項目は、 github-actions のものです。そうです、Depenabotは、新しいバージョンの場合、 setup-python など、リポジトリの任意のワークフローで使用されるgithubアクションも確認します。これにより、GitHub Actionsの最新バージョンに自動化され、心配する必要があるものは1つ少なくなります。

この構成を整えると、Depenabotは週に1回リポジトリをスキャンしてチェックして、依存関係やワークフローにできる更新があるかどうかを確認します。自動的に修正を備えたPRが作成されます。 DepenabotのこれらのPRは、他のワークフローを実行して、Depenabotの変更が糸くずとテストチェックを通過させることを確認します。ダブルウィン!

次のステップ

Issue Triage、Labeling、古い問題管理、PRS へのレビュー担当者の追加など、リポジトリが成長するにつれて自動化できる他の多くのタスクがあります。

また、GitHub Actions は CI/CD のプロバイダーの 1 つにすぎないことにも留意してください。プロジェクトが GitHub でホストされている場合、GitHub Actions を使用すると作業が簡単になります。コードが別のプラットフォーム上にある場合、または代替手段を試したい場合は、他の CI/CD プロバイダーの短いリストを次に示します。

  • GitLab
  • Azureパイプライン
  • Circleci
  • トラヴィスCI

これらのプロバイダーのいずれかをすでに使用している場合、またはリストにないプロバイダーを使用している場合は、お気軽にコメント欄で声を上げて、経験を共有してください。

結論

GitHubアクションを使用して、Pythonプロジェクトに堅牢なCI/CDパイプラインを実装する方法を知っています。このチュートリアルの目標は、既存のコードベースにCI/CDを追加する方法を学ぶためのものでしたが、自分のプロジェクトやパッケージを操作し、独自のワークフローをゼロから作成するのに十分なことを知っていることを願っています。

このチュートリアルでは、次の方法を学習しました。

  • GitHub アクションワークフローを使用します。
  • Python プロジェクトのリンティング、テスト、 デプロイメントを自動化します。
  • 安全な資格情報自動化に使用されます
  • セキュリティと依存関係の更新を自動化します

これらのプロセスを自動化することにより、プロジェクトの保守性と信頼性を大幅に改善しました。これで、コードの品質を確保し、テストを実行し、最小限の手動介入で新しいバージョンを展開する一貫した方法があります。

CI/CD は反復的なプロセスであることに注意してください。プロジェクトが成長し進化するにつれて、ワークフローを調整したり、新しいワークフローを追加したりすることが必要になる場合があります。 GitHub Actions の柔軟性により、変化する要件に簡単に適応できます。

これらのツールとプラクティスが整っていると、Pythonプロジェクトを効率的に管理および拡大する準備が整っています。