-
-
Notifications
You must be signed in to change notification settings - Fork 957
Set up Python monorepo with uv workspaces; migrate kolibri-sync-extras-plugin #14945
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
rtibbles
merged 52 commits into
learningequality:develop
from
rtibblesbot:issue-14663-13d55f
Jul 2, 2026
Merged
Changes from all commits
Commits
Show all changes
52 commits
Select commit
Hold shift + click to select a range
dce2202
Initial commit
bjester 23543a7
Initial commit
bjester f22b965
Complete initial working plugin setup
bjester 47562d4
Merge pull request #1 from bjester/main
bjester 20aac9c
Update python workflow
bjester c4cb8a6
Merge branch 'main' of github.com:learningequality/kolibri-sync-extra…
bjester a345cbd
Add KOLIBRI_HOME env to workflow setup
bjester aff5276
Fix linting issues and broken python workflow
bjester 35c67aa
Add ending new line to requirements
bjester e029d07
Add pypi publish workflow
bjester fb792df
Version 0.1.0
bjester d8807ac
Fix issue with Manifest excluding sources
bjester 8031e64
Merge pull request #2 from learningequality/bjester-main
bjester 93a8eac
Fix missing check for option; fix serializing set to JSON
bjester 4640c97
Bump version to 0.1.2
bjester 84cbcf6
Merge pull request #3 from learningequality/bjester-main
bjester 09c1f6b
Remove duplicate tests
bjester 56d5d4b
Fix broken operations tests
bjester 6af62f0
Fix issue with wrong method name for 'deserializing_operations'
bjester b832f67
Update worfklows
bjester 9fee101
Bump version
bjester 8a4312c
Merge branch 'main' into bjester-main
bjester 4e576a8
Merge pull request #6 from learningequality/bjester-main
bjester d67f3b8
upgrade queue mechanisms to kolibri 0.16
ad1cde6
Separate extra_metadata
0881fad
Merge pull request #9 from learningequality/upgrade_to_0.16
jredrejo e7435c8
Bump version to 0.2.x for Kolibri 0.16
bjester 23226a5
Missing comma
38dd78b
fix test
25ee083
Merge pull request #10 from learningequality/missing_comma
jredrejo 2642c7c
update version
e93a82c
Remove extranous command option
bjester a9f11f6
Fix broken test
bjester 620357d
Merge pull request #12 from learningequality/extraneous
bjester 2a64172
Migrate to uv, setuptools-scm, prek, ruff plus pre-commit add-ons
bjester 2b3c8eb
Update Github CI for migration
bjester ed4a816
Apply new formatting
bjester 8eafeb1
Merge pull request #13 from learningequality/uv-migration
rtibbles a239985
Merge kolibri-sync-extras-plugin history into python_packages/
rtibblesbot ae06e99
Add python_packages/ as a uv workspace member and migrate kolibri-syn…
rtibblesbot 288bf95
Remove kolibri-sync-extras-plugin's redundant standalone CI/lint config
rtibblesbot 82332c5
Add OIDC-based PyPI publishing workflow
rtibblesbot f087f93
Split Python CI into a Stage 1 / Stage 2 cascade
rtibblesbot 9676c80
Document the Python monorepo structure and CI cascade
rtibblesbot ade348e
Merge remote-tracking branch 'origin/develop' into issue-14663-13d55f
rtibblesbot 9b20a7c
Correct the python_monorepo howto's uv sync guidance
rtibblesbot 6a3cdf3
Fix sync_extras_plugin_tests dropping root kolibri deps from the shar…
rtibblesbot 32ca3f0
Fix stale uv sync guidance in kolibri-sync-extras-plugin's README
rtibblesbot 154043e
Correct python_monorepo howto: --package also drops root kolibri deps
rtibblesbot ed37b20
Fill in howto gaps for adding a Python member package
rtibblesbot e2cff6e
Clean up kolibri-sync-extras-plugin's remaining standalone-repo artif…
rtibblesbot 0c43fbc
Simplify pypi_publish.sh's version-comparison logic
rtibblesbot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| name: Publish packages to PyPI | ||
| on: | ||
| push: | ||
| branches: | ||
| - develop | ||
| paths: | ||
| - 'python_packages/kolibri-sync-extras-plugin/pyproject.toml' | ||
| workflow_dispatch: | ||
| inputs: | ||
| pypi_package: | ||
| description: 'Package to publish (or "all" to auto-detect)' | ||
| required: true | ||
| type: choice | ||
| default: 'all' | ||
| options: | ||
| - 'all' | ||
| - 'kolibri-sync-extras-plugin' | ||
| target: | ||
| description: 'Index to publish to' | ||
| required: true | ||
| type: choice | ||
| default: 'pypi' | ||
| options: | ||
| - 'pypi' | ||
| - 'testpypi' | ||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| jobs: | ||
| publish: | ||
| runs-on: ubuntu-latest | ||
| env: | ||
| PYPI_TARGET: ${{ github.event.inputs.target }} | ||
| permissions: | ||
| contents: read | ||
| id-token: write # Required for PyPI OIDC trusted publishing | ||
| steps: | ||
| - uses: actions/checkout@v7.0.0 | ||
| - name: Set up uv | ||
| uses: astral-sh/setup-uv@v8.2.0 | ||
| with: | ||
| enable-cache: true | ||
| cache-python: true | ||
| - name: Install Python | ||
| run: uv python install 3.10 | ||
| - name: Publish | ||
| id: publish | ||
| run: | | ||
| if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ github.event.inputs.pypi_package }}" != "all" ]; then | ||
| ./scripts/pypi_publish.sh "${{ github.event.inputs.pypi_package }}" | ||
| else | ||
| ./scripts/pypi_publish.sh | ||
| fi | ||
| if [ -f publish_summary.md ]; then | ||
| cat publish_summary.md >> "$GITHUB_STEP_SUMMARY" | ||
| echo "published=true" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "No packages needed publishing — all versions match the target index." >> "$GITHUB_STEP_SUMMARY" | ||
| fi | ||
| - name: Build Slack message | ||
| if: steps.publish.outputs.published == 'true' && env.PYPI_TARGET != 'testpypi' | ||
| id: slack_message | ||
| run: | | ||
| run_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" | ||
| { | ||
| echo "text<<SLACKEOF" | ||
| echo ":package: *PyPI package published* (<${run_url}|workflow run>)" | ||
| sed -n 's#^| *\[\([^]]*\)\](\([^)]*\)) *| *\([^ |]*\) *|$#• <\2|\1> v\3#p' publish_summary.md | ||
| echo "SLACKEOF" | ||
| } >> "$GITHUB_OUTPUT" | ||
| - name: Notify Slack | ||
| if: steps.publish.outputs.published == 'true' && env.PYPI_TARGET != 'testpypi' | ||
| uses: slackapi/slack-github-action@v3 | ||
| with: | ||
| # Intentionally shared with npm_publish.yml — one Slack channel for | ||
| # all package-publish notices; the message text disambiguates them. | ||
| webhook: ${{ secrets.SLACK_NPM_PACKAGES_WEBHOOK }} | ||
| webhook-type: incoming-webhook | ||
| payload: | | ||
| { | ||
| "text": ${{ toJSON(steps.slack_message.outputs.text) }} | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| # Adding a Python member package | ||
|
|
||
| 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/`. | ||
|
|
||
| ## Adding a new package | ||
|
|
||
| 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). | ||
| 2. If it depends on `kolibri` itself, resolve that dependency against this workspace instead of PyPI: | ||
| ```toml | ||
| [tool.uv.sources] | ||
| kolibri = { workspace = true } | ||
| ``` | ||
| 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. | ||
| 4. Run `uv sync --group dev` at the repo root to update the shared lockfile. | ||
| 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. | ||
| 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. | ||
| 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. | ||
|
|
||
| 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. | ||
|
|
||
| ## Marking a package as publishable | ||
|
|
||
| By default, a package under `python_packages/` is workspace-only — nothing publishes it. To publish it to PyPI: | ||
|
|
||
| 1. Add its `pyproject.toml` path to the `paths:` filter in `.github/workflows/pypi_packages_publish.yml`'s `push` trigger. | ||
| 2. Add its name to the `workflow_dispatch.inputs.pypi_package.options` list in the same file. | ||
| 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. | ||
|
|
||
| ## CI cascade | ||
|
|
||
| Python tests run in two stages (`.github/workflows/tox.yml`): | ||
|
|
||
| - **Stage 1** (blocking, fast feedback): core Kolibri tests on Python 3.10, and Postgres tests. Runs in parallel. | ||
| - **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. | ||
|
|
||
| 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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| # python_packages/ | ||
|
|
||
| Member packages of the Kolibri Python monorepo, managed as a uv workspace. | ||
|
|
||
| Each subdirectory is an independently-versioned, independently-publishable Python | ||
| package with its own `pyproject.toml`. See | ||
| [docs/howtos/python_monorepo.md](../docs/howtos/python_monorepo.md) for how to add | ||
| one. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| # Kolibri's root .gitignore already covers standard Python/IDE artifacts; | ||
| # this file only needs entries specific to this package. | ||
| .kolibri/* | ||
| !.kolibri/options.ini |
3 changes: 3 additions & 0 deletions
3
python_packages/kolibri-sync-extras-plugin/.kolibri/options.ini
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| [Sync] | ||
| BACKGROUND_INITIALIZATION = True | ||
| BACKGROUND_FINALIZATION = True |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
|
|
||
| Credits | ||
| ======= | ||
|
|
||
| Development Lead and Copyright Holder | ||
| ------------------------------------- | ||
|
|
||
| * Learning Equality – info@learningequality.org | ||
|
|
||
| Community | ||
| --------- | ||
|
|
||
| Please feel free to add your name on this list if you do a PR! | ||
|
|
||
| * Blaine Jester |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.