Skip to content

Initial SDK Template Scaffold#1

Merged
danielphan-dp merged 18 commits into
mainfrom
feature/initial-scaffold
Dec 20, 2025
Merged

Initial SDK Template Scaffold#1
danielphan-dp merged 18 commits into
mainfrom
feature/initial-scaffold

Conversation

@danielphan-dp
Copy link
Copy Markdown
Owner

No description provided.

Copilot AI review requested due to automatic review settings December 20, 2025 20:47
@danielphan-dp danielphan-dp merged commit 4add984 into main Dec 20, 2025
2 of 3 checks passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces the initial scaffold for a multilingual SDK/CLI template that supports Python, Rust, and C++ backends. The template provides a production-ready starting point with development tooling, testing infrastructure, and pre-commit hooks.

Key changes:

  • Python CLI implementation with argparse-based command routing and optional native backend integration
  • Rust native backend with cargo workspace configuration and comprehensive test coverage
  • C++ native backend with CMake build system and custom test framework
  • Development environment setup with VS Code integration, pre-commit hooks, and linting/formatting tools

Reviewed changes

Copilot reviewed 48 out of 51 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pyproject.toml Python project configuration with dev dependencies and tooling setup
uv.lock Python dependency lock file with package versions
src/sdk_template/ Main Python package with CLI, native bridge, and version info
tests/test_cli.py Comprehensive Python test suite for CLI functionality
native/rust/ Rust backend implementation with Cargo configuration
native/cpp/ C++ backend with CMake build system and tests
.pre-commit-config.yaml Pre-commit hooks for code quality
.vscode/ VS Code workspace settings and tasks
Documentation files README, CHANGELOG, LICENSE, and guidance documents

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.



def _repo_root() -> Path:
env_root = os.environ.get("SDK_TEMPLATE_REPO_ROOT")
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The environment variable name mismatch could cause runtime errors. The code checks for "SDK_TEMPLATE_REPO_ROOT" but the tests and documentation reference "CLI_TEMPLATE_REPO_ROOT". This inconsistency needs to be resolved - choose one naming convention and use it throughout the codebase.

Copilot uses AI. Check for mistakes.
Comment thread tests/test_cli.py
Comment on lines +12 to +21
from sdk_template import __version__
from sdk_template._native import (
NativeBackendError,
_cpp_bin_path,
_repo_root,
_rust_bin_path,
run_cpp,
run_rust,
)
from sdk_template.cli import main
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test imports reference "cli_template" module but the actual package is named "sdk_template" (as shown in pyproject.toml and the src directory structure). Update all test imports to use "sdk_template" instead of "cli_template".

Copilot uses AI. Check for mistakes.
Comment thread tests/test_cli.py
Comment on lines +168 to +402
with mock.patch("cli_template.cli.run_rust") as mock_run:
mock_run.return_value = 0
result = main(["--impl", "rust", "hello"])
assert result == 0
mock_run.assert_called_once_with(["hello", "world"])

def test_impl_cpp_hello_success(self) -> None:
"""Test cpp impl hello succeeds when binary exists."""
with mock.patch("cli_template.cli.run_cpp") as mock_run:
mock_run.return_value = 0
result = main(["--impl", "cpp", "hello"])
assert result == 0
mock_run.assert_called_once_with(["hello", "world"])

def test_impl_rust_echo_success(self) -> None:
"""Test rust impl echo succeeds when binary exists."""
with mock.patch("cli_template.cli.run_rust") as mock_run:
mock_run.return_value = 0
result = main(["--impl", "rust", "echo", "hello", "world"])
assert result == 0
mock_run.assert_called_once_with(["echo", "hello", "world"])

def test_impl_cpp_echo_success(self) -> None:
"""Test cpp impl echo succeeds when binary exists."""
with mock.patch("cli_template.cli.run_cpp") as mock_run:
mock_run.return_value = 0
result = main(["--impl", "cpp", "echo", "hello", "world"])
assert result == 0
mock_run.assert_called_once_with(["echo", "hello", "world"])

def test_impl_rust_echo_error(self, monkeypatch: pytest.MonkeyPatch) -> None:
"""Test rust impl echo fails gracefully when binary missing."""
monkeypatch.setenv("CLI_TEMPLATE_REPO_ROOT", "/nonexistent")
with pytest.raises(SystemExit) as exc_info:
main(["--impl", "rust", "echo", "test"])
assert exc_info.value.code == 2

def test_impl_cpp_echo_error(self, monkeypatch: pytest.MonkeyPatch) -> None:
"""Test cpp impl echo fails gracefully when binary missing."""
monkeypatch.setenv("CLI_TEMPLATE_REPO_ROOT", "/nonexistent")
with pytest.raises(SystemExit) as exc_info:
main(["--impl", "cpp", "echo", "test"])
assert exc_info.value.code == 2

def test_impl_rust_sum_success(self) -> None:
"""Test rust impl sum succeeds when binary exists."""
with mock.patch("cli_template.cli.run_rust") as mock_run:
mock_run.return_value = 0
result = main(["--impl", "rust", "sum", "1", "2"])
assert result == 0
mock_run.assert_called_once_with(["sum", "1", "2"])

def test_impl_cpp_sum_success(self) -> None:
"""Test cpp impl sum succeeds when binary exists."""
with mock.patch("cli_template.cli.run_cpp") as mock_run:
mock_run.return_value = 0
result = main(["--impl", "cpp", "sum", "1", "2"])
assert result == 0
mock_run.assert_called_once_with(["sum", "1", "2"])

def test_impl_rust_sum_error(self, monkeypatch: pytest.MonkeyPatch) -> None:
"""Test rust impl sum fails gracefully when binary missing."""
monkeypatch.setenv("CLI_TEMPLATE_REPO_ROOT", "/nonexistent")
with pytest.raises(SystemExit) as exc_info:
main(["--impl", "rust", "sum", "1", "2"])
assert exc_info.value.code == 2

def test_impl_cpp_sum_error(self, monkeypatch: pytest.MonkeyPatch) -> None:
"""Test cpp impl sum fails gracefully when binary missing."""
monkeypatch.setenv("CLI_TEMPLATE_REPO_ROOT", "/nonexistent")
with pytest.raises(SystemExit) as exc_info:
main(["--impl", "cpp", "sum", "1", "2"])
assert exc_info.value.code == 2

def test_impl_rust_info_success(self) -> None:
"""Test rust impl info succeeds when binary exists."""
with mock.patch("cli_template.cli.run_rust") as mock_run:
mock_run.return_value = 0
result = main(["--impl", "rust", "info"])
assert result == 0
mock_run.assert_called_once_with(["info"])

def test_impl_cpp_info_success(self) -> None:
"""Test cpp impl info succeeds when binary exists."""
with mock.patch("cli_template.cli.run_cpp") as mock_run:
mock_run.return_value = 0
result = main(["--impl", "cpp", "info"])
assert result == 0
mock_run.assert_called_once_with(["info"])

def test_impl_rust_info_error(self, monkeypatch: pytest.MonkeyPatch) -> None:
"""Test rust impl info fails gracefully when binary missing."""
monkeypatch.setenv("CLI_TEMPLATE_REPO_ROOT", "/nonexistent")
with pytest.raises(SystemExit) as exc_info:
main(["--impl", "rust", "info"])
assert exc_info.value.code == 2

def test_impl_cpp_info_error(self, monkeypatch: pytest.MonkeyPatch) -> None:
"""Test cpp impl info fails gracefully when binary missing."""
monkeypatch.setenv("CLI_TEMPLATE_REPO_ROOT", "/nonexistent")
with pytest.raises(SystemExit) as exc_info:
main(["--impl", "cpp", "info"])
assert exc_info.value.code == 2


class TestInvalidInput:
"""Tests for invalid input handling."""

def test_missing_command(self) -> None:
"""Test that missing command exits with error."""
with pytest.raises(SystemExit) as exc_info:
main([])
assert exc_info.value.code == 2

def test_invalid_command(self) -> None:
"""Test that invalid command exits with error."""
with pytest.raises(SystemExit) as exc_info:
main(["invalid_command"])
assert exc_info.value.code == 2

def test_invalid_sum_argument(self) -> None:
"""Test that invalid sum argument exits with error."""
with pytest.raises(SystemExit) as exc_info:
main(["sum", "not_a_number", "3"])
assert exc_info.value.code == 2

def test_invalid_impl_choice(self) -> None:
"""Test that invalid impl choice exits with error."""
with pytest.raises(SystemExit) as exc_info:
main(["--impl", "invalid", "hello"])
assert exc_info.value.code == 2


class TestNativeBackend:
"""Tests for native backend utilities."""

def test_repo_root_found(self) -> None:
"""Test that repo root can be found."""
root = _repo_root()
assert (root / "pyproject.toml").is_file()

def test_repo_root_from_env(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
"""Test repo root from environment variable."""
# Create a fake pyproject.toml
fake_root = tmp_path / "fake_project"
fake_root.mkdir()
(fake_root / "pyproject.toml").write_text("[project]\nname = 'test'\n")

monkeypatch.setenv("CLI_TEMPLATE_REPO_ROOT", str(fake_root))
root = _repo_root()
assert root == fake_root

def test_repo_root_not_found(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
"""Test that repo root raises error when not found."""
# Change to a directory without pyproject.toml and clear env var
monkeypatch.delenv("CLI_TEMPLATE_REPO_ROOT", raising=False)
monkeypatch.chdir(tmp_path)
with pytest.raises(NativeBackendError, match="Could not locate repo root"):
_repo_root()

def test_native_backend_error(self) -> None:
"""Test NativeBackendError can be raised."""
with pytest.raises(NativeBackendError):
raise NativeBackendError("test error")

def test_rust_bin_path(self) -> None:
"""Test Rust binary path construction."""
root = Path("/fake/root")
path = _rust_bin_path(root)
assert path == root / "native" / "rust" / "target" / "release" / "cli-template-native-rs"

def test_cpp_bin_path(self) -> None:
"""Test C++ binary path construction."""
root = Path("/fake/root")
path = _cpp_bin_path(root)
assert path == root / "build" / "native-cpp" / "cli-template-native-cpp"

def test_run_rust_success(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
"""Test successful Rust binary execution."""
# Create a fake binary
fake_root = tmp_path / "fake_project"
fake_root.mkdir(parents=True)
(fake_root / "pyproject.toml").write_text("[project]\nname = 'test'\n")

binary_dir = fake_root / "native" / "rust" / "target" / "release"
binary_dir.mkdir(parents=True)
binary = binary_dir / "cli-template-native-rs"
binary.write_text("#!/bin/sh\necho 'fake rust'\n")
binary.chmod(0o755)

monkeypatch.setenv("CLI_TEMPLATE_REPO_ROOT", str(fake_root))

# Mock subprocess.run to avoid actually running anything
with mock.patch("cli_template._native.subprocess.run") as mock_run:
mock_run.return_value = mock.Mock(returncode=0)
result = run_rust(["hello"])
assert result == 0
mock_run.assert_called_once()

def test_run_cpp_success(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
"""Test successful C++ binary execution."""
# Create a fake binary
fake_root = tmp_path / "fake_project"
fake_root.mkdir(parents=True)
(fake_root / "pyproject.toml").write_text("[project]\nname = 'test'\n")

binary_dir = fake_root / "build" / "native-cpp"
binary_dir.mkdir(parents=True)
binary = binary_dir / "cli-template-native-cpp"
binary.write_text("#!/bin/sh\necho 'fake cpp'\n")
binary.chmod(0o755)

monkeypatch.setenv("CLI_TEMPLATE_REPO_ROOT", str(fake_root))

# Mock subprocess.run to avoid actually running anything
with mock.patch("cli_template._native.subprocess.run") as mock_run:
mock_run.return_value = mock.Mock(returncode=0)
result = run_cpp(["hello"])
assert result == 0
mock_run.assert_called_once()

def test_run_cpp_windows_path(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
"""Test C++ binary path has .exe suffix on Windows."""
# Create a fake binary with .exe suffix
fake_root = tmp_path / "fake_project"
fake_root.mkdir(parents=True)
(fake_root / "pyproject.toml").write_text("[project]\nname = 'test'\n")

binary_dir = fake_root / "build" / "native-cpp"
binary_dir.mkdir(parents=True)
binary = binary_dir / "cli-template-native-cpp.exe"
binary.write_text("fake windows exe")

monkeypatch.setenv("CLI_TEMPLATE_REPO_ROOT", str(fake_root))
monkeypatch.setattr("cli_template._native.sys.platform", "win32")
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mock patch paths reference "cli_template" module but should reference "sdk_template" to match the actual package name defined in pyproject.toml.

Copilot uses AI. Check for mistakes.
Comment thread tests/test_cli.py
Comment on lines +429 to +441
import cli_template.__main__ as main_module

# Verify the module imports main from cli
assert hasattr(main_module, "main")

# Test that main is callable
with mock.patch.object(main_module, "main", return_value=0) as mock_main:
# The module-level code runs at import, so we test the imported function
assert callable(main_module.main)

def test_main_module_direct_execution(self, capsys: pytest.CaptureFixture[str]) -> None:
"""Test the main() function directly from __main__ module."""
import cli_template.__main__ as main_module
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test attempts to import "cli_template.main" but the actual module is "sdk_template.main". Update the import to match the actual package name.

Copilot uses AI. Check for mistakes.
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.

2 participants