Try Fuzzy: A Try Syntax Alternative
It’s no secret that I’m not a fan of try syntax, it’s a topic I’ve blogged about on several occasions before. Today, I’m pleased to announce that there’s a real alternative now landed on mozilla-central. It works on all platforms with mercurial and git. For those who just like to dive in:
$ mach mercurial-setup --update # only if using hg
$ mach try fuzzy
This will prompt you to install fzf. After bootstrapping is finished, you’ll enter an interface populated with a list of all possible taskcluster tasks. Start typing and the list will be filtered down using a fuzzy matching algorithm. I won’t go into details on how to use this tool in this blog post, for that see:
$ mach try fuzzy --help # or
$ man fzf
For who prefer to look before you leap, I’ve recorded a demo:
Like the existing mach try
command, this should work with mercurial via the push-to-try
extension or git via git-cinnabar
. If you encounter any problems or bad UX, please file a bug
under Testing :: General.
Try Task Config
The following section is all about the implementation details, so if you’re curious or want to write your own tools for selecting tasks on try, read on!
This new try selector is not based on try syntax. Instead it’s using a brand new scheduling
mechanism called try task config. Instead of encoding scheduling information in the commit
message, mach try fuzzy
encodes it in a JSON file at the root of the tree called
try_task_config.json
. Very simply (for now), the decision task knows to look for that file on try.
If found, it will read the JSON object and schedule every task label it finds. There are also hooks
to prevent this file from accidentally being landed on non-try branches.
What this means is that anything that can generate a list (or dict) of task labels can be a try selector. This new JSON format is much easier for tools to write, and for taskgraph to read.
Creating a Try Selector
There are currently two ways to schedule tasks on try (syntax and fuzzy). But I envision 4-5 different
methods in the future. For example, we might implement a TestResolver
based try selector which
given a path can determine all affected jobs. Or there could be one that uses globbing/regex to
filter down the task list which would be useful for saving “presets”. Or there could be one that
uses a curses UI like the hg trychooser
extension.
To manage all this, each try selector is implemented as an @SubCommand
of mach try
. The regular
syntax selector, is implemented under mach try syntax
now (though mach try
without any
subcommand will dispatch to syntax to maintain backwards compatibility). All this lives in a newly
created tryselect module.
If you have want to create a new try selector, you’ll need two things:
- A list of task labels as input.
- The ability to write those labels to
try_task_config.json
and push it to try.
Luckily tryselect provides both those things. The first, can be obtained using the tasks.py
module. It basically does the equivalent of running mach taskgraph target
, but will also
automatically cache the resulting task list so future invocations run much quicker.
The second can be achieved using the vcs.py module. This uses the same approach that the old
syntax selector has been using all along. It will commit try_task_config.json
temporarily and
then remove all traces of the commit (and of try_task_config.json
).
So to recap, creating a new try selector involves:
- Add an
@SubCommand
to the mach_commands.py, which dispatches to a file under the selectors directory. - Generate a list of tasks using tasks.py.
- Somehow filter down that list (this part is up to you)
- Push the filtered list using vcs.py
You can inspect the fuzzy implementation to see how all this ties together.
Future Considerations
Right now, the try_task_config.json
method only allows specifying a list of task labels. This is
good enough to say what is running, but not how it should run. In the future, we could expand
this to be a dict where task labels make up the keys. The values would be extra task metadata that
the taskgraph module would know how to apply to the relevant tasks.
With this scheme, we could do all sorts of crazy things like set prefs/env/arguments directly from a try selector specialized to deal with those things. There are no current plans to implement any of this, but it would definitely be a cool ability to have!