Closed mrosm20 closed 2 years ago
That's a good one. There is one way to make this work but I think we can do more to make it better.
You currently have a global build
command. The trick to make this work would be to define local install
and uininstall
commands that are scoped to just a single tree. We can then use garden cmd
to run all three commands in one shot and it won't do anything in the other trees that don't define the install and uninstall commands.
If commands
is configured in tree scope then only that tree will have that command. Trees that don't have the command will be a no-op and nothing will run when those trees are visited. The invocation looks like this:
garden cmd my-garden install build uninstall
The room-for-improvement is that this relies on install
and uninstall
being local commands that have to be attached to very specific trees (the first and last trees, respectively). You'd need to attach the install
command to the very first tree in the garden, and uninstall
to the very last tree in the garden/group.
The reason is that the way we loop over trees when running commands goes like this:
for each tree in the query:
for each command:
run command in the resolved context for this tree
so it's going to run (install, build, uninstall) over each tree: (tree1:install, tree1:build, tree1:uninstall), (tree2:install, tree2:build, tree2:uninstall)
.
I've also had cases where I've wanted to loop inside out so that it would instead do: (tree1:install, tree2:install, tree1: build, tree2: build, tree1: uninstall, tree2:uninstall)
.
This is kinda like the choice between breath-first or depth-first traversal. This does seem like it could be a command-line option to switch the loop order to be:
for each command:
for each tree in the query:
run command in the resolved context for this tree
I'm not sure what I would call the command-line flags, though. What do you think about this?
-d, --depth-first run all commands over each tree before visiting the next tree
-b, --breadth-first run a command across all trees before running the next command
I'm totally open to changing the default to --depth-first
. Right now we basically do --breadth-first
.
It almost seems like depth-first is a better default because usually we'd want to "build them all", and then "test them all", or "clean them all", etc.
I've actually run into this usability wrinkle myself. I think I've just about convinced myself to change the default and add these options.
What do you think?
Here's another detail that might be helpful. Since you have a global build
command you can actually do without an uninstall
command because you can basically extend the build
command for the very last tree, and then when build
is executing it is going to run the global build
steps and then it will run the local build
steps afterwards.
In other words, you can simplify it down to,
garden cmd my-garden install build
.. by extending the tree definition for the last tree in the garden/group to include its own build
command. This local build
command is considered an extension of the global command. The steps in that tree's context always run after the global command.
Note that the iteration options will only make it so that we don't have to attach install
to specific trees -- at that point we can attach it to any tree (1 or more, in case different trees have different install steps) and we'll be ensured that all of the install
steps will be run first.
After we add options for iteration another enhancement might be to introduce a garden-commands
block that can be attached to garden definitions.
The semantics would be that we could define install
(and uninstall
) in a garden-command
and it would only get executed once in the context of that garden, whereas the build
command would get executed once for each tree.
The invocation would still look the same: garden cmd my-garden install build uninstall
but we would instead define install
and uninstall
alongside the garden rather than attaching it to an arbitrary tree.
NOTE: the names "install" and "uninstall" are probably not the best choice of names because they may be confused for traditional "make install / uninstall" commands which normally happen after "make all" (build) steps.
If it helps, when reading the above replace install
with setup
and uninstall
with teardown
.
garden cmd my-garden setup build teardown
might make more sense to someone reading along.
Another note in case it helps.. it should hopefully be obvious, but running:
garden setup my-garden
garden build my-garden
garden teardown my-garden # or extend the `build` command for the last tree as noted above
Would also work today.
This issue will remain open until we implement the traversal options.
At that point we'll also submit a new issue to add the garden-level pre and post-commands. "pre" commands run before tree-level commands, and "post" commands run after tree-level commands. Please let me know what you think.
thank you, i got it to work like this:
make a separate tree that not part of the garden group name it the same as the garden create the command with the same name then recursively call the garden, not pretty but it works
the command would be:
garden build @
command: build:
I testing this out with a group of developers, because I like the design and we have a use-case of 10 repos that need to be part of a garden, but i don't want to make the commands themselves to complex. The garden yaml is where i would prefer all the complexities. i like the idea of teardown and setup. Maybe something like this:
setup build:
I've implemented a -b
/ --breadth-first
option to garden cmd
that runs commands in breadth-first order.
The default traversal is depth-first.
Let's say we have two trees, tree1
and tree2
in a garden called my-garden
. These trees provide custom setup
, build
and teardown
commands.
Here is what happens with the default depth-first traversal -- all of the commands are run before visiting the next tree.
garden cmd my-garden setup build teardown
The commands are run in this order:
tree1:setup tree1:build tree1:teardown
tree2:setup tree2:build tree2:teardown
The new feature is that we can use the -b
option to enable the --breadth-first
traversal mode.
garden cmd -b my-garden setup build teardown
When in this mode the commands are run in this order:
tree1:setup tree2:setup
tree1:build tree2:build
tree1:teardown tree2:teardown
As before, if a tree doesn't define setup
or teardown
commands then they are skipped and are effectively no-ops.
The traversal modes seems like they should be sufficient for this use case so I've closed this issue as complete.
I haven't added separate commands_pre
or commands_post
features at this time since it seems like we won't strictly need them (especially alongside the breadth-first traversal mode) but I'm open to reconsidering and reopening this issue if it would simplify workflows.
Thanks for the sug, and let me know what you think.
In addition to the breadth-first opiton, I'm adding one last feature which will make this very convenient.
I'm adding a concept of "pre-commands" and "post-commands".
These are specified as the names of other commands to run before or after a named command.
For example:
commands:
custom-cmd: echo custom-cmd
custom-cmd<: before-cmd
custom-cmd>:
- after-cmd1
- after-cmd2
before-cmd: echo before
after-cmd1: echo after1
after-cmd2: echo after2
Running garden custom-cmd
will product the following output:
before
custom-cmd
after1
after2
The custom-cmd: echo custom-cmd
part is optional -- specifying just the custom-cmd<
pre-commands and/or custom-cmd>
post-commands is sufficient.
The values configured for cmd<
and cmd>
must be references to other named commands -- they are not commands themselves.
This is analogous to Makefile targets where one target can depend on another target.
Scenario:
Let's say you have 5 tree in a group thats part of a garden. The name of the command you want to run is call" "Build". So you make a global command. Perfect!
When you go to run that command over the garden you first need to install something. Then after all the trees a built you want to uninstall something.
Is that possible?
$ garden Build