Releases: TekWizely/run
Bug: RUNFILE_ROOTS - v0.11.2
Fixes a bug introduced in #69 which ended up breaking RUNFILE_ROOTS logic :(
See #73 for details of the bug and #74 for the PR
Thanks to @xkcd386at for reporting the issue !
Bug: Commands With Dash In Name - v0.11.1
Running Other Commands & Including .ENV Files - v0.11.0
About
Run is task runner that helps you easily manage and invoke small scripts and wrappers.
Do you find yourself using tools like make
to manage non build-related scripts?
Build tools are great, but they are not optimized for general script management.
Run aims to be better at managing small scripts and wrappers, while incorporating a familiar make-like syntax.
What's Changed in v0.11.0
- feat: Allow commands to RUN other commands (#63)
- feat: Add support for Hidden and Private Commands (#64)
- feat: Add support for RUN.ENV (#65)
- feat: Add support for INCLUDE.ENV (#66)
- feat: Use $RUNFILE in $RUNFILE_ROOTS Logic (#69)
- feat: Explicitly make single-file INCLUDE optional
- feat: Explicitly make .env includes required
- bug: Sets config.CurrentRunfile for Primary runfile
- bug: No-longer prints cmd not found error when Runfile could not be loaded.
Full Changelog: v0.10.0...v0.11.0
Running Other Commands
You can invoke other commands (with arguments) from your Runfile before or after your command executes:
Runfile
##
# RUN hello "Newman"
# RUN.AFTER goodbye
test:
echo "How are you?"
hello:
echo "Hello, ${1:-World}"
goodbye:
echo "Goodbye, now"
output
$ run test
Hello, Newman
How are you?
Goodbye, now
Note: Any standard variable assignment value can be used (quoted strings, variable references, etc)
Exported Variables
Your command's exported environment variables are also exported to the invoked command:
exported variable example
##
# EXPORT NAME := "Newman"
# RUN hello
test:
echo "Goodbye, now"
hello:
echo "Hello, ${NAME:-world}"
output
$ run test
Hello, Newman
Goodbye, now
Notes:
RUN.BEFORE
is also supported, and behaves just likeRUN
- Commands are invoked in the order they are defined
- Your command only runs if all before commands return exit code zero (0)
- After commands only run if your command returns exit code zero (0)
- Execution halts if any RUN returns a non-zero exit code
- You cannot invoke builtin commands (help, version, etc)
Setting Variables via RUN.ENV
A common occurrence in Runfiles is to have a central command which computes a set of variables, which is then invoked by multiple other commands that need to use those variables:
eval example
##
# export .RUN, .RUNFILE
test:
eval $( "$RUN" newman )
echo "Hello, ${HELLO:-World}"
## Generates script suitable for 'eval' by caller
newman:
echo "HELLO=Newman"
This technique works well, but Run also supports a similar feature using RUN.ENV
:
run.env example
##
# RUN.ENV newman
# ASSERT [ -n "${HELLO}" ] "HELLO not defined"
test:
echo "Hello, ${HELLO:-World}"
## Generates output compatible with simplified .env assignments
newman:
echo "# Let's say hi to Newman"
echo "export HELLO=Newman"
output
$ run newman
# Let's say hi to Newman
export HELLO=Newman
$ run test
Hello, Newman
Notes:
RUN.ENV
commands are run after EXPORTSRUN.ENV
commands are run before ASSERTS- Commands invoked via
RUN.ENV
are expected to generate relatively simple variable assignments - Run uses the subosito/gotenv library to parse command output
#
comments are supported and will be safely ignoredexport
keyword is optional and will be safely ignored- Simple variable references in assignments are supported, but variables defined within your Runfile are not (currently) accessible - This may be addressed in a future release
- Visit the gotenv project page to learn more about which
.env
features are supported
Including .ENV Files
.env
files allow users to manage runfile configuration without modifying the Runfile directly.
Your Runfile can include .env files using the following syntax:
INCLUDE.ENV <file pattern> | "<file pattern>" | '<file pattern>'
Simple example:
Runfile.env
HELLO=Newman
Runfile
INCLUDE.ENV Runfile.env
##
# export HELLO
hello:
echo "Hello, ${HELLO:-World}"
output
$ run hello
Hello, Newman
Notes:
- Variables are immediately available, as if they had been defined in the same place in the Runfile.
- Variables are not automatically exported.
- Run uses the subosito/gotenv library to parse command output
#
comments are supported and will be safely ignoredexport
keyword is optional and is (currently) ignored - This may be addressed in a future release- Simple variable references in assignments are supported, but variables defined within your Runfile are not (currently) accessible - This may be addressed in a future release
- Visit the gotenv project page to learn more about which
.env
features are supported
File(s) Not Found
By default, Run considers it OK no .env file is found (using either a single filename or a globbing pattern).
To force an error if no file(s) are found, use !
:
Runfile
INCLUDE.ENV ! Runfile-might-not-exist.env # ERROR if no file(s) found
Hidden / Private Commands
Hidden Commands
You can mark a command as Hidden using a leading .
:
hidden command example
##
# Prints 'Hello, Newman', then 'Goodbye, now'
# RUN hello Newman
test:
echo "Goodbye, now"
## Hello command is hidden
.hello:
echo "Hello, ${1:-world}"
Hidden commands don't show up when listing commands:
list commands
$ run list
Commands:
...
test Prints 'Hello, Newman', then 'Goodbye, now'
But they can still be invoked by using their full name, with .
:
run hidden command
$ run .hello
Hello, world
Private Commands
You can mark a command as Private using a leading !
:
private command example
##
# Prints 'Hello, Newman', then 'Goodbye, now'
# RUN hello Newman
test:
echo "Goodbye, now"
## Hello command is private
!hello:
echo "Hello, ${1:-world}"
Private commands don't show up when listing commands:
list commands
$ run list
Commands:
...
test Prints 'Hello, Newman', then 'Goodbye, now'
And they cannot be invoked from outside the Runfile:
try to run private command
$ run hello
run: command not found: hello
$ run '!hello'
run: command not found: !hello
Support Required Options; Support Default Option Values - v0.10.0
About
Run is task runner that helps you easily manage and invoke small scripts and wrappers.
Do you find yourself using tools like make
to manage non build-related scripts?
Build tools are great, but they are not optimized for general script management.
Run aims to be better at managing small scripts and wrappers, while incorporating a familiar make-like syntax.
What's Changed in v0.10.0
- feat: Support required options; Support default option values by @TekWizely in #62
Full Changelog: v0.9.1...v0.10.0
Making Options Required
You can now use !
to indicate that an option is required:
Runfile
##
# Hello world example.
# Prints "Hello, <name>".
# OPTION NAME! -n,--name <name> Name to say hello to
hello:
echo "Hello, ${NAME}"
Required Indicator on Help Text
Required options will be indicated in help text:
$ run help hello
hello:
Hello world example.
Prints "Hello, <name>".
Options:
-h, --help
Show full help screen
-n, --name <name> (required)
Name to say hello to
Error When Required Option Not Provided
An error will be generated if a required option is not provided:
$ run hello
hello: ERROR: Missing required option:
-n, --name <name>
Name to say hello to
Providing A Default Option Value
You can now use ?=
to specify a default value for an option, which will be used if the option is not provided:
# OPTION NAME ?= Newman -n,--name <name> Name to say hello to
The default value will be used if you invoke the command without explicitly providing the option:
output with default value
$ run hello
Hello, Newman
Note: Any standard variable assignment value can be used (quoted strings, variable references, etc)
Default Indicator on Help Text
Default values will be indicated in help text:
-n, --name <name> (default: Newman)
Boolean Default Option Values
You can specify a default value for boolean options, but they behave slightly different from standard options:
# OPTION NEWMAN ?= enabled --newman Say hello to Newman
Defaulted Value Always Assumed to be True
The content of the default value text is not used to determine the option's default true/false value.
Why?
Since boolean values are already always false
by default, providing a "default value" can only have the effect of defaulting the value to true
.
output with defaulted boolean option
$ run hello
Hello, Newman
Default Indicator on Help Text
Even though a boolean option with provided default is always assumed to default to true, the default value text is still useful in that it will be displayed in the help text:
--newman (default: enabled)
This allows you to give better messaging than just "true" or "1" (i.e "enabled" in this example)
Misc
Explicitly Marking Options as "Optional"
Although options are already optional by default, you can now use ?
to explicitly indicate that an option is optional:
# OPTION NAME? -n,--name <name> Name to say hello to
NOTE: This exists mostly for parity with !
and behaves the same as when it is not used
Includes; Overriding Commands; Easily Export Attributes; Mac Arm64 Binary - v0.9.0
About
Run is task runner that helps you easily manage and invoke small scripts and wrappers.
Do you find yourself using tools like make
to manage non build-related scripts?
Build tools are great, but they are not optimized for general script management.
Run aims to be better at managing small scripts and wrappers, while incorporating a familiar make-like syntax.
What's Changed in v0.9.0
- feat: Add support for INCLUDE directive by @TekWizely in #46
- feat: Add support for overriding commands by @TekWizely in #51
- feat: Add .RUNFILE.DIR, .SELF, .SELF.DIR by @TekWizely in #55
- bug: Allow Dynamic Content in Simple Titles by @TekWizely in #59
- feat: Easily export attributes by @TekWizely in #60
Full Changelog: v0.8.0...v0.9.0
Mac ARM64 Binary
In addition to code changes, this release also introduces a darwin_arm64
binary in the pre-compiled assets.
Includes
Includes let you organize commands across multiple Runfiles.
Simple example:
file layout
Runfile
Runfile-hello
Runfile
INCLUDE Runfile-hello
Runfile-hello
hello:
echo "Hello from Runfile-hello"
output
$ run hello
Hello from Runfile-hello
Overriding Commands
This release now allows you override commands, as long as they were originally registered in a different Runfile.
Runfile
## defined in Runfile
command1:
echo command1 from Runfile
INCLUDE Runfile-include
## defined in Runfile
command2:
echo command2 from Runfile
Runfile-include
## defined in Runfile-include
command1:
echo command1 from Runfile-include
## defined in Runfile-include
command2:
echo command2 from Runfile-include
list commands
$ run list
Commands:
...
command1 defined in Runfile-include
command2 defined in Runfile
Notice that the included runfile overrides command1
, but the primary runfile overrides command2
.
.RUNFILE.DIR, .SELF, .SELF.DIR
This release includes a few extra attributes to help Runfiles know where they exist in the file system. In addition to already present .RUNFILE
attribute, we now also have:
Attribute | Description |
---|---|
.RUNFILE |
Contains the absolute path of the primary Runfile. |
.RUNFILE.DIR |
Contains the absolute path of the parent folder of the primary runfile. |
.SELF |
Contains the absolute path of the current (primary or included) runfile. |
.SELF.DIR |
Contains the absolute path of the parent folder of the current runfile. |
Dynamic Content in Simple Titles
This release fixes a bug that now allows you to use dynamic data within simple one-line titles:
Runfile
EXPORT HELLO ?= "World"
## Prints "Hello, ${HELLO}"
hello:
echo Hello, ${HELLO}
usage
$ HELLO=Newman run help hello
hello:
Prints "Hello, Newman"
Easily Export Attributes
This release makes it easier to export attributes as variables for use in your own commands:
Simple Export
You can quickly export an attribute with a default variable name:
Runfile
EXPORT .RUNFILE, .RUNFILE.DIR
## Prints the value of .RUNFILE
runfile:
echo "${RUNFILE}"
## Prints the value of .RUNFILE.DIR
runfile-dir:
echo "${RUNFILE_DIR}"
With this technique, Run uses the attribute's name to determine the exported variable's name by:
- Removing the leading
.
character - Substituting any remaining
.
characters with_
Export With Name
If you want to export an attribute with a non-default variable name, you can use the AS
syntax:
EXPORT .RUNFILE AS RF
EXPORT .RUNFILE.DIR AS RFD
## Prints the value of .RUNFILE
runfile:
echo "${RF}"
## Prints the value of .RUNFILE.DIR
runfile-dir:
echo "${RFD}"
Exit Codes; $RUNFILE; $RUNFILE_ROOTS - v0.8.0
What's Changed
- run: Plumb the exit code of a command back to run by @rburchell in #35
- exec: Provide a way to cleanup the temporary dir by @rburchell in #37
- run: Show a better error on duplicate command by @rburchell in #38
- feature: Adds support for RUNFILE env variable by @TekWizely in #40
- feat(find runfile): Adds support for $RUNFILE_ROOTS path variable by @TekWizely in #41
- refactor: Simplify messaging, remove calls to os.Exit and log.Fatal by @TekWizely in #42
Capture Command Exit Code
Runfile
exit:
exit ${1:-0}
usage
run exit; echo $?
0
run exit 1; echo $?
1
run exit 127; echo $?
127
$RUNFILE Environment Variable
You can specify a runfile using the $RUNFILE
environment variable:
$ export RUNFILE="/path/to/my/Runfile"
$ run <command>
For some other interesting uses of $RUNFILE
, see:
NOTE: When specifying a runfile, the file does not have to be named "Runfile"
.
$RUNFILE_ROOTS Path Variable
You can instruct run to look up the directory path in search of a runfile.
You do this using the $RUNFILE_ROOTS
path variable.
$RUNFILE_ROOTS
is treated as a list of path entries (using standard os path separator)- Behaves largely similar to GIT_CEILING_DIRECTORIES
- If
$PWD
is a child of a root entry, run walks-up looking forRunfile
- Roots themselves are generally treated as exclusive (ie not checked)
$HOME
, if a configured root, is treated as inclusive (ie it is checked)
general usage
export RUNFILE_ROOTS="${HOME}" # Will walk up to $HOME (inclusively)
most permissive
export RUNFILE_ROOTS="/" # Will walk up to / (exclusively)
NOTE: $HOME
is given special treatment to support the case where a project is given its own user account and lives in the home folder of that user.
For the case of creating globally available tasks, see the Special Modes section.
New Contributors
- @rburchell made their first contribution in #35
Full Changelog: v0.7.2...v0.8.0
Assertions + Ignoring Script Lines - v0.7.2
Changelog
0da0b32 Add support for assertions (#33)
a73a61a Add ability to ignore script lines (#34)
Assertions
Assertions let you check against expected conditions, exiting with an error message when checks fail.
Assertions have the following syntax:
ASSERT <condition> [ "<error message>" | '<error message>' ]
Note: The error message is optional and will default to "Assertion failed"
if not provided
Condition
The following condition patterns are supported:
[ ... ]
[[ ... ]]
( ... )
(( ... ))
Assertion Example
Runfile
##
# Not subject to any assertions
world:
echo Hello, World
# Assertion applies to ALL following commands
ASSERT [ -n "${HELLO}" ] "Variable HELLO not defined"
##
# Subject to HELLO assertion, even though it doesn't use it
newman:
echo Hello, Newman
##
# Subject to HELLO assertion, and adds another
# ASSERT [ -n "${NAME}" ] 'Variable NAME not defined'
name:
echo ${HELLO}, ${NAME}
example with no vars
$ run world
Hello, World
$ run newman
run: Variable HELLO not defined
$ run name
run: Variable HELLO not defined
example with HELLO
$ HELLO=Hello run newman
Hello, Newman
$ HELLO=Hello run name
run: Variable NAME not defined
example with HELLO and NAME
$ HELLO=Hello NAME=Everybody run name
Hello, Everybody
Note: Assertions only apply to commands and are only checked when a command is invoked. Any globally-defined assertions will apply to ALL commands defined after the assertion.
Ignoring Script Lines
You can use a #
on the first column of a command script to ignore a line:
Runfile
hello:
# This comment WILL be present in the executed command script
echo "Hello, Newman"
# This comment block WILL NOT be present in the executed command script
# echo "Hello, World"
echo "Goodbye, now"
Note: Run detects and skips these comment lines when parsing the runfile, so the #
will work regardless of what language the script text is written in (i.e even if the target language doesn't support #
for comments).
No Empty Command Scripts - v0.7.1
Changelog
c0a123e Errors on empty command script
53fdc75 Adds line:col to parse errors; Adds TokenUnknownRune
9537f38 Updates install section for brew and compiled binaries
5f20709 Adds NPM Package + Updates README
8fefa67 Adds an Archlinux PKGBUILD (#2)
bbeca28 Adds Archlinux Installation Info to README
9a1b3bb Add Archlinux installation info
No Empty Command Scripts
Adds a check to ensure that command scripts are not empty.
Runfile
##
# Empty command script
empty:
hello:
echo "Hello, World"
output
$ run hello
run: 5.0: command 'empty' contains an empty script.
.RUN & .RUNFILE - v0.7.0
Changelog
4cd9fd0 Adds .RUN and .RUNFILE attributes (#21)
584e19b Renames version as run-version in shebang mode (#19)
5eda761 Makes .SHELL available for read (#17)
e466d2a Makes attributes available to command exports (#15)
14598e7 Adds brew core section to README
3792b87 Updates version string wit[h] BuildTool/builder
0c9ebbe Adds initial goreleaser config
.RUN & .RUNFILE Attributes
Adds .RUN
and .RUNFILE
attributes to make it possible to invoke other commands / runfiles from within your command script.
Runfile
##
# Invokes hello
# EXPORT RUN := ${.RUN}
# EXPORT RUNFILE := ${.RUNFILE}
test:
"${RUN}" -r "${RUNFILE}" hello
hello:
echo "Hello, World"
output
$ run test
Hello, World
Breaking Changes
This release is considered a breaking change since it now resolves the absolute path of the Runfile and uses that to process the file.
Version Command : v0.6.5
This release adds a version
command (already prepped for v0.6.5
)
$ run version
run v0.6.5
NOTE: There are no feature changes - If you have installed v0.6.2
or later, then there is no need to grab this version.