From c0d4f012c8b7b2ac1402eda217d2fbc347837ea2 Mon Sep 17 00:00:00 2001 From: Xubin Ren <52506698+Re-bin@users.noreply.github.com> Date: Sat, 23 May 2026 00:42:13 +0800 Subject: [PATCH] test(cli): cover CLI Apps on Windows CI --- .github/workflows/ci.yml | 2 +- tests/cli_apps/test_service.py | 27 +++++++++++++++------------ tests/cli_apps/test_tool.py | 28 ++++++++++++++++------------ 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a64accf8..7deda73db 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: strategy: fail-fast: false matrix: - os: ${{ github.event_name == 'pull_request' && fromJSON('["ubuntu-latest"]') || fromJSON('["ubuntu-latest","windows-latest"]') }} + os: ${{ fromJSON('["ubuntu-latest","windows-latest"]') }} # CI concentrates on newer runtimes (3.11/3.12 still supported per pyproject requires-python). python-version: ${{ fromJSON('["3.13","3.14"]') }} diff --git a/tests/cli_apps/test_service.py b/tests/cli_apps/test_service.py index b4bfc04d0..3b6eb93ff 100644 --- a/tests/cli_apps/test_service.py +++ b/tests/cli_apps/test_service.py @@ -1,8 +1,6 @@ from __future__ import annotations import json -import os -import stat import subprocess import sys import time @@ -341,17 +339,22 @@ def test_run_installed_cli_uses_argv_without_shell( ) -> None: manager = _manager(tmp_path) _seed_catalog(manager) - bin_dir = tmp_path / "bin" - bin_dir.mkdir() - cli = bin_dir / "cli-anything-gimp" - cli.write_text( - "#!/usr/bin/env python3\n" - "import sys\n" - "print('ARGS=' + repr(sys.argv[1:]))\n", - encoding="utf-8", + resolved = str(tmp_path / "bin" / "cli-anything-gimp") + monkeypatch.setattr( + "nanobot.cli_apps.service.shutil.which", + lambda entry: resolved if entry == "cli-anything-gimp" else None, ) - cli.chmod(cli.stat().st_mode | stat.S_IEXEC) - monkeypatch.setenv("PATH", f"{bin_dir}{os.pathsep}{os.environ.get('PATH', '')}") + + def fake_run(argv: list[str], **kwargs: object) -> subprocess.CompletedProcess[str]: + assert "shell" not in kwargs or kwargs["shell"] is False + return subprocess.CompletedProcess( + argv, + 0, + stdout="ARGS=" + repr(argv[1:]), + stderr="", + ) + + monkeypatch.setattr("nanobot.cli_apps.service.subprocess.run", fake_run) manager._save_installed( { "gimp": { diff --git a/tests/cli_apps/test_tool.py b/tests/cli_apps/test_tool.py index b11d7e593..d75f110ac 100644 --- a/tests/cli_apps/test_tool.py +++ b/tests/cli_apps/test_tool.py @@ -2,8 +2,7 @@ from __future__ import annotations import asyncio import json -import os -import stat +import subprocess import time from pathlib import Path @@ -45,17 +44,22 @@ def test_run_cli_app_uses_installed_registry_app( CliAppManager(workspace=workspace, data_dir=data_dir)._save_installed( {"gimp": {"entry_point": "cli-anything-gimp"}} ) - bin_dir = tmp_path / "bin" - bin_dir.mkdir() - cli = bin_dir / "cli-anything-gimp" - cli.write_text( - "#!/usr/bin/env python3\n" - "import sys\n" - "print('tool:' + ' '.join(sys.argv[1:]))\n", - encoding="utf-8", + resolved = str(tmp_path / "bin" / "cli-anything-gimp") + monkeypatch.setattr( + "nanobot.cli_apps.service.shutil.which", + lambda entry: resolved if entry == "cli-anything-gimp" else None, ) - cli.chmod(cli.stat().st_mode | stat.S_IEXEC) - monkeypatch.setenv("PATH", f"{bin_dir}{os.pathsep}{os.environ.get('PATH', '')}") + + def fake_run(argv: list[str], **kwargs: object) -> subprocess.CompletedProcess[str]: + assert "shell" not in kwargs or kwargs["shell"] is False + return subprocess.CompletedProcess( + argv, + 0, + stdout="tool:" + " ".join(argv[1:]), + stderr="", + ) + + monkeypatch.setattr("nanobot.cli_apps.service.subprocess.run", fake_run) monkeypatch.setattr("nanobot.cli_apps.service.get_runtime_subdir", lambda _name: data_dir) tool = CliAppsTool(