task
task copied to clipboard
Add `if:` keyword to control when a task or command is ran?
There are some cases where task: is called under cmds: and the task needs to be conditionally run. Take the following as an example:
---
version: '3'
tasks:
python:requirements:
deps:
- :install:software:python
run: once
cmds:
- task: python:requirements:poetry
- task: :{{if eq .REPOSITORY_TYPE "ansible"}}common:python:requirements:ansible{{else}}donothing{{end}}
status:
- '[[ "${container:=}" == "docker" ]]'
I'm currently getting around the issue by having a task called donothing that gets called when the task should not run. It would be nice if we could conditionally run tasks somehow. Maybe something like this:
---
version: '3'
tasks:
test:
cmds:
- task: anothertask
when:
sh: '[[ "$CONTAINER" == 'docker' ]]'
Hi @ProfessorManhattan,
Something I had in mind for a while is that we could potentially have an if keyword for tasks and commands:
version: '3'
tasks:
foo:
cmds:
- echo 'bar'
if: '[[ "$ENV" == "bar" ]]'
or
version: '3'
tasks:
foo:
cmds:
- cmd: echo 'bar'
if: '[[ "$ENV" == "bar" ]]'
NOTE: We already have preconditions, which is similar but makes the call fail when an error is returned, which means if still makes sense to have for skipping without failing.
isn't that what status is supposed to do? decide to skip a step?
Unlike status which will skip a task if it is up to date, and continue executing tasks that depend on it, a precondition will fail a task, along with any other tasks that depend on it.
isn't that what
statusis supposed to do? decide to skip a step?
You have a good point, we'd have some intersection between these two features.
status currently prints Task "foo" is up-to-date messages, though. This is accurate for statuses but not for other reasons why you'd want to skip a task.
Also, if would be the opposite of status with regarding the expected status: if runs on zero, status runs on non-zero statuses.
So, I don't have a strong opinion, but maybe it would still make sense to have both if and status. Alternatively, we could add if: only to commands and not to the task itself.
Thanks @andreynering
Another thing we might want to keep in mind is handling the --force command line parameter. Currently, this will just ignore status which forces the user to wrap everything in ifs (even using status) for logic that doesn't relate to a particular project. In my use case, I share the same set of Taskfiles across hundreds of repositories of many different types - it is not feasible to generate the Taskfiles for each project type.. it would take too long.
I would like to see an if: that can be added at the least to the task and cmd level. It should also not be impacted by any --force logic. Take the following example:
---
version: '3'
tasks:
mytask:
cmds:
- gsettings set org.gnome.settings-daemon.plugins.color night-light-enabled true
if:
- ls /usr/bin/*session | grep gnome-session
status:
- [[ $(gsettings get org.gnome.settings-daemon.plugins.color night-light-enabled) == 'true' ]]
Both the if: and status: are used in this example. The if: parameter makes sure GNOME is being run on the system and the status: is used to achieve idempotency. This would make even more sense if we were running a command that requires a reboot. In this example, we would need the --force command to obey the if: or else we would get an error if GNOME is not on the system.
Currently, with any complex flows that rely on status, things can easily get messy when using --force but the --force command could potentially be pretty useful for cache busting. I see adding an if: parameter as a possible solution.
Probably the best use-case for if would be to add steps that depend only on specific platforms, like Windows, Linux, MacOS. Adding extra code for platform on each called shells script is a PITA, one that could be easily avoided with an "if".
For those interested, there's an ongoing discussion about a possible key specificly to select given OS/Arch on a task or command:
- https://github.com/go-task/task/issues/978
- https://github.com/go-task/task/pull/980
A +1 for if.
I really over-use status, which requires some mental gymnastics ("Only run this on ARM machines, which means status needs to be 0 on x86 machines, so raise an error on ARM"!), and isn't compatible with --force ("now we're running it on x86 machines?!")
Though I do empathize that it still has lots of overlap with status...
@andreynering i have a couple of env vars where if would be useful. I'd be willing to open up a PR if there isn't anything in flight, going with your proposal in the reply. In combination with https://github.com/go-task/task/pull/1220 this would allow us to put most of our release pipeline into taskfiles, enabling matrix tests and targeting along with that "run offline" concept.
@titpetric Contributions are welcome! I would advise you to wait until #1220 is merged to avoid any conflicts. Also, that would allow you to test both features together.
FYI #1220 has been merged
FYI #1220 has been merged
Though IIUC this is a bit different — for rather than if?
Right; I'm just saying this is ready for development per this comment
Right; I'm just saying this is ready for development per this comment
Sorry, I didn't read up far enough. Thanks @JonZeolla
if keyword have any progress?
status kind of works, but its interactions with --force and sources make it unviable.
A when (more presence than if) that hooks to the same logic that status currently has, would be suitable. Any preference? If I can figure out the code, I might try create a PR.
statuskind of works, but its interactions with--forceandsourcesmake it unviable.A
when(more presence thanif) that hooks to the same logic thatstatuscurrently has, would be suitable. Any preference? If I can figure out the code, I might try create a PR.
After reading though the code, and considering the problem a bit more, there seem to be 3 possible paths:
- Add a new keyword like "if" or "when". I'm not convinced this is a good idea for the reasons; the calling task may need to know about the called task (and that might not be knowable until runtime) so that could end up being a mess, and as soon as there is an "if" ... we can be sure "else", "switch", "or" and friends will follow.
- Add a "skip" which is a duplication of the logic behind "status", but behaves independently of the "--force" flag. That gets the desired behaviour ... but ... conflicts a little with ...
- Add a "skip" attribute to the existing preconditions and change the behaviour of preconditions such that if all preconditions which fail have that skip attribute (set to true), then the task is skipped rather than erroring.
To my mind, adding a "skip" attribute to preconditions, and adjusting the behavior of precondition evaluation, is the better option.