Lightweight Python task runner that just gets it
Project description
๐ฅ๏ธ dony
A lightweight Python command runner with a simple and consistent workflow. A Justfile alternative.
How it works
Define your commands in donyfiles/ in the root of your project.
import dony
@dony.command()
def hello_world():
"""Prints "Hello, World!" """
dony.shell('echo "Hello, World!"')
Run dony to fuzzy-search your commands from anywhere in your project.
๐ squash
๐ release
โ ๐ hello_world
3/3 โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Select command ๐
โญโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ Prints "Hello, World!" โ
โ โ
โ โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
Or call them directly: dony <command_name> [--arg value].
Quick Start
-
Install Prerequisites: Python 3.8+,
pipx(for installation only, yor may use any other tool you like), optionalfzffor fuzzy-search andshfmtfor pretty command outputs.For macOS, run
brew install pipx brew install fzf brew install shfmt
-
Install
dony:pipx install dony
-
cd into your project:
cd my/project/path
-
Create
donyfiles/with a sample command and auvenvironment:dony --init -
Add your own commands under
donyfiles/commands/. -
Use:
dony
Commands
import dony
@dony.command()
def greet(
greeting: str = 'Hello',
name: str = None
):
name = name or dony.input('What is your name?')
dony.shell(f"echo {greeting}, {name}!")
- Use the convenient shell wrapper
dony.shell - Use a bundle of useful user interaction functions, like
input,confirmandpress_any_key_to_continue - Run commands without arguments โ defaults are mandatory
Example
import re
import dony
@dony.command()
def squash(
new_branch: str = None,
commit_message: str = None,
checkout_to_new_branch: str = None,
):
"""Squashes current branch to main, checkouts to a new branch"""
# - Get default branch if not set
new_branch = new_branch or f"workflow_{dony.shell('date +%Y%m%d_%H%M%S', quiet=True)}"
# - Get current branch
original_branch = dony.shell(
"git branch --show-current",
quiet=True,
)
# - Get commit message from the user
if not commit_message:
while True:
commit_message = dony.input(f"Enter commit message for merging branch {original_branch} to main:")
if bool(
re.match(
r"^(?:(?:feat|fix|docs|style|refactor|perf|test|chore|build|ci|revert)(?:\([A-Za-z0-9_-]+\))?(!)?:)\s.+$",
commit_message.splitlines()[0],
)
):
break
dony.print("Only conventional commits are allowed, try again")
# - Check if user wants to checkout to a new branch
checkout_to_new_branch = dony.confirm(
f"Checkout to new branch {new_branch}?",
provided_answer=checkout_to_new_branch,
)
# - Do the process
dony.shell(
f"""
# - Make up to date
git diff --name-only | grep -q . && git stash squash-{new_branch}
git checkout main
git pull
# - Merge
git merge --squash {original_branch}
git commit -m "{commit_message}"
git push
# - Remove current branch
git branch -D {original_branch}
git push origin --delete {original_branch}
"""
)
if checkout_to_new_branch:
dony.shell(
f"""
git checkout -b {new_branch}
git push --set-upstream origin {new_branch}
""",
)
if __name__ == "__main__":
squash()
Use cases
- Build & Configuration
- Quality & Testing
- Release Management
- Deployment & Operations
- Documentation & Resources
- Git management
donyfiles/
donyfiles/
... (uv environment)
โโโ commands/
โ โโโ my_command.py # one command per file
โ โโโ my-service/
โ โ โโโ service_command.py # will be displayed as `my-service/service_command`
โ โ โโโ _helper.py # non-command file
Things to know
- All commands run from the project root (where
donyfiles/is located) - Available prompts based on
questionary:dony.input: free-text entrydony.confirm: yes/no ([Y/n] or [y/N])dony.select: option picker (supports multi & fuzzy)dony.select_or_input: option picker (supports multi & fuzzy) with the ability to enter a custom valuedony.press_any_key_to_continue: pause until keypressdony.path: filesystem path entrydony.autocomplete: suggestion-driven inputdony.print: styled text outputdony.error: โ error messagedony.success: โ success message
donyenforces files to be named after functions and will rename them automatically when invoked
License
MIT License
Author
Mark Lidenberg marklidenberg@gmail.com
Project details
Release history Release notifications | RSS feed
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 dony-0.1.8.tar.gz.
File metadata
- Download URL: dony-0.1.8.tar.gz
- Upload date:
- Size: 82.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5facb1122996759bbb2ce0aae79d465df54c9c2a514fb7f3fb70f9516d3a583d
|
|
| MD5 |
ab0c8d82bc005a1424ed44adecbe6f19
|
|
| BLAKE2b-256 |
57b6ec20905f6637c055eddcb0f8b808ab29015426a16267b5c95a9d49702983
|
File details
Details for the file dony-0.1.8-py3-none-any.whl.
File metadata
- Download URL: dony-0.1.8-py3-none-any.whl
- Upload date:
- Size: 22.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
777352aa77ba9c75650aed56324dfd1b9f10babd22c89cd7c75af227f8f18bcc
|
|
| MD5 |
d3b4433595fab00b0308429d4f3317b9
|
|
| BLAKE2b-256 |
a1167a51fdf9476f37b60c523b167fde7938164601d8c14fd2e8e9b8cd90df50
|