Opinionated release toolkit for modern Python projects
Project description
relkit: Opinionated Release Toolkit for Modern Python Projects
"This Way or No Way" - A strict, opinionated release workflow enforcer for Python projects using uv.
Features
- 🚀 Workspace Support: Per-package versioning in monorepos
- 🔒 Atomic Releases: Version, changelog, commit, tag, and push in one command
- 🎯 Explicit Operations: No magic, every action is intentional
- ✅ Pre-flight Checks: Validates everything before release
- 📝 Changelog Enforcement: Required for all releases
- 🏷️ Smart Tagging:
v1.0.0for single packages,package-v1.0.0for workspaces - 🚫 Safety First: Blocks dangerous operations before they happen
Installation
# Add to your project as a dev dependency
uv add --dev relkit
# Or install from GitHub
uv add --dev git+https://github.com/angelsen/relkit.git
Quick Start
Single Package Projects
# Initialize git hooks (recommended)
relkit init-hooks
# Check project status
relkit status
# Make changes, update CHANGELOG.md, then bump version
relkit bump patch # or minor/major
# Full release workflow
relkit release
Workspace Projects
# Show workspace overview
relkit status
# Work with specific packages (--package is required)
relkit status --package termtap
relkit bump patch --package termtap
relkit build --package termtap
relkit publish --package termtap
# Package-specific tags are created automatically
# e.g., termtap-v1.0.0, webtap-v2.1.0
Commands
Core Commands
relkit status [--package NAME]- Show release readinessrelkit bump <major|minor|patch> [--package NAME]- Atomic version bump with changelog, commit, and tagrelkit release [--package NAME]- Complete release workflowrelkit version- Show current version
Build & Publish
relkit build [--package NAME]- Build distribution packagesrelkit test- Test built packagesrelkit publish [--package NAME]- Publish to PyPI (requires confirmation)
Development Tools
relkit check <all|git|changelog|format|lint|types> [--fix]- Run quality checksrelkit init-hooks- Install git hooks
Git Wrappers
relkit git <command>- Pass-through to git with awareness
Workspace Support
Relkit seamlessly handles three project types:
1. Single Package (default)
[project]
name = "mypackage"
version = "1.0.0"
- Commands work without
--packageflag - Tags:
v1.0.0
2. Pure Workspace
[tool.uv.workspace]
members = ["packages/*"]
# No [project] section in root
- All commands require
--packageflag - Tags:
package-v1.0.0
3. Hybrid Workspace
[project]
name = "root-package"
version = "2.0.0"
[tool.uv.workspace]
members = ["packages/*"]
- Root package and workspace members
- Use
--package root-packageor--package member-name - Tags:
v2.0.0for root,member-v1.0.0for members
Philosophy
Explicit Over Magic
- Workspace operations require explicit
--packageselection - No automatic dependency cascades
- Clear errors when package selection is ambiguous
Separation of Concerns
- uv: Manages dependencies and workspace setup
- relkit: Manages releases and versioning
- git: Version control (wrapped for safety)
Atomic Operations
The bump command is atomic - it handles everything in one transaction:
- Updates version in pyproject.toml
- Updates CHANGELOG.md
- Commits changes
- Syncs lockfile if needed
- Creates appropriate tag
- Pushes to remote
Safety Features
Blocked Operations
❌ Direct version edits
# Editing version in pyproject.toml directly is blocked
git commit -am "bump version" # BLOCKED by pre-commit hook
❌ Manual tag creation
git tag v1.0.0 # BLOCKED by git hook
# Tags must be created via: relkit bump
❌ Dirty working directory
# With uncommitted changes:
relkit bump patch # BLOCKED - requires clean git
Required Confirmations
- Publishing to PyPI requires explicit confirmation
- Major version bumps trigger breaking change warning
- All operations show clear next steps on failure
Configuration
Relkit reads from pyproject.toml:
[project]
name = "your-package"
version = "0.1.0" # Never edit directly!
[tool.uv.workspace]
members = ["packages/*"] # Optional workspace config
Each package maintains its own:
pyproject.tomlwith versionCHANGELOG.mdwith release notes- Git tags with appropriate naming
Error Messages
All errors are actionable:
✗ Workspace requires --package
Available packages: termtap, webtap, logtap
Next steps:
1. Specify a package: relkit bump patch --package <name>
2. Use package name from pyproject.toml [project] section
Development
# Clone repository
git clone https://github.com/angelsen/relkit.git
cd relkit
# Install in development mode
uv sync
# Run tests
uv run pytest
# Check types
uv run pyright
Contributing
This tool is intentionally opinionated. We welcome contributions that:
- Improve error messages
- Add safety checks
- Enhance workspace support
- Fix bugs
We generally reject:
- Features that add "escape hatches"
- Options to bypass safety checks
- Implicit or magical behaviors
License
MIT
Credits
Created by Fredrik Angelsen. Built with Python 3.12+ and uv.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file relkit-1.5.5.tar.gz.
File metadata
- Download URL: relkit-1.5.5.tar.gz
- Upload date:
- Size: 39.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ef7efc85ce3ff1b804c81f05b6d729ec353c86eda11bdcb4bc0e770d54130be
|
|
| MD5 |
63ef39d08e360b506b038fbe43c0150b
|
|
| BLAKE2b-256 |
9f80486484548f8934fe65300a36b6b91e9bf9789447d33735682d47fdb8f988
|
File details
Details for the file relkit-1.5.5-py3-none-any.whl.
File metadata
- Download URL: relkit-1.5.5-py3-none-any.whl
- Upload date:
- Size: 53.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d2261424f679b64bd95d37b4062007957e6cd7dd6eb6df1ed51b30cd8668553b
|
|
| MD5 |
72e097d628d89718218040f532eed9d0
|
|
| BLAKE2b-256 |
fbc256095ff0038941a2a224e8ce8508a45920d7fea1da62d5699ee7869f0556
|