refactor(image-cache): replace warn_if_stale with StaleImageError; add launch template
- image_cache: StaleImageError exception + check_stale/check_stale_path (raise instead of warn) - BottleBackend.launch: template method (skip_stale flag) that calls _image_stale_checks then _launch_impl - Each backend: _image_stale_checks delegates to a stale_checks() function in its launch module; _launch_impl replaces launch override - macos_container: adds image_created_at to util, cached-image support in _build_images, stale_checks - cli/start.py: catches StaleImageError, prompts interactively, retries with skip_stale=True; headless mode dies on it
This commit is contained in:
@@ -105,10 +105,6 @@ class TestLaunchCommittedImage(unittest.TestCase):
|
||||
launch_mod.docker_mod, "image_exists", return_value=image_present,
|
||||
), mock.patch.object(
|
||||
launch_mod.docker_mod, "build_image", side_effect=fake_build,
|
||||
), mock.patch.object(
|
||||
launch_mod.docker_mod, "image_created_at",
|
||||
), mock.patch.object(
|
||||
launch_mod, "warn_if_stale",
|
||||
), mock.patch.object(
|
||||
launch_mod, "egress_tls_init",
|
||||
return_value=(Path("/egress_ca"), Path("/egress_cert")),
|
||||
|
||||
@@ -81,7 +81,7 @@ def _plan(
|
||||
provisioned_env={"CODEX_HOME": "/run/codex-home"},
|
||||
)
|
||||
return cast(MacosContainerBottlePlan, SimpleNamespace(
|
||||
spec=SimpleNamespace(),
|
||||
spec=SimpleNamespace(image_policy="fresh"),
|
||||
manifest=_MANIFEST,
|
||||
stage_dir=stage_dir,
|
||||
slug="dev-abc",
|
||||
@@ -292,7 +292,7 @@ class TestMacosContainerLaunchArgv(unittest.TestCase):
|
||||
|
||||
def _build_plan(stage_dir: Path) -> MacosContainerBottlePlan:
|
||||
return MacosContainerBottlePlan(
|
||||
spec=cast(BottleSpec, SimpleNamespace()),
|
||||
spec=cast(BottleSpec, SimpleNamespace(image_policy="fresh")),
|
||||
manifest=_MANIFEST,
|
||||
stage_dir=stage_dir,
|
||||
git_gate_plan=cast(GitGatePlan, SimpleNamespace(upstreams=())),
|
||||
|
||||
@@ -187,56 +187,6 @@ class TestAgentFromPath(unittest.TestCase):
|
||||
dockerfile="/repo/Dockerfile",
|
||||
)
|
||||
|
||||
def test_cached_policy_uses_existing_artifact_without_build(self):
|
||||
with tempfile.TemporaryDirectory(prefix="cached-smolmachine.") as tmp:
|
||||
digest = "abcdef0123456789"
|
||||
artifact = Path(tmp) / f"{digest}.smolmachine.smolmachine"
|
||||
artifact.write_text("")
|
||||
plan = SimpleNamespace(
|
||||
slug="dev-abc12",
|
||||
agent_image="bot-bottle-claude:latest",
|
||||
spec=SimpleNamespace(image_policy="cached"),
|
||||
)
|
||||
with patch.object(
|
||||
_launch_mod, "_SMOLMACHINE_CACHE_DIR", Path(tmp),
|
||||
), patch.object(
|
||||
_launch_mod, "read_committed_image", return_value="",
|
||||
), patch.object(
|
||||
_launch_mod.docker_mod, "image_exists", return_value=True,
|
||||
), patch.object(
|
||||
_launch_mod.docker_mod, "image_id",
|
||||
return_value=f"sha256:{digest}fffffffffffffffff",
|
||||
), patch.object(
|
||||
_launch_mod, "warn_if_stale_path",
|
||||
), patch.object(
|
||||
_launch_mod, "_ensure_smolmachine",
|
||||
) as ensure:
|
||||
result = _launch_mod._agent_from_path(cast(Any, plan))
|
||||
|
||||
self.assertEqual(artifact, result)
|
||||
ensure.assert_not_called()
|
||||
|
||||
def test_cached_policy_dies_when_artifact_missing(self):
|
||||
with tempfile.TemporaryDirectory(prefix="cached-smolmachine.") as tmp:
|
||||
plan = SimpleNamespace(
|
||||
slug="dev-abc12",
|
||||
agent_image="bot-bottle-claude:latest",
|
||||
spec=SimpleNamespace(image_policy="cached"),
|
||||
)
|
||||
with patch.object(
|
||||
_launch_mod, "_SMOLMACHINE_CACHE_DIR", Path(tmp),
|
||||
), patch.object(
|
||||
_launch_mod, "read_committed_image", return_value="",
|
||||
), patch.object(
|
||||
_launch_mod.docker_mod, "image_exists", return_value=True,
|
||||
), patch.object(
|
||||
_launch_mod.docker_mod, "image_id",
|
||||
return_value="sha256:abcdef0123456789fffffffffffffffff",
|
||||
):
|
||||
from bot_bottle.log import Die
|
||||
with self.assertRaises(Die):
|
||||
_launch_mod._agent_from_path(cast(Any, plan))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user