Read the Kolibri version from one shared helper across platforms - #15106
Read the Kolibri version from one shared helper across platforms#15106rtibblesbot wants to merge 3 commits into
Conversation
Build Artifacts
Smoke test screenshot |
049574b to
45afba7
Compare
45afba7 to
ad1d187
Compare
rtibbles
left a comment
There was a problem hiding this comment.
My first impression of this from a skim is that this is incredibly verbose for what it achieves and rather than consolidating things and reducing code duplication it seems to add rather a lot of code.
|
Fair, and mostly deserved. Pushed a trim in a78fd26 and cut the PR body down too. The helper was carrying two readers nobody calls. No caller passes an sdist tar — android extracts it and hands over the tree — so the On the volume, with the helper's test set aside the diff is now +112/-98 — so the consolidation is close to line-neutral, and the test file is most of what is left. The Two adds are not consolidation and I should flag them as such: Two places I could go further if you want it — say the word rather than my guessing:
|
1e1d433 to
baf843c
Compare
rtibbles
left a comment
There was a problem hiding this comment.
This is more concise, but I'm confused by the changes to kolibri-server, unless I'm just missing something?
| with open(os.path.join(path, VERSION_MODULE)) as version_module: | ||
| source = version_module.read() | ||
| # ast, not exec: handles either quoting style without running build output. | ||
| for node in ast.parse(source).body: |
There was a problem hiding this comment.
I don't understand why _version.py can't just be imported? It's a standalone file.
There was a problem hiding this comment.
Agreed — it can, and now it is executed rather than parsed. The ast walk is gone:
if path.endswith(".whl"):
with zipfile.ZipFile(path) as wheel:
source = wheel.read(VERSION_MODULE)
else:
with open(os.path.join(path, VERSION_MODULE), "rb") as version_module:
source = version_module.read()
# _version.py imports nothing and only assigns, so running it is the same as
# importing it -- which is not an option for a member of a wheel.
namespace = {}
exec(source, namespace)
return namespace["__version__"]The one reason it is exec on the source rather than an import of the path: the pex target hands over a .whl, and a member of a zip cannot be imported without unpacking it — so reading the text and running it is the single form that covers both a tree and a wheel. The helper is 36 lines now, and the two tests that only pinned the parse (quoting style, version-alias-only) went with it, leaving the two that assert the actual interface: read from a tree, read from a wheel.
rtibbles
left a comment
There was a problem hiding this comment.
OK, let's tidy up the commit history ready for merge here, this doesn't need to be more than a few commits.
ebaa9c0 to
4fff366
Compare
|
Squashed to three commits, one per acceptance criterion — the tree is byte-identical to the previous head:
|
f0c1c0d to
31122b8
Compare
Every platform had its own way of finding the version of the Kolibri it was packaging: android read the plaintext kolibri/VERSION out of the extracted tar, kolibri-server's CI stripped it off the whl job's tar artifact filename, and the pex target parsed wheel METADATA with pkginfo. build_tools/read_whl_version.py becomes read_kolibri_version.py and covers all of them, reading kolibri/_version.py -- the setuptools-scm source of truth -- out of a directory or a wheel. kolibri-server needs no helper call: make deb runs under uv run, so the changelog generator's import kolibri fallback already resolves the same _version.py. So the tar-file-name input, the version step and the cross-job needs: whl all go, which lets the job start in parallel with whl instead of waiting on it. kolibri/VERSION keeps shipping in the sdist despite losing its last in-repo reader: kolibri-installer-debian reads it out of our tar, so deleting it would redden the PR deb job. Both sites now say so. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
needs-version dropped pkginfo.Installed for the shared helper, reading the same kolibrisrc/ tree PyInstaller bundles. $(shell) swallows a nonzero exit, so an empty read gets its own guard rather than passing an empty version into the build. pkginfo was the last consumer of that dependency, so it leaves the build extra. The only way to get a whl in place was make get-whl whl=<URL>, and no released whl ships _version.py, so add stage-workspace-whl to build and stage the checked-out Kolibri instead -- the counterpart to android's stage-workspace-tar. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Quick Start and Initial Setup still told you to clone kolibri-installer-android, make a standalone uv venv and download a pinned v0.17.0 tar, all of which contradicted the monorepo section directly above them. Quick Start now uses the workspace sync and stage-workspace-tar, Initial Setup goes (it duplicated Quick Start otherwise), and make help's stage-workspace-tar line joins the target list. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
31122b8 to
88d4ae4
Compare
Summary
Each platform build read the Kolibri version its own way:
pkginfoagainst an unpacked wheel, the plaintextkolibri/VERSION, or a strip of the sdist tar's filename. The three that have no importable Kolibri at their read point — desktop-app, android, the rootpextarget — now go through one stdlib-only helper keyed onkolibri/_version.py, the file setuptools-scm writes and the onekolibri.__version__itself reads. kolibri-server's read is deleted rather than routed: its.debbuild already runs inside the workspace uv env, sogenerate_changelog.pyimports the version itself. Per-platform conversions (PEP 440 → Debian, AndroidversionCode) stay with their platform. The desktop app also gainsstage-workspace-whl, mirroring android'sstage-workspace-tar, so it can bundle the Kolibri you have checked out instead of a wheel downloaded from a URL.Excluding the helper's test, the diff is +96/-121. The helper is 33 lines and replaces three bespoke reads; the fourth goes away.
pkginfoleaves the desktop app'sbuildextra with it.References
Fixes #15077. Related: #15072 (release-path migration — where the external installer consumers move).
Acceptance criteria
build_tools/read_kolibri_version.pyis the single reader ofkolibri/_version.pyfor the platforms that cannot import it: android (app/build.gradle:113), desktop-app (Makefile:23) and the rootpextarget (Makefile:229). kolibri-server can import it, so it does —generate_changelog.py:52, the same readplatform-debian-server-release.yml:35already used — and its tar-filename strip is gone.stage-workspace-whlmirroring android'sstage-workspace-tar.platforms/desktop-app/Makefile:80.get-tarinstructions gone fromplatforms/android/README.md.grep -n "get-tar\|kolibri-installer-android\|uv venv\|--extra build\|0\.17\.0" platforms/android/README.mdreturns nothing.(Ticked here and in this issue comment rather than in the issue body — this account lacks
UpdateIssuepermission onlearningequality/kolibri.)Deviations from the issue spec
kolibri/VERSIONis not retired, though the issue thread asked for it once android stopped reading it. It has no reader in this repo, butkolibri-installer-debianuntars the sdist we publish and reads it out of that tar (Makefile:18-21atv0.16.1), and this repo calls that installer frompr_build_kolibri.yml:24-30andrelease_kolibri.yml:78. Deleting the file turns the PRdebjob red, takingzip,pi_smoke_testandserver_smoke_testwith it.Makefile:204records this; please sanity-check the pins. (The externalkolibri-installer-androidreads it too, but no workflow here calls that repo any more —platforms/android/builds both the PR and the release APK — so the retention rests on the one Debian consumer.).deb-filename parse (platforms/raspberry-pi/Makefile:62). The.debit packages is the correct artifact there — the version is already Debian-converted and no_version.pyexists at Pi-image build — so the helper would mean reading a version it does not ship.Open question
_version.py, so aworkflow_dispatchofplatform-android-build_apk.ymlwith a pre-monorepo releasetar-urlnow fails at Gradle configure. The reusable-call path frompr_build_kolibri.ymlis unaffected (same-commit tar). Acceptable, or should the read fall back?platforms/desktop-app/README.md:44still saysgit clone kolibri-app.git. Its build section is rewritten here forstage-workspace-whl, but that pre-monorepo clone step is left — the same staleness AC3 fixed for android, and AC3 names only the android file. Happy to fold it in.AI usage
Used Claude Code to implement the plan agreed in the issue thread, writing the version-read helper test-first and scoping the
kolibri/VERSIONquestion against the external installer repos before deciding not to delete it. Verified with thetest/suite,prek run --all-files, a real Gradle configure against a workspace-built sdist, an end-to-endmake stage-workspace-whl, and a round-trip of the read throughgenerate_changelog.py's Debian conversion.@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly
How was this generated?
🟡 Waiting for feedback
Last updated: 2026-07-30 06:01 UTC