Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "GitAuto"
version = "1.24.13"
version = "1.24.14"
requires-python = ">=3.14"
dependencies = [
"annotated-doc==0.0.4",
Expand Down
20 changes: 20 additions & 0 deletions services/git/delete_file.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Standard imports
import os
import subprocess

# Third party imports
from anthropic.types import ToolUnionParam
Expand Down Expand Up @@ -38,16 +39,35 @@ def delete_file(
local_path = os.path.join(clone_dir, file_path)

if os.path.isdir(local_path):
logger.info("delete_file: %s is a directory, returning error", file_path)
return f"Error: '{file_path}' is a directory, not a file"

if not os.path.exists(local_path):
logger.info("delete_file: %s not found, returning error", file_path)
return f"Error: File {file_path} not found"

# Sentry AGENT-36X/36W/344 fired with: `git add mongodb-binaries/mongodb-linux-x86_64-amazon2023-v7.0-latest.tgz.md5` → "pathspec did not match any files". The path is gitignored (mongodb-memory-server writes there) so it was never in git's index, and os.remove above cleared it from disk, leaving `git add` with nothing to match. Check tracking BEFORE os.remove so we can skip the commit when the path was never tracked.
ls_files = subprocess.run(
["git", "ls-files", "--error-unmatch", file_path],
cwd=clone_dir,
capture_output=True,
check=False,
)
is_tracked = ls_files.returncode == 0

os.remove(local_path)
logger.info("Deleted local: %s", local_path)

if not is_tracked:
logger.info(
"delete_file: %s is not tracked by git (gitignored or never committed); skipping commit",
file_path,
)
return f"File {file_path} successfully deleted"

git_commit_and_push(
base_args=base_args, message=f"Delete {file_path}", files=[file_path]
)

logger.info("delete_file: %s deleted and commit pushed", file_path)
return f"File {file_path} successfully deleted"
73 changes: 71 additions & 2 deletions services/git/test_delete_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,79 @@ def test_delete_file_end_to_end(local_repo, create_test_base_args):
assert not os.path.exists(os.path.join(clone_dir, "src", "main.py"))

log = subprocess.run(
["git", "log", "--oneline", "feature/delete-test", "-1"],
["git", "log", "--format=%s", "feature/delete-test", "-1"],
cwd=bare_dir,
capture_output=True,
text=True,
check=False,
)
assert "Delete src/main.py" in log.stdout
assert log.stdout.strip() == "Delete src/main.py"


@pytest.mark.integration
def test_delete_gitignored_file_skips_commit(local_repo, create_test_base_args):
"""Reproduces AGENT-36X/36W/344: the agent deletes a local gitignored file
(e.g. mongodb-binaries/*.tgz cached from a prior CI run). delete_file used to
rm the file then run `git add <path>` which fails with 'pathspec did not match
any files' because git never tracked it. Now we detect untracked paths and
skip the commit entirely."""
bare_url, _work_dir = local_repo
bare_dir = bare_url.replace("file://", "")

with tempfile.TemporaryDirectory() as clone_dir:
git_clone_to_tmp(clone_dir, bare_url, "main")

# .gitignore the mongodb-binaries directory, then drop a file in it locally.
with open(os.path.join(clone_dir, ".gitignore"), "a", encoding="utf-8") as f:
f.write("mongodb-binaries/\n")
os.makedirs(os.path.join(clone_dir, "mongodb-binaries"), exist_ok=True)
(
os.path.join(clone_dir, "mongodb-binaries", "cache.tgz")
) # noqa: B018 -- path existence below
with open(
os.path.join(clone_dir, "mongodb-binaries", "cache.tgz"),
"w",
encoding="utf-8",
) as f:
f.write("binary data")

# Capture remote head BEFORE deletion so we can prove nothing was pushed.
head_before = subprocess.run(
["git", "rev-parse", "HEAD"],
cwd=bare_dir,
capture_output=True,
text=True,
check=True,
).stdout.strip()

base_args = create_test_base_args(
clone_dir=clone_dir,
clone_url=bare_url,
new_branch="feature/delete-gitignored",
)

result = delete_file("mongodb-binaries/cache.tgz", base_args)

assert result == "File mongodb-binaries/cache.tgz successfully deleted"
assert not os.path.exists(
os.path.join(clone_dir, "mongodb-binaries", "cache.tgz")
)

# No commit/push should have occurred because the file was never tracked.
head_after = subprocess.run(
["git", "rev-parse", "HEAD"],
cwd=bare_dir,
capture_output=True,
text=True,
check=True,
).stdout.strip()
assert head_after == head_before

# And the new_branch should not exist on the remote.
branch_check = subprocess.run(
["git", "ls-remote", "--heads", bare_url, "feature/delete-gitignored"],
capture_output=True,
text=True,
check=True,
)
assert branch_check.stdout.strip() == ""
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.