Automate packaging NiceGUI apps with PyInstaller and releasing them with Github Actions – a complete workflow

python
nicegui
pyinstaller
github-actions
Author

Yurkov Sergey

Published

April 19, 2024

Having learned the practice of CI/CD, I decided to apply this technique to continuously deliver some of my projects starting with a recent NiceGUI app – File Copier.

Initially, I went to Github Marketplace and searched for pre-build PyInstaller actions. Because I’m packaging for the Windows platform I ended up selecting PyInstaller Windows which is the most popular action in the category at the time of writing.

- name: PyInstaller Windows
  uses: JackMcKew/pyinstaller-action-windows@main
  with:
    path: src

The above code snippet shows how easy it is to integrate this action into the workflow. However, I encountered three problems with this approach:

With that said, there was the need for an alternative approach. Below is what I was able to come up with.

name: Python application

on:
  push:
    tags:
      - v*

permissions:
  contents: write

jobs:
  build:
    runs-on: windows-2019

    steps:
      - uses: actions/checkout@v3
      - name: Set up Python
        uses: actions/setup-python@v3
        with:
          # python-version: "3.8"
          # python-version: "3.9"
          python-version: "3.10"
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          python -m pip install -r requirements.txt
      - name: PyInstaller
        run: |
          python build.py

      - name: Release
        uses: technote-space/action-gh-release@v2
        if: startsWith(github.ref, 'refs/tags/')
        with:
          files: ./dist/file-copier.exe
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

First, we set up the trigger – a push event on the tags which help us mark a commit for release. We can add tags with the folloing command: git tag -a v1.0 -m "Release version 1.0". Later when we push changes to the main branch we also push them on the tag: git push origin main v1.0 which activates the release action.

Second, we set up write access to the repository for uploading a compiled executable to releases. Then, we specify the container for the jobs to run inside of – in this case windows-2019. Now onto the actual workflow:

Warning

Update: While it is possible to downgrade and build the pythonnet package with Python 3.8 and 3.9 in a Windows container on Github Actions, running the final executable still results in an exception.

import os
import subprocess
from pathlib import Path

import nicegui

cmd = [
    "python",
    "-m",
    "PyInstaller",
    "--noconfirm",
    "main.py",  # your main file with ui.run()
    #
    "--name",
    "file-copier",  # name of your app
    #
    # "--onedir",
    "--onefile",
    #
    "--windowed",  # prevent console appearing, only use with ui.run(native=True, ...)
    #
    "--add-data",
    f"{Path(nicegui.__file__).parent}{os.pathsep}nicegui",
]
subprocess.call(cmd)

After all these steps are done with, we can see the v1.0 release on the repository page.