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
35 changes: 30 additions & 5 deletions src/helper_lib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import os
import subprocess
import sys
from enum import Enum
from pathlib import Path
from typing import Any

Expand All @@ -24,6 +25,12 @@
LOGGER = get_logger(__name__)


class ExecutionEnvironment(Enum):
BAZEL_RUN = "bazel_run"
BAZEL_BUILD = "bazel_build"
DIRECT = "direct"


def config_setdefault(config: Config, name: str, value: Any) -> None:
"""Set a Sphinx config value only if not explicitly set it in conf.py."""

Expand All @@ -47,6 +54,15 @@ def find_ws_root() -> Path | None:
return Path(ws_dir) if ws_dir else None


def identify_environment() -> ExecutionEnvironment:
"""Identify how the current Python process was started."""
if find_ws_root() is not None:
return ExecutionEnvironment.BAZEL_RUN
if Runfiles.Create() is not None:
return ExecutionEnvironment.BAZEL_BUILD
return ExecutionEnvironment.DIRECT


def find_git_root() -> Path | None:
"""
Find the git root directory, starting from workspace root or current directory.
Expand All @@ -56,13 +72,22 @@ def find_git_root() -> Path | None:
- 'bazel build' => ❌ None (sandbox has no .git)
- 'direct sphinx' => ✅ Git root path (fallback to cwd)
"""
start_path = find_ws_root()
if start_path is None:
start_path = Path.cwd()
git_root = Path(start_path).resolve()
match identify_environment():
case ExecutionEnvironment.BAZEL_RUN:
# A Bazel workspace can be nested inside a larger Git repository,
# so the workspace is only the starting point for the search below.
start_path = find_ws_root()
assert start_path is not None
case ExecutionEnvironment.BAZEL_BUILD:
# Bazel build actions run inside a sandbox without a Git worktree.
return None
case ExecutionEnvironment.DIRECT:
start_path = Path.cwd()

git_root = start_path.resolve()
while not (git_root / ".git").exists():
git_root = git_root.parent
if git_root == Path("/"):
if git_root == git_root.parent:
return None
return git_root

Expand Down
16 changes: 16 additions & 0 deletions src/helper_lib/test_helper_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

from src.helper_lib import (
config_setdefault,
find_git_root,
get_current_git_hash,
get_github_repo_info,
get_runfiles_dir,
Expand Down Expand Up @@ -82,6 +83,21 @@ def git_repo(temp_dir: Path) -> Path:
return git_dir


def test_find_git_root_ignores_bazel_sandbox_ancestor_git_repo(
temp_dir: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""A sandbox must not discover a Git repository outside its execroot."""
(temp_dir / ".git").mkdir()
sandbox_dir = temp_dir / "sandbox" / "linux-sandbox" / "1" / "execroot" / "_main"
sandbox_dir.mkdir(parents=True)
monkeypatch.chdir(sandbox_dir)
monkeypatch.delenv("BUILD_WORKSPACE_DIRECTORY", raising=False)
monkeypatch.delenv("RUNFILES_MANIFEST_FILE", raising=False)
monkeypatch.setenv("RUNFILES_DIR", str(temp_dir / "runfiles"))

assert find_git_root() is None


@pytest.fixture
def git_repo_multiple_remotes(temp_dir: Path) -> Path:
"""Create a git repository with multiple remotes for testing."""
Expand Down
Loading