From 99dfd2d14f85feaea8da61a8a9a8ccf5cd0a508e Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Fri, 12 Jun 2026 12:38:36 +0100 Subject: [PATCH] Add holoscan-cli tool-runner alias Add a holoscan-cli console script alias so package-name based tool runners can execute the CLI directly while keeping holoscan as the canonical command. Extend wheel smoke coverage and CI tool-runner checks for uvx and pipx run. Co-authored-by: Codex --- .github/scripts/smoke_test.sh | 4 +++ .github/scripts/tool_runner_smoke.sh | 46 ++++++++++++++++++++++++++++ .github/workflows/main.yaml | 6 ++++ .github/workflows/release.yaml | 4 +++ README.md | 16 ++++++++++ pyproject.toml | 1 + tests/unit/test_package_data.py | 13 +++++--- 7 files changed, 85 insertions(+), 5 deletions(-) create mode 100755 .github/scripts/tool_runner_smoke.sh diff --git a/.github/scripts/smoke_test.sh b/.github/scripts/smoke_test.sh index 6f91a25..8a27983 100755 --- a/.github/scripts/smoke_test.sh +++ b/.github/scripts/smoke_test.sh @@ -15,11 +15,15 @@ set -euo pipefail bin_dir=${1:?usage: smoke_test.sh } holoscan="$bin_dir/holoscan" +holoscan_cli="$bin_dir/holoscan-cli" python="$bin_dir/python" "$holoscan" --help "$holoscan" version "$holoscan" lint --dryrun +"$holoscan_cli" --help +diff -u <("$holoscan" version | sed '/^Executable:/d') \ + <("$holoscan_cli" version | sed '/^Executable:/d') # Every registered command must surface working `--help`. Pull the list # from the registry so this cannot drift if a subcommand is renamed. diff --git a/.github/scripts/tool_runner_smoke.sh b/.github/scripts/tool_runner_smoke.sh new file mode 100755 index 0000000..4ebdda9 --- /dev/null +++ b/.github/scripts/tool_runner_smoke.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Verify that package-name based tool runners can execute holoscan-cli +# directly from the wheel built by this workflow. +# +# Usage: tool_runner_smoke.sh +set -euo pipefail + +wheel_input=${1:-dist} +if [[ -d "$wheel_input" ]]; then + wheel=$(find "$wheel_input" -name 'holoscan_cli-*.whl' | head -n1) +else + wheel="$wheel_input" +fi + +if [[ -z "${wheel:-}" || ! -f "$wheel" ]]; then + echo "no holoscan_cli-*.whl found at $wheel_input" >&2 + exit 1 +fi + +if ! command -v uvx >/dev/null; then + echo "uvx is required for tool-runner smoke tests" >&2 + exit 1 +fi +if ! command -v pipx >/dev/null; then + echo "pipx is required for tool-runner smoke tests" >&2 + exit 1 +fi + +wheel=$(python -c 'from pathlib import Path; import sys; print(Path(sys.argv[1]).resolve())' "$wheel") +tmp_dir=$(mktemp -d) +trap 'rm -rf "$tmp_dir"' EXIT + +export UV_TOOL_DIR="$tmp_dir/uv/tools" +export UV_CACHE_DIR="$tmp_dir/uv/cache" +export PIPX_HOME="$tmp_dir/pipx/home" +export PIPX_BIN_DIR="$tmp_dir/pipx/bin" +mkdir -p "$UV_TOOL_DIR" "$UV_CACHE_DIR" "$PIPX_HOME" "$PIPX_BIN_DIR" + +echo "--- uvx --from $wheel holoscan-cli version" +uvx --from "$wheel" holoscan-cli version + +echo "--- pipx run --spec $wheel holoscan-cli version" +pipx run --spec "$wheel" holoscan-cli version diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 0a7d6f5..58c7cb1 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -205,6 +205,12 @@ jobs: - name: Smoke test run: .github/scripts/smoke_test.sh /tmp/holoscan-cli-smoke/bin + - name: Install tool runners + run: python -m pip install --upgrade uv pipx + + - name: Tool-runner smoke test + run: .github/scripts/tool_runner_smoke.sh dist + cpu-cli-docker-smoke: name: CPU CLI + Docker smoke test runs-on: ubuntu-latest diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 085a095..4746994 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -276,6 +276,10 @@ jobs: /tmp/holoscan-cli-smoke/bin/pip install "${wheel}" - name: Smoke Test run: .github/scripts/smoke_test.sh /tmp/holoscan-cli-smoke/bin + - name: Install tool runners + run: python -m pip install --upgrade uv pipx + - name: Tool-runner smoke test + run: .github/scripts/tool_runner_smoke.sh dist testpypi-deploy: name: publish-test-pypi diff --git a/README.md b/README.md index 965e6c1..4337578 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,22 @@ pip install holoscan-cli holoscan --help ``` +For transient use without keeping an installed environment, package-name based +tool runners can use the compatibility alias: + +```bash +uvx holoscan-cli --help +pipx run holoscan-cli --help +``` + +The primary CLI command remains `holoscan`. Explicit package/command forms also +work when you want the canonical command name from a transient runner: + +```bash +uvx --from holoscan-cli holoscan --help +pipx run --spec holoscan-cli holoscan --help +``` + ## Versioning `holoscan-cli` release versions are aligned with Holoscan SDK GA release diff --git a/pyproject.toml b/pyproject.toml index 37d2da0..4996c13 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -107,6 +107,7 @@ poetry-dynamic-versioning = { version = ">=1.5.0,<2.0.0", extras = ["plugin"] } [project.scripts] holoscan = 'holoscan_cli.__main__:main' +holoscan-cli = 'holoscan_cli.__main__:main' [tool.codespell] skip = '.ruff_cache,.cache,build,dist,htmlcov,tests/reports' diff --git a/tests/unit/test_package_data.py b/tests/unit/test_package_data.py index 40f0cc0..a6a7454 100644 --- a/tests/unit/test_package_data.py +++ b/tests/unit/test_package_data.py @@ -19,8 +19,8 @@ files an installed ``holoscan-cli`` wheel must ship: the ``py.typed`` marker, the project metadata JSON schemas under ``holoscan_cli.metadata``, the logging configuration, and the CTest scripts under ``holoscan_cli.testing``. -The tests also pin the public ``holoscan`` console script entry point so the -installed package keeps a single, stable command name on disk. +The tests also pin the public ``holoscan`` console script entry point and the +``holoscan-cli`` package-name tool-runner alias. Entry-point checks read ``pyproject.toml`` directly (the ground truth for what a fresh ``pip install`` will register) instead of the runtime @@ -161,10 +161,13 @@ def test_bundled_template_script_uses_bundled_requirements(tmp_path): # ---- pyproject.toml entry-point declarations -------------------------------- -def test_pyproject_declares_only_holoscan_console_script(): - """The shipped wheel must register exactly one console script.""" +def test_pyproject_declares_expected_console_scripts(): + """The shipped wheel must register the canonical CLI and tool-runner alias.""" declared = _pyproject().get("project", {}).get("scripts", {}) - assert declared == {"holoscan": "holoscan_cli.__main__:main"}, declared + assert declared == { + "holoscan": "holoscan_cli.__main__:main", + "holoscan-cli": "holoscan_cli.__main__:main", + }, declared def test_pyproject_does_not_declare_legacy_console_scripts():