5933fdc789
Give bot-bottle a real distribution path so new users can install
without cloning the repo:
- pyproject.toml: full project metadata, a `bot-bottle` console-script
entry point (bot_bottle.cli:main), and package-data for the runtime
assets (Dockerfiles, egress entrypoint, netpool defaults, macos init).
Still zero runtime pip dependencies.
- install.sh: POSIX, sudo-free, idempotent bootstrapper — checks Python
>= 3.11, creates ~/.bot-bottle/{agents,bottles,contrib}, installs via
pipx (pip --user fallback), then runs `bot-bottle doctor`.
- `bot-bottle doctor`: new store-free subcommand reporting Python
version, backend availability (reuses is_backend_available rather than
hardcoding Docker), and config-dir presence. Exits non-zero when a hard
prerequisite is unmet.
- PRD prd-new-install-script and unit tests for doctor, the packaging
contract, and the install script.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
46 lines
1.5 KiB
Python
46 lines
1.5 KiB
Python
"""Unit: pyproject.toml packaging contract.
|
|
|
|
Guards the install/distribution surface: the console-script entry point,
|
|
the stdlib-only (empty) dependency list, and that every package-data glob
|
|
still points at a file that exists (so an installed wheel isn't missing a
|
|
Dockerfile or entrypoint the runtime reads).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import tomllib
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
|
PYPROJECT = REPO_ROOT / "pyproject.toml"
|
|
|
|
|
|
class TestPyproject(unittest.TestCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
with PYPROJECT.open("rb") as fh:
|
|
cls.data = tomllib.load(fh)
|
|
|
|
def test_entry_point_targets_cli_main(self):
|
|
scripts = self.data["project"]["scripts"]
|
|
self.assertEqual("bot_bottle.cli:main", scripts["bot-bottle"])
|
|
|
|
def test_no_runtime_dependencies(self):
|
|
# AGENTS.md: the package has no runtime pip dependencies.
|
|
self.assertEqual([], self.data["project"]["dependencies"])
|
|
|
|
def test_requires_python_311(self):
|
|
self.assertEqual(">=3.11", self.data["project"]["requires-python"])
|
|
|
|
def test_package_data_files_exist(self):
|
|
pkg_data = self.data["tool"]["setuptools"]["package-data"]["bot_bottle"]
|
|
self.assertTrue(pkg_data, "expected package-data entries")
|
|
for rel in pkg_data:
|
|
path = REPO_ROOT / "bot_bottle" / rel
|
|
self.assertTrue(path.is_file(), f"package-data missing: {path}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|