diff --git a/agent/builder.py b/agent/builder.py index beb63728..a4586287 100644 --- a/agent/builder.py +++ b/agent/builder.py @@ -1,6 +1,7 @@ from __future__ import annotations import contextlib +import json import os import re import shlex @@ -327,6 +328,22 @@ def _inject_additional_packages(self, packages: list[str]): with open(dockerfile_path, "w") as f: f.write(content) + def _set_flow_server_manager(self): + """Have the bench's supervisor run the Flow server when Frappe declares it""" + frappe_path = os.path.join(self.build_directory, "apps", "frappe") + pyproject = get_package_manager_files({"frappe": frappe_path})["frappe"]["pyproject"] or {} + if "flow_server" not in pyproject.get("tool", {}).get("pilot", {}).get("processes", {}): + return + + config_path = os.path.join(self.build_directory, "common_site_config.json") + with open(config_path, "r") as f: + config = json.load(f) + + config["flow_server_manager"] = "supervisor" + + with open(config_path, "w") as f: + json.dump(config, f, indent=4) + @step("Prepare Build Context") def prepare_build_context(self): """Clone the apps passed from build instructions and return the build context directory path""" @@ -358,6 +375,7 @@ def prepare_build_context(self): additional_packages = self._parse_additional_packages() self._inject_additional_packages(additional_packages) + self._set_flow_server_manager() @dataclass diff --git a/agent/tests/test_builder.py b/agent/tests/test_builder.py index 3e1ea14a..8e216b98 100644 --- a/agent/tests/test_builder.py +++ b/agent/tests/test_builder.py @@ -1,6 +1,7 @@ from __future__ import annotations import importlib +import json import os import shutil import sys @@ -68,6 +69,28 @@ def test_build_context_includes_the_asset_store_script(self): ContextManager._copy_build_config_files(context) self.assertTrue(os.path.isfile(os.path.join(build_directory, "get_cached_app.py"))) + def test_image_has_supervisor_run_the_flow_server_frappe_declares(self): + from agent.builder import ContextManager + + build_config_path = os.path.join(os.path.dirname(agent.__file__), "build_configs") + declared = '[tool.pilot.processes.flow_server]\nfrappe_command = ["flow-server", "serve"]\n' + for pyproject, manager in [(declared, "supervisor"), ('[project]\nname = "frappe"\n', None)]: + with self.subTest(manager=manager), tempfile.TemporaryDirectory() as build_directory: + context = SimpleNamespace( + build_config_path=build_config_path, build_directory=build_directory + ) + ContextManager._copy_build_config_files(context) + os.makedirs(os.path.join(build_directory, "apps", "frappe")) + with open(os.path.join(build_directory, "apps", "frappe", "pyproject.toml"), "w") as f: + f.write(pyproject) + + ContextManager._set_flow_server_manager(context) + + with open(os.path.join(build_directory, "common_site_config.json")) as f: + config = json.load(f) + self.assertEqual(config.get("flow_server_manager"), manager) + self.assertEqual(config["webserver_port"], 8000) + class TestStoredAssetsInBuildContext(unittest.TestCase): def test_stored_assets_are_downloaded_into_the_build_context(self):