.. 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 other requirements to contribute to icalendar-anonymizer.
.. _development-prerequisites:
.. include:: ./_include/prerequisites.inc
.. _development-configure-git:
.. include:: ./_include/configure-git.inc
.. include:: ./_include/configure-git-card-dev.inc
.. include:: ./_include/configure-git-steps.inc
Install icalendar-anonymizer for development
============================================
Change your directory to your local clone.
.. code-block:: shell
cd icalendar-anonymizer
Install icalendar-anonymizer for development—including all of its dependencies for tests, documentation, and formatting code, as well as a Python virtual environment—with the following command.
.. code-block:: shell
make dev
Development workflow
====================
This section covers the general development workflow.
Subsequent sections go into more detail.
Follow these steps from the root of your clone.
1. Check out the ``main`` branch, update it locally, and create a branch from it.
.. code-block:: shell
git checkout main
git pull origin main
git checkout -b feature-name
#. Write your code changes, corresponding tests, docstrings, and narrative documentation.
All new features must include tests and documentation.
#. Run tests.
You can pass any options that pytest supports as an environment variable or argument ``TESTOPTS``.
.. code-block:: shell
make test
#. Build documentation and view a live preview in a web browser.
.. code-block:: shell
make livehtml
#. Check links in documentation.
.. code-block:: shell
make linkcheckbroken
#. Check spelling, style, and grammar in narrative documentation.
.. code-block:: shell
make vale
#. Lint and format code.
.. code-block:: shell
make lint-check # Check for linting errors
make lint-fix # Auto-fix linting errors
make format # Format code
#. Commit your changes, using the `Conventional Commits `_ message format that follows :doc:`contribute/commit-format`.
.. code-block:: shell
git add .
git commit -m "feat: add new feature description"
#. Push your changes to GitHub.
.. code-block:: shell
git push origin feature-name
#. Open a pull request on GitHub.
Run tests
=========
This section describes how to run tests.
Run all tests
-------------
.. code-block:: shell
make test
Run tests with coverage
-----------------------
.. code-block:: shell
make coverage
The test coverage report will be in ``htmlcov/index.html``.
Test requirements
-----------------
All tests must satisfy the following requirements.
- A minimum of 90% coverage is required and enforced by continuous integration (CI).
- All tests must pass.
- All new features and bug fixes must have tests.
- Use parametrized tests to reduce duplication, as described in :ref:`test-organization`.
CI test matrix
--------------
Continuous integration runs tests on the matrix cross-product of the following parameters.
- Python versions 3.11, 3.12, and 3.13
- Ubuntu, Windows, and macOS operating systems
This creates nine test jobs.
Tests must pass across the entire matrix.
Code quality
============
Use `Ruff `_ for linting and formatting code.
Ruff is configured to limit line length to one-hundred characters.
Check for lint errors
---------------------
.. code-block:: shell
make lint-check
Fix lint errors
---------------
.. code-block:: shell
make lint-fix
Format code
-----------
.. code-block:: shell
make format
Configuration
-------------
Ruff settings are in :file:`pyproject.toml` under the ``[tool.ruff]`` table.
CI enforces the same Ruff version as that used in development.
pre-commit hooks
================
pre-commit hooks catch issues before committing, providing feedback faster than waiting for CI.
These are installed automatically when creating a development environment.
The hooks are defined in :file:`.pre-commit-config.yaml`.
What runs on every commit
-------------------------
- Code lint
- Code format
- REUSE compliance validates SPDX license headers
- File integrity checks:
- Trailing whitespace removal
- End-of-file fixer
- YAML, JSON, and TOML syntax validation
- Python AST check
- Case conflict check
- Merge conflict detection
- Large file prevention, configured to detect files larger than 1MB
- Line ending normalization to ``LF``
- Debug statement detection
- Commit message validation, enforcing Conventional Commits format
Performance
-----------
All checks complete in under five seconds.
Run pre-commit manually
-----------------------
You can run pre-commit manually.
Run all hooks on all files.
.. code-block:: shell
make pc
pre-commit run ruff --all-files # Run specific hook
Skip hooks
----------
For work-in-progress commits, you can skip pre-commit hooks with the following command.
Use it sparingly.
.. code-block:: shell
git commit --no-verify
.. note::
pre-commit is optional for contributors.
CI enforces the same checks regardless.
Core maintainers should use it.
Code style guidelines
=====================
This section describes guidelines for writing code in icalendar-anonymizer.
Docstrings
----------
Use Google-style docstrings with multi-line format:
.. code-block:: python
def foo(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
"""
Include an Examples section only with real, testable doctests.
.. _test-organization:
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
-----------
The maximum line length for code is 100 characters maximum.
It is enforced by Ruff.
Documentation style guidelines
==============================
This section describes the guidelines for writing documentation for icalendar-anonymizer.
API documentation
-----------------
Use :program:`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
====================
This section describes the guidelines for working with pull requests for icalendar-anonymizer.
Requirements
------------
The following list of requirements must be satisfied to merge a pull request.
- At least one approval is required before merge
- All tests must pass
- Coverage must be greater than or equal to 90%
- Pull request title must follow :doc:`contribute/commit-format`
- A change log entry
Title format
------------
Pull request titles must follow conventional commits because maintainers use squash merge:
.. code-block:: text
feat: add preserve parameter to anonymize function
fix: correct UID uniqueness handling
docs: update installation instructions
The pull request title becomes the commit message on the ``main`` branch.
Change log
----------
Add your changes to :file:`CHANGES.rst` following the formatting rules documented in the file header.
See :ref:`change-log-format` below.
.. _change-log-format:
Change log format
=================
Add entries under the appropriate category in :file:`CHANGES.rst`.
Breaking changes
Incompatible API changes
New features
New functionality
Minor changes
Small improvements
Bug fixes
Bug fixes
Format rules
------------
Use the following reStructuredText format 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 for files and directories.
.. code-block:: rst
:file:`docs/conf.py`
:file:`pyproject.toml`
:file:`src/tests/`
Issue links
^^^^^^^^^^^
Reference issues using `sphinx-issues `_ syntax, after the change log entry.
.. code-block:: rst
- My change log entry. :issue:`123`
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 to preserve functionality.
See `Issue 53 `_.
See the :file:`CHANGES.rst` file header for complete formatting guidelines.
License 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 :file:`REUSE.toml`
-----------------------------------
All new source files must include SPDX headers.
Autogenerated files that cannot have persistent headers may instead rely on entries in :file:`REUSE.toml` as a fallback.
SPDX headers are required in all source files:
Python files
^^^^^^^^^^^^
.. code-block:: python
# SPDX-FileCopyrightText: 2025 icalendar-anonymizer contributors
# SPDX-License-Identifier: AGPL-3.0-or-later
reStructuredText files
^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: rst
.. SPDX-FileCopyrightText: 2025 icalendar-anonymizer contributors
.. SPDX-License-Identifier: AGPL-3.0-or-later
Markdown files
^^^^^^^^^^^^^^
.. code-block:: markdown
:file:`REUSE.toml`
^^^^^^^^^^^^^^^^^^
Use :file:`REUSE.toml` only as a fallback for autogenerated files that cannot reasonably include headers.
It must not be treated as a substitute for adding headers to regular source files.
Check compliance
================
pre-commit hooks automatically check REUSE compliance.
You can also run the check manually:
.. code-block:: shell
reuse lint
All files must pass REUSE compliance before merge.
Get 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