Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
7c9d0fa
chore(downstream): uv driver and TOML recipes for downstream checks
RonnyPfannschmidt May 6, 2026
df2257b
ci: add manual downstream workflow for recipe matrix
RonnyPfannschmidt May 6, 2026
9b120a9
ci: run downstream workflow when PR has run-downstream label
RonnyPfannschmidt May 6, 2026
82b714c
ci: gate downstream PR runs on branch name containing downstream
RonnyPfannschmidt May 6, 2026
895d3fe
ci: use full git history for downstream workflow checkout
RonnyPfannschmidt May 6, 2026
f8fb1ee
fix(downstream): install pytest-mock for hatch recipe
RonnyPfannschmidt May 10, 2026
b806ff9
fix(downstream): resolve env setup issues in downstream recipes
RonnyPfannschmidt May 10, 2026
9102a49
fix(downstream): fix tox CI detection, devpi deselect, drop conda env…
RonnyPfannschmidt May 11, 2026
198eb6a
fix(downstream): remove CI env vars for tox instead of overriding
RonnyPfannschmidt May 12, 2026
e56d977
fix(downstream): configure conda channels via condarc for test suite
RonnyPfannschmidt May 12, 2026
f418924
fix(downstream): deselect conda export-from-history test
RonnyPfannschmidt May 12, 2026
b8fceda
refactor(downstream): simplify to uv-venv and script env kinds
RonnyPfannschmidt May 12, 2026
b6be9d9
refactor(downstream): flatten environment schema, distinguish by stru…
RonnyPfannschmidt May 12, 2026
fa2af2b
cleanup(downstream): remove redundant type conversions in driver
RonnyPfannschmidt May 12, 2026
40f3ab1
fix(downstream): fix RuntimeError from mutating dict during iteration
RonnyPfannschmidt May 13, 2026
5b9a37c
Apply suggestions from code review
RonnyPfannschmidt May 17, 2026
2ca2419
fix(downstream): revert CONDARC tmpfile change in conda.bash
RonnyPfannschmidt May 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions .github/workflows/downstream.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Downstream checks run on pull requests to main when the head branch name
# contains "downstream", or any time via workflow_dispatch. For dispatch-only
# runs: Actions → downstream → Run workflow → pick a branch under "Use workflow from".
#
# The workflow must exist on the default branch for it to appear under the
# upstream repo's Actions tab; until the workflow is merged, use the fork's
# Actions (or dispatch from a branch that contains this file).
name: downstream

on:
workflow_dispatch:
pull_request:
branches:
- main

permissions: {}

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
recipe:
name: downstream (${{ matrix.recipe }})
runs-on: ubuntu-latest
timeout-minutes: 120
if: >-
github.event_name == 'workflow_dispatch'
|| (github.event_name == 'pull_request' && contains(github.head_ref, 'downstream'))
strategy:
fail-fast: false
matrix:
recipe:
- conda
- datasette
- devpi
- hatch
- pytest
- python-lsp-server
- tox
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
allow-prereleases: true
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
- name: Run downstream recipe
run: uv run downstream/run_downstream.py "${{ matrix.recipe }}"
5 changes: 3 additions & 2 deletions RELEASING.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
Release Procedure
-----------------

#. Dependening on the magnitude of the changes in the release, consider testing
#. Depending on the magnitude of the changes in the release, consider testing
some of the large downstream users of pluggy against the upcoming release.
You can do so using the scripts in the ``downstream/`` directory.
You can do so with ``uv run downstream/run_downstream.py <recipe>``;
use ``--list`` to discover available recipes.

#. From a clean work tree, execute::

Expand Down
1 change: 1 addition & 0 deletions downstream/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
/devpi/
/hatch/
/pytest/
/python-lsp-server/
/tox/
31 changes: 29 additions & 2 deletions downstream/README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,29 @@
This directory contains scripts for testing some downstream projects
against your current pluggy worktree.
This directory contains tooling for testing some downstream projects against
your current pluggy checkout.

Each project is described by a TOML recipe in `recipes/` with three sections:

1. **`[git]`** — repository URL, local directory name (`into`), optional `shallow`
(default: shallow clone).
2. **`[environment]`** — distinguished by structure (no `kind` key needed):
- **uv-venv** (has `editables`): creates `uv venv`, installs via
`uv pip install`. `editables` are passed as `-e` args. Optional
`groups` and `packages` for extra dependencies.
- **script** (has `run`): delegates bootstrap, install, and test to a
bash script (path relative to `downstream/`). No `[[test]]` steps.
3. **`[[test]]`** (uv-venv only) — one or more `argv` arrays. The driver sets
**`VIRTUAL_ENV`** and prepends the venv's `bin` to **`PATH`**, so test
commands can use bare names like `pytest`. Optional **`env`** table sets
extra environment variables; an empty string removes the variable (e.g.
`env = { CI = "" }` to unset `CI`).
Install only: `--only-install`. Skip install: `--skip-install`.

Run the driver (PEP 723 in `run_downstream.py`):

```bash
uv run downstream/run_downstream.py --list
uv run downstream/run_downstream.py pytest
uv run downstream/run_downstream.py pytest --skip-install
```

Requirements: Python 3.11+ for the driver, `git`, and `uv`.
12 changes: 0 additions & 12 deletions downstream/conda.sh

This file was deleted.

10 changes: 0 additions & 10 deletions downstream/datasette.sh

This file was deleted.

13 changes: 0 additions & 13 deletions downstream/devpi.sh

This file was deleted.

10 changes: 0 additions & 10 deletions downstream/hatch.sh

This file was deleted.

10 changes: 0 additions & 10 deletions downstream/pytest.sh

This file was deleted.

31 changes: 0 additions & 31 deletions downstream/python-lsp-server.sh

This file was deleted.

22 changes: 22 additions & 0 deletions downstream/recipes/conda.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
# Bootstrap, install, and test conda against the local pluggy checkout.
# Called from run_downstream.py via the conda recipe.
set -eu

cd "$(dirname "$0")/../conda"

# dev/start needs relaxed error handling during bootstrap.
set +eu
source dev/start
set -eu

# Install pluggy editable from the parent checkout.
pip install -e ../..

# Mirror conda's own CI condarc-defaults so tests that create temporary
# environments can resolve packages.
conda config --add channels defaults

pytest \
-m 'not integration and not installed' \
--deselect=tests/cli/test_main_export.py::test_export_from_history_format
7 changes: 7 additions & 0 deletions downstream/recipes/conda.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[git]
url = "https://github.com/conda/conda"
into = "conda"
shallow = false

[environment]
run = "recipes/conda.bash"
10 changes: 10 additions & 0 deletions downstream/recipes/datasette.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[git]
url = "https://github.com/simonw/datasette"
into = "datasette"

[environment]
editables = [".", "../.."]
groups = ["dev"]

[[test]]
argv = ["pytest"]
21 changes: 21 additions & 0 deletions downstream/recipes/devpi.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[git]
url = "https://github.com/devpi/devpi"
into = "devpi"

[environment]
editables = ["common", "server", "client", "web", "../.."]
groups = ["pytest"]

[[test]]
argv = ["pytest", "common"]

[[test]]
argv = ["pytest", "server"]

[[test]]
# Ignore test_upload: upstream conftest bug compares code=[200,200,200]
# against integers, causing TypeError on every upload-with-docs test.
argv = ["pytest", "client", "--ignore=client/testing/test_upload.py"]

[[test]]
argv = ["pytest", "web"]
18 changes: 18 additions & 0 deletions downstream/recipes/hatch.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[git]
url = "https://github.com/pypa/hatch"
into = "hatch"

[environment]
editables = [".", "./backend", "../.."]
packages = [
"pytest",
"pytest-mock",
"pytest-xdist",
"filelock",
"flit-core",
"trustme",
"editables",
]

[[test]]
argv = ["pytest", "tests/backend"]
10 changes: 10 additions & 0 deletions downstream/recipes/pytest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[git]
url = "https://github.com/pytest-dev/pytest"
into = "pytest"
shallow = false

[environment]
editables = [".[dev]", "../.."]

[[test]]
argv = ["pytest"]
15 changes: 15 additions & 0 deletions downstream/recipes/python-lsp-server.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[git]
url = "https://github.com/python-lsp/python-lsp-server.git"
into = "python-lsp-server"

[environment]
editables = [".[all,test]", "../.."]

[[test]]
# Deselect two jedi-environment tests that require /tmp/pyenv/ fixture
# not provided by the default test environment.
argv = [
"pytest",
"--deselect=test/plugins/test_completion.py::test_jedi_completion_environment",
"--deselect=test/plugins/test_symbols.py::test_symbols_all_scopes_with_jedi_environment",
]
16 changes: 16 additions & 0 deletions downstream/recipes/tox.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[git]
url = "https://github.com/tox-dev/tox"
into = "tox"
shallow = false

[environment]
editables = [".[completion]", "../.."]
groups = ["test"]

[[test]]
argv = ["pytest"]
# tox's is_ci() checks presence of CI, value of GITHUB_ACTIONS, and
# other env vars. Empty string = remove from environment, non-empty
# overrides value. Both must be gone for list_dependencies to default
# to False and test expectations (no freeze steps, etc.) to hold.
env = { CI = "", GITHUB_ACTIONS = "" }
Loading
Loading