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
22 changes: 17 additions & 5 deletions src/smith/providers/azdo_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,18 @@ def _git_auth_subprocess(self: Any, args: list[str], *, cwd: str | None = None)
env=self._git_noninteractive_env() if extra_configs else None,
)

def _git_auth_subprocess_output(self: Any, args: list[str], *, cwd: str | None = None) -> str:
extra_configs = self._git_http_auth_extra_configs()
result = subprocess.run(
self._prepare_git_command(args, extra_configs=extra_configs),
cwd=cwd,
check=True,
capture_output=True,
text=True,
env=self._git_noninteractive_env() if extra_configs else None,
)
return result.stdout

def _git_subprocess_result(
self: Any,
args: list[str],
Expand Down Expand Up @@ -334,11 +346,11 @@ def _local_checkout_refresh_marker(checkout_dir: str) -> str:
return os.path.join(checkout_dir, ".git", "smith-last-fetch")

def _reset_local_checkout(self: Any, checkout_dir: str) -> None:
self._git_subprocess(["git", "-C", checkout_dir, "reset", "--hard", "HEAD"])
self._git_subprocess(["git", "-C", checkout_dir, "clean", "-fd"])
self._git_auth_subprocess(["git", "-C", checkout_dir, "reset", "--hard", "HEAD"])
self._git_auth_subprocess(["git", "-C", checkout_dir, "clean", "-fd"])

def _checkout_local_ref(self: Any, checkout_dir: str, ref: str) -> None:
self._git_subprocess(
self._git_auth_subprocess(
["git", "-C", checkout_dir, "checkout", "--force", "--detach", ref]
)

Expand All @@ -360,10 +372,10 @@ def _apply_sparse_patterns(
checkout_dir: str,
patterns: list[str] | None,
) -> None:
_local_checkout.apply_sparse_patterns(self._git_subprocess, checkout_dir, patterns)
_local_checkout.apply_sparse_patterns(self._git_auth_subprocess, checkout_dir, patterns)

def _remote_head_sha(self: Any, checkout_dir: str, branch: str) -> str | None:
return _local_checkout.remote_head_sha(self._git_subprocess_output, checkout_dir, branch)
return _local_checkout.remote_head_sha(self._git_auth_subprocess_output, checkout_dir, branch)

def _local_head_sha(self: Any, checkout_dir: str) -> str | None:
return _local_checkout.local_head_sha(self._git_subprocess_output, checkout_dir)
Expand Down
22 changes: 17 additions & 5 deletions src/smith/providers/gitlab_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,18 @@ def _git_auth_subprocess(self: Any, args: list[str], *, cwd: str | None = None)
env=self._git_noninteractive_env() if extra_configs else None,
)

def _git_auth_subprocess_output(self: Any, args: list[str], *, cwd: str | None = None) -> str:
extra_configs = self._git_http_auth_extra_configs()
result = subprocess.run(
self._prepare_git_command(args, extra_configs=extra_configs),
cwd=cwd,
check=True,
capture_output=True,
text=True,
env=self._git_noninteractive_env() if extra_configs else None,
)
return result.stdout

def _git_subprocess_result(
self: Any,
args: list[str],
Expand Down Expand Up @@ -784,11 +796,11 @@ def _local_checkout_refresh_marker(checkout_dir: str) -> str:
return os.path.join(checkout_dir, ".git", "smith-last-fetch")

def _reset_local_checkout(self: Any, checkout_dir: str) -> None:
self._git_subprocess(["git", "-C", checkout_dir, "reset", "--hard", "HEAD"])
self._git_subprocess(["git", "-C", checkout_dir, "clean", "-fd"])
self._git_auth_subprocess(["git", "-C", checkout_dir, "reset", "--hard", "HEAD"])
self._git_auth_subprocess(["git", "-C", checkout_dir, "clean", "-fd"])

def _checkout_local_ref(self: Any, checkout_dir: str, ref: str) -> None:
self._git_subprocess(["git", "-C", checkout_dir, "checkout", "--force", "--detach", ref])
self._git_auth_subprocess(["git", "-C", checkout_dir, "checkout", "--force", "--detach", ref])

def _local_checkout_has_expected_origin(self: Any, checkout_dir: str, remote_url: str) -> bool:
try:
Expand All @@ -806,10 +818,10 @@ def _apply_sparse_patterns(
checkout_dir: str,
patterns: list[str] | None,
) -> None:
_local_checkout.apply_sparse_patterns(self._git_subprocess, checkout_dir, patterns)
_local_checkout.apply_sparse_patterns(self._git_auth_subprocess, checkout_dir, patterns)

def _remote_head_sha(self: Any, checkout_dir: str, branch: str) -> str | None:
return _local_checkout.remote_head_sha(self._git_subprocess_output, checkout_dir, branch)
return _local_checkout.remote_head_sha(self._git_auth_subprocess_output, checkout_dir, branch)

def _local_head_sha(self: Any, checkout_dir: str) -> str | None:
return _local_checkout.local_head_sha(self._git_subprocess_output, checkout_dir)
Expand Down
142 changes: 142 additions & 0 deletions tests/unit/test_azdo_provider_internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,148 @@ def test_azdo_ls_remote_precheck_skips_fetch_when_head_matches(
assert mark_calls == [checkout_dir]


def test_azdo_remote_head_sha_uses_token_auth_when_available(monkeypatch: Any) -> None:
provider = _provider()
checkout_dir = os.path.join("tmp", "checkout")
git_calls: list[dict[str, Any]] = []
monkeypatch.setattr(provider, "_get_token", lambda force_refresh=False: "ado-token")

def _fake_run(args: list[str], **kwargs: Any) -> Any:
git_calls.append({"args": args, "env": kwargs.get("env")})
return SimpleNamespace(stdout="abc123\trefs/heads/main\n", stderr="", returncode=0)

monkeypatch.setattr("smith.providers.azdo_code.subprocess.run", _fake_run)

assert provider._remote_head_sha(checkout_dir, "main") == "abc123"
assert git_calls == [
{
"args": [
"git",
"-c",
f"core.hooksPath={os.devnull}",
"-c",
"credential.interactive=never",
"-c",
"http.extraHeader=Authorization: Bearer ado-token",
"-C",
checkout_dir,
"ls-remote",
"origin",
"main",
],
"env": {**os.environ, "GIT_TERMINAL_PROMPT": "0"},
}
]


def test_azdo_apply_sparse_patterns_uses_token_auth_when_available(monkeypatch: Any, tmp_path: Any) -> None:
provider = _provider()
checkout_dir = tmp_path / "checkout"
(checkout_dir / ".git").mkdir(parents=True)
git_calls: list[dict[str, Any]] = []
monkeypatch.setattr(provider, "_get_token", lambda force_refresh=False: "ado-token")

def _fake_run(args: list[str], **kwargs: Any) -> Any:
git_calls.append({"args": args, "env": kwargs.get("env")})
return SimpleNamespace(stdout="", stderr="", returncode=0)

monkeypatch.setattr("smith.providers.azdo_code.subprocess.run", _fake_run)

provider._apply_sparse_patterns(str(checkout_dir), ["/*", "**/*.yml"])

assert git_calls == [
{
"args": [
"git",
"-c",
f"core.hooksPath={os.devnull}",
"-c",
"credential.interactive=never",
"-c",
"http.extraHeader=Authorization: Bearer ado-token",
"-C",
str(checkout_dir),
"sparse-checkout",
"set",
"--no-cone",
"/*",
"**/*.yml",
],
"env": {**os.environ, "GIT_TERMINAL_PROMPT": "0"},
}
]


def test_azdo_checkout_and_reset_use_token_auth_when_available(monkeypatch: Any) -> None:
provider = _provider()
checkout_dir = os.path.join("tmp", "checkout")
git_calls: list[dict[str, Any]] = []
monkeypatch.setattr(provider, "_get_token", lambda force_refresh=False: "ado-token")

def _fake_run(args: list[str], **kwargs: Any) -> Any:
git_calls.append({"args": args, "env": kwargs.get("env")})
return SimpleNamespace(stdout="", stderr="", returncode=0)

monkeypatch.setattr("smith.providers.azdo_code.subprocess.run", _fake_run)

provider._checkout_local_ref(checkout_dir, "FETCH_HEAD")
provider._reset_local_checkout(checkout_dir)

assert git_calls == [
{
"args": [
"git",
"-c",
f"core.hooksPath={os.devnull}",
"-c",
"credential.interactive=never",
"-c",
"http.extraHeader=Authorization: Bearer ado-token",
"-C",
checkout_dir,
"checkout",
"--force",
"--detach",
"FETCH_HEAD",
],
"env": {**os.environ, "GIT_TERMINAL_PROMPT": "0"},
},
{
"args": [
"git",
"-c",
f"core.hooksPath={os.devnull}",
"-c",
"credential.interactive=never",
"-c",
"http.extraHeader=Authorization: Bearer ado-token",
"-C",
checkout_dir,
"reset",
"--hard",
"HEAD",
],
"env": {**os.environ, "GIT_TERMINAL_PROMPT": "0"},
},
{
"args": [
"git",
"-c",
f"core.hooksPath={os.devnull}",
"-c",
"credential.interactive=never",
"-c",
"http.extraHeader=Authorization: Bearer ado-token",
"-C",
checkout_dir,
"clean",
"-fd",
],
"env": {**os.environ, "GIT_TERMINAL_PROMPT": "0"},
},
]


def test_azdo_ripgrep_files_with_matches_uses_subprocess(
monkeypatch: Any, tmp_path: Any
) -> None:
Expand Down
148 changes: 148 additions & 0 deletions tests/unit/test_gitlab_provider_internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,154 @@ def _fake_run(args: list[str], **kwargs: Any) -> Any:
]


def test_gitlab_remote_head_sha_uses_token_auth_when_available(monkeypatch: Any) -> None:
provider = _provider()
checkout_dir = os.path.join("tmp", "checkout")
git_calls: list[dict[str, Any]] = []
monkeypatch.setattr(provider, "_get_token", lambda force_refresh=False: "env-token")

def _fake_run(args: list[str], **kwargs: Any) -> Any:
git_calls.append({"args": args, "env": kwargs.get("env")})
return SimpleNamespace(stdout="abc123\trefs/heads/main\n", stderr="", returncode=0)

monkeypatch.setattr("smith.providers.gitlab_code.subprocess.run", _fake_run)

expected_basic = base64.b64encode(b"oauth2:env-token").decode("ascii")

assert provider._remote_head_sha(checkout_dir, "main") == "abc123"
assert git_calls == [
{
"args": [
"git",
"-c",
f"core.hooksPath={os.devnull}",
"-c",
"credential.interactive=never",
"-c",
f"http.extraHeader=Authorization: Basic {expected_basic}",
"-C",
checkout_dir,
"ls-remote",
"origin",
"main",
],
"env": {**os.environ, "GIT_TERMINAL_PROMPT": "0"},
}
]


def test_gitlab_apply_sparse_patterns_uses_token_auth_when_available(monkeypatch: Any, tmp_path: Any) -> None:
provider = _provider()
checkout_dir = tmp_path / "checkout"
(checkout_dir / ".git").mkdir(parents=True)
git_calls: list[dict[str, Any]] = []
monkeypatch.setattr(provider, "_get_token", lambda force_refresh=False: "env-token")

def _fake_run(args: list[str], **kwargs: Any) -> Any:
git_calls.append({"args": args, "env": kwargs.get("env")})
return SimpleNamespace(stdout="", stderr="", returncode=0)

monkeypatch.setattr("smith.providers.gitlab_code.subprocess.run", _fake_run)

expected_basic = base64.b64encode(b"oauth2:env-token").decode("ascii")

provider._apply_sparse_patterns(str(checkout_dir), ["/*", "**/*.yml"])

assert git_calls == [
{
"args": [
"git",
"-c",
f"core.hooksPath={os.devnull}",
"-c",
"credential.interactive=never",
"-c",
f"http.extraHeader=Authorization: Basic {expected_basic}",
"-C",
str(checkout_dir),
"sparse-checkout",
"set",
"--no-cone",
"/*",
"**/*.yml",
],
"env": {**os.environ, "GIT_TERMINAL_PROMPT": "0"},
}
]


def test_gitlab_checkout_and_reset_use_token_auth_when_available(monkeypatch: Any) -> None:
provider = _provider()
checkout_dir = os.path.join("tmp", "checkout")
git_calls: list[dict[str, Any]] = []
monkeypatch.setattr(provider, "_get_token", lambda force_refresh=False: "env-token")

def _fake_run(args: list[str], **kwargs: Any) -> Any:
git_calls.append({"args": args, "env": kwargs.get("env")})
return SimpleNamespace(stdout="", stderr="", returncode=0)

monkeypatch.setattr("smith.providers.gitlab_code.subprocess.run", _fake_run)

expected_basic = base64.b64encode(b"oauth2:env-token").decode("ascii")

provider._checkout_local_ref(checkout_dir, "FETCH_HEAD")
provider._reset_local_checkout(checkout_dir)

assert git_calls == [
{
"args": [
"git",
"-c",
f"core.hooksPath={os.devnull}",
"-c",
"credential.interactive=never",
"-c",
f"http.extraHeader=Authorization: Basic {expected_basic}",
"-C",
checkout_dir,
"checkout",
"--force",
"--detach",
"FETCH_HEAD",
],
"env": {**os.environ, "GIT_TERMINAL_PROMPT": "0"},
},
{
"args": [
"git",
"-c",
f"core.hooksPath={os.devnull}",
"-c",
"credential.interactive=never",
"-c",
f"http.extraHeader=Authorization: Basic {expected_basic}",
"-C",
checkout_dir,
"reset",
"--hard",
"HEAD",
],
"env": {**os.environ, "GIT_TERMINAL_PROMPT": "0"},
},
{
"args": [
"git",
"-c",
f"core.hooksPath={os.devnull}",
"-c",
"credential.interactive=never",
"-c",
f"http.extraHeader=Authorization: Basic {expected_basic}",
"-C",
checkout_dir,
"clean",
"-fd",
],
"env": {**os.environ, "GIT_TERMINAL_PROMPT": "0"},
},
]


def test_gitlab_grep_no_clone_skips_local_checkout(monkeypatch: Any) -> None:
provider = _provider()
monkeypatch.setenv("GITLAB_GREP_USE_LOCAL_CACHE", "true")
Expand Down
Loading