From a8ae6669bc08bde510dcb2d441111c98586b3c14 Mon Sep 17 00:00:00 2001 From: Mackenzie Mathis Date: Mon, 23 Mar 2026 15:11:27 +0100 Subject: [PATCH 1/6] Refactor Python package release workflow Updated the workflow to streamline the release process and improve Python setup. --- .github/workflows/python-package.yml | 211 +++++---------------------- 1 file changed, 38 insertions(+), 173 deletions(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index a1c83cb..3434f81 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -1,203 +1,68 @@ -name: Build, validate & Release - -# Usage: -# - For PRs: this workflow runs automatically to validate the package builds and installs correctly on multiple Python versions. No artifacts are published for PRs. -# - For releases: when you push a tag like v1.2.3, this workflow runs the full matrix validation, then builds the release artifacts, and finally publishes to PyPI if all checks pass. -# - For manual re-runs: use "Run workflow" and provide a tag-like value such as v2.0.0rc1. +name: Update pypi release on: - workflow_dispatch: - inputs: - release_tag: - description: 'Tag to build/publish (e.g. v1.2.3 or v2.0.0rc1)' - required: true - type: string - # Release pipeline: run only when pushing a version-like tag (e.g. v1.2.3) - # Test pipeline: run tests on main/master pushes & pull requests AND tags. push: tags: - - "v*.*.*" + - 'v*.*.*' + pull_request: branches: - main - master - - # Validation pipeline: run on PRs targeting main/master (no publishing) - pull_request: - branches: [main, master] - types: [opened, edited, synchronize, reopened] - -# This workflow only needs to read repo contents -permissions: - contents: read + types: + - labeled + - opened + - edited + - synchronize + - reopened jobs: - test_matrix: - # PR + tag validation: ensure the project builds and installs on multiple Pythons - name: Test install & smoke (Py ${{ matrix.python-version }}) + release: runs-on: ubuntu-latest - strategy: - # Run all versions even if one fails (helps spot version-specific issues) - fail-fast: false - matrix: - python-version: ["3.10", "3.11", "3.12"] steps: - - name: Validate manual tag input - if: ${{ github.event_name == 'workflow_dispatch' }} - shell: bash - run: | - case "${{ inputs.release_tag }}" in - v*.*.*) - echo "Manual release tag accepted: ${{ inputs.release_tag }}" - ;; - *) - echo "release_tag must look like v1.2.3 (or similar, e.g. v2.0.0rc1)" - exit 1 - ;; - esac - - - name: Checkout sources - uses: actions/checkout@v6 + - name: Setup Python + id: setup-python + uses: actions/setup-python@v5 with: - ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', inputs.release_tag) || github.ref }} + python-version: '3.x' - - name: Set up Python - uses: actions/setup-python@v6 + - name: Cache dependencies + id: pip-cache + uses: actions/cache@v4 with: - python-version: ${{ matrix.python-version }} + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('pyproject.toml', 'requirements.txt', 'setup.cfg', 'setup.py') }} + restore-keys: | + ${{ runner.os }}-pip-${{ steps.setup-python.outputs.python-version }}- + ${{ runner.os }}-pip- - name: Install Qt/OpenGL runtime deps (Ubuntu) run: | sudo apt-get update - sudo apt-get install -y \ libegl1 \ libgl1 \ libopengl0 \ libxkbcommon-x11-0 \ libxcb-cursor0 - - # Install packaging toolchain: - # - build: creates wheel + sdist - # - twine: validates metadata and can upload (upload only happens in publish job) - - name: Install build tools - run: python -m pip install -U pip build twine - - # Build distributions just to verify packaging config works on this Python - - name: Build (for validation only) - run: python -m build - - # Validate dist metadata (README rendering, required fields, etc.) - - name: Twine check - run: python -m twine check dist/* - - # Smoke test: install the built wheel and verify the package imports - - name: Install from wheel & smoke test + + - name: Install dependencies run: | - WHEEL=$(ls -1 dist/*.whl | head -n 1) - echo "Using wheel: $WHEEL" - python -m pip install \ - --extra-index-url https://download.pytorch.org/whl/cpu \ - "deeplabcut-live-gui[pytorch] @ file://$(pwd)/${WHEEL}" - python -c "import dlclivegui; print('Imported dlclivegui OK')" - QT_QPA_PLATFORM=offscreen dlclivegui --help - - build_release: - # Tag-only build: produce the "official" release artifacts once matrix passed - name: Build release artifacts - runs-on: ubuntu-latest - needs: test_matrix - # Safety gate: only run for version tags, never for PRs/branches - if: ${{ startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' }} - - steps: - - name: Validate manual tag input - if: ${{ github.event_name == 'workflow_dispatch' }} - shell: bash - run: | - case "${{ inputs.release_tag }}" in - v*.*.*) - echo "Manual release tag accepted: ${{ inputs.release_tag }}" - ;; - *) - echo "release_tag must look like v1.2.3 (or similar, e.g. v2.0.0rc1)" - exit 1 - ;; - esac - # Fetch sources for the tagged revision - - name: Checkout sources - uses: actions/checkout@v6 - with: - # For a manual run, we want to check out the commit at the provided tag - ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', inputs.release_tag) || github.ref }} - - # Use a single, modern Python for the canonical release build - - name: Set up Python (release build) - uses: actions/setup-python@v6 - with: - python-version: "3.12" - - # Install build + validation tooling - - name: Install build tools - run: python -m pip install -U pip build twine - - # Produce both sdist and wheel in dist/ - - name: Build distributions - run: python -m build - - # Re-check metadata on the final artifacts we intend to publish - - name: Twine check - run: python -m twine check dist/* - - # Store dist/ outputs so the publish job uploads exactly what we built here - - name: Upload dist artifacts - uses: actions/upload-artifact@v4 - with: - name: dist - path: dist/* - - publish: - # Tag-only publish: download built artifacts and upload them to PyPI - name: Publish to PyPI (API token) - runs-on: ubuntu-latest - needs: build_release - # Safety gate: only run for version tags - if: ${{ startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' }} - - steps: - # Retrieve the exact distributions produced in build_release - - name: Download dist artifacts - uses: actions/download-artifact@v4 - with: - name: dist - path: dist + pip install --upgrade pip + pip install wheel + pip install "packaging>=24.2" + pip install build + pip install twine - # Set up Python (only needed to run Twine) - - name: Set up Python (publish) - uses: actions/setup-python@v6 - with: - python-version: "3.12" + - name: Checkout code + uses: actions/checkout@v4 - # Install twine for uploading - - name: Install Twine - run: python -m pip install -U twine - - # Check that the PyPI API token is present before attempting upload (fails fast if not set) - - name: Check PyPI credential presence - shell: bash - env: - TWINE_PASSWORD: ${{ secrets.TWINE_API_KEY }} - run: | - if [ -z "$TWINE_PASSWORD" ]; then - echo "TWINE_PASSWORD is empty" - exit 1 - else - echo "TWINE_PASSWORD is present" - fi - - # Upload to PyPI using an API token stored in repo secrets. - # --skip-existing avoids failing if you re-run a workflow for the same version. - - name: Publish to PyPI + - name: Build and publish to PyPI + if: ${{ github.event_name == 'push' }} env: TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.TWINE_API_KEY }} - run: python -m twine upload --non-interactive --skip-existing dist/* + run: | + python -m build + ls dist/ + tar tvf dist/deeplabcut-live-gui-*.tar.gz + python3 -m twine upload --verbose dist/* From 99fb5fbc689b20b51298ab38d28e5a2bb425b50f Mon Sep 17 00:00:00 2001 From: Mackenzie Mathis Date: Mon, 23 Mar 2026 15:13:43 +0100 Subject: [PATCH 2/6] Update python-package.yml --- .github/workflows/python-package.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 3434f81..dca0f16 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -39,6 +39,7 @@ jobs: - name: Install Qt/OpenGL runtime deps (Ubuntu) run: | sudo apt-get update + sudo apt-get install -y \ libegl1 \ libgl1 \ libopengl0 \ From 309ce838c01615c6ad7e50562056cf388ce43cd1 Mon Sep 17 00:00:00 2001 From: Mackenzie Mathis Date: Mon, 23 Mar 2026 15:17:54 +0100 Subject: [PATCH 3/6] Update .github/workflows/python-package.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/python-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index dca0f16..e7bdfb2 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -66,4 +66,4 @@ jobs: python -m build ls dist/ tar tvf dist/deeplabcut-live-gui-*.tar.gz - python3 -m twine upload --verbose dist/* + python -m twine upload --verbose dist/* From c971bf340557bf0bd309a40352b11d2fac58ff7d Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Mar 2026 10:29:53 -0500 Subject: [PATCH 4/6] Fix pip cache ordering: move checkout first, use setup-python built-in cache (#71) * Initial plan * Fix checkout order and use setup-python built-in pip cache Co-authored-by: MMathisLab <28102185+MMathisLab@users.noreply.github.com> Agent-Logs-Url: https://github.com/DeepLabCut/DeepLabCut-live-GUI/sessions/21ab9ebe-25bd-4963-b3c9-01ecbf60de45 * Upgrade actions/checkout and setup-python to v6 Update .github/workflows/python-package.yml to use actions/checkout@v6 and actions/setup-python@v6. Keeps the workflow up-to-date with no functional changes to Python version or caching. * Cache only pyproject.toml in CI Update GitHub Actions workflow to use pyproject.toml as the sole cache-dependency-path for pip, removing requirements.txt, setup.cfg, and setup.py to avoid unnecessary cache invalidation. Add a clarifying comment and clean up trailing whitespace in the workflow file. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: MMathisLab <28102185+MMathisLab@users.noreply.github.com> Co-authored-by: Cyril Achard --- .github/workflows/python-package.yml | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index e7bdfb2..b557794 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -20,21 +20,18 @@ jobs: runs-on: ubuntu-latest steps: + - name: Checkout code + uses: actions/checkout@v6 + - name: Setup Python id: setup-python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: '3.x' - - - name: Cache dependencies - id: pip-cache - uses: actions/cache@v4 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('pyproject.toml', 'requirements.txt', 'setup.cfg', 'setup.py') }} - restore-keys: | - ${{ runner.os }}-pip-${{ steps.setup-python.outputs.python-version }}- - ${{ runner.os }}-pip- + cache: 'pip' + # we only use pyproject.toml for dependencies + cache-dependency-path: | + pyproject.toml - name: Install Qt/OpenGL runtime deps (Ubuntu) run: | @@ -45,7 +42,7 @@ jobs: libopengl0 \ libxkbcommon-x11-0 \ libxcb-cursor0 - + - name: Install dependencies run: | pip install --upgrade pip @@ -54,9 +51,6 @@ jobs: pip install build pip install twine - - name: Checkout code - uses: actions/checkout@v4 - - name: Build and publish to PyPI if: ${{ github.event_name == 'push' }} env: From bd3cd2fcf5d2f2f3786c2bd5b8ce9a05f27f4296 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Mar 2026 10:30:16 -0500 Subject: [PATCH 5/6] Fix apt get install (#70) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> From 6aba30479ea7185a16ed79da5626daadb84a978f Mon Sep 17 00:00:00 2001 From: Cyril Achard Date: Mon, 23 Mar 2026 10:38:08 -0500 Subject: [PATCH 6/6] Add manual release_tag input and validation Add a workflow_dispatch input (release_tag) to allow manual builds/publishes for a specific tag. Validate the provided tag format in a new bash step when triggered manually, and adjust the checkout step to use the provided tag ref for workflow_dispatch events. Also remove an obsolete comment in the Python setup step. --- .github/workflows/python-package.yml | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index b557794..d40d1be 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -4,6 +4,7 @@ on: push: tags: - 'v*.*.*' + pull_request: branches: - main @@ -15,13 +16,36 @@ on: - synchronize - reopened + workflow_dispatch: + inputs: + release_tag: + description: 'Tag to build/publish (e.g. v1.2.3 or v2.0.0rc1)' + required: true + type: string + jobs: release: runs-on: ubuntu-latest steps: + - name: Validate manual tag input + if: ${{ github.event_name == 'workflow_dispatch' }} + shell: bash + run: | + case "${{ inputs.release_tag }}" in + v*.*.*) + echo "Manual release tag accepted: ${{ inputs.release_tag }}" + ;; + *) + echo "release_tag must look like v1.2.3 (or similar, e.g. v2.0.0rc1)" + exit 1 + ;; + esac + - name: Checkout code uses: actions/checkout@v6 + with: + ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', inputs.release_tag) || github.ref }} - name: Setup Python id: setup-python @@ -29,7 +53,6 @@ jobs: with: python-version: '3.x' cache: 'pip' - # we only use pyproject.toml for dependencies cache-dependency-path: | pyproject.toml