diff --git a/.github/actions/prepare/action.yml b/.github/actions/prepare/action.yml index 688ff7f..081c2a1 100644 --- a/.github/actions/prepare/action.yml +++ b/.github/actions/prepare/action.yml @@ -1,40 +1,28 @@ name: "Prepare Build Environment" -description: "Checkout, cache, build liburing, and install Python deps" +description: "Build/install liburing and install Python deps (repo must already be checked out with submodules)" +inputs: + python-version: + description: "Python version to set up" + required: false + default: "3.12" runs: using: "composite" steps: - - name: Checkout repo - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-depth: 0 - - - name: Get system info and liburing commit hash + - name: Get liburing commit hash id: cache-info shell: bash - run: | - echo "sysinfo=$(uname -a | md5sum | cut -d ' ' -f1)" >> $GITHUB_OUTPUT - echo "liburing_hash=$(cd libs && git rev-parse HEAD)" >> $GITHUB_OUTPUT - - - name: Cache Python dependencies - id: cache-python - uses: actions/cache@v3 - with: - path: | - .venv - ~/.cache/uv - key: ${{ runner.os }}-py-${{ hashFiles('uv.lock') }} + run: echo "liburing_hash=$(cd libs && git rev-parse HEAD)" >> $GITHUB_OUTPUT - name: Cache liburing build id: cache-liburing - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: libs/ - key: ${{ steps.cache-info.outputs.os }}-${{ steps.cache-info.outputs.arch }}-liburing-${{ steps.cache-info.outputs.liburing_hash }} + key: ${{ runner.os }}-${{ runner.arch }}-liburing-${{ steps.cache-info.outputs.liburing_hash }} - uses: actions/setup-python@v5 with: - python-version: "3.12" + python-version: ${{ inputs.python-version }} - name: Build liburing (if cache miss) if: steps.cache-liburing.outputs.cache-hit != 'true' @@ -44,13 +32,6 @@ runs: ./configure make - - name: Save liburing cache - if: steps.cache-liburing.outputs.cache-hit != 'true' - uses: actions/cache/save@v3 - with: - path: libs/ - key: ${{ steps.cache-info.outputs.os }}-${{ steps.cache-info.outputs.arch }}-liburing-${{ steps.cache-info.outputs.liburing_hash }} - - name: Install liburing (always) shell: bash run: | @@ -60,19 +41,11 @@ runs: - name: Install UV uses: astral-sh/setup-uv@v5 with: - version: "0.6.2" + version: "0.8.13" enable-cache: true - - name: Install Python dependencies (if cache miss) - if: steps.cache-python.outputs.cache-hit != 'true' + - name: Install Python dependencies shell: bash + env: + UV_PYTHON: ${{ inputs.python-version }} run: uv sync --group dev - - - name: Save Python dependencies cache - if: steps.cache-python.outputs.cache-hit != 'true' - uses: actions/cache/save@v3 - with: - path: | - .venv - ~/.cache/uv - key: ${{ runner.os }}-py-${{ hashFiles('uv.lock') }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0e74288..6f98339 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,18 +6,30 @@ on: pull_request: branches: [ main ] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: ci: runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + python-version: ["3.12", "3.13"] + env: + UV_PYTHON: ${{ matrix.python-version }} steps: - name: Checkout Repo uses: actions/checkout@v4 with: submodules: recursive - fetch-depth: 0 - name: Prepare environment uses: ./.github/actions/prepare + with: + python-version: ${{ matrix.python-version }} - name: Lint run: uv run ruff check uringloop tests diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 26e9c7f..dcad568 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -10,12 +10,12 @@ permissions: jobs: release-build: runs-on: ubuntu-latest + timeout-minutes: 15 steps: - name: Checkout Repo uses: actions/checkout@v4 with: submodules: recursive - fetch-depth: 0 - name: Prepare environment uses: ./.github/actions/prepare @@ -24,9 +24,11 @@ jobs: run: | uv build -v --sdist + # TODO: switch to PyPI Trusted Publishing (OIDC) and drop the token: + # https://docs.pypi.org/trusted-publishers/ - name: Upload distributions env: TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} # - run: | + TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} + run: | uv run twine upload --verbose --repository pypi dist/* diff --git a/pyproject.toml b/pyproject.toml index 1cded92..02e8b57 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,10 +29,17 @@ dev = [ "mdformat>=0.7.22", "pytest>=8.3.5", "pytest-asyncio>=0.26.0", + "pytest-timeout>=2.3.1", "ruff>=0.11.4", "twine>=6.1.0", ] +## pytest +[tool.pytest.ini_options] +# the e2e tests drive a real event loop; a wedged loop should fail the +# test instead of hanging CI forever +timeout = 120 + ## ruff [tool.ruff] # Exclude a variety of commonly ignored directories. diff --git a/uv.lock b/uv.lock index 785a122..9db3133 100644 --- a/uv.lock +++ b/uv.lock @@ -351,6 +351,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/7f/338843f449ace853647ace35870874f69a764d251872ed1b4de9f234822c/pytest_asyncio-0.26.0-py3-none-any.whl", hash = "sha256:7b51ed894f4fbea1340262bdae5135797ebbe21d8638978e35d31c6d19f72fb0", size = 19694, upload-time = "2025-03-25T06:22:27.807Z" }, ] +[[package]] +name = "pytest-timeout" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/82/4c9ecabab13363e72d880f2fb504c5f750433b2b6f16e99f4ec21ada284c/pytest_timeout-2.4.0.tar.gz", hash = "sha256:7e68e90b01f9eff71332b25001f85c75495fc4e3a836701876183c4bcfd0540a", size = 17973, upload-time = "2025-05-05T19:44:34.99Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/b6/3127540ecdf1464a00e5a01ee60a1b09175f6913f0644ac748494d9c4b21/pytest_timeout-2.4.0-py3-none-any.whl", hash = "sha256:c42667e5cdadb151aeb5b26d114aff6bdf5a907f176a007a30b940d3d865b5c2", size = 14382, upload-time = "2025-05-05T19:44:33.502Z" }, +] + [[package]] name = "pywin32-ctypes" version = "0.2.3" @@ -494,6 +506,7 @@ dev = [ { name = "mdformat" }, { name = "pytest" }, { name = "pytest-asyncio" }, + { name = "pytest-timeout" }, { name = "ruff" }, { name = "twine" }, ] @@ -506,6 +519,7 @@ dev = [ { name = "mdformat", specifier = ">=0.7.22" }, { name = "pytest", specifier = ">=8.3.5" }, { name = "pytest-asyncio", specifier = ">=0.26.0" }, + { name = "pytest-timeout", specifier = ">=2.3.1" }, { name = "ruff", specifier = ">=0.11.4" }, { name = "twine", specifier = ">=6.1.0" }, ]