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
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,6 @@ my_project/
├── cpu_worker.py # CPU worker with @remote function
├── .env # Environment variable template
├── .gitignore # Git ignore patterns
├── .flashignore # Flash deployment ignore patterns
├── pyproject.toml # Python dependencies (uv/pip compatible)
└── README.md # Project documentation
```
Expand Down Expand Up @@ -543,7 +542,7 @@ For information on load-balanced endpoints (required for HTTP services), see [do

**No @remote functions found:**
- Ensure your functions are decorated with `@remote(resource_config)`
- Check that Python files are not excluded by `.gitignore` or `.flashignore`
- Check that Python files are not excluded by `.gitignore`
- Verify function decorators have valid syntax

**Build succeeded but deployment failed:**
Expand Down
2 changes: 1 addition & 1 deletion TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ make validate-wheel
- Or test specific module: `uv run pytest --cov=src/runpod_flash/cli/utils/skeleton`

**Hidden files require explicit glob patterns**
- Pattern `**/.*` needed in pyproject.toml to include `.env`, `.gitignore`, `.flashignore`
- Pattern `**/.*` needed in pyproject.toml to include `.env`, `.gitignore`
- Verify with: `unzip -l dist/runpod_flash-*.whl | grep skeleton_template`

## Pre-Release Checklist
Expand Down
3 changes: 1 addition & 2 deletions scripts/validate-wheel.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ echo "Checking wheel contents..."
REQUIRED_TEMPLATE_FILES=(
"runpod_flash/cli/utils/skeleton_template/.env.example"
"runpod_flash/cli/utils/skeleton_template/.gitignore"
"runpod_flash/cli/utils/skeleton_template/.flashignore"
"runpod_flash/cli/utils/skeleton_template/cpu_worker.py"
"runpod_flash/cli/utils/skeleton_template/gpu_worker.py"
"runpod_flash/cli/utils/skeleton_template/lb_worker.py"
Expand Down Expand Up @@ -75,7 +74,7 @@ flash init test_project > /dev/null 2>&1
# Verify critical files exist
echo ""
echo "Verifying created files..."
REQUIRED_FILES=(".env.example" ".gitignore" ".flashignore" "cpu_worker.py" "gpu_worker.py" "lb_worker.py" "pyproject.toml" "README.md" "requirements.txt")
REQUIRED_FILES=(".env.example" ".gitignore" "cpu_worker.py" "gpu_worker.py" "lb_worker.py" "pyproject.toml" "README.md" "requirements.txt")
MISSING_IN_OUTPUT=0

for file in "${REQUIRED_FILES[@]}"; do
Expand Down
2 changes: 1 addition & 1 deletion src/runpod_flash/cli/commands/build_utils/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def discover_remote_functions(self) -> List[RemoteFunctionMetadata]:
"""Discover all @remote decorated functions and classes."""
functions = []

# Use .gitignore / .flashignore aware file walker with early directory pruning.
# Use .gitignore aware file walker with early directory pruning.
# This avoids descending into .venv, __pycache__, .flash, etc.
spec = load_ignore_patterns(self.project_dir)
all_files = get_file_tree(self.project_dir, spec)
Expand Down
42 changes: 33 additions & 9 deletions src/runpod_flash/cli/utils/ignore.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def parse_ignore_file(file_path: Path) -> list[str]:
Parse an ignore file and return list of patterns.

Args:
file_path: Path to ignore file (.flashignore or .gitignore)
file_path: Path to ignore file (.gitignore)

Returns:
List of pattern strings
Expand All @@ -40,7 +40,7 @@ def parse_ignore_file(file_path: Path) -> list[str]:

def load_ignore_patterns(project_dir: Path) -> pathspec.PathSpec:
"""
Load ignore patterns from .flashignore and .gitignore files.
Load ignore patterns from .gitignore and built-in defaults.

Args:
project_dir: Flash project directory
Expand All @@ -50,12 +50,14 @@ def load_ignore_patterns(project_dir: Path) -> pathspec.PathSpec:
"""
patterns = []

# Load .flashignore
# Warn if project still has a .flashignore (removed in v1.4)
flashignore = project_dir / ".flashignore"
if flashignore.exists():
flash_patterns = parse_ignore_file(flashignore)
patterns.extend(flash_patterns)
log.debug(f"Loaded {len(flash_patterns)} patterns from .flashignore")
log.warning(
".flashignore is no longer supported; "
"patterns are now built-in. "
"Move any custom patterns to .gitignore and delete .flashignore."
)

# Load .gitignore
gitignore = project_dir / ".gitignore"
Expand All @@ -64,19 +66,41 @@ def load_ignore_patterns(project_dir: Path) -> pathspec.PathSpec:
patterns.extend(git_patterns)
log.debug(f"Loaded {len(git_patterns)} patterns from .gitignore")

# Always exclude build artifacts, virtual environments, and Python bytecode
# Built-in patterns: always excluded from Flash builds.
# Includes build artifacts, caches, virtual environments, IDE files,
# and files tracked by git but irrelevant to deployment (tests, docs).
always_ignore = [
# Build artifacts and caches
".build/",
".flash/",
".runpod/",
".venv/",
"venv/",
"*.tar.gz",
".git/",
"__pycache__/",
"*.pyc",
"*.pyo",
"*.pyd",
"*.egg-info/",
"dist/",
"build/",
# Virtual environments
".venv/",
"venv/",
"env/",
# IDE
".vscode/",
".idea/",
# Environment files
".env",
".env.local",
# Tests (tracked by git, excluded from Flash builds)
"tests/",
"test_*.py",
"*_test.py",
# Documentation (tracked by git, excluded from Flash builds)
"docs/",
"*.md",
"!README.md",
]
Comment on lines 72 to 104
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The built-in ignore patterns are missing .gitignore which was explicitly excluded in the old .flashignore file. Git configuration files like .gitignore should not be included in deployment builds as they serve no purpose in the deployed application. Add .gitignore to the always_ignore list to maintain parity with the previous behavior.

Copilot uses AI. Check for mistakes.
patterns.extend(always_ignore)

Expand Down
40 changes: 0 additions & 40 deletions src/runpod_flash/cli/utils/skeleton_template/.flashignore

This file was deleted.

2 changes: 1 addition & 1 deletion tests/integration/test_lb_remote_execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def get_status():

with tempfile.TemporaryDirectory() as tmpdir:
project_dir = Path(tmpdir)
py_file = project_dir / "test_api.py"
py_file = project_dir / "api_worker.py"
py_file.write_text(code)

scanner = RemoteDecoratorScanner(project_dir)
Expand Down
22 changes: 11 additions & 11 deletions tests/unit/cli/commands/build_utils/test_scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def test_discover_simple_function():
project_dir = Path(tmpdir)

# Create a simple test file
test_file = project_dir / "test_module.py"
test_file = project_dir / "worker_module.py"
test_file.write_text(
"""
from runpod_flash import LiveServerless, remote
Expand Down Expand Up @@ -42,7 +42,7 @@ def test_discover_class():
with tempfile.TemporaryDirectory() as tmpdir:
project_dir = Path(tmpdir)

test_file = project_dir / "test_module.py"
test_file = project_dir / "worker_module.py"
test_file.write_text(
"""
from runpod_flash import LiveServerless, remote
Expand Down Expand Up @@ -72,7 +72,7 @@ def test_discover_multiple_functions_same_config():
with tempfile.TemporaryDirectory() as tmpdir:
project_dir = Path(tmpdir)

test_file = project_dir / "test_module.py"
test_file = project_dir / "worker_module.py"
test_file.write_text(
"""
from runpod_flash import LiveServerless, remote
Expand Down Expand Up @@ -102,7 +102,7 @@ def test_discover_functions_different_configs():
with tempfile.TemporaryDirectory() as tmpdir:
project_dir = Path(tmpdir)

test_file = project_dir / "test_module.py"
test_file = project_dir / "worker_module.py"
test_file.write_text(
"""
from runpod_flash import LiveServerless, CpuLiveServerless, remote
Expand Down Expand Up @@ -163,7 +163,7 @@ def test_discover_inline_config():
with tempfile.TemporaryDirectory() as tmpdir:
project_dir = Path(tmpdir)

test_file = project_dir / "test_module.py"
test_file = project_dir / "worker_module.py"
test_file.write_text(
"""
from runpod_flash import LiveServerless, remote
Expand All @@ -186,7 +186,7 @@ def test_ignore_non_remote_functions():
with tempfile.TemporaryDirectory() as tmpdir:
project_dir = Path(tmpdir)

test_file = project_dir / "test_module.py"
test_file = project_dir / "worker_module.py"
test_file.write_text(
"""
async def normal_function(data):
Expand All @@ -208,7 +208,7 @@ def test_discover_sync_function():
with tempfile.TemporaryDirectory() as tmpdir:
project_dir = Path(tmpdir)

test_file = project_dir / "test_module.py"
test_file = project_dir / "worker_module.py"
test_file.write_text(
"""
from runpod_flash import LiveServerless, remote
Expand Down Expand Up @@ -236,7 +236,7 @@ def test_exclude_venv_directory():
# Create .venv directory with Python files
venv_dir = project_dir / ".venv" / "lib" / "python3.11"
venv_dir.mkdir(parents=True)
venv_file = venv_dir / "test_module.py"
venv_file = venv_dir / "worker_module.py"
venv_file.write_text(
"""
from runpod_flash import LiveServerless, remote
Expand Down Expand Up @@ -405,7 +405,7 @@ def test_fallback_to_variable_name_when_name_parameter_missing():
with tempfile.TemporaryDirectory() as tmpdir:
project_dir = Path(tmpdir)

test_file = project_dir / "test_module.py"
test_file = project_dir / "worker_module.py"
test_file.write_text(
"""
from runpod_flash import LiveServerless, remote
Expand All @@ -431,7 +431,7 @@ def test_ignore_non_serverless_classes_with_serverless_in_name():
with tempfile.TemporaryDirectory() as tmpdir:
project_dir = Path(tmpdir)

test_file = project_dir / "test_module.py"
test_file = project_dir / "worker_module.py"
test_file.write_text(
"""
from runpod_flash import LiveServerless, remote
Expand Down Expand Up @@ -462,7 +462,7 @@ def test_extract_resource_name_with_special_characters():
with tempfile.TemporaryDirectory() as tmpdir:
project_dir = Path(tmpdir)

test_file = project_dir / "test_module.py"
test_file = project_dir / "worker_module.py"
test_file.write_text(
"""
from runpod_flash import LiveServerless, remote
Expand Down
Loading
Loading