Thank you for your interest in contributing to frappecli! This document provides guidelines and instructions for contributing.
By participating in this project, you agree to maintain a respectful and inclusive environment.
- Python 3.12 or higher
- uv package manager
- Git
- Fork and clone the repository:
git clone https://github.com/YOUR_USERNAME/frappecli.git
cd frappecli- Install dependencies:
uv sync- Install pre-commit hooks:
uv pip install pre-commit
pre-commit install- Verify installation:
uv run frappecli --version
uv run pytestWe follow Test-Driven Development (TDD) and GitHub best practices.
Pick Issue β Assign β Branch β Write Tests β Implement β Test β PR β Review β Merge
# View open issues
gh issue list --label "phase-1"
# Pick an issue
gh issue view 2
# Assign to yourself
gh issue edit 2 --add-assignee @me# Branch naming: feature/{issue-number}-{description}
git checkout -b feature/2-config-managementBranch naming conventions:
feature/{issue-number}-{description}- New featuresfix/{issue-number}-{description}- Bug fixesdocs/{issue-number}-{description}- Documentation changestest/{issue-number}-{description}- Test improvements
Examples:
feature/2-config-managementfix/15-handle-spaces-in-namesdocs/23-update-api-docs
Test-Driven Development - Red, Green, Refactor:
- π΄ RED: Write a failing test
- π’ GREEN: Write minimal code to pass the test
- π΅ REFACTOR: Improve the code
# Create test file FIRST
touch tests/test_config.py
# Write failing test
cat > tests/test_config.py << 'EOF'
def test_load_config():
config = Config("test_config.yaml")
assert config.data is not None
EOF
# Run test - it will FAIL (RED)
uv run pytest tests/test_config.py -v
# FAILED - Config class doesn't exist yet
# Now implement the code
cat > src/frappecli/config.py << 'EOF'
class Config:
def __init__(self, path):
self.data = self._load(path)
def _load(self, path):
# Implementation
return {}
EOF
# Run test - it should PASS (GREEN)
uv run pytest tests/test_config.py -v
# PASSED
# Refactor if needed (REFACTOR)
# Improve code quality while keeping tests greenFollow these guidelines:
- Formatting: Ruff format (100 char line length)
- Linting: Ruff with comprehensive rule set
- Type Hints: Required on all functions
- Docstrings: Required for public APIs (Google style)
Run before committing:
# Format code
uv run ruff format .
# Fix linting issues
uv run ruff check --fix .
# Check types
uv run mypy src/
# Or let pre-commit do it:
git commit -m "your message"- Write tests for all new features
- Maintain 80%+ code coverage
- Use pytest fixtures for common setup
- Mock external API calls with
responses
# Run all tests
uv run pytest
# Run with coverage
uv run pytest --cov
# Run specific test
uv run pytest tests/test_client.py -v
# Run without integration tests
uv run pytest -m "not integration"- Update README.md for user-facing changes
- Update AGENTS.md for developer context
- Add docstrings for new functions/classes
- Update CHANGELOG.md (see below)
We follow Conventional Commits:
type(scope): description
[optional body]
[optional footer]
Types:
feat: New featurefix: Bug fixdocs: Documentation onlystyle: Code style changes (formatting)refactor: Code refactoringtest: Adding or updating testschore: Maintenance tasks
Examples:
git commit -m "feat(client): add retry logic with exponential backoff"
git commit -m "fix(upload): handle spaces in filenames correctly"
git commit -m "docs: update installation instructions"
git commit -m "test(doctypes): add tests for quoted arguments"# Run all tests
uv run pytest tests/ -v
# Check coverage (should be 80%+)
uv run pytest --cov=src/frappecli --cov-report=term-missing
# All checks must pass
uv run ruff format .
uv run ruff check --fix .
uv run mypy src/git add .
git commit -m "feat(config): implement configuration management
- Add Config class with YAML loading
- Support environment variable substitution
- Add multi-site configuration
- Add comprehensive tests
Closes #2"# Push branch
git push origin feature/2-config-management
# Create PR with GitHub CLI
gh pr create \
--title "feat(config): implement configuration management" \
--body "Closes #2
## Changes
- Configuration loading with YAML
- Environment variable substitution
- Multi-site support
## Test Coverage
- 100% coverage for config module
- All tests pass
## Checklist
- [x] Tests written first (TDD)
- [x] All tests pass
- [x] Code formatted
- [x] Type hints added
- [x] Documentation updated" \
--base mainPR should include:
- Title - Following conventional commit format
- Description - "Closes #X" to link issue
- Changes - What was implemented
- Tests - Coverage information
- Checklist - All requirements met
Before submitting, ensure:
- Code follows style guidelines (ruff format/check pass)
- Type hints added (mypy passes)
- Tests written and passing
- Documentation updated
- CHANGELOG.md updated
- Commit messages follow conventional format
- No merge conflicts with main branch
- Pre-commit hooks pass
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
How was this tested?
## Checklist
- [ ] Tests pass locally
- [ ] Code follows style guidelines
- [ ] Documentation updated
- [ ] CHANGELOG.md updated- Automated checks run (CI/CD)
- Maintainer reviews code
- Feedback addressed
- Approved and merged
- Test individual functions/methods
- Mock external dependencies
- Fast execution (< 1s total)
Example:
from frappecli.client import FrappeClient
import responses
@responses.activate
def test_client_get_doctype():
responses.add(
responses.GET,
"https://example.com/api/resource/User/admin",
json={"message": {"name": "admin"}},
status=200,
)
client = FrappeClient("https://example.com", "key", "secret")
doc = client.get("User", "admin")
assert doc["name"] == "admin"- Test command end-to-end
- Mock at HTTP level
- Mark with
@pytest.mark.integration
tests/
βββ conftest.py # Shared fixtures
βββ fixtures/
β βββ sample_config.yaml
β βββ api_responses.json
βββ test_client.py # Client tests
βββ test_config.py # Config tests
βββ test_commands_*.py # Command tests
Use Google style:
def upload_file(
file_path: str,
is_private: bool = True,
folder: str = "Home"
) -> dict:
"""Upload a file to Frappe.
Args:
file_path: Path to file to upload
is_private: Upload as private file (default: True)
folder: Target folder name
Returns:
Dict with file_url, file_name, and other metadata
Raises:
FileNotFoundError: If file_path doesn't exist
APIError: If upload fails
Example:
>>> result = upload_file("doc.pdf", is_private=True)
>>> print(result['file_url'])
/private/files/doc-abc123.pdf
"""Add entry under "Unreleased" section:
## [Unreleased]
### Added
- New `bulk-upload` command for batch file uploads
### Changed
- Improved error messages for authentication failures
### Fixed
- Handle spaces in doctype names correctly
### Deprecated
- Old config format (will be removed in v1.0)frappecli/
βββ .github/
β βββ workflows/ # CI/CD workflows
β βββ ISSUE_TEMPLATE/ # Issue templates
βββ docs/
β βββ plans/ # Implementation plans
β βββ linting-framework.md
βββ src/
β βββ frappecli/
β βββ cli.py # Main CLI
β βββ client.py # API client
β βββ config.py # Config management
β βββ commands/ # Command implementations
β βββ site.py
β βββ doctypes.py
β βββ files.py
β βββ reports.py
β βββ rpc.py
βββ tests/ # Test suite
βββ pyproject.toml # Project config
βββ README.md
βββ AGENTS.md
βββ CONTRIBUTING.md
βββ LICENSE
- Create command in appropriate file under
src/frappecli/commands/ - Register in
src/frappecli/cli.py - Write tests in
tests/test_commands_*.py - Update README.md with usage example
- Add to CHANGELOG.md
Example:
# src/frappecli/commands/doctypes.py
@click.command()
@click.argument("doctype", type=str)
def my_command(doctype: str) -> None:
"""Command description."""
console.print(f"Processing {doctype}")- Add method to
FrappeClientinsrc/frappecli/client.py - Add type hints and docstring
- Write tests with mocked responses
- Use in command implementation
# Add new dependency
uv add package-name
# Add dev dependency
uv add --dev package-name
# Update all dependencies
uv sync --upgrade- Questions: Open a Discussion
- Bugs: Open an Issue
- Chat: (Coming soon)
When reviewing PRs, check for:
- Functionality: Does it work as intended?
- Tests: Are there tests? Do they pass?
- Code Quality: Is it readable and maintainable?
- Performance: Are there any obvious bottlenecks?
- Security: Any security concerns?
- Documentation: Is it documented?
By contributing, you agree that your contributions will be licensed under the MIT License.
Contributors are recognized in:
- GitHub contributors page
- Release notes
- (Future) CONTRIBUTORS.md file
Thank you for contributing to frappecli! π