feat(build-time-versioning): xceadmin committed fallback stub and CLI version wiring

Commits a fallback src/xceadmin/src/xceadmin/_build_info.py (GIT_COMMIT/
BUILD_TIME both "unknown") for install paths that never run meson-build.sh
(e.g. `pip install -e .`), and wires click.version_option() on cli.py's
top-level group. cli.py imports _build_info defensively (try/except
ImportError with an inline fallback) and composes the version string from
importlib.metadata.version("xceadmin") plus both build-info fields.

Verified independently by review: editable install shows "unknown" for
both fields with no import error; the meson-built wheel shows real,
matching commit id + build time; full xceadmin suite 261 passed/3 skipped
(258 baseline + 3 new tests); ruff clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-08-20 14:47:20 +00:00
parent e1cd9d257c
commit 7f5c87ce9d
No known key found for this signature in database
GPG key ID: 5BCDAAE0123E9FE2
4 changed files with 114 additions and 5 deletions

View file

@ -90,7 +90,7 @@
- _Boundary: xcecli/cmd/main.go, xcecli/router/router.go_
- _Depends: 4.1_
- [ ] 5. Core: xceadmin version display
- [x] 5. Core: xceadmin version display
- [x] 5.1 (P) meson-build.sh generates a build-info module before packaging
- `commit_id`/`build_time` passed as 2 new positional args (`$6`/`$7`, matching this custom_target's existing all-positional style); write block sits between schema-sync and `pip install`, with an independent-per-field `unknown` fallback and a file-existence guard checking the exact path it just wrote (the mirrored tree, not the real source tree)
- Observable confirmed live (full real build+test+wheel cycle, independently re-run by review): mirrored tree's `_build_info.py` and the packaged wheel both contain real, matching, non-`unknown` values; 258 tests pass, 3 skips confirmed as documented live-HA e2e tests
@ -98,12 +98,13 @@
- _Boundary: xceadmin/meson.build, xceadmin/meson-build.sh_
- _Depends: 1_
- [ ] 5.2 (P) Committed fallback stub and CLI version wiring
- Commit a fallback `src/xceadmin/src/xceadmin/_build_info.py` with both fields set to `unknown` (used whenever 5.1's generated version isn't present, e.g. `pip install -e .`)
- Wire `click.version_option()` on `cli.py`'s top-level group, importing `_build_info` defensively and composing its version string from `pyproject.toml`'s static version plus the two build-info fields
- Observable: both `pip install -e .` (no meson) and the meson-built wheel produce a working `xceadmin --version` that prints and exits; the editable-install case shows `unknown` for both build fields, never an import error
- [x] 5.2 (P) Committed fallback stub and CLI version wiring
- Committed `src/xceadmin/src/xceadmin/_build_info.py` with `GIT_COMMIT`/`BUILD_TIME` both `"unknown"` -- exact variable names verified identical to 5.1's `meson-build.sh`-generated module; `cli.py`'s import is a genuine `try/except ImportError` (inline fallback class), not a bare import
- `click.version_option()` wired directly on the top-level `@click.group() def cli()`; version string composed via `importlib.metadata.version("xceadmin")` plus both `_build_info` fields, no hand-parsed `pyproject.toml`
- Observable confirmed live (independently re-verified by review, both install paths): fresh scratch-venv editable install (`pip install --no-deps -e .`, no meson) -> `xceadmin --version` prints `0.1.0 (unknown, unknown)`, exit 0, no import error; the meson-built wheel installed into a separate scratch venv -> `--version` shows real, non-`unknown` commit id + build time. Full meson build/test: 261 passed, 3 skipped (258 baseline + 3 new tests)
- _Requirements: 1.1, 1.2, 2.1_
- _Boundary: xceadmin/src/xceadmin_
- _Depends: 5.1_
- [ ] 6. Integration: cross-toolchain consistency and regression verification
- [ ] 6.1 Motivating-incident regression test

View file

@ -0,0 +1,19 @@
"""Committed fallback build-info stub (build-time-versioning task 5.2).
Both fields are always "unknown" here. This file ships checked into git so
that a non-meson `pip install -e .` (the documented fast-iteration path,
`build-deployment.md`) still imports `xceadmin._build_info` cleanly without
ever having run the meson build -- Requirement 1.4's "record as unknown
rather than fail" applies here too.
When built via the meson custom_target (`src/xceadmin/meson-build.sh`, task
5.1), this exact filename is regenerated with real `GIT_COMMIT`/`BUILD_TIME`
values -- but only in meson's own out-of-tree MIRRORED copy of this package
(`$BUILD_DIR/repo-mirror/src/xceadmin/src/xceadmin/_build_info.py`). This
checked-in copy, under the live source tree, is never overwritten.
"""
from __future__ import annotations
GIT_COMMIT = "unknown"
BUILD_TIME = "unknown"

View file

@ -29,6 +29,8 @@ from __future__ import annotations
from collections.abc import Callable
from datetime import datetime, timezone
from importlib.metadata import PackageNotFoundError
from importlib.metadata import version as _package_version
import click
@ -37,6 +39,41 @@ from xceadmin.build import build_cluster_config, dump_cluster_config, write_outp
from xceadmin.push import probe_config, push_config
from xceadmin.scheduler import RecordResult, dump, record_start, record_status, record_stop
try:
from xceadmin import _build_info
except ImportError: # pragma: no cover - defensive only: a committed
# "unknown"-only fallback stub (task 5.2, src/xceadmin/src/xceadmin/
# _build_info.py) always ships in-tree, and the meson build (task 5.1)
# overwrites it with real values -- this module should therefore always
# be importable in practice. Guarded anyway per the task's own "import
# defensively" wording, matching this feature's established empty ->
# "unknown" fail-soft discipline (go_build, meson-build.sh,
# xce_version_field()) rather than letting a genuinely broken/partial
# install turn into an import error at CLI startup (Requirement 1.4).
class _build_info: # type: ignore[no-redef]
GIT_COMMIT = "unknown"
BUILD_TIME = "unknown"
def _compose_version() -> str:
"""Composes the string `xceadmin --version` prints: pyproject.toml's
static semantic version -- read via ``importlib.metadata`` (the standard
way to read an *installed* package's own version, rather than
hand-parsing pyproject.toml) -- plus the two build-info fields, which are
either task 5.1's meson-generated real values or task 5.2's committed
"unknown" fallback, whichever this install currently carries
(Requirements 1.1, 1.2, 2.1).
"""
try:
pkg_version = _package_version("xceadmin")
except PackageNotFoundError: # pragma: no cover - only if xceadmin
# itself isn't installed/registered, which shouldn't happen for an
# entry point already running as `xceadmin`; fails soft to
# "unknown" rather than raising, matching Requirement 1.4.
pkg_version = "unknown"
return f"{pkg_version} ({_build_info.GIT_COMMIT}, {_build_info.BUILD_TIME})"
_DEFAULT_OUTPUT = "cluster.bin"
_DEFAULT_CONTROLLER = "localhost:9991"
# Every --controller option below also reads this env var (click precedence:
@ -51,6 +88,7 @@ _STATUS_LABEL_WIDTH = 13 # len("started at:") + 2 -- requirements.md's "Status
@click.group()
@click.version_option(version=_compose_version(), prog_name="xceadmin")
def cli() -> None:
"""xceadmin: build and deploy XCE cluster configuration."""

View file

@ -70,6 +70,57 @@ def test_xcecommon_is_importable_independent_of_xceadmin() -> None:
import xcecommon # noqa: F401 - import success is the assertion
# ---------------------------------------------------------------------------
# --version (build-time-versioning task 5.2): click.version_option() wired on
# the top-level group, composing pyproject.toml's static semantic version
# with the two _build_info fields (task 5.1's meson-generated real values, or
# task 5.2's committed "unknown"-only fallback stub for a non-meson `pip
# install -e .`). Observable: `xceadmin --version` prints and exits 0, never
# an import error, regardless of which _build_info variant is installed.
# ---------------------------------------------------------------------------
def test_cli_version_flag_exits_zero_and_shows_package_version() -> None:
"""`xceadmin --version` must exit 0 and print pyproject.toml's static
semantic version (0.1.0) plus build-info fields -- Requirements 1.1,
1.2, 2.1."""
runner = CliRunner()
result = runner.invoke(cli, ["--version"])
assert result.exit_code == 0, result.output
assert "0.1.0" in result.output # pyproject.toml's static [project].version
assert "version" in result.output.lower()
def test_cli_version_flag_includes_build_info_fields() -> None:
"""The printed --version string must include BOTH _build_info fields
(whichever variant -- "unknown" fallback or meson-generated real values
-- is currently installed), not just the bare package version, so
--version and the eventual startup log line (out of this task's scope)
can never disagree (Requirement 2.2)."""
from xceadmin import _build_info
runner = CliRunner()
result = runner.invoke(cli, ["--version"])
assert result.exit_code == 0, result.output
assert _build_info.GIT_COMMIT in result.output
assert _build_info.BUILD_TIME in result.output
def test_build_info_module_is_importable_with_string_fields() -> None:
"""xceadmin._build_info must always be importable with both fields
present as non-empty strings -- whether it's the committed "unknown"-only
fallback stub (task 5.2, a non-meson `pip install -e .`) or the
meson-generated real-value module (task 5.1) this test run happens to be
installed against. Never an import error (tasks.md 5.2's Observable
bullet, Requirement 1.4)."""
from xceadmin import _build_info
assert isinstance(_build_info.GIT_COMMIT, str) and _build_info.GIT_COMMIT
assert isinstance(_build_info.BUILD_TIME, str) and _build_info.BUILD_TIME
# ---------------------------------------------------------------------------
# config build
# ---------------------------------------------------------------------------