|
| 1 | +# Contributing to Ratelink |
| 2 | + |
| 3 | +Thank you for your interest in contributing to Ratelink! This guide will help you get started. |
| 4 | + |
| 5 | +## Code of Conduct |
| 6 | + |
| 7 | +Be respectful, inclusive, and constructive. We're here to build great software together. |
| 8 | + |
| 9 | +## How to Contribute |
| 10 | + |
| 11 | +### Reporting Bugs |
| 12 | + |
| 13 | +1. Check [existing issues](https://github.com/vladlen-codes/ratelink/issues) first |
| 14 | +2. Use the bug report template |
| 15 | +3. Include: |
| 16 | + - Python version |
| 17 | + - Ratelink version |
| 18 | + - Minimal reproducible example |
| 19 | + - Expected vs actual behavior |
| 20 | + - Relevant logs/tracebacks |
| 21 | + |
| 22 | +### Suggesting Features |
| 23 | + |
| 24 | +1. Check [discussions](https://github.com/vladlen-codes/ratelink/discussions) first |
| 25 | +2. Open an issue with `[Feature Request]` prefix |
| 26 | +3. Describe: |
| 27 | + - Use case and motivation |
| 28 | + - Proposed API/behavior |
| 29 | + - Alternatives considered |
| 30 | + - Willingness to implement |
| 31 | + |
| 32 | +### Submitting Pull Requests |
| 33 | + |
| 34 | +1. Fork the repository |
| 35 | +2. Create a feature branch (`git checkout -b feature/amazing-feature`) |
| 36 | +3. Make your changes |
| 37 | +4. Add/update tests |
| 38 | +5. Update documentation |
| 39 | +6. Run quality checks (see below) |
| 40 | +7. Commit with clear messages |
| 41 | +8. Push and create a PR |
| 42 | + |
| 43 | +## Development Setup |
| 44 | + |
| 45 | +### Prerequisites |
| 46 | + |
| 47 | +- Python 3.7+ |
| 48 | +- Git |
| 49 | +- (Optional) Docker for Redis/PostgreSQL |
| 50 | + |
| 51 | +### Setup Steps |
| 52 | + |
| 53 | +```bash |
| 54 | +# Clone your fork |
| 55 | +git clone https://github.com/YOUR-USERNAME/ratelink.git |
| 56 | +cd ratelink |
| 57 | + |
| 58 | +# Create virtual environment |
| 59 | +python -m venv venv |
| 60 | +source venv/bin/activate # On Windows: venv\Scripts\activate |
| 61 | + |
| 62 | +# Install in development mode with all dependencies |
| 63 | +pip install -e ".[dev,all]" |
| 64 | + |
| 65 | +# Install pre-commit hooks (optional but recommended) |
| 66 | +pre-commit install |
| 67 | +``` |
| 68 | + |
| 69 | +### Project Structure |
| 70 | + |
| 71 | +``` |
| 72 | +ratelink/ |
| 73 | +├── ratelink/ # Source code |
| 74 | +│ ├── algorithms/ # Rate limiting algorithms |
| 75 | +│ ├── backends/ # Storage backends |
| 76 | +│ ├── core/ # Core RateLimiter class |
| 77 | +│ ├── advanced/ # Advanced features |
| 78 | +│ ├── observability/ # Metrics, logging, tracing |
| 79 | +│ ├── integration/ # Framework integrations |
| 80 | +│ ├── utils/ # Key generators, decorators |
| 81 | +│ └── testing/ # Testing utilities |
| 82 | +│ |
| 83 | +├── tests/ # Test suites |
| 84 | +│ ├── algorithms/ |
| 85 | +│ ├── backends/ |
| 86 | +│ ├── core/ |
| 87 | +│ ├── advanced/ |
| 88 | +│ ├── observability/ |
| 89 | +│ ├── integration/ |
| 90 | +│ └── testing/ |
| 91 | +│ |
| 92 | +├── docs/ # Documentation |
| 93 | +├── examples/ # Example applications |
| 94 | +├── benchmarks/ # Performance benchmarks |
| 95 | +└── pyproject.toml # Project configuration |
| 96 | +``` |
| 97 | + |
| 98 | +## Development Workflow |
| 99 | + |
| 100 | +### Running Tests |
| 101 | + |
| 102 | +```bash |
| 103 | +# Run all tests |
| 104 | +pytest |
| 105 | + |
| 106 | +# Run specific test file |
| 107 | +pytest tests/algorithms/test_token_bucket.py |
| 108 | + |
| 109 | +# Run with coverage |
| 110 | +pytest --cov=ratelink --cov-report=html |
| 111 | + |
| 112 | +# Run specific markers |
| 113 | +pytest -m "not slow" # Skip slow tests |
| 114 | +pytest -m integration # Only integration tests |
| 115 | +pytest -m redis_required # Tests requiring Redis |
| 116 | +``` |
| 117 | + |
| 118 | +### Code Quality |
| 119 | + |
| 120 | +We use several tools to maintain code quality: |
| 121 | + |
| 122 | +```bash |
| 123 | +# Format code with black |
| 124 | +black ratelink tests |
| 125 | + |
| 126 | +# Check formatting |
| 127 | +black --check ratelink tests |
| 128 | + |
| 129 | +# Lint with flake8 |
| 130 | +flake8 ratelink tests |
| 131 | + |
| 132 | +# Type check with mypy |
| 133 | +mypy ratelink |
| 134 | + |
| 135 | +# Security check with bandit |
| 136 | +bandit -r ratelink |
| 137 | + |
| 138 | +# Run all checks |
| 139 | +./scripts/quality-check.sh # If available |
| 140 | +``` |
| 141 | + |
| 142 | +### Code Style |
| 143 | + |
| 144 | +- **Black**: Line length 100, Python 3.7+ target |
| 145 | +- **Type hints**: Required for all public APIs |
| 146 | +- **Docstrings**: Google style for all public functions/classes |
| 147 | +- **Imports**: Organized with isort (black compatible) |
| 148 | + |
| 149 | +### Testing Guidelines |
| 150 | + |
| 151 | +1. **Coverage**: Aim for >90% coverage on new code |
| 152 | +2. **Test Types**: |
| 153 | + - Unit tests for algorithms and backends |
| 154 | + - Integration tests for framework integrations |
| 155 | + - Functional tests for end-to-end scenarios |
| 156 | +3. **Markers**: Use appropriate pytest markers |
| 157 | + ```python |
| 158 | + @pytest.mark.slow |
| 159 | + @pytest.mark.integration |
| 160 | + @pytest.mark.redis_required |
| 161 | + ``` |
| 162 | +4. **Fixtures**: Use provided fixtures from `ratelink.testing.fixtures` |
| 163 | +5. **Assertions**: Use helper assertions from `ratelink.testing.assertions` |
| 164 | + |
| 165 | +### Documentation |
| 166 | + |
| 167 | +Documentation is as important as code: |
| 168 | + |
| 169 | +1. **Docstrings**: All public APIs must have docstrings |
| 170 | + ```python |
| 171 | + def check(self, key: str, weight: int = 1) -> Tuple[bool, Dict[str, Any]]: |
| 172 | + """ |
| 173 | + Check if a request should be allowed. |
| 174 | + |
| 175 | + Args: |
| 176 | + key: Rate limit key (e.g., "user:123") |
| 177 | + weight: Request weight (default: 1) |
| 178 | + |
| 179 | + Returns: |
| 180 | + Tuple of (allowed, state) where: |
| 181 | + - allowed: True if request allowed, False otherwise |
| 182 | + - state: Dict with remaining, limit, retry_after, etc. |
| 183 | + |
| 184 | + Example: |
| 185 | + >>> limiter = RateLimiter(algorithm="token_bucket", limit=100, window=60) |
| 186 | + >>> allowed, state = limiter.check("user:123") |
| 187 | + >>> if allowed: |
| 188 | + ... process_request() |
| 189 | + """ |
| 190 | + ``` |
| 191 | + |
| 192 | +2. **Markdown Docs**: Update relevant docs in `docs/` |
| 193 | +3. **Examples**: Add runnable examples for new features |
| 194 | +4. **Changelog**: Add entry to `CHANGELOG.md` |
| 195 | + |
| 196 | +### Commit Messages |
| 197 | + |
| 198 | +Use clear, descriptive commit messages: |
| 199 | + |
| 200 | +``` |
| 201 | +feat: Add support for custom key extractors |
| 202 | +fix: Correct token bucket refill calculation |
| 203 | +docs: Update FastAPI integration guide |
| 204 | +test: Add tests for sliding window algorithm |
| 205 | +refactor: Simplify Redis backend connection handling |
| 206 | +``` |
| 207 | + |
| 208 | +Prefixes: |
| 209 | +- `feat`: New feature |
| 210 | +- `fix`: Bug fix |
| 211 | +- `docs`: Documentation |
| 212 | +- `test`: Tests |
| 213 | +- `refactor`: Code refactoring |
| 214 | +- `perf`: Performance improvement |
| 215 | +- `chore`: Maintenance tasks |
| 216 | + |
| 217 | +### Pull Request Process |
| 218 | + |
| 219 | +1. **Title**: Clear, descriptive (`feat: Add MongoDB backend`) |
| 220 | +2. **Description**: |
| 221 | + - What and why |
| 222 | + - Link to related issues |
| 223 | + - Breaking changes (if any) |
| 224 | +3. **Checklist**: |
| 225 | + - [ ] Tests added/updated |
| 226 | + - [ ] Documentation updated |
| 227 | + - [ ] Changelog updated |
| 228 | + - [ ] All checks passing |
| 229 | +4. **Review**: Address feedback constructively |
| 230 | +5. **Merge**: Squash and merge (we'll handle this) |
| 231 | + |
| 232 | +## Code Review Guidelines |
| 233 | + |
| 234 | +### For Contributors |
| 235 | + |
| 236 | +- Be open to feedback |
| 237 | +- Respond to comments |
| 238 | +- Ask questions if unclear |
| 239 | +- Keep PRs focused and reasonably sized |
| 240 | + |
| 241 | +### For Reviewers |
| 242 | + |
| 243 | +- Be constructive and specific |
| 244 | +- Explain the "why" not just "what" |
| 245 | +- Approve when ready, request changes when needed |
| 246 | +- Respond promptly |
| 247 | + |
| 248 | +## Testing Integration with Services |
| 249 | + |
| 250 | +### Redis |
| 251 | + |
| 252 | +```bash |
| 253 | +# Start Redis with Docker |
| 254 | +docker run -d -p 6379:6379 redis |
| 255 | + |
| 256 | +# Run Redis tests |
| 257 | +pytest -m redis_required |
| 258 | +``` |
| 259 | + |
| 260 | +### PostgreSQL |
| 261 | + |
| 262 | +```bash |
| 263 | +# Start PostgreSQL with Docker |
| 264 | +docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres |
| 265 | + |
| 266 | +# Run PostgreSQL tests |
| 267 | +pytest -m postgres_required |
| 268 | +``` |
| 269 | + |
| 270 | +### All Services |
| 271 | + |
| 272 | +```bash |
| 273 | +# Use docker-compose (if available) |
| 274 | +docker-compose up -d |
| 275 | + |
| 276 | +# Run all integration tests |
| 277 | +pytest -m integration |
| 278 | +``` |
| 279 | + |
| 280 | +## Release Process (Maintainers Only) |
| 281 | + |
| 282 | +1. Update version in `pyproject.toml` |
| 283 | +2. Update `CHANGELOG.md` |
| 284 | +3. Run full test suite |
| 285 | +4. Build: `python -m build` |
| 286 | +5. Test on TestPyPI |
| 287 | +6. Publish to PyPI: `twine upload dist/*` |
| 288 | +7. Tag release: `git tag v1.0.0` |
| 289 | +8. Create GitHub release |
| 290 | + |
| 291 | +## Questions? |
| 292 | + |
| 293 | +- **General Questions**: [GitHub Discussions](https://github.com/vladlen-codes/ratelink/discussions) |
| 294 | +- **Bug Reports**: [GitHub Issues](https://github.com/vladlen-codes/ratelink/issues) |
| 295 | +- **Security Issues**: Email security@example.com (do not open public issues) |
| 296 | + |
| 297 | +## Recognition |
| 298 | + |
| 299 | +Contributors are listed in: |
| 300 | +- GitHub contributors page |
| 301 | +- Release notes |
| 302 | +- Documentation acknowledgments |
| 303 | + |
| 304 | +Thank you for contributing to Ratelink! 🎉 |
0 commit comments