Contributing¤
Contributions are welcome, and they are greatly appreciated. Every little bit helps, and credit will always be given.
Please always create an issue before working on a new feature or a bug fix, so that we can discuss the implementation and make sure that your work will be merged.
Environment setup¤
Install uv and direnv, fork and clone the repository, then:
git clone https://github.com/pawamoy/git-ew.git
cd git-ew
direnv allow
make setup
You now have the dependencies installed.
- Create a branch:
git switch -c feature-or-bugfix-name - Make your changes
- Run checks:
make format # Auto-format code make check # Run all checks make test # Run tests - If updating documentation:
make docsand verify at http://localhost:8000 - Follow the commit message convention below
Project Structure¤
src/git_ew/_internal/
├── cli.py # Command-line interface
├── app.py # FastAPI application
├── models.py # SQLAlchemy models
├── database.py # Database operations
├── email_parser.py # Email parsing
├── email_fetcher.py # Fetch from sources
├── email_sender.py # SMTP sending
├── thread_utils.py # Thread organization
├── sync.py # Email sync
├── templates/ # Jinja2 templates
└── static/ # CSS and JavaScript
tests/
├── test_database.py
├── test_email_parser.py
└── test_thread_utils.py
The entry-point to run commands and tasks is the make Python script, located in the scripts directory. Try running make to show the available commands and tasks. The commands do not need the Python dependencies to be installed, while the tasks do. The cross-platform tasks are written in Python, thanks to duty.
Run tests with pytest:
pytest
pytest --cov # With coverage
Write async tests with pytest-asyncio:
import pytest
from git_ew._internal.database import Database
@pytest.mark.asyncio
async def test_database():
db = Database("sqlite+aiosqlite:///:memory:")
await db.init_db()
thread = await db.create_thread("Test", "msg1", is_patch=False)
assert thread.id is not None
Code Style¤
- Follow PEP 8
- Use type hints
- Write docstrings for public APIs
- Prefer async/await for I/O operations
- Keep functions focused and small
Example:
async def get_thread_messages(
db: Database,
thread_id: int,
) -> list[Message]:
"""Get all messages in a thread.
Args:
db: Database instance.
thread_id: Thread ID.
Returns:
List of messages in chronological order.
"""
thread = await db.get_thread(thread_id)
if not thread:
return []
return sorted(thread.messages, key=lambda m: m.date)
Adding Features¤
When adding a new email source type:
- Create fetcher class in
_internal/email_fetcher.py - Update factory function
- Add tests
- Update documentation
Debugging¤
Database inspection:
sqlite3 git_ew.db
.tables
SELECT * FROM threads;
Enable debug logging:
import logging
logging.basicConfig(level=logging.DEBUG)
Commit Message Convention¤
Follow the Angular convention:
<type>[(scope)]: Subject
[Body]
Types: build, chore, ci, deps, docs, feat, fix, perf, refactor, style, tests
Subject and body must be valid Markdown. Capitalize subject but no trailing dot.
Add trailers at the end for references:
Issue #10: https://github.com/namespace/project/issues/10
Pull Requests¤
Link related issues in the PR message.
Use fixups during review:
git commit --fixup=SHA
git rebase -i --autosquash main
git push -f
Or push each commit and we'll squash before merging.
Email Patches¤
Send patches via email:
git format-patch origin/main
git send-email *.patch
Questions¤
- Check documentation
- Open a GitHub issue
- Join Matrix/Gitter discussion
- Email maintainers