trigger: glob description: Starlark Language, Macro, and Testing Invariants globs: “.bzl,BUILD,BUILD.bazel,.bazel”

Starlark Language & Macro Invariants

Macro Target Canonicalization

  • In macro implementations, internal repository target references MUST be canonicalized using str(Label("//path/to:target")) so they resolve in the macro‘s module context rather than the caller’s repository context.
  • Note that python/private/common_labels.bzl defines labels, a struct containing common canonicalized label strings used across the project.

Manual Tag on Internal Macro Helper Targets

  • When macros instantiate internal helper targets (such as private rule targets for artifact extraction or linking support), always include tags = ["manual"].
  • Why: This prevents internal helper targets from being implicitly built when wildcard target patterns (e.g., //...) are expanded.

Private Alias Pattern when Appending to User deps

  • When macros append internal helper targets to user-provided dependency lists (deps), use private alias targets (e.g. //python/private/cc:current_py_cc_headers_private_alias) to prevent “duplicate dependency label” analysis errors if the user also explicitly passes the public target label in their deps (including in select() expressions).

Attribute Normalization at Function Entry

  • Always normalize input list attributes at the start of macro definitions (e.g., deps = deps or [], copts = copts or []).
  • Why: This avoids inlining the normalization as part of a complex expression later in the macro expansion.

native.test_suite API

  • Don't forward target tags to native.test_suite; tags on test suites filter tests instead of setting target execution behavior.

Control Flow & Algorithmic Restrictions

  • Iterative Algorithms Only (No Recursion): Starlark does not support recursive function calls; always implement iterative algorithms using bounded loops.
  • Iterable for Loops Only (No while Loops): Starlark does not support while loops; iterate over fixed-size ranges or explicit collections.

Depset Element Invariants & Optimizations

  • Providers over Structs for Depset Elements: Use provider() (without -Info suffix, e.g. *Fileset) instead of struct() for composite objects in depsets; providers perform key sharing and reduce memory overhead.
  • Depset Element Immutability: All depset elements and nested provider fields must be immutable when depset() is called (eager check before rule freeze). Use tuple[T] or depset[T] in providers placed into depsets; do not use mutable list[T].

Code Style & Conventions

  • Dict union (|): Use | instead of dicts.add(...) from @bazel_skylib//lib:dicts.bzl when merging dictionaries.
  • Non-Info Provider Naming: Add # buildifier: disable=name-conventions above provider() declarations that do not end in Info (e.g. *Fileset).
  • Docstring Formatting Invariants: Use triple-quoted strings for multi-line docstrings without trailing backslashes (\) for line continuation.
  • No Bazel Copyright Headers: Do not add Bazel copyright headers to new or existing files unless explicitly directed by the user.
  • Line Length & Wrapping: Wrap Markdown and Starlark lines to 80 columns in accordance with .editorconfig.

Starlark Testing (rules_testing)

  • rules_testing over bazel_skylib: Always use @rules_testing (analysis tests with env.expect.that_...) rather than bazel_skylib for Starlark rule analysis tests.
  • Analysis Test Two-Part Structure: Separate tests into a setup target function def _test_foo(name) calling analysis_test and an implementation function def _test_foo_impl(env, target).
  • Test Suite Registration: Collect test setup functions in a private _tests list and register them cleanly via test_suite(name = name, tests = _tests).