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