debatefloor / tests /test_cli /test_push.py
AniketAsla's picture
sync: mirror git d05fcb5 to Space
b4ac377 verified
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.
"""Tests for the openenv push command."""
import os
from pathlib import Path
from unittest.mock import MagicMock, patch
from openenv.cli.__main__ import app
from typer.testing import CliRunner
runner = CliRunner()
def _create_test_openenv_env(env_dir: Path, env_name: str = "test_env") -> None:
"""Create a complete OpenEnv environment for testing."""
import yaml
# Create openenv.yaml
manifest = {
"spec_version": 1,
"name": env_name,
"type": "space",
"runtime": "fastapi",
"app": "server.app:app",
"port": 8000,
}
with open(env_dir / "openenv.yaml", "w") as f:
yaml.dump(manifest, f)
# Create pyproject.toml (required by validate_env_structure)
pyproject_content = f"""[project]
name = "{env_name}"
version = "0.1.0"
dependencies = ["openenv[core]>=0.2.0"]
"""
(env_dir / "pyproject.toml").write_text(pyproject_content)
# Create __init__.py
(env_dir / "__init__.py").write_text("# Test environment\n")
# Create client.py (required by validate_env_structure)
(env_dir / "client.py").write_text("# Test client\n")
# Create models.py (required by validate_env_structure)
(env_dir / "models.py").write_text("# Test models\n")
# Create server directory and files
(env_dir / "server").mkdir(exist_ok=True)
(env_dir / "server" / "__init__.py").write_text("# Server module\n")
(env_dir / "server" / "app.py").write_text("# App module\n")
(env_dir / "server" / "Dockerfile").write_text(
'FROM openenv-base:latest\nCMD ["uvicorn", "server.app:app", "--host", "0.0.0.0", "--port", "8000"]\n'
)
# Create README.md with frontmatter
readme_content = """---
title: Test Environment
sdk: docker
app_port: 8000
---
# Test Environment
"""
(env_dir / "README.md").write_text(readme_content)
def test_push_validates_openenv_directory(tmp_path: Path) -> None:
"""Test that push validates openenv.yaml is present."""
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
assert result.exit_code != 0
assert (
"openenv.yaml" in result.output.lower() or "manifest" in result.output.lower()
)
def test_push_validates_openenv_yaml_format(tmp_path: Path) -> None:
"""Test that push validates openenv.yaml format."""
# Create complete env structure then overwrite openenv.yaml with invalid content
_create_test_openenv_env(tmp_path)
(tmp_path / "openenv.yaml").write_text("invalid: yaml: content: [")
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
assert result.exit_code != 0
assert "parse" in result.output.lower() or "yaml" in result.output.lower()
def test_push_validates_openenv_yaml_has_name(tmp_path: Path) -> None:
"""Test that push validates openenv.yaml has a name field."""
import yaml
# Create complete env structure then overwrite openenv.yaml without name
_create_test_openenv_env(tmp_path)
manifest = {"spec_version": 1, "type": "space"}
with open(tmp_path / "openenv.yaml", "w") as f:
yaml.dump(manifest, f)
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
assert result.exit_code != 0
assert "name" in result.output.lower()
def test_push_authenticates_with_hf(tmp_path: Path) -> None:
"""Test that push ensures Hugging Face authentication."""
_create_test_openenv_env(tmp_path)
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
# Mock whoami to return user info
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None # Prevent actual login prompt
# Mock HfApi
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
# Verify whoami was called
assert mock_whoami.called
def test_push_enables_web_interface_in_dockerfile(tmp_path: Path) -> None:
"""Test that push enables web interface in Dockerfile."""
_create_test_openenv_env(tmp_path)
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None # Prevent actual login prompt
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
# Verify API was called (upload_folder)
assert mock_api.upload_folder.called
def test_push_updates_readme_frontmatter(tmp_path: Path) -> None:
"""Test that push updates README frontmatter with base_path."""
_create_test_openenv_env(tmp_path)
# Create README without base_path
readme_content = """---
title: Test Environment
sdk: docker
app_port: 8000
---
# Test Environment
"""
(tmp_path / "README.md").write_text(readme_content)
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None # Prevent actual login prompt
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
# Verify API was called
assert mock_api.upload_folder.called
def test_push_uses_repo_id_option(tmp_path: Path) -> None:
"""Test that push respects --repo-id option."""
_create_test_openenv_env(tmp_path)
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None # Prevent actual login prompt
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push", "--repo-id", "custom-org/my-env"])
finally:
os.chdir(old_cwd)
# Verify create_repo was called with correct repo_id
mock_api.create_repo.assert_called_once()
call_args = mock_api.create_repo.call_args
assert call_args.kwargs["repo_id"] == "custom-org/my-env"
def test_push_uses_default_repo_id(tmp_path: Path) -> None:
"""Test that push uses default repo-id from username and env name."""
_create_test_openenv_env(tmp_path, env_name="test_env")
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None # Prevent actual login prompt
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
# Verify create_repo was called with default repo_id
mock_api.create_repo.assert_called_once()
call_args = mock_api.create_repo.call_args
assert call_args.kwargs["repo_id"] == "testuser/test_env"
def test_push_uses_private_option(tmp_path: Path) -> None:
"""Test that push respects --private option."""
_create_test_openenv_env(tmp_path)
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None # Prevent actual login prompt
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push", "--private"])
finally:
os.chdir(old_cwd)
# Verify create_repo was called with private=True
mock_api.create_repo.assert_called_once()
call_args = mock_api.create_repo.call_args
assert call_args.kwargs["private"] is True
def test_push_uses_base_image_option(tmp_path: Path) -> None:
"""Test that push respects --base-image option."""
_create_test_openenv_env(tmp_path)
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None # Prevent actual login prompt
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push", "--base-image", "custom-base:latest"])
finally:
os.chdir(old_cwd)
# Verify API was called (we can't easily test Dockerfile modification without reading staging dir)
assert mock_api.upload_folder.called
def test_push_uses_directory_argument(tmp_path: Path) -> None:
"""Test that push respects directory argument."""
env_dir = tmp_path / "my_env"
env_dir.mkdir()
_create_test_openenv_env(env_dir)
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None # Prevent actual login prompt
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
# Directory is a positional argument, not an option
result = runner.invoke(
app,
["push", str(env_dir)],
)
# Verify API was called
assert mock_api.upload_folder.called
def test_push_accepts_dockerfile_at_env_root(tmp_path: Path) -> None:
"""Test that push works when Dockerfile is at environment root instead of server/."""
_create_test_openenv_env(tmp_path)
# Move Dockerfile from server/ to env root
root_dockerfile = tmp_path / "Dockerfile"
(tmp_path / "server" / "Dockerfile").rename(root_dockerfile)
staged_files: list[list[str]] = []
def _capture_staging(*, folder_path: str, **_: object) -> None:
staging = Path(folder_path)
staged_files.append(
sorted(
str(p.relative_to(staging)) for p in staging.rglob("*") if p.is_file()
)
)
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None
mock_api = MagicMock()
mock_api.upload_folder.side_effect = _capture_staging
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
assert result.exit_code == 0, result.output
assert mock_api.upload_folder.called
# Verify the staging directory has Dockerfile at root, not inside server/
files = staged_files[0]
assert "Dockerfile" in files
assert "server/Dockerfile" not in files
def test_push_handles_missing_dockerfile(tmp_path: Path) -> None:
"""Test that push fails when Dockerfile is missing (required for deployment)."""
_create_test_openenv_env(tmp_path)
# Remove Dockerfile (no root Dockerfile either)
(tmp_path / "server" / "Dockerfile").unlink()
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
# Dockerfile is now required - should fail
assert result.exit_code != 0
assert "dockerfile" in result.output.lower() or "missing" in result.output.lower()
def test_push_handles_missing_readme(tmp_path: Path) -> None:
"""Test that push fails when README.md is missing (required for deployment)."""
_create_test_openenv_env(tmp_path)
# Remove README
(tmp_path / "README.md").unlink()
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
# README.md is now required - should fail
assert result.exit_code != 0
assert "readme" in result.output.lower() or "missing" in result.output.lower()
def test_push_initializes_hf_api_without_token(tmp_path: Path) -> None:
"""Test that push initializes HfApi without token parameter."""
_create_test_openenv_env(tmp_path)
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None # Prevent actual login prompt
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
# Verify HfApi was initialized without token parameter
mock_hf_api_class.assert_called_once()
call_args = mock_hf_api_class.call_args
# Should not have token in kwargs
assert "token" not in (call_args.kwargs or {})
def test_push_validates_repo_id_format(tmp_path: Path) -> None:
"""Test that push validates repo-id format."""
_create_test_openenv_env(tmp_path)
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None # Prevent actual login prompt
# Mock HfApi to prevent actual API calls
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
# Invalid format (no slash)
result = runner.invoke(app, ["push", "--repo-id", "invalid-repo-id"])
finally:
os.chdir(old_cwd)
assert result.exit_code != 0
assert "repo-id" in result.output.lower() or "format" in result.output.lower()
def test_push_validates_manifest_is_dict(tmp_path: Path) -> None:
"""Test that push validates manifest is a dictionary."""
import yaml
# Create complete env structure then overwrite openenv.yaml with non-dict
_create_test_openenv_env(tmp_path)
with open(tmp_path / "openenv.yaml", "w") as f:
yaml.dump("not a dict", f)
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
assert result.exit_code != 0
assert "dictionary" in result.output.lower() or "yaml" in result.output.lower()
def test_push_handles_whoami_object_return(tmp_path: Path) -> None:
"""Test that push handles whoami returning an object instead of dict."""
_create_test_openenv_env(tmp_path)
# Create a mock object with name attribute
class MockUser:
def __init__(self):
self.name = "testuser"
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = MockUser()
mock_login.return_value = None # Prevent actual login prompt
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
# Verify it worked with object return type
assert mock_api.upload_folder.called
def test_push_handles_authentication_failure(tmp_path: Path) -> None:
"""Test that push handles authentication failure."""
_create_test_openenv_env(tmp_path)
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
# First whoami call fails (not authenticated)
# Login also fails
mock_whoami.side_effect = Exception("Not authenticated")
mock_login.side_effect = Exception("Login failed")
# Mock HfApi to prevent actual API calls
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
assert result.exit_code != 0
assert (
"authentication" in result.output.lower()
or "login" in result.output.lower()
)
def test_push_handles_whoami_missing_username(tmp_path: Path) -> None:
"""Test that push handles whoami response without username."""
_create_test_openenv_env(tmp_path)
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
# Return dict without name, fullname, or username
mock_whoami.return_value = {}
# Mock login to prevent actual login prompt
mock_login.return_value = None
# Mock HfApi to prevent actual API calls
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
assert result.exit_code != 0
assert "username" in result.output.lower() or "extract" in result.output.lower()
def test_push_handles_readme_without_frontmatter(tmp_path: Path) -> None:
"""Test that push handles README without frontmatter."""
_create_test_openenv_env(tmp_path)
# Create README without frontmatter
(tmp_path / "README.md").write_text("# Test Environment\nNo frontmatter here.\n")
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None # Prevent actual login prompt
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
# Verify it still works (should add frontmatter)
assert mock_api.upload_folder.called
def test_push_handles_hf_api_create_repo_error(tmp_path: Path) -> None:
"""Test that push handles HF API create_repo error."""
_create_test_openenv_env(tmp_path)
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None # Prevent actual login prompt
mock_api = MagicMock()
mock_api.create_repo.side_effect = Exception("API Error")
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
# Should continue despite error (warns but doesn't fail)
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
# Should still attempt upload
assert mock_api.upload_folder.called
def test_push_handles_hf_api_upload_error(tmp_path: Path) -> None:
"""Test that push handles HF API upload_folder error."""
_create_test_openenv_env(tmp_path)
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None # Prevent actual login prompt
mock_api = MagicMock()
mock_api.upload_folder.side_effect = Exception("Upload failed")
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
assert result.exit_code != 0
assert "upload" in result.output.lower() or "failed" in result.output.lower()
def test_push_handles_base_image_not_found_in_dockerfile(tmp_path: Path) -> None:
"""Test that push handles Dockerfile without FROM line."""
_create_test_openenv_env(tmp_path)
# Create Dockerfile without FROM line
(tmp_path / "server" / "Dockerfile").write_text(
'RUN echo \'test\'\nCMD ["echo", "test"]\n'
)
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None # Prevent actual login prompt
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push", "--base-image", "custom-base:latest"])
finally:
os.chdir(old_cwd)
# Should still work (adds FROM at beginning)
assert mock_api.upload_folder.called
def test_push_excludes_files_from_ignore_file(tmp_path: Path) -> None:
"""Test that push excludes files using patterns loaded via --exclude."""
_create_test_openenv_env(tmp_path)
# Create files/folders to verify exclusion behavior.
(tmp_path / "excluded_dir").mkdir()
(tmp_path / "excluded_dir" / "secret.txt").write_text("do not upload")
(tmp_path / "weights.bin").write_text("binary payload")
(tmp_path / "keep.txt").write_text("keep me")
ignore_file = tmp_path / ".openenvignore"
ignore_file.write_text(
"""
# comments and empty lines are ignored
excluded_dir/
*.bin
"""
)
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None # Prevent actual login prompt
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
def _assert_upload_payload(*_unused_args, **kwargs):
ignore_patterns = kwargs["ignore_patterns"]
assert "excluded_dir/" in ignore_patterns
assert "*.bin" in ignore_patterns
assert ".*" in ignore_patterns
staged = Path(kwargs["folder_path"])
assert not (staged / "excluded_dir").exists()
assert not (staged / "weights.bin").exists()
assert (staged / "keep.txt").exists()
mock_api.upload_folder.side_effect = _assert_upload_payload
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(
app,
["push", "--exclude", ".openenvignore"],
)
finally:
os.chdir(old_cwd)
assert result.exit_code == 0
assert mock_api.upload_folder.called
def test_push_does_not_use_gitignore_as_default_excludes(tmp_path: Path) -> None:
"""Test that .gitignore patterns are not used by default."""
_create_test_openenv_env(tmp_path)
(tmp_path / ".gitignore").write_text("excluded_from_gitignore/\n")
(tmp_path / "excluded_from_gitignore").mkdir()
(tmp_path / "excluded_from_gitignore" / "secret.txt").write_text("upload me")
(tmp_path / "keep.txt").write_text("keep me")
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None # Prevent actual login prompt
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
def _assert_upload_payload(*_unused_args, **kwargs):
ignore_patterns = kwargs["ignore_patterns"]
assert "excluded_from_gitignore/" not in ignore_patterns
staged = Path(kwargs["folder_path"])
assert (staged / "excluded_from_gitignore").exists()
assert (staged / "keep.txt").exists()
mock_api.upload_folder.side_effect = _assert_upload_payload
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(app, ["push"])
finally:
os.chdir(old_cwd)
assert result.exit_code == 0
assert mock_api.upload_folder.called
def test_push_fails_when_exclude_file_missing(tmp_path: Path) -> None:
"""Test that push fails if --exclude points to a missing file."""
_create_test_openenv_env(tmp_path)
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None # Prevent actual login prompt
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(
app,
["push", "--exclude", "missing.ignore"],
)
finally:
os.chdir(old_cwd)
assert result.exit_code != 0
assert "exclude file" in result.output.lower()
def test_push_create_pr_sets_upload_flag_and_skips_create_repo(tmp_path: Path) -> None:
"""Test that --create-pr uploads with PR mode and skips repo creation."""
_create_test_openenv_env(tmp_path)
with (
patch("openenv.cli.commands.push.whoami") as mock_whoami,
patch("openenv.cli.commands.push.login") as mock_login,
patch("openenv.cli.commands.push.HfApi") as mock_hf_api_class,
):
mock_whoami.return_value = {"name": "testuser"}
mock_login.return_value = None
mock_api = MagicMock()
mock_hf_api_class.return_value = mock_api
old_cwd = os.getcwd()
try:
os.chdir(str(tmp_path))
result = runner.invoke(
app, ["push", "--repo-id", "my-org/my-env", "--create-pr"]
)
finally:
os.chdir(old_cwd)
assert result.exit_code == 0
mock_api.upload_folder.assert_called_once()
call_kwargs = mock_api.upload_folder.call_args[1]
assert call_kwargs.get("create_pr") is True
# When create_pr we do not create the repo (target repo must exist)
mock_api.create_repo.assert_not_called()