Skip to content

docs: document some of our project styles/conventions #2816

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Apr 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true

# Set default charset
[*]
charset = utf-8

# Line width
[*]
max_line_length = 100

# 4 space indentation
[*.{py,bzl}]
indent_style = space
indent_size = 4
49 changes: 49 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,55 @@ The `legacy_foo` arg was removed
:::
```

## Style and idioms

For the most part, we just accept whatever the code formatters do, so there
isn't much style to enforce.

Some miscellanous style, idioms, and conventions we have are:

### Markdown/Sphinx Style

* Use colons for prose sections of text, e.g. `:::{note}`, not backticks.
* Use backticks for code blocks.
* Max line length: 100.

### BUILD/bzl Style

* When a macro generates public targets, use a dot (`.`) to separate the
user-provided name from the generted name. e.g. `foo(name="x")` generates
`x.test`. The `.` is our convention to communicate that it's a generated
target, and thus one should look for `name="x"` when searching for the
definition.
* The different build phases shouldn't load code that defines objects that
aren't valid for their phase. e.g.
* The bzlmod phase shouldn't load code defining regular rules or providers.
* The repository phase shouldn't load code defining module extensions, regular
rules, or providers.
* The loading phase shouldn't load code defining module extensions or
repository rules.
* Loading utility libraries or generic code is OK, but should strive to load
code that is usable for its phase. e.g. loading-phase code shouldn't
load utility code that is predominately only usable to the bzlmod phase.
* Providers should be in their own files. This allows implementing a custom rule
that implements the provider without loading a specific implementation.
* One rule per file is preferred, but not required. The goal is that defining an
e.g. library shouldn't incur loading all the code for binaries, tests,
packaging, etc; things that may be niche or uncommonly used.
* Separate files should be used to expose public APIs. This ensures our public
API is well defined and prevents accidentally exposing a package-private
symbol as a public symbol.

:::{note}
The public API file's docstring becomes part of the user-facing docs. That
file's docstring must be used for module-level API documentation.
:::
* Repository rules should have name ending in `_repo`. This helps distinguish
them from regular rules.
* Each bzlmod extension, the "X" of `use_repo("//foo:foo.bzl", "X")` should be
in its own file. The path given in the `use_repo()` expression is the identity
Bazel uses and cannot be changed.

## Generated files

Some checked-in files are generated and need to be updated when a new PR is
Expand Down