From 95af60ac93b55982828750c8c29121f40bfec303 Mon Sep 17 00:00:00 2001 From: Dima Gerasimov Date: Sat, 18 Jan 2025 21:20:06 +0000 Subject: [PATCH] ci: use uv for running and publishing --- .ci/release-uv | 60 ++++++++++++++++++++++++++++++++++++++ .ci/run | 12 ++------ .github/workflows/main.yml | 16 +++++----- pyproject.toml | 5 ++++ tox.ini | 4 +-- 5 files changed, 77 insertions(+), 20 deletions(-) create mode 100755 .ci/release-uv diff --git a/.ci/release-uv b/.ci/release-uv new file mode 100755 index 0000000..c56697c --- /dev/null +++ b/.ci/release-uv @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +''' +Deploys Python package onto [[https://pypi.org][PyPi]] or [[https://test.pypi.org][test PyPi]]. + +- running manually + + You'll need =UV_PUBLISH_TOKEN= env variable + +- running on Github Actions + + Instead of env variable, relies on configuring github as Trusted publisher (https://docs.pypi.org/trusted-publishers/) -- both for test and regular pypi + + It's running as =pypi= job in [[file:.github/workflows/main.yml][Github Actions config]]. + Packages are deployed on: + - every master commit, onto test pypi + - every new tag, onto production pypi +''' + +UV_PUBLISH_TOKEN = 'UV_PUBLISH_TOKEN' + +import argparse +import os +import shutil +from pathlib import Path +from subprocess import check_call + +is_ci = os.environ.get('CI') is not None + +def main() -> None: + p = argparse.ArgumentParser() + p.add_argument('--use-test-pypi', action='store_true') + args = p.parse_args() + + publish_url = ['--publish-url', 'https://test.pypi.org/legacy/'] if args.use_test_pypi else [] + + root = Path(__file__).absolute().parent.parent + os.chdir(root) # just in case + + if is_ci: + # see https://github.com/actions/checkout/issues/217 + check_call('git fetch --prune --unshallow'.split()) + + # TODO ok, for now uv won't remove dist dir if it already exists + # https://github.com/astral-sh/uv/issues/10293 + dist = root / 'dist' + if dist.exists(): + shutil.rmtree(dist) + + # todo what is --force-pep517? + check_call(['uv', 'build']) + + if not is_ci: + # CI relies on trusted publishers so doesn't need env variable + assert UV_PUBLISH_TOKEN in os.environ, f'no {UV_PUBLISH_TOKEN} passed' + + check_call(['uv', 'publish', *publish_url]) + + +if __name__ == '__main__': + main() diff --git a/.ci/run b/.ci/run index 7438630..c881818 100755 --- a/.ci/run +++ b/.ci/run @@ -22,7 +22,6 @@ if [ -n "${CI-}" ]; then ;; cygwin* | msys* | win*) # windows - : # ugh. parallel stuff seems super flaky under windows, some random failures, "file used by other process" and crap like that tox_cmd='run' ;; @@ -33,12 +32,5 @@ if [ -n "${CI-}" ]; then esac fi - -PY_BIN="python3" -# some systems might have python pointing to python3 -if ! command -v python3 &> /dev/null; then - PY_BIN="python" -fi - -"$PY_BIN" -m pip install --user tox -"$PY_BIN" -m tox $tox_cmd "$@" +# NOTE: expects uv installed +uv tool run --with tox-uv tox $tox_cmd "$@" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 952b30a..81ccfd0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -38,6 +38,8 @@ jobs: - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} + + - uses: astral-sh/setup-uv@v5 - uses: actions/checkout@v4 with: @@ -61,7 +63,9 @@ jobs: pypi: runs-on: ubuntu-latest needs: [build] # add all other jobs here - + permissions: + # necessary for Trusted Publishing + id-token: write steps: # ugh https://github.com/actions/toolkit/blob/main/docs/commands.md#path-manipulation - run: echo "$HOME/.local/bin" >> $GITHUB_PATH @@ -70,6 +74,8 @@ jobs: with: python-version: '3.10' + - uses: astral-sh/setup-uv@v5 + - uses: actions/checkout@v4 with: submodules: recursive @@ -77,14 +83,10 @@ jobs: - name: 'release to test pypi' # always deploy merged master to test pypi if: github.event_name != 'pull_request' && github.event.ref == 'refs/heads/master' - env: - TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD_TEST }} - run: pip3 install --user --upgrade build twine && .ci/release --test + run: .ci/release-uv --use-test-pypi - name: 'release to pypi' # always deploy tags to release pypi # NOTE: release tags are guarded by on: push: tags on the top if: github.event_name != 'pull_request' && startsWith(github.event.ref, 'refs/tags') - env: - TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} - run: pip3 install --user --upgrade build twine && .ci/release + run: .ci/release-uv diff --git a/pyproject.toml b/pyproject.toml index 507fcdb..1b784ad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,3 +58,8 @@ build-backend = "setuptools.build_meta" [tool.setuptools_scm] version_scheme = "python-simplified-semver" local_scheme = "dirty-tag" + +# workaround for error during uv publishing +# see https://github.com/astral-sh/uv/issues/9513#issuecomment-2519527822 +[tool.setuptools] +license-files = [] diff --git a/tox.ini b/tox.ini index ecd9c21..163eed9 100644 --- a/tox.ini +++ b/tox.ini @@ -18,9 +18,7 @@ passenv = MYPY_CACHE_DIR RUFF_CACHE_DIR usedevelop = true # for some reason tox seems to ignore "-e ." in deps section?? -# note: --use-pep517 here is necessary for tox --parallel flag to work properly -# otherwise it seems that it tries to modify .eggs dir in parallel and it fails -install_command = {envpython} -m pip install --use-pep517 {opts} {packages} +uv_seed = true # seems necessary so uv creates separate venvs per tox env? [testenv:ruff]