Skip to content

fix: normalize dev versions to valid SemVer strings - #15270

Open
SatyamPandey-07 wants to merge 1 commit into
learningequality:developfrom
SatyamPandey-07:bugfix/normalize-semver-dev-versions
Open

fix: normalize dev versions to valid SemVer strings#15270
SatyamPandey-07 wants to merge 1 commit into
learningequality:developfrom
SatyamPandey-07:bugfix/normalize-semver-dev-versions

Conversation

@SatyamPandey-07

@SatyamPandey-07 SatyamPandey-07 commented Sep 6, 2026

Copy link
Copy Markdown

Summary

  • Headline: Normalize development and fallback build version strings to valid SemVer 2.0 identifiers.
  • Motivation: When running tests or starting Kolibri in environments without release tags (e.g. fresh clones, forks, or shallow checkouts), setuptools-scm emits fallback development versions such as 0.1.dev38363+g356cfe2f5. During module initialization, kolibri.core.upgrade passes kolibri.__version__ through normalize_version_to_semver() before parsing it with semver.VersionInfo.parse(). Due to a regex flaw in normalize_version_to_semver(), the preceding dot before .dev was captured into the numeric prefix and .dev was duplicated into both after and dev, producing 0.1.-dev38363.dev38363.g356cfe2f5. This causes semver.VersionInfo.parse() to raise an unhandled ValueError: ... is not valid SemVer string, breaking pytest and Django startup entirely. Similarly, standard post-release dev strings like 0.1.2.dev6+gdef09150 resulted in 0.1.2-dev6.dev6.gdef09150.
  • Approach:
    1. Deconstruct the version string into its pre-dev base and .dev suffix separately so the dev fragment is never matched twice.
    2. Parse the base version using ^\d+\.\d+(?:\.\d+)? to prevent trailing dot leakage into the numeric prefix.
    3. Ensure bipartite numeric versions followed by a dev suffix (e.g., 0.1.dev...) receive a .0 patch segment so they comply with SemVer's MAJOR.MINOR.PATCH specification.
    4. Preserve existing behavior for standard release and prerelease tags (0.15.0, 1.10, 0.14a1, 0.16b1).
    5. Add unit test coverage in kolibri/utils/tests/test_version.py for both setuptools-scm dev and bipartite fallback versions.

References

Reviewer guidance

  • Run unit tests for version normalization:
    uv run pytest kolibri/utils/tests/test_version.py
    All 76 tests should pass.
  • Verify Django test settings load and execute properly on dev builds:
    uv run pytest kolibri/core/courses/test/test_models.py
    Verify that kolibri.core.upgrade imports cleanly without ValueError.
  • Verify code formatting and linting:
    uv run ruff check kolibri/utils/version.py kolibri/utils/tests/test_version.py
    uv run ruff format --check kolibri/utils/version.py kolibri/utils/tests/test_version.py

AI usage

I used Antigravity / Gemini to locate where kolibri.core.upgrade fails during pytest startup and identify the regex mismatch in normalize_version_to_semver(). I reviewed the SemVer 2.0 specification and semver library constraints, implemented the fix to prevent trailing dot leakage and duplicate .dev fragments, wrote regression tests in kolibri/utils/tests/test_version.py, and verified the entire test suite runs without errors.

@github-actions github-actions Bot added DEV: backend Python, databases, networking, filesystem... SIZE: small labels Sep 6, 2026
@learning-equality-bot

Copy link
Copy Markdown

👋 Hi @SatyamPandey-07, thanks for contributing!

For the review process to begin, please verify that the following is satisfied:

  • Contribution is aligned with our contributing guidelines

  • Pull request description has correctly filled AI usage section & follows our AI guidance:

    AI guidance

    State explicitly whether you didn't use or used AI & how.

    If you used it, ensure that the PR is aligned with Using AI as well as our DEEP framework. DEEP asks you:

    • Disclose — Be open about when you've used AI for support.
    • Engage critically — Question what is generated. Review code for correctness and unnecessary complexity.
    • Edit — Review and refine AI output. Remove unnecessary code and verify it still works after your edits.
    • Process sharing — Explain how you used the AI so others can learn.

    Examples of good disclosures:

    "I used Claude Code to implement the component, prompting it to follow the pattern in ComponentX. I reviewed the generated code, removed unnecessary error handling, and verified the tests pass."

    "I brainstormed the approach with Gemini, then had it write failing tests for the feature. After reviewing the tests, I used Claude Code to generate the implementation. I refactored the output to reduce verbosity and ran the full test suite."

Also check that issue requirements are satisfied & you ran pre-commit locally.

Pull requests that don't follow the guidelines will be closed.

Reviewer assignment can take up to 2 weeks.

@SatyamPandey-07

Copy link
Copy Markdown
Author

@AlexVelezLl just bumping this PR in case it slipped through your notifications. Let me know if you need any changes or further testing!

@SatyamPandey-07

Copy link
Copy Markdown
Author

@rtibbles just bumping this PR in case it slipped through your notifications. Let me know if you need any changes or further testing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DEV: backend Python, databases, networking, filesystem... SIZE: small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Brief description] Fix invalid SemVer normalization for development and setuptools-scm version strings

1 participant