go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/lucicfg/README.md (about)

     1  # LUCI Configuration Generator
     2  
     3  `lucicfg` is a tool for generating low-level LUCI configuration files based on a
     4  high-level configuration given as a [Starlark] script that uses APIs exposed by
     5  `lucicfg`. In other words, it takes a \*.star file (or files) as input and spits
     6  out a bunch of \*.cfg files (such us `cr-buildbucket.cfg` and
     7  `luci-scheduler.cfg`) as outputs.
     8  
     9  [Starlark]: https://github.com/google/starlark-go
    10  
    11  ## Overview of the design
    12  
    13  `lucicfg` follows a "microkernel" architecture. The kernel is implemented in Go.
    14  It provides a private interface (used internally by the lucicfg's Starlark
    15  standard library) by registering a bunch of builtins. The functionality provided
    16  by the kernel is pretty generic:
    17  
    18  *   A notion of Starlark packages, `load(...)` and `exec(...)` implementation.
    19  *   `lucicfg.var(...)` implementation.
    20  *   A node graph structure to carry the state across module boundaries.
    21  *   Support for traversing the node graph and emitting files to an output.
    22  *   Support for Protobuf messages.
    23  *   Implementation of `lucicfg generate` and `lucicfg validate` logic.
    24  *   Various utilities (regexp, hashes, Go templates, etc.)
    25  
    26  The builtins are wrapped in two layers of Starlark code:
    27  
    28    * [starlark/stdlib/internal], excluding `.../luci`: generic (not LUCI
    29      specific) Starlark standard library that documents and exposes the builtins
    30      via a nicer API. It can be used to build all kinds of config generators
    31      ([1], [2], [3]), as well as extend the LUCI config generator. This API
    32      surface is currently marked as "internal" (meaning there's no backward
    33      compatibility guarantees for it), but it will some day become a part of
    34      lucicfg's public interface, so it should be treated as such (no hacks, no
    35      undocumented functions, adequate test coverage, etc).
    36    * [starlark/stdlib/internal/luci]: all LUCI-specific APIs and declarations,
    37      implementing the logic of generating LUCI configs specifically. It is built
    38  
    39  The standard library and LUCI configs library are bundled with `lucicfg` binary
    40  via starlark/assets.gen.go file generated from the contents of
    41  [starlark/stdlib/internal] by `go generate`.
    42  
    43  [starlark/stdlib/internal]: ./starlark/stdlib/internal
    44  [starlark/stdlib/internal/luci]: ./starlark/stdlib/internal/luci
    45  [1]: https://chrome-internal.googlesource.com/infradata/config/+/refs/heads/main/starlark/common/lib
    46  [2]: https://chrome-internal.googlesource.com/infradata/k8s/+/refs/heads/main/starlark/lib
    47  [3]: https://chrome-internal.googlesource.com/infradata/gae/+/refs/heads/main/starlark/lib
    48  
    49  ## Making changes to the Starlark portion of the code
    50  
    51  1.  Modify a `*.star` file.
    52  2.  In the `lucicfg` directory, where this README.md file is, run
    53      `./fmt-lint.sh` to auto-format and lint new code. Fix all linter warnings.
    54  3.  In the same directory run `go generate ./...` to regenerate
    55      `examples/.../generated` and [doc/README.md].
    56  4.  Run `go test ./...` to verify existing tests pass. If your change modifies
    57      the format of emitted files you need to update the expected output in test
    58      case files. It will most likely happen for [testdata/full_example.star].
    59      Update `Expect configs:` section there.
    60  5.  If your change warrants a new test, add a file somewhere under [testdata/].
    61      See existing files there for examples. There are two kinds of tests:
    62      *   "Expectation style" tests. They have `Expect configs:` or `Expect errors
    63          like:` sections at the bottom. The test runner will execute the Starlark
    64          code and compare the produced output (or errors) to the expectations.
    65      *   More traditional unit tests that use `assert.eq(...)` etc. See
    66          [testdata/misc/version.star] for an example.
    67  6.  Once you are done with the change, evaluate whether you need to bump lucicfg
    68      version. See the section below.
    69  
    70  [doc/README.md]: ./doc/README.md
    71  [testdata/full_example.star]: ./testdata/full_example.star
    72  [testdata/]: ./testdata
    73  [testdata/misc/version.star]: ./testdata/misc/version.star
    74  
    75  ## Updating lucicfg version
    76  
    77  `lucicfg` uses a variant of semantic versioning to identify its own version and
    78  a version of the bundled Starlark libraries. The version string is set in
    79  [version.go] and looks like `MAJOR.MINOR.PATCH`.
    80  
    81  If a user script is relying on a feature which is available only in some recent
    82  lucicfg version, it can perform a check, like so:
    83  
    84  ```starlark
    85  lucicfg.check_version('1.7.8', 'Please update depot_tools')
    86  ```
    87  
    88  That way if the script is executed by an older lucicfg version, the user will
    89  get a nice actionable error message instead of some obscure stack trace.
    90  
    91  Thus it is **very important** to update [version.go] before releasing changes:
    92  
    93  *   Increment `PATCH` version when you make backward compatible changes. A
    94      change is backward compatible if it doesn't reduce Starlark API surface and
    95      doesn't affect lucicfg's emitted output (assuming inputs do not change). In
    96      particular, adding a new feature that doesn't affect existing features is
    97      backward compatible.
    98  *   Increment `MINOR` version when you make backward incompatible changes.
    99      Releasing such changes may require modifying user scripts or asking users to
   100      regenerate their configs to get an updated output. Note that both these
   101      things are painful, since there are dozens of repositories with lucicfg
   102      scripts and, strictly speaking, all of them should be eventually updated.
   103  *   `MAJOR` version is reserved for major architecture changes or rewrites.
   104  
   105  If your new feature is experimental and you don't want to commit to any backward
   106  compatibility promises, hide it behind an experiment. Users will need to opt-in
   107  to use it. See [starlark/stdlib/internal/experiments.star] for more info.
   108  
   109  [version.go]: ./version.go
   110  [starlark/stdlib/internal/experiments.star]: ./starlark/stdlib/internal/experiments.star
   111  
   112  ## Making a release
   113  
   114  1.  Land the code change. For concreteness sake let's assume it resulted in this
   115      [luci-go commit].
   116  2.  Wait until it is rolled into [infra.git]. The roll will look like this
   117      [infra.git commit]. Notice its git hash `86afde8bddae...`.
   118  3.  Wait until the [CIPD package builders] produce per-platform lucicfg
   119      [CIPD packages] tagged with infra.git's hash `git_revision:86afde8bddae...`.
   120      Like [this one].
   121  4.  Land a depot_tools CL to release the new version to developer workstations:
   122      1.  Modify [cipd_manifest.txt]: `infra/tools/luci/lucicfg/${platform}
   123          git_revision:86afde8bddae...`.
   124      2.  As instructed in the comments, regenerate cipd_manifest.versions: `cipd
   125          ensure-file-resolve -ensure-file cipd_manifest.txt`.
   126      3.  Send a CL [like this], describing in the commit message what's new.
   127  5.  Modify [cr-buildbucket/settings.cfg] like [so] to release the change to
   128      bots. This step is necessary since bots don't use depot_tools.
   129  
   130  Steps 2 and 3 usually take about 30 minutes total, and steps 4 and 5 verify
   131  CIPD packages actually exist. So in practice it is OK to just land a lucicfg
   132  CL, go do other things, then come back >30 min later, look up the revision of
   133  the necessary infra.git DEPS roll (or just use the latest one) and proceed to
   134  steps 4 and 5.
   135  
   136  [infra.git]: https://chromium.googlesource.com/infra/infra/
   137  [luci-go commit]: https://chromium.googlesource.com/infra/luci/luci-go.git/+/7ac4bfbe5a282766ea2e8afa5a6a06e8b71879f3
   138  [infra.git commit]: https://chromium.googlesource.com/infra/infra/+/86afde8bddaefce47381b7cc4638b36717803d3a
   139  [CIPD package builders]: https://ci.chromium.org/p/infra-internal/g/infra-packagers/console
   140  [CIPD packages]: https://chrome-infra-packages.appspot.com/p/infra/tools/luci/lucicfg
   141  [this one]: https://chrome-infra-packages.appspot.com/p/infra/tools/luci/lucicfg/linux-amd64/+/git_revision:86afde8bddaefce47381b7cc4638b36717803d3a
   142  [cipd_manifest.txt]: https://chromium.googlesource.com/chromium/tools/depot_tools/+/refs/heads/main/cipd_manifest.txt
   143  [like this]: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/2137983
   144  [cr-buildbucket/settings.cfg]: https://chrome-internal.googlesource.com/infradata/config/+/refs/heads/main/configs/cr-buildbucket/settings.cfg
   145  [so]: https://chrome-internal-review.googlesource.com/c/infradata/config/+/2849250