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

     1  # Copyright 2019 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  """Defines luci.notifier(...) rule."""
    16  
    17  load("@stdlib//internal/lucicfg.star", "lucicfg")
    18  load("@stdlib//internal/validate.star", "validate")
    19  load("@stdlib//internal/luci/common.star", "notifiable")
    20  load("@proto//go.chromium.org/luci/buildbucket/proto/common.proto", buildbucket_common_pb = "buildbucket.v2")
    21  
    22  def _notifier(
    23          ctx,  # @unused
    24          *,
    25          name = None,
    26  
    27          # Conditions.
    28          on_occurrence = None,
    29          on_new_status = None,
    30  
    31          # Step filters.
    32          failed_step_regexp = None,
    33          failed_step_regexp_exclude = None,
    34  
    35          # Deprecated conditions.
    36          on_failure = None,
    37          on_new_failure = None,
    38          on_status_change = None,
    39          on_success = None,
    40  
    41          # Who to notify.
    42          notify_emails = None,
    43          notify_rotation_urls = None,
    44          notify_blamelist = None,
    45  
    46          # Tweaks.
    47          blamelist_repos_whitelist = None,
    48          template = None,
    49  
    50          # Relations.
    51          notified_by = None):
    52      """Defines a notifier that sends notifications on events from builders.
    53  
    54      A notifier contains a set of conditions specifying what events are
    55      considered interesting (e.g. a previously green builder has failed), and a
    56      set of recipients to notify when an interesting event happens. The
    57      conditions are specified via `on_*` fields, and recipients are specified
    58      via `notify_*` fields.
    59  
    60      The set of builders that are being observed is defined through `notified_by`
    61      field here or `notifies` field in luci.builder(...). Whenever a build
    62      finishes, the builder "notifies" all luci.notifier(...) objects subscribed
    63      to it, and in turn each notifier filters and forwards this event to
    64      corresponding recipients.
    65  
    66      Note that luci.notifier(...) and luci.tree_closer(...) are both flavors of
    67      a `luci.notifiable` object, i.e. both are something that "can be notified"
    68      when a build finishes. They both are valid targets for `notifies` field in
    69      luci.builder(...). For that reason they share the same namespace, i.e. it is
    70      not allowed to have a luci.notifier(...) and a luci.tree_closer(...) with
    71      the same name.
    72  
    73      Args:
    74        ctx: the implicit rule context, see lucicfg.rule(...).
    75  
    76        name: name of this notifier to reference it from other rules. Required.
    77  
    78        on_occurrence: a list specifying which build statuses to notify for.
    79          Notifies for every build status specified. Valid values are string
    80          literals `SUCCESS`, `FAILURE`, and `INFRA_FAILURE`. Default is None.
    81        on_new_status: a list specifying which new build statuses to notify for.
    82          Notifies for each build status specified unless the previous build
    83          was the same status. Valid values are string literals `SUCCESS`,
    84          `FAILURE`, and `INFRA_FAILURE`. Default is None.
    85        on_failure: Deprecated. Please use `on_new_status` or `on_occurrence`
    86          instead. If True, notify on each build failure. Ignores transient (aka
    87          "infra") failures. Default is False.
    88        on_new_failure: Deprecated. Please use `on_new_status` or `on_occurrence`
    89          instead. If True, notify on a build failure unless the previous build
    90          was a failure too. Ignores transient (aka "infra") failures. Default
    91          is False.
    92        on_status_change: Deprecated. Please use `on_new_status` or
    93          `on_occurrence` instead. If True, notify on each change to a build
    94          status (e.g. a green build becoming red and vice versa). Default is
    95          False.
    96        on_success: Deprecated. Please use `on_new_status` or `on_occurrence`
    97          instead. If True, notify on each build success. Default is False.
    98  
    99        failed_step_regexp: an optional regex or list of regexes, which is matched
   100          against the names of failed steps. Only build failures containing
   101          failed steps matching this regex will cause a notification to be sent.
   102          Mutually exclusive with `on_new_status`.
   103        failed_step_regexp_exclude: an optional regex or list of regexes, which
   104          has the same function as `failed_step_regexp`, but negated - this regex
   105          must *not* match any failed steps for a notification to be sent.
   106          Mutually exclusive with `on_new_status`.
   107  
   108        notify_emails: an optional list of emails to send notifications to.
   109        notify_rotation_urls: an optional list of URLs from which to fetch
   110          rotation members. For each URL, an email will be sent to the currently
   111          active member of that rotation. The URL must contain a JSON object, with
   112          a field named 'emails' containing a list of email address strings.
   113        notify_blamelist: if True, send notifications to everyone in the computed
   114          blamelist for the build. Works only if the builder has a repository
   115          associated with it, see `repo` field in luci.builder(...). Default is
   116          False.
   117  
   118        blamelist_repos_whitelist: an optional list of repository URLs (e.g.
   119          `https://host/repo`) to restrict the blamelist calculation to. If empty
   120          (default), only the primary repository associated with the builder is
   121          considered, see `repo` field in luci.builder(...).
   122        template: a luci.notifier_template(...) to use to format notification
   123          emails. If not specified, and a template `default` is defined in the
   124          project somewhere, it is used implicitly by the notifier.
   125  
   126        notified_by: builders to receive status notifications from. This relation
   127          can also be defined via `notifies` field in luci.builder(...).
   128      """
   129      name = validate.string("name", name)
   130  
   131      on_occurrence = _buildbucket_status_validate(validate.list("on_occurrence", on_occurrence))
   132      on_new_status = _buildbucket_status_validate(validate.list("on_new_status", on_new_status))
   133  
   134      # deprecated
   135      on_failure = validate.bool("on_failure", on_failure, required = False)
   136      on_new_failure = validate.bool("on_new_failure", on_new_failure, required = False)
   137      on_status_change = validate.bool("on_status_change", on_status_change, required = False)
   138      on_success = validate.bool("on_success", on_success, required = False)
   139  
   140      failed_step_regexp = validate.regex_list("failed_step_regexp", failed_step_regexp)
   141      failed_step_regexp_exclude = validate.regex_list("failed_step_regexp_exclude", failed_step_regexp_exclude)
   142  
   143      if (failed_step_regexp or failed_step_regexp_exclude) and (on_new_status or on_new_failure or on_status_change):
   144          fail("failed step regexes cannot be used in combination with status change predicates")
   145  
   146      if not (on_failure or on_new_failure or on_status_change or on_success or on_occurrence or on_new_status):
   147          fail("at least one on_... condition is required")
   148  
   149      notify_emails = validate.list("notify_emails", notify_emails)
   150      for e in notify_emails:
   151          validate.string("notify_emails", e)
   152  
   153      notify_rotation_urls = validate.list(
   154          "notify_rotation_urls",
   155          notify_rotation_urls,
   156          required = False,
   157      )
   158      for r in notify_rotation_urls:
   159          validate.string("notify_rotation_urls", r)
   160  
   161      notify_blamelist = validate.bool("notify_blamelist", notify_blamelist, required = False)
   162      blamelist_repos_whitelist = validate.list("blamelist_repos_whitelist", blamelist_repos_whitelist)
   163      for repo in blamelist_repos_whitelist:
   164          validate.repo_url("blamelist_repos_whitelist", repo)
   165      if blamelist_repos_whitelist and not notify_blamelist:
   166          fail("blamelist_repos_whitelist requires notify_blamelist to be True")
   167  
   168      return notifiable.add(
   169          name = name,
   170          props = {
   171              "name": name,
   172              "kind": "luci.notifier",
   173              "on_occurrence": on_occurrence,
   174              "on_new_status": on_new_status,
   175              "on_failure": on_failure,
   176              "on_new_failure": on_new_failure,
   177              "on_status_change": on_status_change,
   178              "on_success": on_success,
   179              "failed_step_regexp": failed_step_regexp,
   180              "failed_step_regexp_exclude": failed_step_regexp_exclude,
   181              "notify_emails": notify_emails,
   182              "notify_rotation_urls": notify_rotation_urls,
   183              "notify_blamelist": notify_blamelist,
   184              "blamelist_repos_whitelist": blamelist_repos_whitelist,
   185          },
   186          template = template,
   187          notified_by = notified_by,
   188      )
   189  
   190  def _buildbucket_status_validate(status_list):
   191      """Validates a list of buildbucket statuses.
   192  
   193      Args:
   194        status_list: a list of status strings; i.e. "SUCCESS" or "FAILURE"
   195  
   196      Returns:
   197        A list of the enum identifiers corresponding to the given statuses.
   198      """
   199      for status in status_list:
   200          if not hasattr(buildbucket_common_pb, status):
   201              fail("%s is not a valid status. Try one of the following %s." %
   202                   (status, str(dir(buildbucket_common_pb))))
   203  
   204      return [getattr(buildbucket_common_pb, status) for status in status_list]
   205  
   206  notifier = lucicfg.rule(impl = _notifier)