Skip to main content

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

  1. Install Prerequisites: Python 3.8+, pipx (for installation only, yor may use any other tool you like), optional fzf for fuzzy-search and shfmt for pretty command outputs.

    For macOS, run

    brew install pipx
    brew install fzf 
    brew install shfmt
    
  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(
        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 entry
    • dony.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 value
    • dony.press_any_key_to_continue: pause until keypress
    • dony.path: filesystem path entry
    • dony.autocomplete: suggestion-driven input
    • dony.print: styled text output
    • dony.error: โŒ error message
    • dony.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.8.tar.gz (82.7 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.8-py3-none-any.whl (22.7 kB view details)

Uploaded Python 3

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

Hashes for dony-0.1.8.tar.gz
Algorithm Hash digest
SHA256 5facb1122996759bbb2ce0aae79d465df54c9c2a514fb7f3fb70f9516d3a583d
MD5 ab0c8d82bc005a1424ed44adecbe6f19
BLAKE2b-256 57b6ec20905f6637c055eddcb0f8b808ab29015426a16267b5c95a9d49702983

See more details on using hashes here.

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

Hashes for dony-0.1.8-py3-none-any.whl
Algorithm Hash digest
SHA256 777352aa77ba9c75650aed56324dfd1b9f10babd22c89cd7c75af227f8f18bcc
MD5 d3b4433595fab00b0308429d4f3317b9
BLAKE2b-256 a1167a51fdf9476f37b60c523b167fde7938164601d8c14fd2e8e9b8cd90df50

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