Add Contributing
478
Contributing.md
Normal file
478
Contributing.md
Normal file
@@ -0,0 +1,478 @@
|
||||
# 🤝 Contributing to AdGuard Control Hub
|
||||
|
||||
Thank you for your interest in contributing! This guide will help you get started with contributing to AdGuard Control Hub.
|
||||
|
||||
## 📋 Ways to Contribute
|
||||
|
||||
### 🐛 Bug Reports
|
||||
- Search existing issues before creating new ones
|
||||
- Include detailed reproduction steps
|
||||
- Provide system information and logs
|
||||
- Use the bug report template
|
||||
|
||||
### 💡 Feature Requests
|
||||
- Describe the problem you're trying to solve
|
||||
- Explain your proposed solution
|
||||
- Consider alternative approaches
|
||||
- Discuss implementation complexity
|
||||
|
||||
### 📝 Documentation
|
||||
- Fix typos and grammatical errors
|
||||
- Improve existing documentation
|
||||
- Add examples and use cases
|
||||
- Translate content to other languages
|
||||
|
||||
### 💻 Code Contributions
|
||||
- Bug fixes
|
||||
- New features
|
||||
- Performance improvements
|
||||
- Code refactoring
|
||||
- Test improvements
|
||||
|
||||
## 🚀 Getting Started
|
||||
|
||||
### 1. Set Up Development Environment
|
||||
|
||||
Follow the [Development Guide](Development) to set up your environment:
|
||||
|
||||
```bash
|
||||
# Fork and clone the repository
|
||||
git clone https://your-gitea-domain.com/your-username/adguard-control-hub.git
|
||||
cd adguard-control-hub
|
||||
|
||||
# Set up Python environment
|
||||
python -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install -r requirements-dev.txt
|
||||
|
||||
# Set up pre-commit hooks
|
||||
pre-commit install
|
||||
```
|
||||
|
||||
### 2. Create Feature Branch
|
||||
|
||||
```bash
|
||||
# Create branch from main
|
||||
git checkout main
|
||||
git pull upstream main
|
||||
git checkout -b feature/your-feature-name
|
||||
|
||||
# Or for bug fixes
|
||||
git checkout -b fix/issue-description
|
||||
```
|
||||
|
||||
### 3. Make Changes
|
||||
|
||||
- Follow the [Code Style Guide](#code-style-guide)
|
||||
- Write tests for new functionality
|
||||
- Update documentation as needed
|
||||
- Ensure all tests pass
|
||||
|
||||
### 4. Submit Pull Request
|
||||
|
||||
```bash
|
||||
# Commit changes
|
||||
git add .
|
||||
git commit -m "feat: add new feature description"
|
||||
git push origin feature/your-feature-name
|
||||
|
||||
# Create pull request via web interface
|
||||
```
|
||||
|
||||
## 📏 Code Style Guide
|
||||
|
||||
### Python Code Standards
|
||||
|
||||
We follow PEP 8 with some modifications:
|
||||
|
||||
```python
|
||||
# Line length: 127 characters (Black default)
|
||||
# Use type hints for all function signatures
|
||||
def process_client_data(client_name: str, settings: dict[str, Any]) -> bool:
|
||||
"""Process client data with proper typing."""
|
||||
return True
|
||||
|
||||
# Use descriptive variable names
|
||||
client_blocking_enabled = True # Good
|
||||
cbe = True # Bad
|
||||
|
||||
# Use f-strings for string formatting
|
||||
message = f"Client {client_name} updated successfully"
|
||||
|
||||
# Use early returns to reduce nesting
|
||||
def validate_client(client: dict) -> bool:
|
||||
"""Validate client configuration."""
|
||||
if not client.get("name"):
|
||||
return False
|
||||
|
||||
if not client.get("ids"):
|
||||
return False
|
||||
|
||||
return True
|
||||
```
|
||||
|
||||
### Documentation Standards
|
||||
|
||||
```python
|
||||
class AdGuardClient:
|
||||
"""Represent an AdGuard Home client.
|
||||
|
||||
Args:
|
||||
name: Friendly name for the client
|
||||
ids: List of IP addresses, MAC addresses, or Client IDs
|
||||
filtering_enabled: Whether DNS filtering is enabled
|
||||
|
||||
Attributes:
|
||||
name: Client name as stored in AdGuard Home
|
||||
blocked_services: List of blocked service identifiers
|
||||
|
||||
Example:
|
||||
>>> client = AdGuardClient("Kids iPad", ["192.168.1.100"])
|
||||
>>> client.add_blocked_service("youtube")
|
||||
>>> print(client.blocked_services)
|
||||
["youtube"]
|
||||
"""
|
||||
|
||||
def add_blocked_service(self, service_id: str) -> None:
|
||||
"""Add a service to the blocked list.
|
||||
|
||||
Args:
|
||||
service_id: Identifier of the service to block
|
||||
|
||||
Raises:
|
||||
ValueError: If service_id is not recognized
|
||||
|
||||
Example:
|
||||
>>> client.add_blocked_service("netflix")
|
||||
"""
|
||||
```
|
||||
|
||||
### Commit Message Format
|
||||
|
||||
We use Conventional Commits:
|
||||
|
||||
```bash
|
||||
# Feature additions
|
||||
feat: add client bulk update service
|
||||
feat(api): implement service scheduling support
|
||||
|
||||
# Bug fixes
|
||||
fix: resolve authentication timeout issue
|
||||
fix(switch): correct client switch state reporting
|
||||
|
||||
# Documentation
|
||||
docs: update installation guide
|
||||
docs(wiki): add troubleshooting for SSL issues
|
||||
|
||||
# Tests
|
||||
test: add integration tests for config flow
|
||||
test(api): increase coverage for error handling
|
||||
|
||||
# Refactoring
|
||||
refactor: simplify API error handling
|
||||
refactor(coordinator): optimize data update logic
|
||||
|
||||
# Chores
|
||||
chore: update dependencies
|
||||
chore(ci): improve workflow performance
|
||||
```
|
||||
|
||||
## 🧪 Testing Requirements
|
||||
|
||||
### Test Coverage
|
||||
|
||||
- All new code must have tests
|
||||
- Aim for >90% test coverage
|
||||
- Include both unit and integration tests
|
||||
- Test error conditions and edge cases
|
||||
|
||||
### Writing Tests
|
||||
|
||||
```python
|
||||
import pytest
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
from homeassistant.core import HomeAssistant
|
||||
from custom_components.adguard_hub.api import AdGuardHomeAPI
|
||||
|
||||
class TestAdGuardAPI:
|
||||
"""Test AdGuard Home API wrapper."""
|
||||
|
||||
@pytest.fixture
|
||||
async def api(self):
|
||||
"""Create API instance for testing."""
|
||||
session = MagicMock()
|
||||
return AdGuardHomeAPI(
|
||||
host="localhost",
|
||||
port=3000,
|
||||
username="admin",
|
||||
password="test",
|
||||
session=session
|
||||
)
|
||||
|
||||
async def test_get_clients_success(self, api):
|
||||
"""Test successful client retrieval."""
|
||||
# Mock API response
|
||||
expected_response = {"clients": [{"name": "Test Client"}]}
|
||||
api.session.request.return_value.__aenter__.return_value.json.return_value = expected_response
|
||||
|
||||
# Call method
|
||||
result = await api.get_clients()
|
||||
|
||||
# Assert results
|
||||
assert result == expected_response
|
||||
api.session.request.assert_called_once()
|
||||
|
||||
async def test_get_clients_connection_error(self, api):
|
||||
"""Test client retrieval with connection error."""
|
||||
# Mock connection error
|
||||
api.session.request.side_effect = aiohttp.ClientError("Connection failed")
|
||||
|
||||
# Verify exception is raised
|
||||
with pytest.raises(aiohttp.ClientError):
|
||||
await api.get_clients()
|
||||
```
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
pytest
|
||||
|
||||
# Run with coverage report
|
||||
pytest --cov=custom_components.adguard_hub --cov-report=html
|
||||
|
||||
# Run specific test category
|
||||
pytest tests/test_api.py -v
|
||||
pytest -k "test_client" -v
|
||||
|
||||
# Run integration tests
|
||||
pytest tests/test_integration.py -v -s
|
||||
```
|
||||
|
||||
## 📚 Documentation Guidelines
|
||||
|
||||
### Wiki Pages
|
||||
|
||||
When adding features that affect users:
|
||||
|
||||
1. **Update relevant wiki pages**
|
||||
2. **Add examples to documentation**
|
||||
3. **Include troubleshooting steps**
|
||||
4. **Update service reference**
|
||||
|
||||
### Code Comments
|
||||
|
||||
```python
|
||||
# Good comments explain WHY, not WHAT
|
||||
def calculate_block_percentage(blocked: int, total: int) -> float:
|
||||
"""Calculate blocking percentage with safe division."""
|
||||
# Prevent division by zero which can occur during startup
|
||||
# when statistics haven't been collected yet
|
||||
if total == 0:
|
||||
return 0.0
|
||||
|
||||
return (blocked / total) * 100
|
||||
```
|
||||
|
||||
### README Updates
|
||||
|
||||
For significant features:
|
||||
- Update feature list
|
||||
- Add configuration examples
|
||||
- Include usage examples
|
||||
- Update screenshots if needed
|
||||
|
||||
## 🔍 Code Review Process
|
||||
|
||||
### Pull Request Guidelines
|
||||
|
||||
1. **One feature per PR**: Keep changes focused and reviewable
|
||||
2. **Descriptive title**: Clearly describe what the PR does
|
||||
3. **Detailed description**: Explain the problem and solution
|
||||
4. **Link related issues**: Reference issue numbers
|
||||
5. **Include tests**: All new code must be tested
|
||||
6. **Update docs**: Update relevant documentation
|
||||
|
||||
### PR Template
|
||||
|
||||
```markdown
|
||||
## Description
|
||||
Brief description of changes and motivation.
|
||||
|
||||
## Type of Change
|
||||
- [ ] Bug fix (non-breaking change that fixes an issue)
|
||||
- [ ] New feature (non-breaking change that adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
|
||||
- [ ] Documentation update
|
||||
|
||||
## Testing
|
||||
- [ ] Unit tests added/updated
|
||||
- [ ] Integration tests added/updated
|
||||
- [ ] Manual testing completed
|
||||
- [ ] All tests pass
|
||||
|
||||
## Documentation
|
||||
- [ ] Code comments updated
|
||||
- [ ] Wiki pages updated
|
||||
- [ ] README updated (if needed)
|
||||
- [ ] Service reference updated (if applicable)
|
||||
|
||||
## Checklist
|
||||
- [ ] Code follows style guidelines
|
||||
- [ ] Self-review completed
|
||||
- [ ] Lint checks pass
|
||||
- [ ] Security considerations reviewed
|
||||
```
|
||||
|
||||
### Review Process
|
||||
|
||||
1. **Automated Checks**: CI pipeline runs automatically
|
||||
2. **Code Review**: Maintainer reviews code quality and design
|
||||
3. **Testing**: Reviewer tests functionality manually
|
||||
4. **Feedback**: Reviewer provides constructive feedback
|
||||
5. **Iteration**: Author addresses feedback and updates PR
|
||||
6. **Approval**: Maintainer approves and merges PR
|
||||
|
||||
## 🎯 Contribution Areas
|
||||
|
||||
### High Priority
|
||||
|
||||
- **Performance improvements**
|
||||
- **Bug fixes**
|
||||
- **Documentation improvements**
|
||||
- **Test coverage increases**
|
||||
- **Security enhancements**
|
||||
|
||||
### Feature Requests
|
||||
|
||||
- **New service blocking categories**
|
||||
- **Advanced scheduling features**
|
||||
- **Mobile app integration**
|
||||
- **Statistics dashboard improvements**
|
||||
- **Multi-language support**
|
||||
|
||||
### Good First Issues
|
||||
|
||||
Look for issues labeled:
|
||||
- `good first issue`
|
||||
- `help wanted`
|
||||
- `documentation`
|
||||
- `enhancement`
|
||||
|
||||
## 🔒 Security Considerations
|
||||
|
||||
### Reporting Security Issues
|
||||
|
||||
**Do not create public issues for security vulnerabilities.**
|
||||
|
||||
Instead:
|
||||
1. Email security details to maintainers
|
||||
2. Include detailed reproduction steps
|
||||
3. Wait for confirmation before public disclosure
|
||||
4. Coordinate responsible disclosure timeline
|
||||
|
||||
### Security Best Practices
|
||||
|
||||
```python
|
||||
# Sanitize user input
|
||||
def sanitize_client_name(name: str) -> str:
|
||||
"""Sanitize client name to prevent injection."""
|
||||
# Remove potentially dangerous characters
|
||||
return re.sub(r'[<>"']', '', name.strip())
|
||||
|
||||
# Validate configuration
|
||||
def validate_host(host: str) -> bool:
|
||||
"""Validate host is safe to connect to."""
|
||||
try:
|
||||
ipaddress.ip_address(host)
|
||||
return True
|
||||
except ValueError:
|
||||
# Validate hostname format
|
||||
return bool(re.match(r'^[a-zA-Z0-9.-]+$', host))
|
||||
|
||||
# Never log sensitive data
|
||||
_LOGGER.debug("Connecting to %s (credentials hidden)", api_host)
|
||||
# Not: _LOGGER.debug("Connecting with %s:%s", username, password)
|
||||
```
|
||||
|
||||
## 🏆 Recognition
|
||||
|
||||
### Contributors
|
||||
|
||||
All contributors are recognized in:
|
||||
- Repository contributors list
|
||||
- Release notes
|
||||
- Documentation credits
|
||||
- Special thanks in major releases
|
||||
|
||||
### Contribution Types
|
||||
|
||||
We value all types of contributions:
|
||||
- **Code**: Features, fixes, improvements
|
||||
- **Documentation**: Guides, examples, translations
|
||||
- **Testing**: Bug reports, test cases, validation
|
||||
- **Design**: UI improvements, user experience
|
||||
- **Community**: Support, discussions, feedback
|
||||
|
||||
## 📞 Getting Help
|
||||
|
||||
### Communication Channels
|
||||
|
||||
- **GitHub Issues**: Bug reports and feature requests
|
||||
- **Discussions**: General questions and ideas
|
||||
- **Discord/Chat**: Real-time development discussion
|
||||
- **Email**: Security issues and private communication
|
||||
|
||||
### Mentor Program
|
||||
|
||||
New contributors can:
|
||||
- Ask for guidance on good first issues
|
||||
- Request code review assistance
|
||||
- Get help setting up development environment
|
||||
- Pair program on complex features
|
||||
|
||||
### Development Questions
|
||||
|
||||
Common questions and where to get help:
|
||||
|
||||
| Question Type | Where to Ask |
|
||||
|---------------|--------------|
|
||||
| How to implement a feature | GitHub Discussions |
|
||||
| Bug in my code | GitHub Issues |
|
||||
| Home Assistant integration questions | HA Community Forum |
|
||||
| AdGuard Home API questions | AdGuard GitHub |
|
||||
| Development environment issues | GitHub Discussions |
|
||||
|
||||
## ✅ Contribution Checklist
|
||||
|
||||
Before submitting:
|
||||
|
||||
### Code Quality
|
||||
- [ ] Code follows style guidelines (Black, isort, flake8)
|
||||
- [ ] Type hints added for all functions
|
||||
- [ ] Docstrings added for public methods
|
||||
- [ ] Error handling implemented
|
||||
- [ ] Logging added for debugging
|
||||
|
||||
### Testing
|
||||
- [ ] Unit tests written and passing
|
||||
- [ ] Integration tests added (if applicable)
|
||||
- [ ] Manual testing completed
|
||||
- [ ] Edge cases considered
|
||||
- [ ] Error conditions tested
|
||||
|
||||
### Documentation
|
||||
- [ ] Code comments explain complex logic
|
||||
- [ ] Wiki pages updated (if user-facing changes)
|
||||
- [ ] Examples added for new features
|
||||
- [ ] README updated (if needed)
|
||||
|
||||
### Security & Performance
|
||||
- [ ] Security implications considered
|
||||
- [ ] Performance impact evaluated
|
||||
- [ ] Resource usage optimized
|
||||
- [ ] No sensitive data in logs
|
||||
|
||||
---
|
||||
|
||||
**Ready to contribute?** Pick an issue, follow this guide, and submit your first pull request! We're excited to work with you. 🚀
|
Reference in New Issue
Block a user