https://github.com/rommeld/mixed-pickles
Simple git linter written in Rust.
https://github.com/rommeld/mixed-pickles
beta-release git linter pypi python rust
Last synced: about 2 months ago
JSON representation
Simple git linter written in Rust.
- Host: GitHub
- URL: https://github.com/rommeld/mixed-pickles
- Owner: rommeld
- License: mit
- Created: 2025-12-10T19:29:29.000Z (7 months ago)
- Default Branch: main
- Last Pushed: 2026-01-03T20:18:17.000Z (6 months ago)
- Last Synced: 2026-01-06T22:25:12.587Z (6 months ago)
- Topics: beta-release, git, linter, pypi, python, rust
- Language: Rust
- Homepage: https://pypi.org/project/mixed-pickles/
- Size: 359 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
Awesome Lists containing this project
README
# Mixed Pickles
A fast git commit message linter written in Rust. Validates commit messages against best practices and provides actionable suggestions.
## Installation
### Python (Recommended)
```bash
pip install mixed-pickles
```
Or with [uv](https://github.com/astral-sh/uv):
```bash
uv pip install mixed-pickles
```
### Rust
```bash
cargo install mixed-pickles
```
Or build from source:
```bash
git clone https://github.com/rommeld/mixed-pickles.git
cd mixed-pickles
cargo build --release
```
## What It Checks
| Validation | Default Severity | Description |
| ------------------ | ---------------- | -------------------------------------------- |
| `WipCommit` | Error | WIP markers, fixup!, squash! |
| `ShortCommit` | Warning | Messages below threshold (default: 30 chars) |
| `NonImperative` | Warning | Non-imperative mood ("Added" vs "Add") |
| `VagueLanguage` | Warning | Generic phrases ("fix bug", "update code") |
| `MissingReference` | Info | No issue reference (#123, PROJ-456) |
| `InvalidFormat` | Info | Not following conventional commits |
## Usage
### CLI
```bash
# Analyze all commits in current repo
mixed-pickles
# Analyze last 10 commits
mixed-pickles --limit 10
# Analyze specific repo
mixed-pickles --path /path/to/repo
# Strict mode (warnings become errors)
mixed-pickles --strict
# Customize severity
mixed-pickles --error short,vague --ignore ref
# Quiet mode (output only on issues)
mixed-pickles --quiet
# Run only on specific branches (supports glob patterns)
mixed-pickles --branch main --branch develop
mixed-pickles --branch "feature/*" --branch "release/**"
```
### Python API
```python
import mixed_pickles
# Basic analysis - auto-loads pyproject.toml config
mixed_pickles.analyze_commits()
# Analyze with options
mixed_pickles.analyze_commits(
path=".", # Repository path
limit=10, # Number of commits
quiet=True, # Suppress output unless issues
strict=True # Treat warnings as errors
)
# Disable auto-loading of config file
mixed_pickles.analyze_commits(use_config=False)
# Load config from pyproject.toml or .mixed-pickles.toml
config = mixed_pickles.ValidationConfig.discover()
config = mixed_pickles.ValidationConfig.discover("/path/to/project")
# Load config from specific file
config = mixed_pickles.ValidationConfig.from_file("pyproject.toml")
config = mixed_pickles.ValidationConfig.from_file(".mixed-pickles.toml")
# Manual configuration
config = mixed_pickles.ValidationConfig(
threshold=50, # Minimum message length
require_issue_ref=False, # Disable issue reference check
require_conventional_format=False,
check_vague_language=True,
check_wip=True,
check_imperative=True,
branches=["main", "develop"] # Only validate on these branches
)
mixed_pickles.analyze_commits(config=config)
# Branch filtering with glob patterns
config = mixed_pickles.ValidationConfig(
branches=["main", "release/*", "hotfix/**"]
)
mixed_pickles.analyze_commits(config=config)
# Adjust severity levels
config = mixed_pickles.ValidationConfig()
config.set_severity(
mixed_pickles.Validation.MissingReference,
mixed_pickles.Severity.Error
)
config.set_severity(
mixed_pickles.Validation.ShortCommit,
mixed_pickles.Severity.Ignore
)
mixed_pickles.analyze_commits(config=config)
# Fetch commits for custom processing
commits = mixed_pickles.fetch_commits(limit=5)
for commit in commits:
print(f"{commit.short_hash}: {commit.message}")
```
### Pre-commit Hook
Add to your `.pre-commit-config.yaml`:
```yaml
repos:
- repo: local
hooks:
- id: mixed-pickles
name: Validate commit messages
entry: mixed-pickles
language: python
additional_dependencies: [mixed-pickles]
always_run: true
pass_filenames: false
stages: [pre-push]
```
With uv, you can also run it directly:
```yaml
repos:
- repo: local
hooks:
- id: mixed-pickles
name: Validate commit messages
entry: uv run mixed-pickles
language: system
always_run: true
pass_filenames: false
stages: [pre-push]
```
### CI/CD Integration
#### GitHub Actions
Add to your workflow (`.github/workflows/lint-commits.yml`):
```yaml
name: Lint Commits
on:
pull_request:
branches: [main, develop]
jobs:
lint-commits:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for commit analysis
- run: pip install mixed-pickles
- run: mixed-pickles --strict --quiet
```
#### GitLab CI
Add to your `.gitlab-ci.yml`:
```yaml
lint-commits:
stage: lint
image: python:3.12
before_script:
- pip install mixed-pickles
script:
- mixed-pickles --strict --quiet
rules:
- if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main"
- if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop"
```
## CLI Options
| Option | Description |
| ------------------ | -------------------------------------------- |
| `--path ` | Repository path (default: current directory) |
| `--limit ` | Max commits to analyze |
| `--threshold ` | Minimum message length (default: 30) |
| `--branch ` | Only validate on matching branches (repeatable, supports globs) |
| `--quiet`, `-q` | Suppress output unless issues found |
| `--strict` | Treat warnings as errors |
| `--error ` | Validations to treat as errors |
| `--warn ` | Validations to treat as warnings |
| `--ignore ` | Validations to skip reporting |
| `--disable ` | Validations to disable entirely |
| `--config ` | Path to configuration file |
| `--no-config` | Ignore configuration file |
Validation aliases for CLI: `short`, `ref`, `format`, `vague`, `wip`, `imperative`
## Configuration
Configure mixed-pickles via `pyproject.toml` for project-specific settings:
```toml
[tool.mixed-pickles]
# Minimum commit message length (default: 30)
threshold = 50
# Only validate on specific branches (supports glob patterns)
# Empty = validate on all branches (default)
branch = ["main", "develop", "release/*"]
# Disable specific validations entirely
disable = ["reference", "format"]
# Override severity levels
[tool.mixed-pickles.severity]
wip = "error" # Block on WIP commits (default)
short = "warning" # Warn but allow (default)
vague = "ignore" # Don't report
reference = "info" # Informational only (default)
```
Or use a dedicated `.mixed-pickles.toml` file (takes precedence over `pyproject.toml`):
```toml
threshold = 50
branch = ["main", "develop"]
disable = ["format"]
[severity]
short = "error"
```
### Configuration Precedence
Settings are applied in this order (later overrides earlier):
1. **Defaults** - Built-in default values
2. **Config file** - `pyproject.toml` or `.mixed-pickles.toml`
3. **CLI arguments** - Command-line flags
### Available Validations
| Name | Aliases | Default | Description |
|------|---------|---------|-------------|
| `short` | `short-commit` | warning | Message below threshold |
| `wip` | `wip-commit` | error | WIP/fixup/squash markers |
| `reference` | `ref`, `missing-reference` | info | Missing issue reference |
| `format` | `invalid-format` | info | Not conventional commits |
| `vague` | `vague-language` | warning | Generic descriptions |
| `imperative` | `non-imperative` | warning | Past/continuous tense |
## Severity Levels
- **Error**: Fails the check (exit code 1)
- **Warning**: Reported but passes (fails with `--strict`)
- **Info**: Informational only
- **Ignore**: Tracked but not reported
## Branch Filtering
Run validations only on specific branches. Useful for CI/CD pipelines where you want strict rules on `main`/`develop` but flexibility on feature branches.
### Glob Patterns
| Pattern | Matches | Does Not Match |
|---------|---------|----------------|
| `main` | `main` | `main-v2`, `feature/main` |
| `feature/*` | `feature/login`, `feature/auth` | `feature/user/profile` |
| `release/**` | `release/v1`, `release/v1/hotfix` | `releases/v1` |
| `*-stable` | `v1-stable`, `prod-stable` | `stable`, `v1-stable-2` |
| `release-?` | `release-1`, `release-2` | `release-10` |
### Behavior
- **Empty `branch`**: Validates on all branches (default)
- **Detached HEAD**: Validation is skipped
- **Non-matching branch**: Validation is skipped (exits successfully)
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines.