Skip to content
Open
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
25 changes: 25 additions & 0 deletions src/google/adk/cli/cli_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
_SUCCESS_MSG_CODE = """
Agent created in {agent_folder}:
- .env
- .gitignore
- __init__.py
- agent.py

Expand All @@ -88,6 +89,7 @@
_SUCCESS_MSG_CONFIG = """
Agent created in {agent_folder}:
- .env
- .gitignore
- __init__.py
- root_agent.yaml

Expand Down Expand Up @@ -188,6 +190,28 @@ def _prompt_for_google_api_key(
return google_api_key


def _ensure_dotenv_gitignored(agent_folder: str) -> None:
"""Ensures generated dotenv files are ignored by git."""
gitignore_file_path = os.path.join(agent_folder, ".gitignore")
dotenv_ignore_entry = ".env"

if not os.path.exists(gitignore_file_path):
with open(gitignore_file_path, "w", encoding="utf-8") as f:
f.write(f"{dotenv_ignore_entry}\n")
return

with open(gitignore_file_path, "r", encoding="utf-8") as f:
content = f.read()

if dotenv_ignore_entry in (line.strip() for line in content.splitlines()):
return

with open(gitignore_file_path, "a", encoding="utf-8") as f:
if content and not content.endswith("\n"):
f.write("\n")
f.write(f"{dotenv_ignore_entry}\n")


def _generate_files(
agent_folder: str,
*,
Expand Down Expand Up @@ -218,6 +242,7 @@ def _generate_files(
if google_cloud_region:
lines.append(f"GOOGLE_CLOUD_LOCATION={google_cloud_region}")
f.write("\n".join(lines))
_ensure_dotenv_gitignored(agent_folder)

if type == "config":
with open(agent_config_file_path, "w", encoding="utf-8") as f:
Expand Down
30 changes: 30 additions & 0 deletions tests/unittests/cli/utils/test_cli_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def test_generate_files_with_api_key(agent_folder: Path) -> None:
env_content = (agent_folder / ".env").read_text()
assert "GOOGLE_API_KEY=dummy-key" in env_content
assert "GOOGLE_GENAI_USE_VERTEXAI=0" in env_content
assert (agent_folder / ".gitignore").read_text() == ".env\n"
assert (agent_folder / "agent.py").exists()
assert (agent_folder / "__init__.py").exists()

Expand Down Expand Up @@ -149,6 +150,34 @@ def test_generate_files_no_params(agent_folder: Path) -> None:
assert key not in env_content


def test_generate_files_appends_dotenv_to_existing_gitignore(
agent_folder: Path,
) -> None:
"""Existing .gitignore entries should be preserved."""
agent_folder.mkdir(parents=True, exist_ok=True)
(agent_folder / ".gitignore").write_text("__pycache__")

cli_create._generate_files(
str(agent_folder), model="gemini-2.0-flash-001", type="code"
)

assert (agent_folder / ".gitignore").read_text() == "__pycache__\n.env\n"


def test_generate_files_does_not_duplicate_dotenv_gitignore_entry(
agent_folder: Path,
) -> None:
"""Existing .env ignore entries should not be duplicated."""
agent_folder.mkdir(parents=True, exist_ok=True)
(agent_folder / ".gitignore").write_text("__pycache__\n.env\n")

cli_create._generate_files(
str(agent_folder), model="gemini-2.0-flash-001", type="code"
)

assert (agent_folder / ".gitignore").read_text() == "__pycache__\n.env\n"


# run_cmd
def test_run_cmd_overwrite_reject(
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
Expand Down Expand Up @@ -230,6 +259,7 @@ def test_run_cmd_with_type_config(
env_file = agent_dir / ".env"
assert env_file.exists()
assert "GOOGLE_API_KEY=test-key" in env_file.read_text()
assert (agent_dir / ".gitignore").read_text() == ".env\n"


# Prompt helpers
Expand Down