You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/development_workflow.rst
+3Lines changed: 3 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -95,6 +95,9 @@ First, all automated checks need to pass before merging. Then...
95
95
* The reviewer might approve the PR, but also request minor changes such as a typo fix or variable name update. The submitter can then make the change and merge it themselves, with the understanding that the new changes will be limited in scope
96
96
* Stale reviews should be dismissed by the PR submitter when the feedback has been addressed
97
97
98
+
.. note::
99
+
Python tests run in a two-stage cascade (Stage 1: Python 3.10 + Postgres required before Stage 2). See :doc:`/howtos/python_monorepo`.
Kolibri's Python code is organized as a [uv workspace](https://docs.astral.sh/uv/concepts/projects/workspaces/). The main `kolibri` package is the workspace root; additional packages live under `python_packages/`.
4
+
5
+
## Adding a new package
6
+
7
+
1. Create `python_packages/<package-name>/` with its own `pyproject.toml` — a normal, independently-buildable Python package (own `[build-system]`, own static `version`, own dependencies).
8
+
2. If it depends on `kolibri` itself, resolve that dependency against this workspace instead of PyPI:
9
+
```toml
10
+
[tool.uv.sources]
11
+
kolibri = { workspace = true }
12
+
```
13
+
3. No change is needed to the root `pyproject.toml` — its `[tool.uv.workspace]``members` list already includes the glob `python_packages/*`, so any new package directory under it is picked up automatically.
14
+
4. Run `uv sync --group dev` at the repo root to update the shared lockfile.
15
+
5. Run `uv sync --group dev --all-packages` to install the new package into the shared workspace venv. `--all-packages` is required — a plain `uv sync` (or `uv sync --package <package-name>`) scopes the sync to a single project and drops root Kolibri's own runtime dependencies (Django, Click, etc.) from the shared venv.
16
+
6. Add a test job for it in `.github/workflows/tox.yml`, in the Stage 2 section (see "CI cascade" below) — model it on the `sync_extras_plugin_tests` job, and add the new job's id to `stage2_required_checks`'s `needs:` list in the same file. A job left out of that list can fail without blocking merge, since branch protection only requires `stage2_required_checks` itself to pass.
17
+
7. Add the package's import name to `known-first-party` in root `pyproject.toml`'s `[tool.ruff.lint.isort]` table, so ruff sorts its own imports as first-party rather than third-party.
18
+
19
+
Member package versions are independent of each other and of the main `kolibri` package — there's no enforcement linking them. Use a static `version = "x.y.z"` field, not `setuptools-scm`-derived dynamic versioning: this repo's git tags are Kolibri's own release tags, so dynamic versioning inside the workspace would report Kolibri's version instead of the package's own.
20
+
21
+
## Marking a package as publishable
22
+
23
+
By default, a package under `python_packages/` is workspace-only — nothing publishes it. To publish it to PyPI:
24
+
25
+
1. Add its `pyproject.toml` path to the `paths:` filter in `.github/workflows/pypi_packages_publish.yml`'s `push` trigger.
26
+
2. Add its name to the `workflow_dispatch.inputs.pypi_package.options` list in the same file.
27
+
3. Register a pending trusted publisher on PyPI and TestPyPI (see the "Python packages" section of [the release process docs](../release_process.rst)) before merging.
28
+
29
+
## CI cascade
30
+
31
+
Python tests run in two stages (`.github/workflows/tox.yml`):
32
+
33
+
-**Stage 1** (blocking, fast feedback): core Kolibri tests on Python 3.10, and Postgres tests. Runs in parallel.
34
+
-**Stage 2** (gated on Stage 1 via `needs:`): the rest of the Python version matrix, plus a test job per publishable member package. Acts as a broader safety net — it rarely fails once Stage 1 passes, but still gates merge.
35
+
36
+
Both stages are required checks in branch protection. Lint, wheel build, and JS tests are unaffected — they run in their own workflows, in parallel with Stage 1.
Packages in ``python_packages/`` are published to PyPI independently of Kolibri releases and independently of each other. Only publishable packages are published; everything else is workspace-only. A package is publishable if it's listed in ``pypi_packages_publish.yml``'s ``paths:`` filter and ``workflow_dispatch`` options.
66
+
67
+
Automatic publishing
68
+
--------------------
69
+
70
+
When code merging to ``develop`` changes a listed package's ``pyproject.toml``, the ``pypi_packages_publish.yml`` workflow compares that package's version against PyPI and publishes it if newer.
71
+
72
+
Authentication uses PyPI OIDC trusted publishing (no API tokens).
73
+
74
+
The workflow can also be triggered manually from the Actions tab — either for a specific package or for all packages — and can target TestPyPI instead of PyPI via the ``target`` input.
75
+
76
+
Bumping a version
77
+
-----------------
78
+
79
+
.. code-block:: bash
80
+
81
+
uv version --package <package-name> --bump patch
82
+
83
+
Or set an exact version: ``uv version --package <package-name> <new-version>``. Commit the resulting ``pyproject.toml``/``uv.lock`` change and merge to ``develop``.
84
+
85
+
First publish of a new package
86
+
------------------------------
87
+
88
+
PyPI and TestPyPI support registering a *pending* trusted publisher for a project that doesn't exist yet. Before merging the PR that adds the package, register a pending publisher on both `pypi.org <https://pypi.org/manage/account/publishing/>`__ and `test.pypi.org <https://test.pypi.org/manage/account/publishing/>`__ for the new project name, with owner ``learningequality``, repository ``kolibri``, and workflow ``pypi_packages_publish.yml``.
0 commit comments