Skip to content

Add a packaging gate and tag-triggered release validation - #243

Merged
danielrmerskine merged 1 commit into
mainfrom
de/packaging-gate
Aug 13, 2026
Merged

Add a packaging gate and tag-triggered release validation#243
danielrmerskine merged 1 commit into
mainfrom
de/packaging-gate

Conversation

@danielrmerskine

Copy link
Copy Markdown
Collaborator

Nothing in CI validated the artifact a user pip-installs -- every job installs the CLI
editable from a full checkout. Running these checks against a built wheel for the first
time found five defect classes behind twelve green checks:

Defect State
lager-mcp console script targets lager.mcp.server (box tree) -- ModuleNotFoundError on every pip install issue #242
Vendored elftools missing construct/lib in the repo -- 30 modules + the lager debug gdb ELF path cannot import anywhere issue #240
cli.impl.box_config / cli.impl.power.enable_disable import lager.* from the box tree issue #241
prompt_toolkit undeclared -- cli/terminal imports it unconditionally fixed in this PR (install_requires)
setup.py ships in the wheel as cli.setup structural, documented in the baseline

PR Gate: Packaging (packaging.yml): build sdist+wheel, twine check, install the
wheel and the sdist each into a fresh venv, smoke lager --version/--help, assert the
reported version equals the source's __version__, and import-walk the installed package
(tools/check_imports.py) against tools/packaging_import_baseline.txt.

The baseline is TWO-SIDED, same pattern as the shellcheck exclusions: a failure not listed
fails the gate, and a listed module that starts importing cleanly also fails with "remove
it" -- the file can only shrink honestly. Every functional entry names its owning issue.
The walker refuses to run outside a venv and asserts the package resolved from inside it
(that guard caught a shadowing global install on its very first local run).

Release: Validate Tag (release-validation.yml): the same proof on every v* tag,
plus an installed-version==tag assert (the classic bumped-changelog-forgot-__init__.py
release), plus dist/ uploaded as a 90-day artifact. RELEASE_PROCESS.md steps 7-8 now
say: wait for green, download the artifact, twine upload those exact bytes -- no local
rebuild.

lager-mcp is deliberately not smoked until its issue is resolved (workflow header
comment).

Verified locally: full pipeline (build, twine check, wheel venv, sdist venv, import walk)
green end to end on this branch; the walk reconciles exactly 34 known failures against the
baseline in both venvs; all three checker failure arms fault-injected (new failure, stale
entry, package resolving from outside the venv); both workflows YAML-parse and every
embedded script passes bash -n.

Every CI job installs the CLI editable from a full checkout, so nothing
validated the artifact a user pip-installs. The first run of these
checks against a built wheel found five defect classes sitting behind
twelve green checks:

- the lager-mcp console script targets lager.mcp.server, which lives
  under box/ and has never shipped in the wheel: ModuleNotFoundError
  on every pip install (issue #242)
- the vendored elftools tree is missing construct/lib IN THE REPO, so
  30 cli.elftools modules and the lager debug gdb ELF path cannot
  import anywhere, dev checkouts included (issue #240)
- cli.impl.box_config and cli.impl.power.enable_disable import lager.*
  from the box tree the wheel does not ship (issue #241)
- prompt_toolkit was undeclared: cli/terminal imports it
  unconditionally, install_requires never mentioned it. Fixed here --
  the import walk proves cli.terminal now imports from a clean install.
- setup.py ships inside the wheel as cli.setup (structural, harmless,
  documented in the baseline as a note; whether it IMPORTS depends on
  the venv's python -- 3.11 seeds setuptools, 3.12+ does not, which
  the gate's own first run demonstrated)

PR Gate: Packaging (packaging.yml): build sdist+wheel, twine check,
install the wheel AND the sdist each into a fresh venv, smoke the
lager entry point, assert the reported version matches the source,
and import-walk the installed package (tools/check_imports.py) against
tools/packaging_import_baseline.txt. The baseline is two-sided: a new
failure fails, and an entry that starts importing cleanly also fails,
so the file only shrinks honestly. The walker refuses to run outside a
venv and asserts the package resolved from inside it -- on this
machine that guard immediately caught a shadowing global install.

Release: Validate Tag (release-validation.yml): the same proof on
every v* tag, plus lager --version must equal the tag, plus dist/
uploaded as a 90-day artifact. RELEASE_PROCESS.md steps 7-8 now
download and twine-upload THAT artifact instead of rebuilding locally,
so what ships is the bytes the validation proved.

The lager-mcp entry point is deliberately not smoked until its issue
is resolved; the workflow header says so.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant