These rules provide a simple interface for running multiple commands in
parallel with a single bazel run invocation. This is especially useful
for running multiple linters or formatters with a single command.
Setup the tools you want to run:
load("@rules_multirun//:defs.bzl", "command", "multirun")
load("@rules_python//python:defs.bzl", "py_binary")
sh_binary(
name = "some_linter",
...
)
py_binary(
name = "some_other_linter",
...
)
command(
name = "lint-something",
command = ":some_linter",
arguments = ["check"], # Optional arguments passed directly to the tool
)
command(
name = "lint-something-else",
command = ":some_other_linter",
environment = {"CHECK": "true"}, # Optional environment variables set when invoking the command
data = ["..."] # Optional runtime data dependencies
)
multirun(
name = "lint",
commands = [
"lint-something",
"lint-something-else",
],
jobs = 0, # Set to 0 to run in parallel, defaults to sequential
)Run the multirun target with bazel:
$ bazel run //:lintSet ibazel_notify_changes on multirun to compose long-lived commands while
preserving the incremental build protocol used by targets such as
js_run_devserver:
load("@rules_multirun//:defs.bzl", "multirun")
multirun(
name = "dev",
commands = [
":admin_devserver",
":frontend_devserver",
],
ibazel_notify_changes = True,
)Run it with ibazel run //:dev. Commands tagged ibazel_notify_changes
receive build notifications on stdin and remain alive across rebuilds. Commands
that cannot consume the protocol can instead use affected-target restarts:
load("@rules_multirun//:defs.bzl", "command", "multirun")
command(
name = "backend_dev",
command = ":backend",
)
multirun(
name = "dev",
commands = [
":frontend_devserver",
":backend_dev",
],
ibazel_notify_changes = True,
ibazel_restart_affected_commands = True,
)After each successful structured build event, multirun restarts only commands
whose Bazel labels iBazel reports as affected. The initial build does not restart
commands. If iBazel cannot completely attribute a change, multirun safely
restarts every non-notification command. No path routing is configured in the
BUILD file.
Set ibazel_defer_non_notification_commands when user-visible commands must not
start before iBazel finishes its initial watch-discovery catch-up build:
multirun(
name = "dev",
commands = [
":frontend_devserver",
":backend_dev",
":desktop_app",
],
ibazel_defer_non_notification_commands = True,
ibazel_notify_changes = True,
ibazel_restart_affected_commands = True,
)Notification-capable commands start immediately. Other commands start after the first successful structured build event, so an initial live reload can finish before a desktop app or browser becomes visible. Failed initial builds keep the deferred commands stopped.
Commands that only advertise ibazel_notify_changes receive the legacy
protocol. Commands that advertise ibazel_notify_changes_v1 additionally
receive structured IBAZEL_EVENT messages containing changed files. Selective
restarts require structured version 1 events with affected-target attribution.
See the full API docs for more info.
In case if the multirun rule requires a transition to other configuration than target then
a new multirun-like rule can be defined as in the following example
load("@rules_multirun//:defs.bzl", "multirun_with_transition")
def _aws_deploy_platforms_impl(settings, attr):
return {"//command_line_option:platforms": [":aws_lambda"]}
aws_deploy_transition = transition(
implementation = _aws_deploy_platforms_impl,
inputs = [],
outputs = ["//command_line_option:platforms"],
)
aws_deploy = multirun_with_transition(
aws_deploy_transition,
"@bazel_tools//tools/allowlists/function_transition_allowlist"
)and used in a BUILD file
aws_deploy(
name = "staging",
commands = [
...
]
)Go to the releases page to grab the WORKSPACE snippet for the latest release.
This is a fork of the original multirun rules. Those rules have a dependency on golang to run, which may not be desired, these rules use a python script instead.