Skip to content

Commit 8e34b3a

Browse files
committed
feat: Server client vs. codebase client
1 parent 61964af commit 8e34b3a

File tree

5 files changed

+77
-39
lines changed

5 files changed

+77
-39
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""Client used to abstract the weird stdin/stdout communication we have with the sandbox"""
2+
3+
import logging
4+
5+
from codegen.git.schemas.repo_config import RepoConfig
6+
from codegen.runner.clients.server_client import LocalServerClient
7+
from codegen.runner.models.apis import SANDBOX_SERVER_PORT
8+
9+
logger = logging.getLogger(__name__)
10+
11+
RUNNER_SERVER_PATH = "codegen.runner.sandbox.server:app"
12+
13+
14+
class CodebaseClient(LocalServerClient):
15+
"""Client for interacting with the locally hosted sandbox server."""
16+
17+
repo_config: RepoConfig
18+
git_access_token: str | None
19+
20+
def __init__(self, repo_config: RepoConfig, git_access_token: str | None, host: str = "127.0.0.1", port: int = SANDBOX_SERVER_PORT):
21+
self.repo_config = repo_config
22+
self.git_access_token = git_access_token
23+
super().__init__(server_path=RUNNER_SERVER_PATH, host=host, port=port)
24+
25+
def _get_envs(self):
26+
envs = super()._get_envs()
27+
envs.update(
28+
{
29+
"CODEGEN_REPOSITORY__REPO_PATH": self.repo_config.repo_path,
30+
"CODEGEN_REPOSITORY__REPO_NAME": self.repo_config.name,
31+
"CODEGEN_REPOSITORY__FULL_NAME": self.repo_config.full_name,
32+
"CODEGEN_REPOSITORY__LANGUAGE": self.repo_config.language.value,
33+
"CODEGEN_SECRETS__GITHUB_TOKEN": self.git_access_token,
34+
}
35+
)
36+
return envs

src/codegen/runner/clients/sandbox_client.py renamed to src/codegen/runner/clients/server_client.py

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,71 +8,73 @@
88
import requests
99
from fastapi import params
1010

11-
from codegen.git.schemas.repo_config import RepoConfig
12-
from codegen.runner.models.apis import SANDBOX_SERVER_PORT
13-
1411
logger = logging.getLogger(__name__)
1512

13+
DEFAULT_SERVER_PORT = 4002
14+
15+
EPHEMERAL_SERVER_PATH = "codegen.runner.sandbox.ephemeral_server:app"
1616

17-
class SandboxClient:
18-
"""Client for interacting with the locally hosted sandbox server."""
17+
18+
class LocalServerClient:
19+
"""Client for interacting with the sandbox server."""
1920

2021
host: str
2122
port: int
2223
base_url: str
2324
_process: subprocess.Popen | None
2425

25-
def __init__(self, repo_config: RepoConfig, git_access_token: str | None, host: str = "127.0.0.1", port: int = SANDBOX_SERVER_PORT):
26+
def __init__(self, server_path: str = EPHEMERAL_SERVER_PATH, host: str = "127.0.0.1", port: int = DEFAULT_SERVER_PORT):
2627
self.host = host
2728
self.port = port
2829
self.base_url = f"http://{host}:{port}"
2930
self._process = None
30-
self._start_server(repo_config, git_access_token)
31+
self._start_server(server_path)
32+
33+
def __del__(self):
34+
"""Cleanup the subprocess when the client is destroyed"""
35+
if self._process is not None:
36+
self._process.terminate()
37+
self._process.wait()
38+
39+
def _get_envs(self):
40+
return os.environ.copy()
3141

32-
def _start_server(self, repo_config: RepoConfig, git_access_token: str | None) -> None:
42+
def _start_server(self, server_path: str) -> None:
3343
"""Start the FastAPI server in a subprocess"""
34-
env = os.environ.copy()
35-
env.update(
36-
{
37-
"CODEGEN_REPOSITORY__REPO_PATH": repo_config.repo_path,
38-
"CODEGEN_REPOSITORY__REPO_NAME": repo_config.name,
39-
"CODEGEN_REPOSITORY__FULL_NAME": repo_config.full_name,
40-
"CODEGEN_REPOSITORY__LANGUAGE": repo_config.language.value,
41-
"CODEGEN_SECRETS__GITHUB_TOKEN": git_access_token,
42-
}
43-
)
44+
envs = self._get_envs()
45+
logger.info(f"Starting local server on {self.base_url} with envvars: {envs}")
4446

45-
logger.info(f"Starting local sandbox server on {self.base_url} with repo setup in base_dir {repo_config.base_dir}")
4647
self._process = subprocess.Popen(
4748
[
4849
"uvicorn",
49-
"codegen.runner.sandbox.server:app",
50+
server_path,
5051
"--host",
5152
self.host,
5253
"--port",
5354
str(self.port),
5455
],
55-
env=env,
56+
env=envs,
5657
)
5758
self._wait_for_server()
5859

5960
def _wait_for_server(self, timeout: int = 60, interval: float = 0.1) -> None:
6061
"""Wait for the server to start by polling the health endpoint"""
6162
start_time = time.time()
6263
while (time.time() - start_time) < timeout:
63-
try:
64-
self.get("/")
64+
if self.healthcheck(raise_on_error=False):
6565
return
66-
except requests.ConnectionError:
67-
time.sleep(interval)
66+
time.sleep(interval)
6867
msg = "Server failed to start within timeout period"
6968
raise TimeoutError(msg)
7069

71-
def __del__(self):
72-
"""Cleanup the subprocess when the client is destroyed"""
73-
if self._process is not None:
74-
self._process.terminate()
75-
self._process.wait()
70+
def healthcheck(self, raise_on_error: bool = True) -> bool:
71+
try:
72+
self.get("/")
73+
return True
74+
except requests.exceptions.ConnectionError:
75+
if raise_on_error:
76+
raise
77+
return False
7678

7779
def get(self, endpoint: str, data: dict | None = None) -> requests.Response:
7880
url = f"{self.base_url}{endpoint}"

tests/integration/codegen/runner/conftest.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from codegen.git.clients.git_repo_client import GitRepoClient
99
from codegen.git.repo_operator.remote_repo_operator import RemoteRepoOperator
1010
from codegen.git.schemas.repo_config import RepoConfig
11-
from codegen.runner.clients.sandbox_client import SandboxClient
11+
from codegen.runner.clients.codebase_client import CodebaseClient
1212
from codegen.shared.configs.session_configs import config
1313
from codegen.shared.enums.programming_language import ProgrammingLanguage
1414

@@ -45,7 +45,7 @@ def git_repo_client(repo_config: RepoConfig) -> Generator[GitRepoClient, None, N
4545

4646

4747
@pytest.fixture
48-
def sandbox_client(repo_config: RepoConfig, get_free_port) -> Generator[SandboxClient, None, None]:
49-
sb_client = SandboxClient(repo_config=repo_config, port=get_free_port, git_access_token=config.secrets.github_token)
48+
def codebase_client(repo_config: RepoConfig, get_free_port) -> Generator[CodebaseClient, None, None]:
49+
sb_client = CodebaseClient(repo_config=repo_config, port=get_free_port, git_access_token=config.secrets.github_token)
5050
sb_client.runner = Mock()
5151
yield sb_client

tests/integration/codegen/runner/test_create_branch.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55

66
from codegen.git.clients.git_repo_client import GitRepoClient
77
from codegen.git.repo_operator.remote_repo_operator import RemoteRepoOperator
8-
from codegen.runner.clients.sandbox_client import SandboxClient
8+
from codegen.runner.clients.codebase_client import CodebaseClient
99
from codegen.runner.models.apis import BRANCH_ENDPOINT, CreateBranchRequest, CreateBranchResponse
1010
from codegen.runner.models.codemod import BranchConfig, Codemod, GroupingConfig
1111

1212

1313
@pytest.mark.asyncio
1414
@pytest.mark.timeout(60)
15-
async def test_create_branch(sandbox_client: SandboxClient, git_repo_client: GitRepoClient, op: RemoteRepoOperator):
15+
async def test_create_branch(codebase_client: CodebaseClient, git_repo_client: GitRepoClient, op: RemoteRepoOperator):
1616
# set-up
1717
codemod_source = """
1818
for file in codebase.files:
@@ -29,7 +29,7 @@ async def test_create_branch(sandbox_client: SandboxClient, git_repo_client: Git
2929
)
3030

3131
# execute
32-
response = sandbox_client.post(endpoint=BRANCH_ENDPOINT, data=request.model_dump())
32+
response = codebase_client.post(endpoint=BRANCH_ENDPOINT, data=request.model_dump())
3333
assert response.status_code == HTTPStatus.OK
3434

3535
# verify

tests/integration/codegen/runner/test_create_branch_with_grouping.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55

66
from codegen.git.clients.git_repo_client import GitRepoClient
77
from codegen.git.repo_operator.remote_repo_operator import RemoteRepoOperator
8-
from codegen.runner.clients.sandbox_client import SandboxClient
8+
from codegen.runner.clients.codebase_client import CodebaseClient
99
from codegen.runner.models.apis import BRANCH_ENDPOINT, CreateBranchRequest, CreateBranchResponse
1010
from codegen.runner.models.codemod import BranchConfig, Codemod, GroupingConfig
1111
from codegen.sdk.codebase.flagging.groupers.enums import GroupBy
1212

1313

1414
@pytest.mark.timeout(120)
1515
@pytest.mark.parametrize("group_by", [GroupBy.INSTANCE, GroupBy.FILE])
16-
def test_create_branch_with_grouping(sandbox_client: SandboxClient, git_repo_client: GitRepoClient, op: RemoteRepoOperator, group_by: GroupBy):
16+
def test_create_branch_with_grouping(codebase_client: CodebaseClient, git_repo_client: GitRepoClient, op: RemoteRepoOperator, group_by: GroupBy):
1717
codemod_source = """
1818
for file in codebase.files[:5]:
1919
flag = codebase.flag_instance(file)
@@ -31,7 +31,7 @@ def test_create_branch_with_grouping(sandbox_client: SandboxClient, git_repo_cli
3131
)
3232

3333
# execute
34-
response = sandbox_client.post(endpoint=BRANCH_ENDPOINT, data=request.model_dump())
34+
response = codebase_client.post(endpoint=BRANCH_ENDPOINT, data=request.model_dump())
3535
assert response.status_code == HTTPStatus.OK
3636

3737
# verify

0 commit comments

Comments
 (0)