fix(packaging): include runtime setup scripts in Python wheel - #2764
fix(packaging): include runtime setup scripts in Python wheel#2764Takeshi Masukawa (takeaship) wants to merge 3 commits into
Conversation
|
@microsoft-github-policy-service agree |
3378c8a to
1fe622a
Compare
1fe622a to
c7f5dd5
Compare
|
Daniel Meppiel (@danielmeppiel) |
There was a problem hiding this comment.
🔵 Needs a closer look
Newly packaged runtime helper/scripts contain non-ASCII status glyphs in output strings; these should be converted to ASCII-only prefixes before shipping them via the wheel.
Pull request overview
Fixes wheel packaging so apm runtime setup can load its embedded setup scripts when APM is installed from a published wheel, while preserving the existing PyInstaller _MEIPASS/scripts/... layout for frozen builds.
Changes:
- Moves runtime setup assets under
apm_cli.runtime, declares them as package data, and switchesRuntimeManagertoimportlib.resourceslookups for non-frozen execution. - Updates PyInstaller spec + release workflow isolated-validation prep to source/copy the helper from the new canonical location.
- Adds regression tests that (a) build+install a wheel into an isolated venv and verify all expected scripts load via
RuntimeManager, and (b) verify the release workflow uploads/prepares the canonical helper path.
File summaries
| File | Description |
|---|---|
| tests/utils/runtime_setup_codex.py | Updates test helper to reference the new canonical setup script location under src/apm_cli/runtime/scripts/runtime/. |
| tests/unit/test_runtime_manager.py | Simplifies script-loading test to assert package-resource loading works. |
| tests/unit/scripts/test_build_release_workflow.py | New tests asserting build-release workflow artifacts and macOS isolated validation prep preserve the helper layout. |
| tests/integration/test_tls_r3_verify.py | Updates TLS script assertions to read from the new packaged script path. |
| tests/integration/test_runtime_wheel_scripts.py | New regression test: build wheel, install outside repo, and verify all runtime scripts + token helper load from the installed wheel. |
| tests/integration/test_runtime_smoke.py | Updates smoke tests to use the new canonical script paths in-tree. |
| tests/integration/test_remaining_modules_coverage.py | Makes runtime script loading assertions mandatory (no longer “acceptable to be missing”). |
| tests/integration/test_integration_runtime_coverage.py | Updates common/token-helper tests to assert package-resource content is present. |
| src/apm_cli/runtime/scripts/runtime/setup-llm.sh | Adds/moves LLM runtime setup script into package resources. |
| src/apm_cli/runtime/scripts/runtime/setup-llm.ps1 | Adds/moves Windows LLM setup script into package resources. |
| src/apm_cli/runtime/scripts/runtime/setup-gemini.sh | Adds/moves Gemini runtime setup script into package resources. |
| src/apm_cli/runtime/scripts/runtime/setup-gemini.ps1 | Adds/moves Windows Gemini setup script into package resources. |
| src/apm_cli/runtime/scripts/runtime/setup-copilot.sh | Moves Copilot setup script into package resources (content unchanged in this hunk). |
| src/apm_cli/runtime/scripts/runtime/setup-copilot.ps1 | Adds/moves Windows Copilot setup script into package resources. |
| src/apm_cli/runtime/scripts/runtime/setup-common.sh | Adds/moves common bash helpers into package resources. |
| src/apm_cli/runtime/scripts/runtime/setup-common.ps1 | Adds/moves common PowerShell helpers into package resources. |
| src/apm_cli/runtime/scripts/runtime/setup-codex.sh | Adds/moves Codex setup script into package resources. |
| src/apm_cli/runtime/scripts/runtime/setup-codex.ps1 | Adds/moves Windows Codex setup script into package resources. |
| src/apm_cli/runtime/scripts/github-token-helper.sh | Adds/moves token helper into package resources so release validation and runtime scripts can source it from the canonical location. |
| src/apm_cli/runtime/manager.py | Switches non-frozen script loading to importlib.resources.files(...) and keeps _MEIPASS behavior for frozen builds. |
| scripts/test-release-validation.sh | Updates sourcing path to the canonical packaged token helper. |
| scripts/test-integration.sh | Updates sourcing path and comment to reflect the canonical packaged token helper. |
| pyproject.toml | Declares apm_cli.runtime scripts as wheel package data. |
| docs/src/content/docs/integrations/runtime-compatibility.md | Updates docs to point contributors to the new canonical setup-script path. |
| build/apm.spec | Updates PyInstaller datas to pull scripts/helper from the new canonical source location while emitting the same frozen layout. |
| .github/workflows/build-release.yml | Updates artifact upload and macOS isolated release-validation prep to include/copy the helper from the new canonical location. |
Review details
- Files reviewed: 15/26 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
These characters already exist in the original scripts; this PR relocates them without changing their behavior. I'd prefer to address ASCII-only output separately to keep this fix focused on wheel packaging. |
fix(packaging): include runtime setup scripts in Python wheel
TL;DR
The published Python wheel omits the runtime setup scripts that
RuntimeManagerexpects, soapm runtime setupfails before running any installer. This change makes those scripts package resources, loads them withimportlib.resources, and retains the existing PyInstaller layout. A regression test builds and installs the wheel into an isolated venv, then loads every supported setup script and the Unix token helper from that installed wheel.Note
This is related to closed issue #56, but the Linux reproduction below shows that the underlying failure is wheel packaging rather than Windows support.
Problem (WHY)
apm-cli==0.29.0wheel reportsRUNTIME_SCRIPT_ENTRIES=0andTOKEN_HELPER_ENTRIES=0;apm runtime setup llmexits 1 withScript not found: setup-llm.sh.pip install apm-cli, while the runtime guide documentsapm runtime setup llm. The wheel therefore needs the same runtime assets as the source and binary distributions.Failed to load embedded script setup-copilot.sh: Script not found: setup-copilot.shsymptom afteruv tool install; it was closed after the discussion treated the failure as Windows-specific. The Linux result reproduces the same missing-resource path.Approach (WHAT)
apm_cli.runtime, declare them as package data, and load them withimportlib.resourcesfrom source or wheel installs._MEIPASS/scripts/...lookup and emitted layout; only point the build spec at the new canonical source location.RuntimeManager.Implementation (HOW)
src/apm_cli/runtime/scripts/**,pyproject.toml,src/apm_cli/runtime/manager.pyimportlib.resources..github/workflows/build-release.yml,tests/unit/scripts/test_build_release_workflow.pybuild/apm.specscripts/runtimeandscripts/github-token-helper.shin the frozen application.scripts/test-{integration,release-validation}.sh,tests/integration/{test_runtime_smoke,test_tls_r3_verify}.py,tests/utils/runtime_setup_codex.py,docs/src/content/docs/integrations/runtime-compatibility.mdtests/integration/test_runtime_wheel_scripts.py, existing runtime-manager testsDiagrams
Legend: the dashed nodes are the package-resource path added by this PR; the frozen path keeps its current runtime layout.
flowchart LR A[src/apm_cli/runtime/scripts] B[setuptools package data] C[installed apm_cli.runtime] D{sys.frozen} E[MEIPASS scripts] F[importlib.resources] G[RuntimeManager] A --> B B --> C C --> F D -->|yes| E D -->|no| F E --> G F --> G classDef new stroke-dasharray: 5 5; class A,B,C,F new;Trade-offs
src/apm_cli/runtime/scripts; a second checked-in copy or a custom build-time copy hook would create drift or extra packaging logic.importlib.resourcesbehavior inside every frozen build, preserving the supported binary path and its existing filesystem layout.Benefits
RuntimeManagerloads every script without access to the source checkout, andapm runtime setup llmcompletes instead of failing withScript not found.scripts/...layout continue to use the same canonical assets.Validation
Latest rebase (
c7f5dd58), author-reported checks: all four targeted tests passed (7.15s), along with Ruff, pylint R0801, auth/architecture checks, andgit diff --check. The broader test run was interrupted; full-suite results below refer to earlier revisions.Official 0.29.0 wheel baseline
The earlier rootless Podman reproduction used
docker.io/library/python:3.13, a fresh venv, no host mounts, and no host credentials:python -m venv /tmp/apm-venv . /tmp/apm-venv/bin/activate python -m pip install --disable-pip-version-check --no-cache-dir -q apm-cli==0.29.0 apm --version apm --help apm runtime setup llmPR wheel in disposable Python 3.13 container
The copied
/tmp/apm-wheel-podman-verify.shran these probes inside the container (each command's exit code is recorded below):Artifact and container results
LOADED_SCRIPTScontained non-empty content forsetup-{codex,copilot,gemini,llm}.{sh,ps1}andsetup-common.{sh,ps1};TOKEN_HELPER_LENGTH=4092. No host home was mounted, no host credentials were passed, all downloads and writes stayed inside the disposable container, and--rmremoved it after exit.Original automated checks (2026-09-03)
The CI YAML I/O, file-length, path, auth, and architecture guards, plus
git diff --checkand touched-shellbash -n, all exited 0.PyInstaller compatibility check
Revalidation after rebase (2026-09-06)
Rebased onto
9cb174b2; reviewed through1fe622a1. Searches across open/closed Issues and PRs found no competing wheel fix; #56 remains closed. Independent review found a missed release-workflow helper path; it is now fixed and re-reviewed.Rebased 0.29.1 verification passed: wheel CLI version/help, metadata and all-resource probes, full LLM setup, and a Linux PyInstaller build/version/help plus byte comparisons of all 11 frozen assets. A further Python 3.13 Podman run copied only the frozen distribution (no checkout or credentials) and completed
apm runtime setup llmplusllm --version(0.34), exit 0. Native macOS/Windows execution remains untested.New verification commands and results (historical logs above retained)
The copied script runs the same in-container probes shown above against 0.29.1, asserting 10 runtime entries, one helper, and nonempty resources. No mounts or host credentials; container removed on exit. Wheel SHA256:
8c6c947fef7006a3a4d5ee4c57a5ba6906ccad955246d7a27966de786fac0351.All container commands exited 0, including
apm runtime setup llm; installedllm, version 0.34. Metadata contained 10 runtime scripts and one helper; all loaded, withTOKEN_HELPER_LENGTH=4092.uv run pytest tests/unit tests/test_console.py -x: 21355 passed, 5 skipped, 21 xfailed, 21 warnings in 521.98s; exit 0.uv run --extra dev pytest tests/integration/test_runtime_wheel_scripts.py -n0 -q: 1 passed in 11.50s; exit 0. The same test, building unmodified upstream9cb174b2instead, fails withCould not load setup script: setup-copilot.sh(1 failed in 8.78s; exit 1).uv run --no-sync pytest tests/unit/scripts/test_build_release_workflow.py -n0 -q: 3 passed in 2.20s; exit 0. All 3 fail against the pre-fix workflow (exit 1).action_required); local passes do not claim hosted CI is green.Scenario Evidence
tests/integration/test_runtime_wheel_scripts.py::test_installed_wheel_loads_all_runtime_scripts(regression-trap for #56)tests/unit/test_runtime_manager.py::TestRuntimeManagerGetEmbeddedScripttests/unit/test_build_spec.py::TestSpecFileSyntaxtests/unit/scripts/test_build_release_workflow.pyHow to test
uv run --extra dev pytest tests/integration/test_runtime_wheel_scripts.py tests/unit/scripts/test_build_release_workflow.py -n0 -q; expect four passes covering the installed wheel and release-validation workflow.apm_cli/runtime/scripts/runtime/and one helper underapm_cli/runtime/scripts/, all loadable byRuntimeManager.apm runtime setup llm; expect execution to proceed beyond the formerScript not foundfailure. A full network-backed LLM setup completed in the disposable verification above.Warning
Untested scope: native Windows/macOS execution and network-backed Copilot, Codex, and Gemini installation. The regression loads their shell and PowerShell assets, and Linux PyInstaller was built and smoke-tested, but those external installers were not executed.
apm-spec-waiver: Packaging fix makes existing runtime setup assets available from installed wheels; no OpenAPM behavior changes.AI assistance disclosure: OpenAI Codex helped implement, review, and validate this change; the author reviewed the diff and all reported command results.
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com