Skip to content

Commit aab6e56

Browse files
authored
fix: tweaks to codegen docker runner (#621)
1 parent 5e968d2 commit aab6e56

File tree

8 files changed

+37
-28
lines changed

8 files changed

+37
-28
lines changed

Dockerfile-runner

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ ENV NVM_DIR=/root/.nvm \
1010
PYTHONPATH="/usr/local/lib/python3.13/site-packages" \
1111
IS_SANDBOX=True \
1212
HATCH_BUILD_HOOKS_ENABLE=1
13+
1314
# Update packages lists and install git and curl
1415
RUN apt-get update && apt-get install -y \
1516
git \
@@ -41,17 +42,14 @@ RUN node --version \
4142
&& pnpm --version \
4243
&& python --version
4344

44-
# Install codegen from source instead of PyPI
45+
# Build codegen
4546
WORKDIR /codegen-sdk
4647
COPY . .
47-
48-
# Install dependencies and build codegen with entry points
4948
RUN --mount=type=cache,target=/root/.cache/uv \
5049
uv venv && source .venv/bin/activate \
5150
&& uv sync --frozen --no-dev --all-extras \
5251
&& uv pip install --system -e . --no-deps \
5352
&& uv pip install --system .
54-
5553
RUN codegen --version
5654

5755
# Create a non-root user for local development + debugging

src/codegen/cli/commands/create/main.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,17 @@ def make_relative(path: Path) -> str:
6868
@click.command(name="create")
6969
@requires_init
7070
@click.argument("name", type=str)
71-
@click.argument("path", type=click.Path(path_type=Path), default=Path.cwd())
71+
@click.argument("path", type=click.Path(path_type=Path), default=None)
7272
@click.option("--description", "-d", default=None, help="Description of what this codemod does.")
7373
@click.option("--overwrite", is_flag=True, help="Overwrites function if it already exists.")
74-
def create_command(session: CodegenSession, name: str, path: Path, description: str | None = None, overwrite: bool = False):
74+
def create_command(session: CodegenSession, name: str, path: Path | None, description: str | None = None, overwrite: bool = False):
7575
"""Create a new codegen function.
7676
7777
NAME is the name/label for the function
7878
PATH is where to create the function (default: current directory)
7979
"""
8080
# Get the target path for the function
81-
codemod_path, prompt_path = get_target_paths(name, path)
81+
codemod_path, prompt_path = get_target_paths(name, path or Path.cwd())
8282

8383
# Check if file exists
8484
if codemod_path.exists() and not overwrite:

src/codegen/cli/commands/start/main.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,28 @@
88
from rich.panel import Panel
99

1010
from codegen.configs.models.secrets import SecretsConfig
11+
from codegen.git.repo_operator.local_git_repo import LocalGitRepo
1112
from codegen.git.schemas.repo_config import RepoConfig
13+
from codegen.shared.network.port import get_free_port
1214

1315

1416
@click.command(name="start")
1517
@click.option("--platform", "-t", type=click.Choice(["linux/amd64", "linux/arm64", "linux/amd64,linux/arm64"]), default="linux/amd64,linux/arm64", help="Target platform(s) for the Docker image")
16-
@click.option("--port", "-p", type=int, default=8000)
18+
@click.option("--port", "-p", type=int, default=None, help="Port to run the server on")
1719
@click.option("--detached", "-d", is_flag=True, default=False, help="Starts up the server as detached background process")
18-
def start_command(port: int, platform: str, detached: bool):
20+
def start_command(port: int | None, platform: str, detached: bool):
1921
"""Starts a local codegen server"""
2022
codegen_version = version("codegen")
2123
rich.print(f"[bold green]Codegen version:[/bold green] {codegen_version}")
2224
codegen_root = Path(__file__).parent.parent.parent.parent.parent.parent
25+
if port is None:
26+
port = get_free_port()
2327

2428
try:
2529
rich.print("[bold blue]Building Docker image...[/bold blue]")
2630
_build_docker_image(codegen_root, platform)
2731
rich.print("[bold blue]Starting Docker container...[/bold blue]")
28-
_run_docker_container(port, platform, detached)
32+
_run_docker_container(port, detached)
2933
rich.print(Panel(f"[green]Server started successfully![/green]\nAccess the server at: [bold]http://0.0.0.0:{port}[/bold]", box=ROUNDED, title="Codegen Server"))
3034
except subprocess.CalledProcessError as e:
3135
rich.print(f"[bold red]Error:[/bold red] Failed to {e.cmd[0]} Docker container")
@@ -59,16 +63,15 @@ def _run_docker_container(port: int, detached: bool):
5963
container_repo_path = f"/app/git/{repo_config.name}"
6064
envvars = {
6165
"REPOSITORY_LANGUAGE": repo_config.language.value,
62-
"REPOSITORY_OWNER": repo_config.organization_name,
66+
"REPOSITORY_OWNER": LocalGitRepo(repo_path).owner,
6367
"REPOSITORY_PATH": container_repo_path,
6468
"GITHUB_TOKEN": SecretsConfig().github_token,
6569
}
6670
envvars_args = [arg for k, v in envvars.items() for arg in ("--env", f"{k}={v}")]
67-
6871
mount_args = ["-v", f"{repo_path}:{container_repo_path}"]
6972
run_mode = "-d" if detached else "-it"
7073
entry_point = f"uv run --frozen uvicorn codegen.runner.sandbox.server:app --host 0.0.0.0 --port {port}"
71-
run_cmd = ["docker", "run", run_mode, "-p", f"8000:{port}", *mount_args, *envvars_args, "codegen-runner", entry_point]
74+
run_cmd = ["docker", "run", run_mode, "-p", f"{port}:{port}", *mount_args, *envvars_args, "codegen-runner", entry_point]
7275

7376
rich.print(f"run_cmd: {str.join(' ', run_cmd)}")
7477
subprocess.run(run_cmd, check=True)

src/codegen/git/repo_operator/local_git_repo.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def origin_remote(self) -> Remote | None:
4747
"""Returns the url of the first remote found on the repo, or None if no remotes are set"""
4848
if self.has_remote():
4949
return self.git_cli.remote("origin")
50+
return None
5051

5152
@cached_property
5253
def base_url(self) -> str | None:

src/codegen/git/schemas/repo_config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,5 @@ def repo_path(self) -> Path:
3838
def organization_name(self) -> str | None:
3939
if self.full_name is not None:
4040
return self.full_name.split("/")[0]
41+
4142
return None

src/codegen/runner/sandbox/runner.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class SandboxRunner:
3131

3232
def __init__(self, repo_config: RepoConfig) -> None:
3333
self.repo = repo_config
34-
self.op = RepoOperator(repo_config=self.repo, setup_option=SetupOption.PULL_OR_CLONE)
34+
self.op = RepoOperator(repo_config=self.repo, setup_option=SetupOption.PULL_OR_CLONE, bot_commit=True)
3535
self.commit = self.op.git_cli.head.commit
3636

3737
async def warmup(self) -> None:

src/codegen/shared/network/port.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import socket
2+
from contextlib import closing
3+
4+
5+
def get_free_port() -> int:
6+
"""Find and return a free port on localhost"""
7+
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
8+
s.bind(("", 0))
9+
s.listen(1)
10+
port = s.getsockname()[1]
11+
return int(port)
12+
13+
14+
def is_port_free(port: int, host: str = "localhost") -> bool:
15+
"""Check if a port is free on localhost"""
16+
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
17+
return s.connect_ex((host, port)) != 0

tests/integration/codegen/runner/conftest.py

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import socket
21
from collections.abc import Generator
3-
from contextlib import closing
42
from unittest.mock import Mock
53

64
import pytest
@@ -11,16 +9,7 @@
119
from codegen.git.schemas.repo_config import RepoConfig
1210
from codegen.runner.clients.codebase_client import CodebaseClient
1311
from codegen.shared.enums.programming_language import ProgrammingLanguage
14-
15-
16-
@pytest.fixture
17-
def get_free_port():
18-
"""Find and return a free port on localhost"""
19-
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
20-
s.bind(("", 0))
21-
s.listen(1)
22-
port = s.getsockname()[1]
23-
return port
12+
from codegen.shared.network.port import get_free_port
2413

2514

2615
@pytest.fixture()
@@ -44,7 +33,7 @@ def git_repo_client(op: RepoOperator, repo_config: RepoConfig) -> Generator[GitR
4433

4534

4635
@pytest.fixture
47-
def codebase_client(repo_config: RepoConfig, get_free_port) -> Generator[CodebaseClient, None, None]:
48-
sb_client = CodebaseClient(repo_config=repo_config, port=get_free_port)
36+
def codebase_client(repo_config: RepoConfig) -> Generator[CodebaseClient, None, None]:
37+
sb_client = CodebaseClient(repo_config=repo_config, port=get_free_port())
4938
sb_client.runner = Mock()
5039
yield sb_client

0 commit comments

Comments
 (0)