tusk
tusk copied to clipboard
Allow adding generic global variables
Similar to https://github.com/rliebz/tusk/issues/73.
It would be nice to be able to add generic variables to the tusk file that can be used throughout, such as a command or username or anything else that gets used repeatedly
For example my file calls a command with different arguments depending on the Task being run. It would be nice to make the "root" command (the command name plus 2 args) a variable somewhere and be able to append to it as required.
This is currently possible by creating a Private Option globally, but it is a bit confusing to people new to Tusk. I would envisage that global vars would be overridden by those declared by options within a Task block, in the same way they would be with function variables shadowing global ones in most languages.
variables:
rootCommand: "binary --option1 /always/the/same -v"
tasks:
do-it:
run: ${rootCommand} more arguments
do-another:
run: ${rootCommand} do another
You can already do this by using a private global option with a default value.
I'm aware, and use them often, "This is currently possible by creating a Private Option globally, but it is a bit confusing to people new to Tusk." It feels like a work around though, using an "option" to hold a fixed variable...
#73 raises the idea of this for Env vars, I believe this functionality would be good to use for variables too.
I definitely hear you that private options can be confusing to use. It's hard to tell what's obvious/intuitive to folks approaching the tool from the outside, so the feedback on that front is much appreciated.
In general, my design philosophy with tusk is to try to give capabilities to do the things that you need to be able to do while keeping the learning curve as small as possible. My apprehension around introducing the concept of a global variable in addition to a global option is that it increases the surface area of the config file and mental model without providing any functionality that isn't already available. In other words, one more thing to learn.
That said, I've been pretty happy with some of the short-hand syntaxes that tusk already provides, such as being able to use strings instead of lists of strings, or strings to represent the most commonly defined field of a map, should that make sense. For example, this:
tasks:
foo:
run: echo foo
Is technically a shorthand for this:
tasks:
foo:
run:
- command:
- echo foo
We could imagine a similar shorthand for defining an option:
options:
root-command: "binary --option1 /always/the/same -v"
Which in its most verbose form would translate to:
options:
root-command:
default:
- value: "binary --option1 /always/the/same -v"
I have opted not defined that shorthand syntax for options specifically because I want to discourage people from using options without defining the usage
text for those options. In other words, if you define an option for the CLI, I want you to also include the usage as documentation.
That philosophy doesn't really apply if those options are private, but the challenge is, you can only specify one property to a key if we're talking about a shorthand syntax. I don't think it would be intuitive to define different defaults for an option
depending on whether the option was defined using the short-form or long-form syntax, such as having option-name: option-value
imply private: true
, so we're stuck without a short form for private variables.
Another syntax I've considered is coercing options with leading underscores in their name to private options. So _root-command
would be private by default, while root-command
would be public by default. Combining the shorthand syntax with the private-by-default syntax, the most terse version of what you're describing that I can imagine fitting this model would look like this:
options:
_root-command: "binary --option1 /always/the/same -v"
tasks:
do-it:
run: ${_root-command} more arguments
do-another:
run: ${_root-command} do another
The problems I see with that pattern are twofold:
- This continues to leave open a syntax to easily define an option without defining its usage statement, which leads to tusk configurations that are easier to write but harder to use.
- I'm not necessarily convinced that this lowers the learning curve for folks.
Given that context, I'd be curious to hear your thoughts. My intuition right now is that the best approach to making this a better experience at least in the short term is improving the docs to make this usage pattern more obvious, although I realize that's not necessarily a satisfying response.
If we do have a way for setting top-level variables (or constants) though, I would very much like for it to be different than options. I.e. instead of only allowing simple types, allow complex types like objects or arrays, and ideally, also imports like described in #85.
That would allow tusk to directly use configuration that is generated/intended for something else, as long as the file format is still YAML/JSON.
Plausible syntax?
constants:
_root-command: "binary --option1 /always/the/same -v"
_root2:
command: "binary"
args: "--option1 /always/the/same -v"
imports: // for #85
_root3: config.yaml
tasks:
do-it:
run: ${_root-command} more arguments
do-another:
run: ${_root2.command} -needs-to-be-first ${_root2.args}
do-another:
run: ${_root3.command} -needs-to-be-first ${_root3.args}
Plausible precedence order:
- options (task)
- options (global)
- constants (global)
- imports (global) #85
- environment (task)
- environment(global) #73