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)