Fix clone error when repo directory already exists

This commit is contained in:
aran-yogesh 2026-02-13 18:28:41 -08:00
parent a8844d3a79
commit 7b1c9bfdca
2 changed files with 103 additions and 60 deletions

View file

@ -46,6 +46,12 @@ SANDBOX_CREATION_TIMEOUT = 180
SANDBOX_POLL_INTERVAL = 1.0 SANDBOX_POLL_INTERVAL = 1.0
from .utils.sandbox_state import SANDBOX_BACKENDS from .utils.sandbox_state import SANDBOX_BACKENDS
from .utils.github import (
git_has_uncommitted_changes,
is_valid_git_repo,
remove_directory,
repo_directory_exists,
)
async def _clone_or_pull_repo_in_sandbox( # noqa: PLR0915 async def _clone_or_pull_repo_in_sandbox( # noqa: PLR0915
@ -76,44 +82,54 @@ async def _clone_or_pull_repo_in_sandbox( # noqa: PLR0915
repo_dir = f"/workspace/{repo}" repo_dir = f"/workspace/{repo}"
logger.debug("Checking if repo already exists at %s", repo_dir) # Check if directory exists
try: logger.debug("Checking if repo directory exists at %s", repo_dir)
check_result = await loop.run_in_executor( dir_exists = await loop.run_in_executor(None, repo_directory_exists, sandbox_backend, repo_dir)
None, sandbox_backend.execute, f"test -d {repo_dir}/.git && echo exists"
)
logger.debug(
"Check result: exit_code=%s, output=%s",
check_result.exit_code,
check_result.output[:200] if check_result.output else "",
)
except Exception:
logger.exception("Failed to execute check command in sandbox")
raise
if check_result.exit_code == 0 and "exists" in check_result.output: if dir_exists:
logger.info("Repo already exists at %s, pulling latest changes", repo_dir) is_git_repo = await loop.run_in_executor(None, is_valid_git_repo, sandbox_backend, repo_dir)
try:
status_result = await loop.run_in_executor( if not is_git_repo:
None, sandbox_backend.execute, f"cd {repo_dir} && git status --porcelain" # Directory exists but is not a valid git repo - remove and clone
logger.warning("Directory exists but is not a valid git repo at %s, removing", repo_dir)
try:
removed = await loop.run_in_executor(None, remove_directory, sandbox_backend, repo_dir)
if not removed:
msg = f"Failed to remove invalid directory at {repo_dir}"
logger.error(msg)
raise RuntimeError(msg)
logger.info("Removed invalid directory, will clone fresh repo")
except Exception:
logger.exception("Failed to remove invalid directory")
raise
# Fall through to clone below
else:
# Valid git repo exists, check for uncommitted changes
logger.info("Repo exists at %s, checking for uncommitted changes", repo_dir)
has_changes = await loop.run_in_executor(
None, git_has_uncommitted_changes, sandbox_backend, repo_dir
) )
logger.debug("Git status result: exit_code=%s", status_result.exit_code)
except Exception:
logger.exception("Failed to get git status")
raise
# CRITICAL: Ensure remote URL doesn't contain token (clean up from previous runs) if has_changes:
clean_url = f"https://github.com/{owner}/{repo}.git" logger.warning("Repo has uncommitted changes at %s, skipping pull", repo_dir)
try: return repo_dir
await loop.run_in_executor(
None,
sandbox_backend.execute,
f"cd {repo_dir} && git remote set-url origin {clean_url}",
)
except Exception:
logger.exception("Failed to set remote URL")
raise
if status_result.exit_code == 0 and not status_result.output.strip(): # No uncommitted changes, safe to pull
logger.info("Repo is clean, pulling latest changes from %s/%s", owner, repo)
# CRITICAL: Ensure remote URL doesn't contain token (clean up from previous runs)
clean_url = f"https://github.com/{owner}/{repo}.git"
try:
await loop.run_in_executor(
None,
sandbox_backend.execute,
f"cd {repo_dir} && git remote set-url origin {clean_url}",
)
except Exception:
logger.exception("Failed to set remote URL")
raise
# Pull with authenticated URL
auth_url = f"https://git:{token}@github.com/{owner}/{repo}.git" auth_url = f"https://git:{token}@github.com/{owner}/{repo}.git"
try: try:
pull_result = await loop.run_in_executor( pull_result = await loop.run_in_executor(
@ -129,35 +145,40 @@ async def _clone_or_pull_repo_in_sandbox( # noqa: PLR0915
except Exception: except Exception:
logger.exception("Failed to execute git pull") logger.exception("Failed to execute git pull")
raise raise
else:
logger.info("Cloning repo %s/%s to %s", owner, repo, repo_dir)
clone_url = f"https://git:{token}@github.com/{owner}/{repo}.git"
try:
result = await loop.run_in_executor(
None, sandbox_backend.execute, f"git clone {clone_url} {repo_dir}"
)
logger.debug("Git clone result: exit_code=%s", result.exit_code)
except Exception:
logger.exception("Failed to execute git clone")
raise
if result.exit_code != 0: logger.info("Repo updated at %s", repo_dir)
msg = f"Failed to clone repo {owner}/{repo}: {result.output}" return repo_dir
logger.error(msg)
raise RuntimeError(msg)
clean_url = f"https://github.com/{owner}/{repo}.git" # Directory doesn't exist or was removed - clone it
try: logger.info("Cloning repo %s/%s to %s", owner, repo, repo_dir)
await loop.run_in_executor( clone_url = f"https://git:{token}@github.com/{owner}/{repo}.git"
None, try:
sandbox_backend.execute, result = await loop.run_in_executor(
f"cd {repo_dir} && git remote set-url origin {clean_url}", None, sandbox_backend.execute, f"git clone {clone_url} {repo_dir}"
) )
except Exception: logger.debug("Git clone result: exit_code=%s", result.exit_code)
logger.exception("Failed to set remote URL after clone") except Exception:
raise logger.exception("Failed to execute git clone")
raise
logger.info("Repo setup complete at %s", repo_dir) if result.exit_code != 0:
msg = f"Failed to clone repo {owner}/{repo}: {result.output}"
logger.error(msg)
raise RuntimeError(msg)
# Clean up the remote URL to remove token
clean_url = f"https://github.com/{owner}/{repo}.git"
try:
await loop.run_in_executor(
None,
sandbox_backend.execute,
f"cd {repo_dir} && git remote set-url origin {clean_url}",
)
except Exception:
logger.exception("Failed to set remote URL after clone")
raise
logger.info("Repo cloned successfully at %s", repo_dir)
return repo_dir return repo_dir

View file

@ -20,6 +20,28 @@ def _run_git(sandbox_backend: Any, repo_dir: str, command: str) -> Any:
return sandbox_backend.execute(f"cd {repo_dir} && {command}") return sandbox_backend.execute(f"cd {repo_dir} && {command}")
def repo_directory_exists(sandbox_backend: Any, repo_dir: str) -> bool:
"""Check if repository directory exists."""
safe_repo_dir = shlex.quote(repo_dir)
result = sandbox_backend.execute(f"test -d {safe_repo_dir} && echo exists")
return result.exit_code == 0 and "exists" in result.output
def is_valid_git_repo(sandbox_backend: Any, repo_dir: str) -> bool:
"""Check if directory is a valid git repository."""
git_dir = f"{repo_dir}/.git"
safe_git_dir = shlex.quote(git_dir)
result = sandbox_backend.execute(f"test -d {safe_git_dir} && echo exists")
return result.exit_code == 0 and "exists" in result.output
def remove_directory(sandbox_backend: Any, repo_dir: str) -> bool:
"""Remove a directory and all its contents."""
safe_repo_dir = shlex.quote(repo_dir)
result = sandbox_backend.execute(f"rm -rf {safe_repo_dir}")
return result.exit_code == 0
def git_has_uncommitted_changes(sandbox_backend: Any, repo_dir: str) -> bool: def git_has_uncommitted_changes(sandbox_backend: Any, repo_dir: str) -> bool:
"""Check whether the repo has uncommitted changes.""" """Check whether the repo has uncommitted changes."""
result = _run_git(sandbox_backend, repo_dir, "git status --porcelain") result = _run_git(sandbox_backend, repo_dir, "git status --porcelain")