.. SPDX-FileCopyrightText: 2025 icalendar-anonymizer contributors .. SPDX-License-Identifier: AGPL-3.0-or-later ============ Contributing ============ This guide covers the development workflow, testing, code style, and contribution requirements. .. note:: A shorter quick-reference version is available in the repository's :file:`CONTRIBUTING.md` file for GitHub. Getting Started =============== Fork and Clone -------------- Fork the repository on GitHub, then clone your fork: .. code-block:: shell git clone https://github.com/YOUR-USERNAME/icalendar-anonymizer.git cd icalendar-anonymizer Install Development Dependencies -------------------------------- Install in editable mode with dev extras: .. code-block:: shell pip install -e ".[dev]" This installs: - **pytest** - Testing framework - **ruff** - Linting and code formatting - **pre-commit** - Git hook management - **commitizen** - Conventional commit enforcement - **reuse** - License compliance checking - **build** and **twine** - Package building and publishing For documentation building, also install: .. code-block:: shell pip install -e ".[doc]" Development Workflow ==================== 1. **Create a Feature Branch** Create a branch from ``main``: .. code-block:: shell git checkout main git pull origin main git checkout -b feature-name 2. **Make Changes with Tests** Write your code changes and corresponding tests. All new features must include tests. 3. **Run Tests and Linting** .. code-block:: shell pytest # Run tests ruff check . # Check for linting errors ruff check . --fix # Auto-fix linting errors ruff format . # Format code 4. **Commit with Conventional Format** Follow :doc:`contribute/commit-format` for commit messages: .. code-block:: shell git add . git commit -m "feat: add new feature description" 5. **Push and Open Pull Request** .. code-block:: shell git push origin feature-name Then open a pull request on GitHub. Running Tests ============= Run All Tests ------------- .. code-block:: shell pytest Run with Coverage ----------------- .. code-block:: shell pytest --cov=src/icalendar_anonymizer --cov-report=html Coverage report will be in ``htmlcov/index.html``. Test Requirements ----------------- - **90% minimum coverage** required - PRs fail if coverage drops below this threshold - All tests must pass before merge - Add tests for all new features and bug fixes - Use parametrized tests to reduce duplication (see :ref:`contributing:Test Organization`) CI Test Matrix -------------- Continuous integration runs tests on: - **Python versions**: 3.11, 3.12, 3.13 - **Operating systems**: Ubuntu, Windows, macOS This creates 9 test jobs total. All must pass before merge. Code Quality ============ Linting with Ruff ----------------- We use `Ruff `_ for linting and code formatting with a **100-character line length**. Check for Errors ^^^^^^^^^^^^^^^^ .. code-block:: shell ruff check . Auto-Fix Errors ^^^^^^^^^^^^^^^ .. code-block:: shell ruff check . --fix Format Code ^^^^^^^^^^^ .. code-block:: shell ruff format . Configuration ^^^^^^^^^^^^^ Ruff settings are in ``pyproject.toml`` under ``[tool.ruff]``. The CI enforces the same Ruff version (>=0.14.0) for consistency. Pre-commit Hooks (Recommended) ============================== Pre-commit hooks catch issues before committing, providing faster feedback than waiting for CI. Setup (One-Time) ---------------- .. code-block:: shell pre-commit install # Install pre-commit hooks pre-commit install --hook-type commit-msg # Install commit message validation What Runs on Every Commit ------------------------- - **Ruff linting** (``ruff check --fix``) - Auto-fixes linting errors - **Ruff formatting** (``ruff format``) - Auto-formats Python code - **REUSE compliance** (``reuse lint``) - Validates SPDX license headers - **File integrity checks**: - Trailing whitespace removal - End-of-file fixer - YAML/JSON/TOML validation - Python AST check - Case conflict check - Merge conflict detection - Large file prevention (>1MB) - Line ending normalization (LF) - Debug statement detection - **Commit message validation** - Enforces conventional commits format Performance ----------- All checks complete in under 5 seconds. Run Manually ------------ .. code-block:: shell pre-commit run --all-files # Run all hooks on all files pre-commit run ruff --all-files # Run specific hook Skip Hooks (Sparingly) ---------------------- For work-in-progress commits: .. code-block:: shell git commit --no-verify Note on Pre-commit ------------------ Pre-commit is **optional** for contributors. CI enforces the same checks regardless. Core maintainers should use it. Code Style Guidelines ===================== Docstrings ---------- Use **Google-style docstrings** with multi-line format: .. code-block:: python def function(arg1: str, arg2: int) -> str: """Brief description on first line. More detailed explanation if needed. Can span multiple paragraphs. Args: arg1: Description of first argument arg2: Description of second argument Returns: Description of return value Raises: ValueError: When invalid input provided """ Don't include Examples sections unless they contain real, testable doctests. Test Organization ----------------- Use ``pytest.mark.parametrize`` for duplicate test patterns: .. code-block:: python @pytest.mark.parametrize( ("property_name", "expected_value"), [ ("status", "CONFIRMED"), ("priority", 1), ], ) def test_preserves_metadata(property_name, expected_value): """Test implementation.""" Organize tests into logical groups with clear section comments. Imports ------- - Standard library imports first - Third-party imports second - Local imports third - Sort alphabetically within each group .. code-block:: python # Standard library import hashlib from datetime import datetime # Third-party from icalendar import Calendar # Local from icalendar_anonymizer import anonymize Line Length ----------- **100 characters maximum** - enforced by Ruff. Documentation ------------- API Documentation ^^^^^^^^^^^^^^^^^ Use **autodoc** for API function signatures in Sphinx documentation: .. code-block:: rst .. autofunction:: icalendar_anonymizer.anonymize This ensures documentation stays in sync with code. Don't manually copy function signatures. Code Examples ^^^^^^^^^^^^^ Use **doctest format** for Python examples in documentation: .. code-block:: rst .. doctest:: >>> from icalendar import Calendar >>> from icalendar_anonymizer import anonymize >>> # Example code here This allows examples to be automatically tested for correctness. Pull Request Process ==================== Requirements ------------ - **One approval** required before merge - All tests must pass (9 test jobs) - Coverage must be ≥90% - PR title must follow :doc:`contribute/commit-format` - Update ``CHANGES.rst`` with your changes PR Title Format --------------- PR titles must follow conventional commits because we use squash merge: .. code-block:: text feat: add preserve parameter to anonymize function fix: correct UID uniqueness handling docs: update installation instructions The PR title becomes the commit message on ``main``. Update CHANGES.rst ------------------ Add your changes to ``CHANGES.rst`` following the formatting rules documented in the file header. See :ref:`contributing:CHANGES.rst Formatting` below. CHANGES.rst Formatting ====================== Add entries under the appropriate category in ``CHANGES.rst``: Categories ---------- - **Breaking changes** - Incompatible API changes - **New features** - New functionality - **Minor changes** - Small improvements - **Bug fixes** - Bug fixes Formatting Rules ---------------- Use these RST formatting conventions: Inline Literals ^^^^^^^^^^^^^^^ Use double backticks for property names and inline code: .. code-block:: rst ``PROPERTY`` ``preserve`` parameter Python Objects ^^^^^^^^^^^^^^ Use Python domain roles: .. code-block:: rst :py:func:`function_name` :py:class:`ClassName` :py:meth:`method_name` Files ^^^^^ Use the ``:file:`` directive: .. code-block:: rst :file:`docs/conf.py` :file:`pyproject.toml` Issue Links ^^^^^^^^^^^ Reference issues with full URLs: .. code-block:: rst See `Issue 9 `_. Verbs ^^^^^ Start entries with past tense verbs: - Added - Fixed - Updated - Removed - Deprecated Example Entry ------------- .. code-block:: rst - Added ``preserve`` parameter to :py:func:`anonymize` function. Accepts optional set of property names to preserve beyond defaults. Case-insensitive. Allows preserving properties like ``CATEGORIES`` or ``COMMENT`` for bug reproduction when user confirms no sensitive data. Added 7 tests for preserve functionality. See `Issue 53 `_. See the ``CHANGES.rst`` file header for complete formatting guidelines. Licensing and REUSE Compliance ============================== This project follows the `REUSE specification `_ for clear licensing. License ------- The project is licensed under **AGPL-3.0-or-later**. SPDX Headers and REUSE.toml ---------------------------- **All new source files must include SPDX headers.** Auto-generated files that cannot have persistent headers may instead rely on entries in ``REUSE.toml`` as a fallback. **In-file headers** (required for all source files): Python Files ^^^^^^^^^^^^ .. code-block:: python # SPDX-FileCopyrightText: 2025 icalendar-anonymizer contributors # SPDX-License-Identifier: AGPL-3.0-or-later RST Files ^^^^^^^^^ .. code-block:: rst .. SPDX-FileCopyrightText: 2025 icalendar-anonymizer contributors .. SPDX-License-Identifier: AGPL-3.0-or-later Markdown Files ^^^^^^^^^^^^^^ .. code-block:: markdown **REUSE.toml** (fallback only): Use ``REUSE.toml`` only as a fallback for auto-generated files that cannot reasonably include headers; it must not be treated as a substitute for adding headers to regular source files. Checking Compliance ------------------- Pre-commit hooks automatically check REUSE compliance. You can also run manually: .. code-block:: shell reuse lint All files must pass REUSE compliance before merge. Getting Help ============ - Check the `Issue Tracker `_ - Open a new issue for bugs or feature requests - For major changes, open an issue for discussion before starting work Reference ========= .. toctree:: :maxdepth: 1 contribute/commit-format