|
1 | | -name: Build, validate & Release |
2 | | - |
3 | | -# Usage: |
4 | | -# - For PRs: this workflow runs automatically to validate the package builds and installs correctly on multiple Python versions. No artifacts are published for PRs. |
5 | | -# - 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. |
6 | | -# - For manual re-runs: use "Run workflow" and provide a tag-like value such as v2.0.0rc1. |
| 1 | +name: Update pypi release |
7 | 2 |
|
8 | 3 | on: |
9 | | - workflow_dispatch: |
10 | | - inputs: |
11 | | - release_tag: |
12 | | - description: 'Tag to build/publish (e.g. v1.2.3 or v2.0.0rc1)' |
13 | | - required: true |
14 | | - type: string |
15 | | - # Release pipeline: run only when pushing a version-like tag (e.g. v1.2.3) |
16 | | - # Test pipeline: run tests on main/master pushes & pull requests AND tags. |
17 | 4 | push: |
18 | 5 | tags: |
19 | | - - "v*.*.*" |
| 6 | + - 'v*.*.*' |
| 7 | + pull_request: |
20 | 8 | branches: |
21 | 9 | - main |
22 | 10 | - master |
23 | | - |
24 | | - # Validation pipeline: run on PRs targeting main/master (no publishing) |
25 | | - pull_request: |
26 | | - branches: [main, master] |
27 | | - types: [opened, edited, synchronize, reopened] |
28 | | - |
29 | | -# This workflow only needs to read repo contents |
30 | | -permissions: |
31 | | - contents: read |
| 11 | + types: |
| 12 | + - labeled |
| 13 | + - opened |
| 14 | + - edited |
| 15 | + - synchronize |
| 16 | + - reopened |
32 | 17 |
|
33 | 18 | jobs: |
34 | | - test_matrix: |
35 | | - # PR + tag validation: ensure the project builds and installs on multiple Pythons |
36 | | - name: Test install & smoke (Py ${{ matrix.python-version }}) |
| 19 | + release: |
37 | 20 | runs-on: ubuntu-latest |
38 | | - strategy: |
39 | | - # Run all versions even if one fails (helps spot version-specific issues) |
40 | | - fail-fast: false |
41 | | - matrix: |
42 | | - python-version: ["3.10", "3.11", "3.12"] |
43 | 21 |
|
44 | 22 | steps: |
45 | | - - name: Validate manual tag input |
46 | | - if: ${{ github.event_name == 'workflow_dispatch' }} |
47 | | - shell: bash |
48 | | - run: | |
49 | | - case "${{ inputs.release_tag }}" in |
50 | | - v*.*.*) |
51 | | - echo "Manual release tag accepted: ${{ inputs.release_tag }}" |
52 | | - ;; |
53 | | - *) |
54 | | - echo "release_tag must look like v1.2.3 (or similar, e.g. v2.0.0rc1)" |
55 | | - exit 1 |
56 | | - ;; |
57 | | - esac |
58 | | -
|
59 | | - - name: Checkout sources |
60 | | - uses: actions/checkout@v6 |
| 23 | + - name: Setup Python |
| 24 | + id: setup-python |
| 25 | + uses: actions/setup-python@v5 |
61 | 26 | with: |
62 | | - ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', inputs.release_tag) || github.ref }} |
| 27 | + python-version: '3.x' |
63 | 28 |
|
64 | | - - name: Set up Python |
65 | | - uses: actions/setup-python@v6 |
| 29 | + - name: Cache dependencies |
| 30 | + id: pip-cache |
| 31 | + uses: actions/cache@v4 |
66 | 32 | with: |
67 | | - python-version: ${{ matrix.python-version }} |
| 33 | + path: ~/.cache/pip |
| 34 | + key: ${{ runner.os }}-pip-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('pyproject.toml', 'requirements.txt', 'setup.cfg', 'setup.py') }} |
| 35 | + restore-keys: | |
| 36 | + ${{ runner.os }}-pip-${{ steps.setup-python.outputs.python-version }}- |
| 37 | + ${{ runner.os }}-pip- |
68 | 38 |
|
69 | 39 | - name: Install Qt/OpenGL runtime deps (Ubuntu) |
70 | 40 | run: | |
71 | 41 | sudo apt-get update |
72 | | - sudo apt-get install -y \ |
73 | 42 | libegl1 \ |
74 | 43 | libgl1 \ |
75 | 44 | libopengl0 \ |
76 | 45 | libxkbcommon-x11-0 \ |
77 | 46 | libxcb-cursor0 |
78 | | -
|
79 | | - # Install packaging toolchain: |
80 | | - # - build: creates wheel + sdist |
81 | | - # - twine: validates metadata and can upload (upload only happens in publish job) |
82 | | - - name: Install build tools |
83 | | - run: python -m pip install -U pip build twine |
84 | | - |
85 | | - # Build distributions just to verify packaging config works on this Python |
86 | | - - name: Build (for validation only) |
87 | | - run: python -m build |
88 | | - |
89 | | - # Validate dist metadata (README rendering, required fields, etc.) |
90 | | - - name: Twine check |
91 | | - run: python -m twine check dist/* |
92 | | - |
93 | | - # Smoke test: install the built wheel and verify the package imports |
94 | | - - name: Install from wheel & smoke test |
| 47 | + |
| 48 | + - name: Install dependencies |
95 | 49 | run: | |
96 | | - WHEEL=$(ls -1 dist/*.whl | head -n 1) |
97 | | - echo "Using wheel: $WHEEL" |
98 | | - python -m pip install \ |
99 | | - --extra-index-url https://download.pytorch.org/whl/cpu \ |
100 | | - "deeplabcut-live-gui[pytorch] @ file://$(pwd)/${WHEEL}" |
101 | | - python -c "import dlclivegui; print('Imported dlclivegui OK')" |
102 | | - QT_QPA_PLATFORM=offscreen dlclivegui --help |
103 | | -
|
104 | | - build_release: |
105 | | - # Tag-only build: produce the "official" release artifacts once matrix passed |
106 | | - name: Build release artifacts |
107 | | - runs-on: ubuntu-latest |
108 | | - needs: test_matrix |
109 | | - # Safety gate: only run for version tags, never for PRs/branches |
110 | | - if: ${{ startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' }} |
111 | | - |
112 | | - steps: |
113 | | - - name: Validate manual tag input |
114 | | - if: ${{ github.event_name == 'workflow_dispatch' }} |
115 | | - shell: bash |
116 | | - run: | |
117 | | - case "${{ inputs.release_tag }}" in |
118 | | - v*.*.*) |
119 | | - echo "Manual release tag accepted: ${{ inputs.release_tag }}" |
120 | | - ;; |
121 | | - *) |
122 | | - echo "release_tag must look like v1.2.3 (or similar, e.g. v2.0.0rc1)" |
123 | | - exit 1 |
124 | | - ;; |
125 | | - esac |
126 | | - # Fetch sources for the tagged revision |
127 | | - - name: Checkout sources |
128 | | - uses: actions/checkout@v6 |
129 | | - with: |
130 | | - # For a manual run, we want to check out the commit at the provided tag |
131 | | - ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', inputs.release_tag) || github.ref }} |
132 | | - |
133 | | - # Use a single, modern Python for the canonical release build |
134 | | - - name: Set up Python (release build) |
135 | | - uses: actions/setup-python@v6 |
136 | | - with: |
137 | | - python-version: "3.12" |
138 | | - |
139 | | - # Install build + validation tooling |
140 | | - - name: Install build tools |
141 | | - run: python -m pip install -U pip build twine |
142 | | - |
143 | | - # Produce both sdist and wheel in dist/ |
144 | | - - name: Build distributions |
145 | | - run: python -m build |
146 | | - |
147 | | - # Re-check metadata on the final artifacts we intend to publish |
148 | | - - name: Twine check |
149 | | - run: python -m twine check dist/* |
150 | | - |
151 | | - # Store dist/ outputs so the publish job uploads exactly what we built here |
152 | | - - name: Upload dist artifacts |
153 | | - uses: actions/upload-artifact@v4 |
154 | | - with: |
155 | | - name: dist |
156 | | - path: dist/* |
157 | | - |
158 | | - publish: |
159 | | - # Tag-only publish: download built artifacts and upload them to PyPI |
160 | | - name: Publish to PyPI (API token) |
161 | | - runs-on: ubuntu-latest |
162 | | - needs: build_release |
163 | | - # Safety gate: only run for version tags |
164 | | - if: ${{ startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' }} |
165 | | - |
166 | | - steps: |
167 | | - # Retrieve the exact distributions produced in build_release |
168 | | - - name: Download dist artifacts |
169 | | - uses: actions/download-artifact@v4 |
170 | | - with: |
171 | | - name: dist |
172 | | - path: dist |
| 50 | + pip install --upgrade pip |
| 51 | + pip install wheel |
| 52 | + pip install "packaging>=24.2" |
| 53 | + pip install build |
| 54 | + pip install twine |
173 | 55 |
|
174 | | - # Set up Python (only needed to run Twine) |
175 | | - - name: Set up Python (publish) |
176 | | - uses: actions/setup-python@v6 |
177 | | - with: |
178 | | - python-version: "3.12" |
| 56 | + - name: Checkout code |
| 57 | + uses: actions/checkout@v4 |
179 | 58 |
|
180 | | - # Install twine for uploading |
181 | | - - name: Install Twine |
182 | | - run: python -m pip install -U twine |
183 | | - |
184 | | - # Check that the PyPI API token is present before attempting upload (fails fast if not set) |
185 | | - - name: Check PyPI credential presence |
186 | | - shell: bash |
187 | | - env: |
188 | | - TWINE_PASSWORD: ${{ secrets.TWINE_API_KEY }} |
189 | | - run: | |
190 | | - if [ -z "$TWINE_PASSWORD" ]; then |
191 | | - echo "TWINE_PASSWORD is empty" |
192 | | - exit 1 |
193 | | - else |
194 | | - echo "TWINE_PASSWORD is present" |
195 | | - fi |
196 | | -
|
197 | | - # Upload to PyPI using an API token stored in repo secrets. |
198 | | - # --skip-existing avoids failing if you re-run a workflow for the same version. |
199 | | - - name: Publish to PyPI |
| 59 | + - name: Build and publish to PyPI |
| 60 | + if: ${{ github.event_name == 'push' }} |
200 | 61 | env: |
201 | 62 | TWINE_USERNAME: __token__ |
202 | 63 | TWINE_PASSWORD: ${{ secrets.TWINE_API_KEY }} |
203 | | - run: python -m twine upload --non-interactive --skip-existing dist/* |
| 64 | + run: | |
| 65 | + python -m build |
| 66 | + ls dist/ |
| 67 | + tar tvf dist/deeplabcut-live-gui-*.tar.gz |
| 68 | + python3 -m twine upload --verbose dist/* |
0 commit comments