Skip to content

Contributing to python-gitea

🎉 Thank you for your interest in contributing to python-gitea! Your ideas, fixes, and improvements are welcome and appreciated.

Whether you’re fixing a typo, reporting a bug, suggesting a feature, or submitting a pull request—this guide will help you get started.

How to Contribute

  1. Open an Issue

    • Have a question, bug report, or feature suggestion? Open an issue and describe your idea clearly.
    • Check for existing issues before opening a new one.
  2. Fork and Clone the Repository

    git clone git@github.com:<username>/python-gitea.git
    cd python-gitea
    
  3. Set Up Your Environment

    We recommend using uv to manage virtual environments for installing python-gitea. If you don't have uv installed, you can install it with pip. See the project pages for more details:

    • Install via pip: pip install --upgrade pip && pip install uv
    • Project pages: uv on PyPI | uv on GitHub
    • Full documentation and usage guide: uv docs
    # Create a virtual environment (recommended with uv)
    uv venv --python 3.12
    source .venv/bin/activate  # On Windows: .venv\Scripts\activate
    uv pip install -e .
    
  4. Set Up Pre-commit Hooks

    We use pre-commit to ensure code quality and consistency. After syncing dependencies, run:

    uv run prek install
    

    This installs hooks so formatting, linting, and other checks run when you commit.

    Pull request titles are validated in GitHub Actions (see .github/workflows/semantic_pull_request.yml) using the same Conventional Commit vocabulary described under Commit Message Guidelines.

    Important

    The changelog is auto-generated from commits. Use Conventional Commits locally so git-cliff can classify changes, and match that style in PR titles so CI passes.

  5. Create a New Branch

    Give it a meaningful name like fix-typo-in-docs or feature-add-summary-option.

  6. Make Changes

    • Write clear, concise, and well-documented code.
    • Follow PEP 8 style conventions.
    • Add or update unit tests when applicable.
    • Keep changes atomic and focused: one type of change per commit (e.g., do not mix refactoring with feature addition).
  7. Run Tests

    Ensure that all tests pass before opening a pull request:

    pytest
    

    Mutation testing runs the suite again for each deliberate alteration of the source, and reports the alterations no test noticed:

    uv run mutmut run                  # every module
    uv run mutmut run "gitea.cli.*"    # one subtree, while iterating
    uv run mutmut results              # what survived
    

    A survivor is a change to the code that every test tolerated. Some cannot be killed - a rewritten typing.cast, or anything in a register_commands() that runs at import time - so read the diff uv run mutmut show <mutant> prints before writing a test for one.

    A filter selects which mutants are run, not which are written: every module is mutated either way, so a scoped run still reports mutating the whole tree and its progress counter reads 46/9042, where the denominator counts every mutant written and the numerator counts the ones the filter selected and checked. Take the result of a scoped run from uv run mutmut results rather than from that counter: it lists every mutant that was not killed, labelling each as survived or as not checked, and naming the module it belongs to, so the survivors of a scope are the survived entries whose names begin with it. A filter matching no mutant stops the run with an error instead of quietly widening it, so a scoped run that gets as far as testing is one that scoped.

    That listing names no killed mutant, though, so it cannot say how large the scope was or what share of it died. Both are recorded per module, in the .meta file mutmut writes beside each mutated module, whose exit_code_by_key maps every mutant to the exit code of the run that checked it - 0 survived, 1 killed, null never checked. Counting those gives the verdict of a scope, and shows the modules outside it untouched. Point it at the package directory the scope sits in - every module in the tree has a .meta, so pointing it at the whole of src/gitea prints a line per module:

    uv run python - <<'PY'
    import collections, json, pathlib
    
    status = {0: "survived", 1: "killed", 3: "killed", 5: "no tests", 33: "no tests", None: "not checked"}
    for meta in sorted(pathlib.Path("mutants/src/gitea/project").glob("*.py.meta")):
        codes = json.loads(meta.read_text())["exit_code_by_key"]
        counts = collections.Counter(status.get(c, f"exit {c}") for c in codes.values())
        if counts:
            print(f"{meta.name:24} {dict(counts)}")
    PY
    
    async_project.py.meta    {'killed': 620, 'survived': 16}
    base.py.meta             {'not checked': 215}
    project.py.meta          {'killed': 620, 'survived': 16}
    

    That is the output of a run scoped to the two project resource modules: 636 mutants each, 1,240 of the 1,272 killed, and the 215 of a module outside the scope sitting unchecked. Start from rm -rf mutants when a run has to stand on its own, since the verdicts of one run are otherwise carried into the next.

    To scope what is written as well, and get a counter whose denominator is the scope, point source_paths at the modules and let also_copy carry the rest of the package that the tests import. Scoped to the same two modules as above, that run reports mutating two files and counts 1272/1272:

    [tool.mutmut]
    source_paths = [
      "src/gitea/project/project.py",
      "src/gitea/project/async_project.py",
    ]
    also_copy = ["scripts/", "src/"]
    
  8. Open a Pull Request

    Clearly describe the motivation and scope of your change. Link it to the relevant issue if applicable. The pull request titles should match the Conventional Commits spec.

Commit Message Guidelines

Why this matters: Our changelog is automatically generated from commit messages using git-cliff. Commit messages must follow the Conventional Commits format and adhere to strict rules.

Rules

  1. One type of change per commit

    • Do not mix different types of changes (e.g., bug fixes, features, refactoring) in a single commit.
    • Example: if you refactor code AND add a feature, make two separate commits.
  2. Descriptive and meaningful messages

    • Describe what changed and why, not just what was edited.
    • Avoid vague messages like "fix bug" or "update code"; instead use "fix: prevent signal saturation in noise simulation" or "feat: add support for multi-detector frame merging".
  3. Follow Conventional Commits format

    • All commit messages must follow the Conventional Commits standard.
    • Format: <type>(<scope>): <subject>
    • Allowed types:
      • build: Changes that affect the build system or external dependencies
      • ci: Changes to our CI configuration files and scripts
      • docs: Documentation only changes
      • feat: A new feature
      • fix: A bug fix
      • perf: A code change that improves performance
      • refactor: A code change that neither fixes a bug nor adds a feature
      • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc.)
      • test: Adding missing tests or correcting existing tests
    • Example:

      feat(signal): add BBH waveform generation for aligned-spin systems
      
      This commit introduces support for aligned-spin binary black hole
      waveforms using PyCBC, enabling more realistic simulations.
      
    • Pull request titles are validated by the semantic PR action (see .github/workflows/semantic_pull_request.yml).

Examples

âś… Good commits:

feat(parser): add support for YAML configuration files
fix(logger): prevent crash on empty log messages
docs(readme): update installation instructions for clarity
refactor(utils): simplify data processing pipeline

❌ Bad commits:

fixed stuff
wip: many changes
update code
more fixes (no type/scope)

đź’ˇ Tips

  • Be kind and constructive in your communication.
  • Keep PRs focused and atomic—smaller changes are easier to review.
  • Document new features and update existing docs if needed.
  • Tag your PR with relevant labels if you can.

Licensing

By contributing, you agree that your contributions will be licensed under the project’s MIT License.


Thanks again for being part of the python-gitea community!