🚀

GitHub ActionsでPyInstallerを使ったWindows実行ファイルのリリース自動化

に公開

はじめに

Pythonアプリケーションを.exeファイルとして配布する際、PyInstallerを使うことが一般的ですが、手動でのビルドとリリース作業は手間がかかります。本記事では、GitHub ActionsとPyInstallerを組み合わせて、Windows実行ファイルのビルドからGitHubリリースまでを完全に自動化する方法をまとめます。

対象読者

  • Pythonアプリケーションを.exeファイルとして配布したい開発者
  • GitHub Actionsを使ったCI/CDに興味がある方
  • リリース作業を自動化したい開発者

前提条件

  • GitHubリポジトリでPythonプロジェクトを管理している
  • 基本的なGitHub Actionsの知識がある
  • PyInstallerを使ったことがある、または興味がある

全体方針

1. 対象環境とランナー

  • CI/CDツール: GitHub Actions

  • 実行環境: Windows ランナー(windows-latest

    • PyInstallerはクロスコンパイルに対応していないため、Windows向けビルドにはWindowsランナーが必須

2. トリガー設定

ワークフローのトリガーは2種類を想定:

通常のCI(ブランチpush/PR時)

  • 対象ブランチ: main, develop, feature/**

  • 実行内容:

    • Lint(コード品質チェック)
    • 型チェック
    • テスト実行
    • ビルド(.exe生成)
    • Artifactsへの成果物保存

リリース(タグpush時)

  • トリガー: タグpush(例: v1.2.3

  • 実行内容: 上記CI処理に加えて

    • GitHub Releaseの自動作成
    • .exeファイルとzipファイルの添付公開

3. ジョブ構成(署名なし版)

基本的なワークフローのステップ構成:

Step 1: Checkout

- uses: actions/checkout@v4

Step 2: Python環境セットアップ

  • デフォルト: Python 3.11
  • 必要に応じてマトリクスビルドで複数バージョン対応も可能
- uses: actions/setup-python@v5
  with:
    python-version: '3.11'

Step 3: 依存関係のインストール

  • requirements.txt があればそれを使用

  • なければ、以下をインストール:

    • pytest(テスト)
    • ruff(Lint)
    • mypy(型チェック)
    • pyinstaller(ビルド)
    • 開発インストール(pip install -e .

Step 4: Lint

ruff check src tests

Step 5: 型チェック

mypy src

Step 6: テスト

pytest -q --maxfail=1 --disable-warnings

Step 7: ビルド(PyInstaller)

  • your_tool.spec ファイルがあればそれを使用

  • なければコマンドラインオプションで実行:

    pyinstaller -F -n your_tool -p src src/your_tool/cli.py
    

Step 8: パッケージング

  • dist/your_tool.exepackage/your_tool-<version>.exe にコピー

  • zipファイルも作成

  • <version> の決定ルール:

    • タグpush時: タグ名(例: v1.2.3
    • それ以外: 0.0.0-<短縮コミットハッシュ>

Step 9: Artifactsアップロード(ブランチ/PR時)

  • ビルド成果物をArtifactsとして保存(保存期限付き)

Step 10: GitHub Release作成(タグpush時のみ)

  • リリースタイトル: your_tool vX.Y.Z

  • リリース本文: 簡易的なテンプレート

  • 添付ファイル:

    • dist/your_tool.exe
    • package/*.zip

4. リポジトリ構成の前提

推奨されるプロジェクト構造:

your-tool/
├─ src/
│  └─ your_tool/
│     └─ cli.py                # エントリポイント (main関数)
├─ tests/                      # pytestテストコード
├─ pyproject.toml              # or requirements.txt
├─ your_tool.spec              # PyInstaller設定(任意)
└─ .github/
   └─ workflows/
      └─ build-release.yml    # CI/CDワークフロー

重要なポイント:

  • cli.py には if __name__ == "__main__": main() の構成が推奨
  • 依存関係は requirements.txt または pyproject.toml で管理

5. バージョニングとリリース運用

タグを使ったリリースフロー

  1. 開発が完了したら、バージョンタグを作成:

    git tag v1.0.0
    git push origin v1.0.0
    
  2. GitHub Actionsが自動的にトリガーされ、Releaseが作成される

  3. Releaseページから.exeファイルとzipファイルをダウンロード可能に

開発中のビルド

  • タグなしの通常のCI実行時は、Artifactsから成果物を取得(期限付き保存)

6. セキュリティと配布の注意点(署名なし版)

SmartScreen警告について

  • コード署名なしの.exeファイルは、Windows SmartScreen警告が表示される
  • これは正常な動作であり、署名がないファイルに対する標準的なセキュリティ対策

社内配布での対応策

  • 許可リスト方式: WDAC(Windows Defender Application Control)やDefenderポリシーで許可
  • 配布手順の周知: ユーザーに警告画面の突破方法を説明
  • 社内ネットワーク配布: 信頼できるネットワーク経路での配布

将来的なコード署名導入

  • 予算に余裕ができたら、コード署名証明書の取得を検討
  • できればEV証明書を推奨(即座にSmartScreen警告を回避可能)

7. 追加オプション(段階的に導入可能)

アイコンとバージョン情報の埋め込み

pyinstaller --icon=app.ico --version-file=version_info.txt ...

データファイルの同梱とhiddenimports

  • .spec ファイルで詳細に管理
a = Analysis(
    ['src/your_tool/cli.py'],
    datas=[('data/*', 'data')],
    hiddenimports=['your_hidden_module'],
    ...
)

SBOMとセキュリティスキャン

  • Syft: SBOM(Software Bill of Materials)生成
  • Grype: 脆弱性スキャン

パッケージマネージャーへの配布

  • winget: Microsoftの公式パッケージマネージャー
  • Chocolatey: Windows向けパッケージマネージャー
  • 別ワークフローで自動登録を実装可能

マトリクスビルド

  • 複数のPythonバージョンでビルド&テストを実行
strategy:
  matrix:
    python-version: ['3.9', '3.10', '3.11', '3.12']

8. 実装チェックリスト

実際にCursorなどのエディタで作業する際の手順:

  • .github/workflows/build-release.yml ワークフローファイルの作成

    • 署名ステップは不要(初期段階)
  • src/your_tool/cli.py がエントリポイントになっているか確認

    • if __name__ == "__main__": の記述を確認
  • requirements.txt または pyproject.toml の準備

    • 必要な依存関係が全て記載されているか確認
  • PRを作成してCIが正常に動作するか確認

    • Artifactsから.exeと.zipファイルがダウンロードできること
  • タグpushでリリース動作を確認

    git tag v1.0.0
    git push origin v1.0.0
    
    • GitHub Releaseが自動作成されること
    • ファイルが正しく添付されていること

後続の最適化作業

  • .spec ファイルの最適化

    • アイコン設定
    • データファイルのバンドル
    • UPXによる圧縮
    • hiddenimportsの追加
  • リリースノートの自動生成

    • Changelog生成ツールの導入
    • コミットメッセージからの自動抽出

ワークフローファイルのサンプル

以下は基本的な .github/workflows/build-release.yml のサンプルです:

name: Build and Release

on:
  push:
    branches:
      - main
      - develop
      - 'feature/**'
    tags:
      - 'v*'
  pull_request:
    branches:
      - main
      - develop

jobs:
  build:
    runs-on: windows-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.11'
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install pytest ruff mypy pyinstaller
        if (Test-Path requirements.txt) {
          pip install -r requirements.txt
        }
        pip install -e .
    
    - name: Lint with ruff
      run: ruff check src tests
    
    - name: Type check with mypy
      run: mypy src
    
    - name: Test with pytest
      run: pytest -q --maxfail=1 --disable-warnings
    
    - name: Build with PyInstaller
      run: |
        if (Test-Path your_tool.spec) {
          pyinstaller your_tool.spec
        } else {
          pyinstaller -F -n your_tool -p src src/your_tool/cli.py
        }
    
    - name: Package artifacts
      run: |
        $version = if ($env:GITHUB_REF -match '^refs/tags/v(.+)$') {
          $matches[1]
        } else {
          "0.0.0-$($env:GITHUB_SHA.Substring(0,7))"
        }
        
        New-Item -ItemType Directory -Force -Path package
        Copy-Item dist/your_tool.exe package/your_tool-$version.exe
        Compress-Archive -Path dist/your_tool.exe -DestinationPath package/your_tool-$version.zip
    
    - name: Upload artifacts
      if: startsWith(github.ref, 'refs/tags/v') == false
      uses: actions/upload-artifact@v4
      with:
        name: your_tool-artifacts
        path: package/*
    
    - name: Create Release
      if: startsWith(github.ref, 'refs/tags/v')
      uses: softprops/action-gh-release@v1
      with:
        files: |
          dist/your_tool.exe
          package/*.zip
        body: |
          ## Release ${{ github.ref_name }}
          
          ### Changes
          - See commits for details
          
          ### Installation
          1. Download `your_tool.exe`
          2. Run the executable
          
          **Note**: Windows SmartScreen warning may appear (unsigned binary)
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

まとめ

この構成により、以下のメリットが得られます:

  1. 自動化によるミス削減: 手動ビルドとリリースのヒューマンエラーを防止
  2. 継続的品質保証: 全てのコミットに対してLint、型チェック、テストを自動実行
  3. 迅速なリリース: タグをpushするだけで数分でリリースが完了
  4. トレーサビリティ: 全てのビルドとリリースがGitHub上で管理される
  5. 段階的な改善: 基本構成から始めて、必要に応じて機能を追加できる

初期段階では署名なしで運用し、配布規模が大きくなってきたらコード署名の導入を検討するのが現実的なアプローチです。

参考リンク

次のステップ

この記事の内容を実装した後は、以下のような拡張も検討できます:

  • Linux/macOS向けのクロスプラットフォームビルド
  • Docker内でのビルド実行
  • 自動テストカバレッジレポート
  • 脆弱性スキャンの統合
  • より詳細なリリースノートの自動生成

この記事が、Pythonアプリケーションのリリース自動化の参考になれば幸いです。

Discussion