go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/lucicfg/starlark/stdlib/internal/experiments.star (about)

     1  # Copyright 2020 The LUCI Authors.
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #      http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  
    15  """Internal API for registering and checking experiments."""
    16  
    17  load("@stdlib//internal/strutil.star", "strutil")
    18  
    19  def _register(experiment_id, enable_on_min_version = None):
    20      """Register an experiment with the given ID.
    21  
    22      This ID becomes a valid target for lucicfg.enable_experiment(...) call.
    23      Returns an object that can be used to check whether the experiment was
    24      enabled. It is fine and even recommended to register the experiments during
    25      the module loading time:
    26  
    27      ```python
    28      load('@stdlib//internal/experiments.star', 'experiments')
    29      new_cool_feature_experiment = experiments.register('new_cool_feature')
    30  
    31      ...
    32  
    33      def something(...):
    34          new_cool_feature_experiment.require()
    35      ```
    36  
    37      Registering the same experiment ID multiple times is fine, it results in the
    38      exact same experiment.
    39  
    40      Args:
    41        experiment_id: an ID of the experiment to register. Required.
    42        enable_on_min_version: if present, should be a lucicfg version string (as
    43          `major.minor.revision`) indicating when to auto-enable this experiment:
    44          calling lucicfg.check_version(...) with some version `X` will implicitly
    45          enable all experiments with `enable_on_min_version >= X`. Experiments
    46          that don't have `enable_on_min_version` can only be enabled explicitly
    47          via lucicfg.enable_experiment(...). Be careful when using this
    48          mechanism. Once an experiment gated by a min lucicfg version is
    49          released, it is not really an experiment anymore, but a stable (albeit
    50          non-default) functionality. It must remain backward compatible. Projects
    51          that opt-in into it using lucicfg.check_version(...) don't expect the
    52          generated files to change if a newer lucicfg version is released. If you
    53          need to change an already released auto-enabled experiment, you'll need
    54          to create a new experiment that "mutates" the behavior of the old one,
    55          and gets auto-enabled in a newer lucicfg version.
    56  
    57      Returns:
    58        A struct with methods `require()` and `is_enabled()`:
    59          `is_enabled()` returns True if the experiment is enabled.
    60          `require()` fails the execution if the experiment is not enabled.
    61      """
    62      min_ver = ()
    63      if enable_on_min_version != None:
    64          min_ver = strutil.parse_version(enable_on_min_version)
    65      __native__.register_experiment(experiment_id, min_ver)
    66      return struct(
    67          is_enabled = lambda: _is_enabled(experiment_id),
    68          require = lambda: _require(experiment_id),
    69      )
    70  
    71  def _require(experiment_id):
    72      """Fails the execution if the given experiment ID is not enabled.
    73  
    74      Args:
    75        experiment_id: a string with the ID of the experiment to check.
    76      """
    77      if not _is_enabled(experiment_id):
    78          fail(
    79              "This feature requires enabling the experiment %r.\n" % experiment_id +
    80              "To enable it, add this line somewhere early in your script:\n" +
    81              "  lucicfg.enable_experiment(%r)\n" % experiment_id +
    82              "Note that using experimental features comes with zero guarantees. " +
    83              "See the doc for lucicfg.enable_experiment(...) for more information",
    84          )
    85  
    86  def _is_enabled(experiment_id):
    87      """Returns True if the experiment was enabled."""
    88      return __native__.is_experiment_enabled(experiment_id)
    89  
    90  experiments = struct(
    91      register = _register,
    92  )