Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.aspect.build/llms.txt

Use this file to discover all available pages before exploring further.

Bazel emits a stream of structured events during every build — target outcomes, test results, output file paths, timing, and more. AXL tasks can subscribe to this stream and act on individual events as they arrive. Create an iterator with bazel.build_events.iterator(), pass it to ctx.bazel.build() (or ctx.bazel.test()) via the build_events parameter, and then iterate the handle with for event in events:. Events are delivered synchronously (Starlark is single-threaded), so the iterator blocks until the next event is ready and unblocks when the build finishes. Each event has a kind string that identifies the event type, and a payload whose fields depend on that kind. The full set of event kinds and payload types is defined in Bazel’s Build Event Stream protocol.
Build Event Stream reference

Collecting output files

A common use case is collecting the output files that Bazel produced. Files arrive in named_set_of_files events:
def impl(ctx: TaskContext) -> int:
    events = bazel.build_events.iterator()
    build = ctx.bazel.build(
        build_events = [events],
        *ctx.args.target_pattern,
    )

    outputs = []
    for event in events:
        if event.kind == "named_set_of_files":
            for f in event.payload.files:
                outputs.append(f.name)

    status = build.wait()
    if status.code == 0:
        for name in outputs:
            ctx.std.io.stdout.write(name + "\n")
    return status.code

list_outputs = task(
    implementation = impl,
    args = {
        "target_pattern": args.positional(default = ["..."], maximum = 512),
    },
)
The File payload exposes name, digest, length, and path_prefix directly. The URI is wrapped in a file oneof (uri, contents, or symlink_target_path) — most consumers want name, which is the file’s logical identifier (for example bazel-bin/path/to/target.out).

Filtering by event kind

To skip irrelevant events, pass kinds= to iterator(). Only the listed event kinds are delivered:
events = bazel.build_events.iterator(kinds = ["test_result", "build_finished"])

Reacting to test results

test_result events fire once per test target. The label of the test target is on the event’s id, and the status comes from the payload:
events = bazel.build_events.iterator(kinds = ["test_result"])
build = ctx.bazel.test(build_events = [events], "//...")

for event in events:
    label = event.id.test_result.label
    passed = event.payload.status == "PASSED"
    ctx.std.io.stdout.write("{}: {}\n".format(label, "PASS" if passed else "FAIL"))
See the test_result payload reference for the full list of fields.