Awesome
cmdx
Task runner. It provides useful help messages and supports interactive prompts.
Overview
cmdx
is the task runner.
Using cmdx
you can manage tasks for your project such as test, build, format, lint, and release.
For example, This is the tasks for cmdx
itself.
$ cmdx -l
init, i - setup git hooks
coverage, c - test a package (fzf is required)
test, t - test
fmt - format the go code
vet, v - go vet
lint, l - lint the go code
release, r - release the new version
durl - check dead links (durl is required)
ci-local - run the Drone pipeline at localhost (drone-cli is required)
$ cmdx help release
NAME:
cmdx release - release the new version
USAGE:
cmdx release <version>
DESCRIPTION:
release the new version
ARGUMENTS:
version
cmdx
searches the configuration file from the current directory to the root directory recursively, and runs the task at the directory where the configuration file exists.
Features
- Easy to install (one binary)
- Parse the flag and positional arguments
- Useful help messages
- Interactive prompt by AlecAivazis/survey
- Validate requirements
- Validate flag and positional arguments
- Timeout
- Bash and Zsh completion
- Nested tasks (Sub tasks)
Install
cmdx
is a single binary written in Go.
So you only need to put the executable binary into $PATH
.
brew install suzuki-shunsuke/cmdx/cmdx
aqua g -i suzuki-shunsuke/cmdx
-
Download a prebuilt binary from GitHub Releases and install it into
$PATH
-
Go
go install github.com/suzuki-shunsuke/cmdx/cmd/cmdx@latest
Getting Started
Create the configuration file.
$ cmdx --init
$ cat .cmdx.yaml
Edit the configuration file and register the task hello
.
$ vi .cmdx.yaml
$ cat .cmdx.yaml
---
tasks:
- name: hello
description: hello command
usage: hello command
flags:
- name: source
short: s
usage: source file path
required: true
input_envs:
- NAME
- name: switch
type: bool
args:
- name: name
usage: name
default: bb
environment:
FOO: foo
script: "echo hello {{.source}} $NAME {{if .switch}}on{{else}}off{{end}} {{.name}} $FOO" # use Go's text/template
Output the help.
$ cmdx help
NAME:
cmdx - task runner
USAGE:
cmdx [global options] command [command options] [arguments...]
VERSION:
0.2.2
AUTHOR:
Shunsuke Suzuki
COMMANDS:
hello hello command
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--config value, -c value configuration file path
--name value, -n value configuration file name. The configuration file is searched from the current directory to the root directory recursively
--init, -i create the configuration file
--list, -l list tasks
--help, -h show help
--version, -v print the version
List tasks.
$ cmdx -l
hello - hello command
Run the task hello
.
$ cmdx hello -s README
+ echo hello README $NAME off bb $FOO
hello README README off bb foo
$ cmdx hello -s README --switch
+ echo hello README $NAME on bb $FOO
hello README README on bb foo
$ cmdx hello --target foo
target: foo
Example
In order to understand cmdx
, it is good to execute cmdx
command actually.
We prepare the sample configuration file for you to execute cmdx
.
Please see examples.
Configuration
path | type | description | required | default |
---|---|---|---|---|
.timeout | timeout | the task command timeout | false | |
.input_envs | []string | default environment variable binding | false | [] |
.script_envs | []string | default environment variable binding | false | [] |
.environment | map[string]string | top level environment variables | false | {} |
.quiet | bool | Default configuration whether the content of script is outputted | false | |
.tasks | []task | the list of tasks | true | |
task.name | string | the task name | true | |
task.short | string | the task short name | false | |
task.description | string | the task description | false | "" |
task.usage | string | the task usage | false | "" |
task.flags | []flag | the task flag arguments | false | [] |
task.args | []arg | the task positional arguments | false | [] |
task.input_envs | []string | task level environment variable binding | false | [] |
task.script_envs | []string | task level environment variable binding | false | [] |
task.environment | map[string]string | the task's environment variables | false | {} |
task.script | string | the task command. This is run by sh -c | true | |
task.quiet | bool | task level default configuration whether the content of script is outputted | false | |
task.shell | []string | shell command to run the script | ["sh", "-c"] | |
task.timeout | timeout | the task command timeout | false | |
task.require | require | requirement of task | false | {} |
task.tasks | []task | sub tasks | false | [] |
require.exec | []stringArray | required executable files | false | [] |
require.environment | []stringArray | required environment variables | false | [] |
stringArray | array whose element is string or array of string | |||
timeout.duration | int | the task command timeout (second) | false | 36000 (10 hours) |
timeout.kill_after | int | the duration the kill signal is sent after timeout.duration | false | 0, which means the command isn't killed |
flag.name | string | the flag name | true | |
flag.short | string | the flag short name | false | |
flag.usage | string | the flag usage | false | "" |
flag.default | string | the flag argument's default value | false | "" |
flag.input_envs | []string | flag level environment variable binding | false | [] |
flag.script_envs | []string | flag level environment variable binding | false | [] |
flag.type | string | the flag type. Either "string" or "bool" | false | "string" |
flag.required | bool | whether the flag argument is required | false | false |
flag.validate | []validate | parameters to validate the value of flag | false | [] |
flag.prompt | prompt | prompt | false | prompt is disabled |
prompt.type | string | prompt type | true | |
prompt.message | string | prompt message | false | flag.name or arg.name |
prompt.help | string | prompt help | false | |
prompt.options | []string | entries of select or multi_select prompt | true if the prompt type is select or multi_select | |
arg.name | string | the positional argument name | true | |
arg.usage | string | the positional argument usage | false | "" |
arg.default | string | the positional argument's default value | false | "" |
arg.input_envs | []string | the positional argument level environment variable binding | false | [] |
arg.script_envs | []string | the positional argument level environment variable binding | false | [] |
arg.required | bool | whether the argument is required | false | false |
arg.prompt | prompt | prompt | false | prompt is disabled |
arg.validate | []validate | parameters to validate the value of arg | false | [] |
validate.type | string | value type (email , url , int ) | false | |
validate.regexp | string | the regular expression | false | |
validate.min_length | int | the minimum string length | false | |
validate.max_length | int | the maximum string length | false | |
validate.prefix | string | the prefix | false | |
validate.suffix | string | the suffix | false | |
validate.contain | string | the string which the value should contain | false | |
validate.enum | []string | enum | false |
script
task.script
is the task command.
This is parsed by Go's text/template package.
sprig functions can be used.
The value of the flag and positional argument can be referred by the argument name.
For example,
# refer the value of the argument "source"
script: "echo {{.source}}"
Multiple lines
script: |
echo foo
echo bar
If the positional argument is optional and the argument isn't passed and the default value isn't set,
the value is an empty string ""
.
And some special variables are defined.
name | type | description |
---|---|---|
_builtin.args | []string | the list of positional arguments which aren't defined by the configuration args |
_builtin.args_string | string | the string which joins _builtin.args by the space " " |
_builtin.all_args | []string | the list of all positional arguments |
_builtin.args_string | string | the string which joins _builtin.all_args by the space " " |
input_envs, script_envs
input_envs
is a list of environment variables that are bound to the variable.
tasks:
- name: foo
script: "echo {{.source}}"
args:
- name: source
input_envs:
- command_env
$ COMMAND_ENV=zzz cmdx foo
+ echo zzz
zzz
script_envs
is a list of environment variables which the variable is bound to.
tasks:
- name: foo
script: "echo $COMMAND_ENV"
args:
- name: source
script_envs:
- command_env
$ cmdx foo zzz
+ echo $COMMAND_ENV
zzz
timeout
cmdx
supports the configuration about the timeout of the task.
- send SIGINT after
timeout.duration
seconds (default 36,000 seconds) - if
timeout.kill_after
isn't 0, send SIGKILL aftertimeout.duration + timeout.kill_after
seconds. By defaulttimeout.kill_after
is 0 so SIGKILL isn't sent
For example, the following task foo
's timeout is 3 seconds.
tasks:
- name: foo
script: sleep 100
timeout:
duration: 3
$ cmdx foo
+ sleep 100
the command is timeout: 3 sec
The task timeout configuration inherits the top level timeout configuration.
timeout:
duration: 3
tasks:
- name: foo # the timeout.duration is 3
script: sleep 100
require
task.require
is the requirement to run the task.
require.exec
For example, in the following example both of curl
and wget
is required.
tasks:
- name: foo
script: curl http://example.com
require:
exec:
- curl
- wget
If curl
isn't installed, the task is failed.
$ cmdx foo
curl is required
Note that the shell's alias is ignored. Internally, exec.LookupPath is used.
In the following example, either curl
or wget
is required.
tasks:
- name: foo
script: curl http://example.com
require:
exec:
- - curl
- wget
$ cmdx foo
one of the following is required: curl, wget
require.environment
require.environment
is the required environment variables.
Note that if the value of the environment variable is an emtpy string, the environment variable is treated as unset.
tasks:
- name: foo
script: curl http://example.com
require:
environment:
- GITHUB_TOKEN
$ cmdx foo
the environment variable 'GITHUB_TOKEN' is required
tasks:
- name: foo
script: curl http://example.com
require:
environment:
- - GITHUB_TOKEN
- GITHUB_ACCESS_TOKEN
$ cmdx foo
one of the following environment variables is required: GITHUB_TOKEN, GITHUB_ACCESS_TOKEN
validation
cmdx
supports to validate args
and flags
.
For example,
# .cmdx.yaml
tasks:
- name: hello
script: echo hello
args:
- name: age
validate:
- type: int
$ cmdx hello foo
age is invalid: must be int: foo
quiet
By default cmdx
outputs the content of task's script
when the task is run.
In case of the following example, + echo hello
is outputted.
# .cmdx.yaml
tasks:
- name: hello
script: echo hello
$ cmdx hello
+ echo hello
hello
You can suppress the output by --quiet (-q)
option.
# BAD: cmdx hello -q
$ cmdx -q hello
hello
And you can change the default configuration of quiet
at the global level or the task level.
# .cmdx.yaml
tasks:
- name: hello
script: echo hello
quiet: true # task level
# .cmdx.yaml
quiet: true # global level
tasks:
- name: hello
script: echo hello
quiet: true
The priority is
- command line flag
- task level configuration
- global level configuration
If the quiet is enabled by configuration but you want to output script
, please set the flag -q=false
.
# "=" is needed
$ cmdx -q=false hello
+ echo hello
hello
prompt
cmdx
supports the interactive prompt by AlecAivazis/survey.
cmdx
supports the following prompt types.
- input
- multiline
- password
- confirm
- select
- multi_select
- editor
About prompt type, please see AlecAivazis/survey's document.
value source priority
- command line arguments
- environment variable (input_envs)
- prompt (prompt isn't launched if the value is set by command line argument or environment variable)
- default value
shell
This is an advanced feature.
By default task's script
is run by the command sh -c
.
You can change the command by the shell
option.
For example, you can run Python script.
- name: hello
shell:
- python
- -c
script: |
print("hello")
And you can run the shell script in the container.
- name: hello
shell:
- docker
- exec
- -ti
- foo
- sh
- -c
script: |
whoami
read -p "name?" name
echo "name: $name"
Bash (Zsh) Completion
cmdx
supports Bash (Zsh) Completion powered by urfave/cli.
We test the completion with Zsh, but we don't test the completion with other shell.
To enable the completion, you have to load a shell script. For detail, please see the document of urfave/cli.
Please set cmdx
to PROG
Sub tasks
cmdx
supports sub tasks.
For example,
tasks:
- name: admin
usage: administrator feature
tasks:
- name: cluster
usage: manage clusters
tasks:
- name: create
usage: create a cluster
script: echo "create a cluster"
$ cmdx admin cluster create
+ echo "create a cluster"
create a cluster
The following attributes are inherited from the parent tasks.
- input_envs
- script_envs
- quiet
- environment
- timeout
- requires
For example,
tasks:
- name: admin
usage: administrator feature
require:
exec:
- yamllint
tasks:
- name: cluster
usage: manage clusters
tasks:
- name: create
usage: create a cluster
script: echo "create a cluster"
$ cmdx admin cluster create
yamllint is required
We can't set both task.script
and task.tasks
.
For example,
tasks:
- name: hello
script: echo hello
tasks:
- name: world
script: echo "hello world"
$ cmdx hello
please fix the configuration file: the task `hello` is invalid. when sub tasks are set, 'script' can't b
e set
Contributing
Please see the CONTRIBUTING.md.