Clone
1
Contributing
sq4ind edited this page 2025-09-28 12:47:36 +00:00
🤝 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 to set up your environment:
# 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
# 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
- Write tests for new functionality
- Update documentation as needed
- Ensure all tests pass
4. Submit Pull Request
# 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:
# 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
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:
# 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
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
# 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:
- Update relevant wiki pages
- Add examples to documentation
- Include troubleshooting steps
- Update service reference
Code Comments
# 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
- One feature per PR: Keep changes focused and reviewable
- Descriptive title: Clearly describe what the PR does
- Detailed description: Explain the problem and solution
- Link related issues: Reference issue numbers
- Include tests: All new code must be tested
- Update docs: Update relevant documentation
PR Template
## 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
- Automated Checks: CI pipeline runs automatically
- Code Review: Maintainer reviews code quality and design
- Testing: Reviewer tests functionality manually
- Feedback: Reviewer provides constructive feedback
- Iteration: Author addresses feedback and updates PR
- 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:
- Email security details to maintainers
- Include detailed reproduction steps
- Wait for confirmation before public disclosure
- Coordinate responsible disclosure timeline
Security Best Practices
# 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. 🚀