fix(ci): smoke guard catches tagless builds; DEBUG import must hit the install; pin more workflow invariants

Review findings on PR #13:
- release-branch-semver gives 0.1.0.devN without tags, so the 0.0 guard
  never fired; check_version() now requires >= 0.2 (unit-tested)
- the APPSKELLINGTON_DEBUG child import could resolve the source tree from
  the cwd and false-pass; it now reports its location and must match
- test_ci_workflow: no continue-on-error, matrix python drives container
  and UV_PYTHON, WIP gate compared whole (mutation-tested)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
golem
2026-10-05 14:30:41 -06:00
co-authored by Claude Opus 5.5
parent 6bd717f231
commit 509be4c6bc
3 changed files with 93 additions and 10 deletions
+39 -8
View File
@@ -1,21 +1,40 @@
"""Smoke-test an *installed* app_skellington (wheel, sdist or index release).
Run it from outside the source tree, so the installed copy is the one imported:
Run it from outside the source tree:
cd / && python /path/to/scripts/smoke_import.py [EXPECTED_VERSION]
The script's own directory (scripts/) heads sys.path, so the main import
can't see the source tree. But the APPSKELLINGTON_DEBUG child process puts
its cwd first, which is why the cwd must be outside the repo. The child's
import location is checked too, so a wrong cwd fails instead of passing.
"""
import importlib.metadata
import os
import pathlib
import re
import subprocess
import sys
# Any real release is >= 0.2. With no tags reachable (a shallow clone),
# setuptools_scm's release-branch-semver scheme yields 0.1.0.devN, and other
# schemes yield 0.0.x.
MIN_RELEASE = (0, 2)
def fail(msg):
sys.exit("smoke FAILED: " + msg)
def check_version(version, expected):
major_minor = tuple(int(n) for n in re.match(r"(\d+)\.(\d+)", version).groups())
if major_minor < MIN_RELEASE:
fail("setuptools_scm found no tags (shallow clone?): %s" % version)
if expected is not None and version != expected:
fail("expected version %s, got %s" % (expected, version))
def main(argv):
expected = argv[1] if len(argv) > 1 else None
@@ -35,19 +54,31 @@ def main(argv):
SubMenu,
)
version = importlib.metadata.version("app_skellington")
if version.startswith("0.0"):
fail("setuptools_scm found no tags (shallow clone?): %s" % version)
if expected is not None and version != expected:
fail("expected version %s, got %s" % (expected, version))
check_version(importlib.metadata.version("app_skellington"), expected)
# _bootstrap.py takes a different code path when APPSKELLINGTON_DEBUG is set.
env = dict(os.environ, APPSKELLINGTON_DEBUG="1")
proc = subprocess.run([sys.executable, "-c", "import app_skellington"], env=env)
proc = subprocess.run(
[
sys.executable,
"-c",
"import app_skellington, pathlib;"
"print(pathlib.Path(app_skellington.__file__).resolve())",
],
env=env,
stdout=subprocess.PIPE,
universal_newlines=True,
)
if proc.returncode != 0:
fail("import failed with APPSKELLINGTON_DEBUG=1")
child_location = proc.stdout.strip().splitlines()[-1]
if child_location != str(location):
fail(
"APPSKELLINGTON_DEBUG import resolved %s, not the installed %s"
" (run from outside the source tree)" % (child_location, location)
)
print("smoke ok:", version, location)
print("smoke ok:", importlib.metadata.version("app_skellington"), location)
if __name__ == "__main__":