Skip to main content

Lightweight Python task runner that just gets it

Project description

๐Ÿฅ๏ธ dony

A lightweight Python command runner with a simple, consistent workflow for managing project commands.

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_and_migrate                                                                                                                                                                                             
  ๐Ÿ“ release                                                                                                                                                                                                        
โ–Œ ๐Ÿ“ hello_world                                                                                                                                                                                                    
  3/3 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 
Select command ๐Ÿ‘†                                                                                                                                                                                                   
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ Prints "Hello, World!"                                                โ”‚
โ”‚                                                                       โ”‚
โ”‚                                                                       โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

Or call them directly: dony <command_name> [--arg value].

Quick Start

  1. Install Prerequisites: Python 3.8+, pipx, fzf

    For macOS, run

    brew install pipx
    brew install fzf 
    
  2. Install dony:

    pipx install dony
    
  3. cd into your project:

    cd my/project/path
    
  4. Create donyfiles/ with a sample command and a uv environment:

    dony --init
    
  5. Add your own commands under donyfiles/commands/.

  6. 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, confirm and press_any_key_to_continue
  • Run commands without arguments โ€“ defaults are mandatory

Example

import re
import dony

@dony.command()
def squash_and_migrate(
    new_branch: str = None,
    commit_message: 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")

    # - Squash and migrate

    dony.shell(
        f"""

        # - Make up to date

        git diff --cached --name-only | grep -q . && git stash squash_and_migrate-{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}

        # - Create new branch

        git checkout -b {new_branch}
        git push --set-upstream origin {new_branch}
    """,
    )

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:
    • autocomplete: suggestion-driven input
    • confirm: yes/no ([Y/n] or [y/N])
    • error: โŒ error message
    • input: free-text entry
    • path: filesystem path entry
    • press_any_key_to_continue: pause until keypress
    • print: styled text output
    • select: option picker (supports multi & fuzzy)
    • success: โœ… success message
  • dony enforces files to be named after functions and will rename them automatically when invoked

License

MIT License.

Author

Mark Lidenberg marklidenberg@gmail.com

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

dony-0.1.6.tar.gz (80.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dony-0.1.6-py3-none-any.whl (20.9 kB view details)

Uploaded Python 3

File details

Details for the file dony-0.1.6.tar.gz.

File metadata

  • Download URL: dony-0.1.6.tar.gz
  • Upload date:
  • Size: 80.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.2

File hashes

Hashes for dony-0.1.6.tar.gz
Algorithm Hash digest
SHA256 a655dbf6ce4dd28f6bc9ed2fcfd86c0de95b96854023e49c215beafa327a1c24
MD5 7e26503ee726ea1f419d087eccd9076b
BLAKE2b-256 547e05383c0e054e5c43435dddf7654b9b3c2e92f2b51d53651e2218d2a590ad

See more details on using hashes here.

File details

Details for the file dony-0.1.6-py3-none-any.whl.

File metadata

  • Download URL: dony-0.1.6-py3-none-any.whl
  • Upload date:
  • Size: 20.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.2

File hashes

Hashes for dony-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 cadd7ef16c839b837ccf2d54afc8782a49bd69707ddeb027cc628c7ae15bcbe3
MD5 b9dd6fb1bc0021d9a6084d898cebda93
BLAKE2b-256 fbba706d65d3c020c81c76f86f4ea0a9b6db558f31ec552bf3c5e4279e8ac3af

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page