Skip to content

[releases] Harmonize versions and fix PyPI publishing - #1687

Draft
BenjaminPelletier wants to merge 8 commits into
interuss:mainfrom
BenjaminPelletier:harmonize-versions
Draft

[releases] Harmonize versions and fix PyPI publishing#1687
BenjaminPelletier wants to merge 8 commits into
interuss:mainfrom
BenjaminPelletier:harmonize-versions

Conversation

@BenjaminPelletier

Copy link
Copy Markdown
Member

This PR primarily fixes the PyPI publishing configuration to use the interuss_monitoring package name rather than the unavailable monitoring package name, and to ensure the version used for publishing is valid (follows PEP440). To do this consistently, the PR also coalesces multiple disparate versioning scripts into a single get_versions.py. While doing this, I found that tag.sh is only used in an obsolete release workflow so I did not coalesce tag.sh and instead removed it, correcting the release procedure documentation to match current practices. The complexity of build.sh increases somewhat with these changes, so to avoid duplication, build_dev.sh functionality is merged into build.sh and build_dev.sh removed.

@BenjaminPelletier
BenjaminPelletier marked this pull request as ready for review September 3, 2026 00:49
Comment thread monitoring/build.sh
-f monitoring/Dockerfile \
-t "${DOCKER_TAG}" \
--build-arg version="${VERSION_STR}" \
--build-arg commit_hash="${COMMIT_HASH}" \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changed from HEAD to COMMIT_HASH, witch may include the -dirty flag (nit: and it's not an hash).

This is injected in urls by repo_url_of and generate invalid links.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks; this was unintentional and just trying to put everything related to versions in get_version.py -- I've updated to use the full commit hash (in to-be-pushed commit).

help=(
"Explicit output format.\n"
" pep440: Canonical PEP440 version (e.g., '0.31.0', '0.31.0rc1', '0.31.0+gd56bb4d.dirty'); fails for malformed pre-releases (-RC, -1.2, etc.).\n"
" imagetag: docker image tag version (e.g., 'v0.31.0', 'v0.31.0-d56bb4d417-dirty').\n"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imagetags don't have -rc suffix, but pep ones does. Shouldn't it be consistent?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR was previously trying to be consistent with what we had before, but I agree the rc suffix is probably good to have for the image tag; will adjust.

Comment thread pyproject.toml Outdated
tag_regex = "^interuss/monitoring/v(?P<version>\\d+\\.\\d+\\.\\d+)"

# Strictly anchor to the repo-level prefix, 3-part numeric PEP440/SemVer, and optionally PEP440 lowercase '-rcN' suffixes.
tag_regex = "^interuss/monitoring/v(?P<version>\\d+\\.\\d+\\.\\d+(?:-rc\\d+)?)$"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setuptools_scm don't have the same behavior as the rest. Should just the script be re-used?
(if I uv build I get different results, on my fork it thinks its release 0.28.0, where was get_version.py use the remote and use different tags)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've now completely removed setuptool_scm; its pretend versions were very confusing to me and I think the new approach is clearer (and reuses get_version.py).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that probably a good thing, when preparing the package I used it because it is used in other interuss repos, but it needed to much workarounds.

Comment thread RELEASE.md Outdated
## Background

Releases of monitoring are based on git tags in the format `interuss/monitoring/v[0-9]+\.[0-9]+\.[0-9]+`, optionally suffixed with `-[0-9A-Za-z-.]+`. This tag form follows the pattern `[owner]/[component]/[semantic version]`; see [semantic version](https://semver.org) for more information.
Releases of `monitoring` utilize Git tags structured precisely as `interuss/monitoring/v[X].[Y].[Z]`, optionally accompanied by strict pre-release/candidate identifiers adhering to **PEP 440 Pre-Release Conventions**.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are they? There are '-' in some situation described bellow, witch don't strictly follow PEP440 ? (They are allowed, but that not the normalized form')

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've clarified.

Comment thread RELEASE.md Outdated
* **Release Candidates (`vX.Y.Z-rc[N]`)**: **Strict Pre-Release Identifiers**.
* Pre-release tags **must** utilize the strictly lowercase, hyphenated `-rc[N]` suffix (e.g., `v0.31.0-rc1`).
* Build tooling normalizes these delimiters into PEP 440-compliant pre-release strings (`X.Y.Zrc[N]`) for PyPI compatibility.
* Note: Pre-releases containing uppercase identifiers (e.g., `-RC1`), space delimiters, alphabetic metadata, or non-numeric suffixes (e.g., `-alpha`, `-1.2`) are prevented to avoid accidental malformed PyPI publication.

@the-glu the-glu Sep 3, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, but that not very correct: -RC1 is a valid PEP440 format, -alpha as well. Only -1.2 is invalid, PyPI will accept (and normalize) the rest.

We probably want to restrict tags to a common format, but that the same for the docker image, and that not a PEP/PyPI requirement?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-RC1 is not in PEP440 canonical format to be used in public version identifiers, nor is -alpha.

@the-glu the-glu Sep 7, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but build system normalize it, malformed PyPI publication is not possible (and would reject it - same logic as having + to prevent submission):

cat pyproject.toml
─────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
     │ File: pyproject.toml
─────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1 │ [project]
   2 │ name = "testmcuorb"
   3 │ version = "0.0.1-RC2"
   4 │ description = "Test project"
   5 │ requires-python = ">=3.9"
   6 │ 
   7 │ [build-system]
   8 │ requires = ["hatchling"]
   9 │ build-backend = "hatchling.build"
─────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 maximilien@pluna  ~/tmp/testpypi  uv build
Building source distribution...
Building wheel from source distribution...
Successfully built dist/testmcuorb-0.0.1rc2.tar.gz
Successfully built dist/testmcuorb-0.0.1rc2-py3-none-any.whl

Comment thread RELEASE.md Outdated
* **Interim Import Namespace (Phase 1 Phase-in)**:
* Consumers install the package via `pip install interuss_monitoring`.
* In the current structural phase (Phase 1), internal code modules and external users importing from the PyPI package interact with the Python Import Namespace via **`import monitoring.<submodule>`**.
* *Warning for Interim Consumers*: Users must ensure their active Python virtual environment does not contain a conflicting top-level `monitoring/` directory from alternative third-party packages to prevent Python import-shadowing and runtime `ModuleNotFoundError` conflicts.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the whole style of the doc is a bit off (things like "Interim Consumers")

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Interim Consumers" seems fairly clear to me: consumers of the package while it still using monitoring for imports rather than interuss_monitoring. But, I'll see if I can adjust any way.

Comment thread scripts/git/get_version.py Outdated
# If this is not an exact match on the release tag, or if workspace is dirty, append local version
metadata_segments = []
if not is_exact_tag_boundary:
metadata_segments.append(f"g{commit_hash.lstrip('g')}")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What the 'g' ? It cannot be present in a hash ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without --abbrev=0, describe returns something like interuss/monitoring/v1.2.0-4-g2a3b4c5. But the versioning logic is apparently very difficult even when factored out like this, so I'll work to make it as crystal clear as possible.

@BenjaminPelletier
BenjaminPelletier marked this pull request as draft September 3, 2026 18:29
@BenjaminPelletier
BenjaminPelletier marked this pull request as ready for review September 4, 2026 03:47
@BenjaminPelletier

Copy link
Copy Markdown
Member Author

This PR now has substantial changes after the previous round of comments.

Comment thread scripts/git/get_version.py Outdated

# Retrieve whether commit is local-only
cherry_res = run_git_cmd(["cherry"], check=False)
kwargs["is_localcommit"] = cherry_res.returncode == 0 and cherry_res.stdout.strip()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This return a string instead of bool, witch may create unwanted behavior later since it's declared as a bool.

python
Python 3.14.7 (main, Aug 10 2026, 07:46:56) [GCC 16.1.1 20260728] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> True and "a"
'a'

Comment on lines +155 to +157
env_version = os.environ.get("MONITORING_VERSION")
if env_version:
return env_version

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: This is already done in get_pep440_version who is the only caller, this will never happen.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functions must be encapsulated independent of their usage, so what calls this function shouldn't matter (because, for instance, we could add another caller later without being aware of the expectation the caller was supposed to do something) -- instead, it only matters what this function should do. When deriving the PEP440 version given observed GitInfo, it seems reasonable to check the magic environment variable. Or, we could perhaps change GitInfo to SystemInfo or something like that which could include the information of the environment variable value, but I think that would be a different solution that I'm not sure would be better.

Comment thread .gitignore
Comment on lines +26 to +27
build/lib/
build/bdist*/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are those two still needed?

uv build on my machine don't write to build/, but I know you have restrictions with your python setup.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uv build --wheel leaves these artifacts.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, should we move them out then? build is used for other purposes, having it mixed with others artifacts may be an issue no?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what the suggested action is

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

diff --git a/pyproject.toml b/pyproject.toml
index aea1a74cd..984bb0152 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -130,3 +130,6 @@ namespaces = true
 
 [tool.setuptools.dynamic]
 version = {attr = "monitoring._version.__version__"}
+
+[tool.distutils.build]
+build_base = "buildpip"

(With the name to be revised, really not sure about it)

So everything goes to a different directory than the one we use for others scripts.

(It should probably be git ignored as well)

@the-glu

the-glu commented Sep 7, 2026

Copy link
Copy Markdown
Member

This PR now has substantial changes after the previous round of comments.

Thanks! Found a few extra nits, but overall it looks good. I can't resolve the old threads on my side, so I'll let you clean them up.

@mickmis mickmis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, I think. This was pretty challenging to review and I'm not sure I managed to be exhaustive there. Now, the impact in case there is an issue is also relatively limited (nothing that would blow up in prod, only inconveniences for devs), so that is probably OK. However I think a low hanging fruit to mitigate that would be to add unit tests to get_version.py.

"""True when the current state lies exactly on a valid tag (and therefore is suitable for release)."""

full_commit_hash: str
"""Full SHAA-1 commit hash."""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""Full SHAA-1 commit hash."""
"""Full SHA-1 commit hash."""

def get_git_info(component: str) -> GitInfo:
"""Interrogates git for information relevant to versioning."""

kwargs: dict[str, Any] = {"component": component}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a GitInfo to benefit from the interpreter and typing?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't instantiate a dataclass without specifying all its required fields. Specifying all fields in the constructor will add a line per field (instead of GitInfo(**kwargs), it will be GitInfo(component=component, upstream_owner=upstream_owner, ...), but I can do that for easier typing.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The functions in this file would benefit from having unit tests: there is a large combination of outcomes and ensuring those are all correct and will remain correct in the future is pretty hard.

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

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants