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:

  1. Update relevant wiki pages
  2. Add examples to documentation
  3. Include troubleshooting steps
  4. 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

  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

## 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

# 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. 🚀