amonks / run

Go run some tasks!
https://amonks.github.io/run/
Other
19 stars 4 forks source link

πŸƒπŸ½β€β™€οΈπŸƒπŸΎβ€β™‚οΈπŸƒπŸ»β€β™€οΈπŸ’¨ βΈ»RUN

GitHub go.mod Go version Godoc

non-interactive output interactive TUI

Run is a dependency-aware task runner with an interactive process management UI.

Task runners (like GNU Make, Task, or Gulp) are great for task sequencing, but they aren't suitable for managing the long-running programs that make up a dev environment or a production service. Process managers (like Overmind, Foreman, or Exo) are great for managing long-running programs, but they aren't suitable for sequencing the dependent tasks that make up a build or test process. Run combines the best features from both worlds.

Installation

Run is a single binary, which you can download from from the releases page.

Install Script (MacOS, Linux)

This install command will download the latest version of run to your current directory.

curl -L https://raw.githubusercontent.com/amonks/run/main/install.bash | bash

Install with Go

If you already use go, you can install Run with the go command line tool:

$ go install github.com/amonks/run/cmd/run@latest

Minimal Example

Here's an example task file you can play with. Scroll down to learn more about integrating Run with your projects.

# tasks.toml

[[task]]
  id = "read-example-file"
  type = "long"
  dependencies = ["touch-example-file"]
  cmd = """
    while true; do
      echo "the example file says: $(cat example-file)"
      sleep 1
    done
  """

[[task]]
  id = "touch-example-file"
  type = "short"
  cmd = """
    date > example-file
  """

Run the tasks with run read-example-file. Select the touch-example-file task and use r to restart it. See how the output of read-example-file changes when this happens.

Getting Started

Every codebase is different, but here's a general overview of how to integrate Run into an existing project.

Depending on your learning style, you might prefer perusing the example project.

1. Consider your tasks

Make a list of the scripts and tasks you use to operate your project, making groups of tasks that are run together.

2. Write a task file

Create a file tasks.toml with "dev", "test", and "build" tasks. Here's a basic template:

# tasks.toml

[[task]]
  id = "dev"
  type = "long"
  dependencies = [] # TODO

[[task]]
  id = "test"
  type = "short"
  dependencies = [] # TODO

[[task]]
  id = "build"
  type = "short"
  dependencies = [] # TODO

3. Add your tasks

For each task you identified in step 1, add a new task to your taskfile. For example,

[[task]]
  id = "lint"
  type = "short"
  cmd = "npm run lint"

Then, add the task to the appropriate group,

 [[task]]
   id = "test"
   type = "short"
-  dependencies = [] # TODO
+  dependencies = ["lint"]

4. Enjoy!

Run run -list to check your work. Then, run run build, run dev, or run test to try it!

See the example project for a working demo.

Configuration

Run's configuration file is called tasks.toml. Here's a brief overview of the key fields in a task definition:

Required Fields

Optional Fields

For complete documentation, see the Taskfile Reference section below.

Taskfile Reference

Run is configured with tasks.toml files, which define the tasks that Run will manage.

Task definitions have two required fields: id and type.

[!TIP] It is possible to define a no-op task that specifies dependencies but not cmd. This can be useful for making a task which groups other tasks together.

id (required)

ID is a unique (within this taskfile) identifier for a task. It is used for:

type (required)

Type specifies the task's lifecycle management strategy. The only valid values are long and short:

description

Description is a human-readable description of the task. It's displayed in the TUI task list, the output of run -list, and can be used to document the task's purpose. It can be one line or multiline.

dependencies

Dependencies is a list of other task references that should run alongside this task.

triggers

Triggers is a list of task references to "short" tasks that should run alongside this task, and when completed successfully, cause this task to restart.

[!IMPORTANT] The difference between triggers and dependencies is a bit subtle. In general, "triggers" should always be "short", and "dependencies" should always be "long". Here are some examples,

  • a test runner with a --watch mode might be a "long" "dependency" of a "dev" task. This way, the test runner is started once and kept running, and test runs do not cause the dev server to restart.
  • a CSS builder with a --watch mode might be a "long" "dependency" of a "dev" task, and its output file "style.css" might additionally be a watch. This way, the css builder is run once and kept running, and when "style.css" changes, the dev server will be restarted.
  • a CSS builder without a --watch mode might be a "short" "trigger" of a "dev" task, and it might list the input css files under "watch". This way, the css builder is run whenever the input css files change, and its successful execution triggers a restart of the dev server.

watch

Watch defines file paths or globs to monitor for changes. Any detected change triggers a task restart. Examples include:

env

Env defines a map of environment variables provided to the task's execution environment.

cmd

CMD is a shell script that defines what the task does. It's run in a new bash process, as in:

$ bash -c "$CMD"

In simple cases, the command can be a single line:

[[task]]
  id = "clean"
  type = "short"
  cmd = "go clean -testcache && go clean -modcache"

For more complex commands, or to aid readability, a multiline string is also acceptable (note the triple-quote):

[[task]]
  id = "clean"
  type = "short"
  cmd = """
    echo "Cleaning up..."
    set -x

    rm -rf ./bin
    go clean -testcache
    go clean -modcache
  """

Task References

Run supports "monorepo" use cases: a task file can reference tasks from child directories with the / character. This is supported by all fields that take task ID references: dependencies and triggers. Everything before the last / is treated as a relative path to a directory containing a taskfile. The string following the last / is treated as a task ID in that taskfile. This is easy to understand with a few examples:

Only references to child directories are supported. ../build is not a valid task reference.

tasks.toml css/tasks.toml
[[task]]
  id = "build-css"
  dependencies = ["css/build"]
[[task]]
  id = "build"
  cmd = "npx postcss build"

In the project structure above, "build-css" depends on the "build" task from "css/tasks.toml".

CLI Reference

$ run dev

Run takes one argument: the task ID to run. Run looks for a task file in the current directory.

USAGE

  run [flags] <task>

FLAGS

  -contributors
        Display the contributors list and exit.
  -credits
        Display the open source credits and exit.
  -dir=string (default ".")
        Look for a root taskfile in the given directory.
  -help
        Display the help text and exit.
  -license
        Display the license info and exit.
  -list
        Display the task list and exit. If run is invoked
        with both -list and a task ID, that task's
        dependencies are displayed.
  -ui=string
        Force a particular ui. Legal values are 'tui' and
        'printer'.
  -version
        Display the version and exit.

User Interfaces

Run has two UIs that it deploys in different circumstances, a TUI and a Printer. You can force Run to use a particular UI by passing the 'ui' flag, as in,

$ run -ui=printer dev

Interactive TUI

interactive TUI

The Interactive TUI is used whenever both,

  1. stdout is a tty (eg Run is not being piped to a file), and,
  2. any running task is "long" (eg an ongoing "dev server" process rather than a one-shot "build" procedure).

For example, when running a dev server or test executor that stays running while you make changes.

Non-Interactive Printer UI

in your terminal... or as part of a pipeline...
non-interactive output redirected output

Run prints its output if either,

  1. stdout is not a tty (eg Run is being piped to a file), or,
  2. no tasks are "long" (eg a one-shot "build" procedure, rather than an ongoing "dev server").

Programmatic Use

Run can be used and extended programmatically through its Go API. For more information, including a conceptual overview of the architecture, example code, and reference documentation, see the godoc.

Attribution and License

Run is free for noncommercial and small-business use, with a guarantee that fair, reasonable, and nondiscriminatory paid-license terms will be available for large businesses. Ask about paid licenses at a@monks.co. See LICENSE.md or invoke the program with -license for more details.

Run is made by Andrew Monks, with help from outside contributors. See CONTRIBUTORS.md for more details.

Run makes use of a variety of open source software. See CREDITS.txt for more details.