|
1 | 1 | name: CI |
| 2 | +run-name: "${{ github.event_name == 'workflow_dispatch' && format('CI: {0}', github.ref_name) || '' }}" |
2 | 3 |
|
3 | 4 | on: |
4 | 5 | push: |
5 | 6 | branches: |
6 | 7 | - dev |
7 | 8 | pull_request: |
| 9 | + release: |
| 10 | + types: [published] |
| 11 | + workflow_dispatch: |
8 | 12 |
|
9 | 13 | env: |
10 | | - UV_CACHE_DIR: /tmp/.uv-cache |
| 14 | + ADDITIONAL_PYTHON_VERSIONS: "['3.12']" |
| 15 | + |
| 16 | +concurrency: |
| 17 | + group: ${{ github.workflow }}-${{ (github.event_name == 'release' && github.run_id) || github.event.pull_request.number || github.ref }} |
| 18 | + cancel-in-progress: true |
11 | 19 |
|
12 | 20 | jobs: |
| 21 | + info: |
| 22 | + name: Collect information & prepare |
| 23 | + outputs: |
| 24 | + default_python_version: ${{ steps.info.outputs.default_python_version }} |
| 25 | + python_versions: ${{ steps.info.outputs.python_versions }} |
| 26 | + runs-on: ubuntu-latest |
| 27 | + steps: |
| 28 | + - name: ⤵️ Check out code from GitHub |
| 29 | + uses: actions/checkout@v4.2.2 |
| 30 | + - name: Collect information |
| 31 | + id: info |
| 32 | + run: | |
| 33 | + default_python_version=$(cat .python-version) |
| 34 | + echo "default python version: ${default_python_version}" |
| 35 | + echo "default_python_version=${default_python_version}" >> $GITHUB_OUTPUT |
| 36 | +
|
| 37 | + # Check if ADDITIONAL_PYTHON_VERSIONS contains default_python_version. If not add it |
| 38 | + if [[ ! ${ADDITIONAL_PYTHON_VERSIONS} == *"${default_python_version}"* ]]; then |
| 39 | + ADDITIONAL_PYTHON_VERSIONS="[${ADDITIONAL_PYTHON_VERSIONS:1:-1}, '${default_python_version}']" |
| 40 | + fi |
| 41 | + echo "python_versions: ${ADDITIONAL_PYTHON_VERSIONS}" |
| 42 | + echo "python_versions=${ADDITIONAL_PYTHON_VERSIONS}" >> $GITHUB_OUTPUT |
| 43 | + - name: 🏗 Install uv |
| 44 | + uses: astral-sh/setup-uv@v5 |
| 45 | + with: |
| 46 | + enable-cache: true |
| 47 | + - name: Generate requirements.txt |
| 48 | + run: | |
| 49 | + uv export --no-hashes --no-dev --group test --no-emit-project > requirements.txt |
| 50 | + - name: Upload requirements.txt |
| 51 | + uses: actions/upload-artifact@v4 |
| 52 | + with: |
| 53 | + name: requirements.txt |
| 54 | + path: requirements.txt |
| 55 | + |
13 | 56 | code-quality: |
14 | 57 | runs-on: "ubuntu-latest" |
15 | 58 | name: Check code quality |
@@ -37,68 +80,273 @@ jobs: |
37 | 80 | - name: Verify no getLogger usages |
38 | 81 | run: scripts/check_getLogger.sh |
39 | 82 |
|
40 | | - tests: |
41 | | - runs-on: "ubuntu-latest" |
42 | | - name: Run tests |
| 83 | + build-test-native: |
| 84 | + name: ${{ matrix.platform.name }} ${{ matrix.platform.target }} ${{ matrix.python-version }} |
| 85 | + runs-on: ${{ matrix.platform.runner }} |
| 86 | + needs: |
| 87 | + - info |
| 88 | + - code-quality |
43 | 89 | strategy: |
| 90 | + fail-fast: false |
44 | 91 | matrix: |
45 | | - python-version: |
46 | | - - "3.12" |
47 | | - - "3.13" |
48 | | - env: |
49 | | - # To enable backtrace in case of a crash |
50 | | - RUST_BACKTRACE: 1 |
| 92 | + include: |
| 93 | + - name: Linux |
| 94 | + manylinux: manylinux_2_34 |
| 95 | + - name: Macos |
| 96 | + pytest_args: -m "not docker" |
| 97 | + platform: |
| 98 | + - name: Linux |
| 99 | + runner: ubuntu-latest |
| 100 | + target: x86_64 |
| 101 | + - name: Linux |
| 102 | + runner: ubuntu-24.04-arm |
| 103 | + target: aarch64 |
| 104 | + - name: Windows |
| 105 | + runner: windows-latest |
| 106 | + target: x64 |
| 107 | + - name: Macos |
| 108 | + runner: macos-13 |
| 109 | + target: x86_64 |
| 110 | + - name: Macos |
| 111 | + runner: macos-14 |
| 112 | + target: aarch64 |
| 113 | + python-version: ${{ fromJSON(needs.info.outputs.python_versions) }} |
51 | 114 | steps: |
52 | | - - name: ⤵️ Checkout repository |
53 | | - uses: actions/checkout@v4 |
54 | | - |
55 | | - - name: 🏗 Install uv and Python ${{ matrix.python-version }} |
| 115 | + - uses: actions/checkout@v4 |
| 116 | + - uses: actions/setup-python@v5 |
| 117 | + with: |
| 118 | + python-version: ${{ matrix.python-version }} |
| 119 | + architecture: ${{ (matrix.platform.name == 'Windows') && matrix.platform.target || '' }} |
| 120 | + - name: 🏗 Set package version |
| 121 | + if: ${{ matrix.platform.name != 'Windows' && github.event_name == 'release' }} |
| 122 | + run: | |
| 123 | + sed -i.bak "s/^version = \".*\"/version = \"${{ github.event.release.tag_name }}\"/" pyproject.toml && rm pyproject.toml.bak |
| 124 | + - name: 🏗 Set package version (Windows) |
| 125 | + if: ${{ matrix.platform.name == 'Windows' && github.event_name == 'release' }} |
| 126 | + run: | |
| 127 | + (Get-Content pyproject.toml) -replace 'version = ".*"', 'version = "${{ github.event.release.tag_name }}"' | Set-Content pyproject.toml |
| 128 | + - name: Build wheels |
| 129 | + uses: PyO3/maturin-action@v1 |
| 130 | + with: |
| 131 | + target: ${{ matrix.platform.target }} |
| 132 | + args: --release --strip --out dist -i python${{ matrix.python-version }} |
| 133 | + sccache: "false" |
| 134 | + manylinux: ${{ matrix.manylinux }} |
| 135 | + before-script-linux: python3 -m ensurepip |
| 136 | + - name: Upload wheels |
| 137 | + uses: actions/upload-artifact@v4 |
| 138 | + with: |
| 139 | + name: wheels-${{ matrix.platform.name }}-${{ matrix.platform.target }}-${{ matrix.python-version }} |
| 140 | + path: dist |
| 141 | + - name: 🏗 Install uv |
56 | 142 | uses: astral-sh/setup-uv@v5 |
57 | 143 | with: |
58 | 144 | enable-cache: true |
59 | | - cache-dependency-glob: "uv.lock" |
60 | | - cache-local-path: ${{ env.UV_CACHE_DIR }} |
61 | | - python-version: ${{ matrix.python-version }} |
62 | | - |
63 | | - - name: 🏗 Install the project |
64 | | - run: uv sync --locked --group test |
65 | | - |
| 145 | + - name: Download requirements.txt |
| 146 | + uses: actions/download-artifact@v4 |
| 147 | + with: |
| 148 | + name: requirements.txt |
| 149 | + - name: Prepare env and install wheel |
| 150 | + shell: bash |
| 151 | + run: | |
| 152 | + # Remove sources otherwise pytest will complain about missing rust files |
| 153 | + rm -rf deebot_client |
| 154 | + uv venv -p ${{ matrix.python-version }} |
| 155 | + uv pip install -r requirements.txt |
| 156 | + uv pip install --force-reinstall dist/deebot_client-*.whl |
66 | 157 | - name: Run pytest |
67 | | - run: uv run --frozen pytest tests --cov=./ --cov-report=xml --junitxml=junit.xml -o junit_family=legacy |
68 | | - |
| 158 | + if: ${{ matrix.platform.name != 'Windows' }} |
| 159 | + id: pytest |
| 160 | + run: | |
| 161 | + source .venv/bin/activate |
| 162 | + site_packages=$(python -c "import site; print(site.getsitepackages()[0])") |
| 163 | + echo "site-packages: ${site_packages}" |
| 164 | + pytest tests --cov=${site_packages}/deebot_client --cov-report=xml --junitxml=junit.xml -o junit_family=legacy -v ${{ matrix.pytest_args || ''}} |
| 165 | + - name: Run pytest (windows) |
| 166 | + if: ${{ matrix.platform.name == 'Windows' }} |
| 167 | + id: pytest_windows |
| 168 | + run: | |
| 169 | + .venv/Scripts/activate |
| 170 | + $sitePackages = python -c "import site; print(site.getsitepackages()[0])" |
| 171 | + Write-Output "site-packages: $sitePackages" |
| 172 | + pytest tests --cov="$sitePackages/deebot_client" --cov-report=xml --junitxml=junit.xml -o junit_family=legacy -v -m "not docker" |
69 | 173 | - name: Upload coverage to Codecov |
70 | 174 | uses: codecov/codecov-action@v5 |
| 175 | + env: |
| 176 | + PYTHON: ${{ matrix.python-version }} |
| 177 | + TARGET: ${{ matrix.platform.target }} |
| 178 | + PLATFORM: ${{ matrix.platform.name }} |
71 | 179 | with: |
72 | 180 | fail_ci_if_error: true |
| 181 | + name: ${{ matrix.platform.name }} ${{ matrix.platform.target }} ${{ matrix.python-version }} |
| 182 | + env_vars: PLATFORM,TARGET,PYTHON |
| 183 | + - name: Upload test results to Codecov |
| 184 | + if: ${{ !cancelled() && ((matrix.platform.name == 'Windows' && steps.pytest_windows.outcome) || steps.pytest.outcome) == 'success' }} |
| 185 | + uses: codecov/test-results-action@v1 |
| 186 | + with: |
| 187 | + # fail_ci_if_error: true |
| 188 | + verbose: true |
73 | 189 |
|
| 190 | + build-test-musl: |
| 191 | + name: Musllinux ${{ matrix.platform.target }} ${{ matrix.python-version }} |
| 192 | + runs-on: ubuntu-latest |
| 193 | + needs: |
| 194 | + - info |
| 195 | + - code-quality |
| 196 | + strategy: |
| 197 | + fail-fast: false |
| 198 | + matrix: |
| 199 | + platform: |
| 200 | + - target: x86_64 |
| 201 | + docker_arch: amd64 |
| 202 | + # - target: aarch64 |
| 203 | + # docker_arch: arm64 |
| 204 | + python-version: ${{ fromJSON(needs.info.outputs.python_versions) }} |
| 205 | + steps: |
| 206 | + - uses: actions/checkout@v4 |
| 207 | + - uses: actions/setup-python@v5 |
| 208 | + with: |
| 209 | + python-version: ${{ matrix.python-version }} |
| 210 | + - name: 🏗 Set package version |
| 211 | + if: ${{ github.event_name == 'release' }} |
| 212 | + run: | |
| 213 | + sed -i "s/^version = \".*\"/version = \"${{ github.event.release.tag_name }}\"/" pyproject.toml |
| 214 | + - name: Build wheels |
| 215 | + uses: PyO3/maturin-action@v1 |
| 216 | + with: |
| 217 | + target: ${{ matrix.platform.target }} |
| 218 | + args: --release --strip --out dist -i python${{ matrix.python-version }} |
| 219 | + sccache: "false" |
| 220 | + manylinux: musllinux_1_2 |
| 221 | + - name: Upload wheels |
| 222 | + uses: actions/upload-artifact@v4 |
| 223 | + with: |
| 224 | + name: wheels-musllinux-${{ matrix.platform.target }}-${{ matrix.python-version }} |
| 225 | + path: dist |
| 226 | + - name: Download requirements.txt |
| 227 | + uses: actions/download-artifact@v4 |
| 228 | + with: |
| 229 | + name: requirements.txt |
| 230 | + - name: Install Qemu |
| 231 | + uses: docker/setup-qemu-action@v3 |
| 232 | + - name: Install Docker Buildx |
| 233 | + uses: docker/setup-buildx-action@v3 |
| 234 | + - name: Build image |
| 235 | + uses: docker/build-push-action@v6 |
| 236 | + with: |
| 237 | + context: . |
| 238 | + file: ci/Dockerfile.alpine |
| 239 | + platforms: linux/${{ matrix.platform.docker_arch }} |
| 240 | + push: false |
| 241 | + load: true |
| 242 | + cache-from: type=gha |
| 243 | + cache-to: type=gha,mode=max |
| 244 | + build-args: | |
| 245 | + PYTHON_VERSION=${{ matrix.python-version }} |
| 246 | + tags: deebot_client:${{ matrix.platform.target }}-${{ matrix.python-version }} |
| 247 | + - name: Pytest in docker |
| 248 | + id: pytest |
| 249 | + run: | |
| 250 | + docker run --rm -v ${{ github.workspace }}:/github/workspace --platform linux/${{ matrix.platform.docker_arch }} deebot_client:${{ matrix.platform.target }}-${{ matrix.python-version }} |
| 251 | + - name: Upload coverage to Codecov |
| 252 | + uses: codecov/codecov-action@v5 |
| 253 | + env: |
| 254 | + PYTHON: ${{ matrix.python-version }} |
| 255 | + TARGET: ${{ matrix.platform.target }} |
| 256 | + PLATFORM: Musllinux |
| 257 | + with: |
| 258 | + fail_ci_if_error: true |
| 259 | + name: Musllinux ${{ matrix.platform.target }} ${{ matrix.python-version }} |
| 260 | + env_vars: PLATFORM,TARGET,PYTHON |
74 | 261 | - name: Upload test results to Codecov |
75 | | - if: ${{ !cancelled() }} |
| 262 | + if: ${{ !cancelled() && steps.pytest.outcome == 'success' }} |
76 | 263 | uses: codecov/test-results-action@v1 |
77 | 264 | with: |
78 | 265 | fail_ci_if_error: true |
79 | 266 |
|
80 | 267 | benchmarks: |
81 | 268 | runs-on: "ubuntu-latest" |
82 | 269 | name: Run benchmarks |
| 270 | + if: ${{ github.event_name != 'release' }} |
| 271 | + needs: |
| 272 | + - build-test-native |
| 273 | + - build-test-musl |
| 274 | + - sdist |
83 | 275 | steps: |
84 | 276 | - name: ⤵️ Checkout repository |
85 | 277 | uses: actions/checkout@v4 |
86 | | - |
87 | 278 | - name: 🏗 Install uv |
88 | 279 | uses: astral-sh/setup-uv@v5 |
89 | | - |
90 | 280 | - name: 🏗 Setup Python |
91 | 281 | uses: actions/setup-python@v5 |
92 | 282 | with: |
93 | | - python-version-file: ".python-version" |
94 | | - |
| 283 | + python-version: ${{ needs.info.outputs.default_python_version }} |
| 284 | + - name: Download requirements.txt |
| 285 | + uses: actions/download-artifact@v4 |
| 286 | + with: |
| 287 | + name: requirements.txt |
95 | 288 | - name: 🏗 Install the project |
96 | 289 | run: | |
97 | | - uv export --group benchmark > requirements.txt |
98 | 290 | uv pip install -e . --system -r requirements.txt |
99 | | -
|
100 | 291 | - name: Run benchmarks |
101 | 292 | uses: CodSpeedHQ/action@main |
102 | 293 | with: |
103 | 294 | run: pytest tests/ --codspeed |
104 | 295 | token: ${{ secrets.CODSPEED_TOKEN }} |
| 296 | + |
| 297 | + sdist: |
| 298 | + name: Create source distribution |
| 299 | + runs-on: ubuntu-latest |
| 300 | + needs: code-quality |
| 301 | + steps: |
| 302 | + - name: ⤵️ Check out code from GitHub |
| 303 | + uses: actions/checkout@v4.2.2 |
| 304 | + - name: 🏗 Set up uv |
| 305 | + uses: astral-sh/setup-uv@v5 |
| 306 | + with: |
| 307 | + enable-cache: true |
| 308 | + - name: 🏗 Set package version |
| 309 | + if: ${{ github.event_name == 'release' }} |
| 310 | + run: | |
| 311 | + sed -i "s/^version = \".*\"/version = \"${{ github.event.release.tag_name }}\"/" pyproject.toml |
| 312 | + - name: 📦 Build source package |
| 313 | + run: uv build --sdist |
| 314 | + - name: Upload sdist |
| 315 | + uses: actions/upload-artifact@v4 |
| 316 | + with: |
| 317 | + name: wheels-sdist |
| 318 | + path: dist |
| 319 | + |
| 320 | + release: |
| 321 | + name: Releasing to PyPi |
| 322 | + if: ${{ github.event_name == 'release' }} |
| 323 | + runs-on: ubuntu-latest |
| 324 | + needs: |
| 325 | + - build-test-native |
| 326 | + - build-test-musl |
| 327 | + - sdist |
| 328 | + environment: |
| 329 | + name: release |
| 330 | + url: https://pypi.org/p/deebot-client |
| 331 | + permissions: |
| 332 | + contents: write |
| 333 | + id-token: write |
| 334 | + steps: |
| 335 | + - name: ⤵️ Check out code from GitHub |
| 336 | + uses: actions/checkout@v4.2.2 |
| 337 | + - name: ⬇️ Download wheels |
| 338 | + uses: actions/download-artifact@v4 |
| 339 | + with: |
| 340 | + pattern: wheels-* |
| 341 | + path: dist |
| 342 | + merge-multiple: true |
| 343 | + - name: 🚀 Publish to PyPi |
| 344 | + uses: pypa/gh-action-pypi-publish@v1.12.4 |
| 345 | + with: |
| 346 | + verbose: true |
| 347 | + print-hash: true |
| 348 | + - name: ✍️ Sign published artifacts |
| 349 | + uses: sigstore/gh-action-sigstore-python@v3.0.0 |
| 350 | + with: |
| 351 | + inputs: ./dist/*.tar.gz ./dist/*.whl |
| 352 | + release-signing-artifacts: true |
0 commit comments