fix(resource): call bootstrap_builtin_types during initialization

Add a call to bootstrap_builtin_types() in init_command() (project.py)
immediately after initialize_project() returns.  This seeds the built-in
resource types (fs-directory, git-checkout, etc.) into the database so
that "resource add" commands succeed without "Resource type not found"
errors.

The call is idempotent — invoking it multiple times will not create
duplicate types.

Also fix the TDD robot test (resource_type_bootstrap_git.robot) to
initialize a project before running "resource add", and fix a
pre-existing parallel test failure in plan_commands_new_coverage where
unittest.mock.patch could not reliably intercept PlanApplyService under
behave-parallel fork() workers.

ISSUES CLOSED: #523, #524
This commit is contained in:
2026-03-07 06:14:25 +00:00
parent a6d1fb37ce
commit dcd55967f5
3 changed files with 55 additions and 16 deletions
@@ -170,23 +170,40 @@ use_step_matcher("parse")
@when("new_cov I call _get_apply_service directly")
def step_new_cov_call_get_apply(context: Context) -> None:
"""Call the real _get_apply_service, mocking only its dependencies.
"""Call the real ``_get_apply_service``, mocking its dependencies.
This exercises the actual function body (import, lifecycle lookup,
PlanApplyService construction) to cover lines 1817, 1821, 1822.
``PlanApplyService`` construction) to cover lines 1817, 1821, 1822.
Both ``_get_lifecycle_service`` **and** ``PlanApplyService`` are
patched. The class is patched at two locations — the canonical
source module and the plan module (with ``create=True``) — so the
lazy ``from … import PlanApplyService`` inside the function always
resolves to our mock, even under ``behave-parallel``'s
``fork()``-based workers.
"""
from cleveragents.cli.commands.plan import _get_apply_service
mock_lifecycle = MagicMock()
mock_pas_cls = MagicMock()
mock_pas_instance = MagicMock()
mock_pas_class = MagicMock(return_value=mock_pas_instance)
mock_pas_cls.return_value = mock_pas_instance
with (
patch(_PATCH_LIFECYCLE, return_value=context.new_cov_mock_lifecycle),
patch(_PATCH_PAS_CLASS, mock_pas_class),
patch(_PATCH_LIFECYCLE, return_value=mock_lifecycle),
patch(
"cleveragents.cli.commands.plan.PlanApplyService",
mock_pas_cls,
create=True,
),
patch(_PATCH_PAS_CLASS, mock_pas_cls),
):
context.new_cov_apply_result = _get_apply_service()
context.new_cov_pas_class = mock_pas_class
context.new_cov_pas_instance = mock_pas_instance
result = _get_apply_service()
context.new_cov_apply_result = result
context.new_cov_mock_lifecycle_used = mock_lifecycle
context.new_cov_mock_pas_cls = mock_pas_cls
context.new_cov_mock_pas_instance = mock_pas_instance
# ---------------------------------------------------------------------------
@@ -218,13 +235,16 @@ def step_new_cov_output_contains(context: Context, text: str) -> None:
@then("new_cov the returned object should be a PlanApplyService instance")
def step_new_cov_result_is_pas(context: Context) -> None:
assert context.new_cov_apply_result is context.new_cov_pas_instance, (
f"Expected the mock PAS instance, got {type(context.new_cov_apply_result).__name__}"
result = context.new_cov_apply_result
expected = context.new_cov_mock_pas_instance
assert result is expected, (
f"Expected _get_apply_service to return the mock PlanApplyService "
f"instance, got {type(result).__name__}"
)
@then("new_cov PlanApplyService was constructed with the lifecycle service")
def step_new_cov_pas_called_with_lifecycle(context: Context) -> None:
context.new_cov_pas_class.assert_called_once_with(
lifecycle_service=context.new_cov_mock_lifecycle,
context.new_cov_mock_pas_cls.assert_called_once_with(
lifecycle_service=context.new_cov_mock_lifecycle_used,
)
+11 -4
View File
@@ -12,16 +12,23 @@ Suite Teardown Cleanup Test Environment
*** Test Cases ***
Resource Add Git Checkout Should Not Fail With Type Not Found
[Documentation] Run "agents resource add git-checkout" and verify it does not
... produce a "Resource type not found" error. This currently fails
... because bootstrap_builtin_types() is never called.
[Documentation] Initialize a project then run "agents resource add git-checkout"
... and verify it does not produce a "Resource type not found" error.
... bootstrap_builtin_types() is called during project init.
${proj_dir}= Set Variable ${TEMPDIR}${/}git_checkout_bootstrap_test
Create Directory ${proj_dir}
${init_result}= Run Process ${PYTHON} -m cleveragents init test-git-bootstrap
... cwd=${proj_dir} timeout=120s
Should Be Equal As Integers ${init_result.rc} 0
... msg=Project init failed: rc=${init_result.rc} stderr=${init_result.stderr}
${result}= Run Process ${PYTHON} -m cleveragents resource add
... git-checkout local/test --path /tmp/repo --branch main
... timeout=60s
... cwd=${proj_dir} timeout=60s
Should Not Contain ${result.stdout} Resource type not found
Should Not Contain ${result.stderr} Resource type not found
Should Be Equal As Integers ${result.rc} 0
... msg=Expected exit code 0 but got ${result.rc}. stdout: ${result.stdout} stderr: ${result.stderr}
[Teardown] Run Keyword And Ignore Error Remove Directory ${proj_dir} recursive=True
Git Checkout Type Exists After Bootstrap
[Documentation] Directly call bootstrap_builtin_types() and verify git-checkout
+12
View File
@@ -200,6 +200,18 @@ def init_command(
apply_default_filters=default_filters,
)
# Bootstrap built-in resource types (fs-directory, git-checkout, etc.)
# into the database after schema creation. This must happen after
# initialize_project() because the database tables are created there
# via unit_of_work.init_database(). The call is idempotent — calling
# it multiple times will not create duplicate types.
from cleveragents.application.services.resource_registry_service import (
ResourceRegistryService,
)
resource_registry: ResourceRegistryService = container.resource_registry_service()
resource_registry.bootstrap_builtin_types()
console.print(
Panel(
f"[green]✓[/green] Project '{project.name}' "