go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/lucicfg/starlark/stdlib/internal/luci/rules/gitiles_poller.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.gitiles_poller(...) rule.""" 16 17 load("@stdlib//internal/graph.star", "graph") 18 load("@stdlib//internal/lucicfg.star", "lucicfg") 19 load("@stdlib//internal/validate.star", "validate") 20 load("@stdlib//internal/luci/common.star", "keys", "triggerer") 21 22 def _gitiles_poller( 23 ctx, # @unused 24 *, 25 name = None, 26 bucket = None, 27 repo = None, 28 refs = None, 29 path_regexps = None, 30 path_regexps_exclude = None, 31 schedule = None, 32 triggers = None): 33 r"""Defines a gitiles poller which can trigger builders on git commits. 34 35 It periodically examines the state of watched refs in the git repository. On 36 each iteration it triggers builders if either: 37 38 * A watched ref's tip has changed since the last iteration (e.g. a new 39 commit landed on a ref). Each new detected commit results in a separate 40 triggering request, so if for example 10 new commits landed on a ref 41 since the last poll, 10 new triggering requests will be submitted to the 42 builders triggered by this poller. How they are converted to actual 43 builds depends on `triggering_policy` of a builder. For example, some 44 builders may want to have one build per commit, others don't care and 45 just want to test the latest commit. See luci.builder(...) and 46 scheduler.policy(...) for more details. 47 48 *** note 49 **Caveat**: When a large number of commits are pushed on the ref between 50 iterations of the poller, only the most recent 50 commits will result in 51 triggering requests. Everything older is silently ignored. This is a 52 safeguard against mistaken or deliberate but unusual git push actions, 53 which typically don't have the intent of triggering a build for each 54 such commit. 55 *** 56 57 * A ref belonging to the watched set has just been created. This produces 58 a single triggering request for the commit at the ref's tip. 59 This also applies right after a configuration change which instructs the 60 scheduler to watch a new ref. 61 62 Commits that trigger builders can also optionally be filtered by file paths 63 they touch. These conditions are specified via `path_regexps` and 64 `path_regexps_exclude` fields, each is a list of regular expressions against 65 Unix file paths relative to the repository root. A file is considered 66 "touched" if it is either added, modified, removed, moved (both old and new 67 paths are considered "touched"), or its metadata has changed (e.g. 68 `chmod +x`). 69 70 A triggering request is emitted for a commit if only if at least one touched 71 file is *not* matched by any `path_regexps_exclude` *and* simultaneously 72 matched by some `path_regexps`, subject to following caveats: 73 74 * `path_regexps = [".+"]` will *not* match commits which modify no files 75 (aka empty commits) and as such this situation differs from the default 76 case of not specifying any `path_regexps`. 77 * As mentioned above, if a ref fast-forwards >=50 commits, only the last 78 50 commits are checked. The rest are ignored. 79 80 A luci.gitiles_poller(...) with some particular name can be redeclared many 81 times as long as all fields in all declaration are identical. This is 82 helpful when luci.gitiles_poller(...) is used inside a helper function that 83 at once declares a builder and a poller that triggers this builder. 84 85 Args: 86 ctx: the implicit rule context, see lucicfg.rule(...). 87 name: name of the poller, to refer to it from other rules. Required. 88 bucket: a bucket the poller is in, see luci.bucket(...) rule. Required. 89 repo: URL of a git repository to poll, starting with `https://`. Required. 90 refs: a list of regular expressions that define the watched set of refs, 91 e.g. `refs/heads/[^/]+` or `refs/branch-heads/\d+\.\d+`. The regular 92 expression should have a literal prefix with at least two slashes 93 present, e.g. `refs/release-\d+/foobar` is *not allowed*, because the 94 literal prefix `refs/release-` contains only one slash. The regexp 95 should not start with `^` or end with `$` as they will be added 96 automatically. Each supplied regexp must match at least one ref in the 97 gitiles output, e.g. specifying `refs/tags/v.+` for a repo that doesn't 98 have tags starting with `v` causes a runtime error. If empty, defaults 99 to `['refs/heads/main']`. 100 path_regexps: a list of regexps that define a set of files to watch for 101 changes. `^` and `$` are implied and should not be specified manually. 102 See the explanation above for all details. 103 path_regexps_exclude: a list of regexps that define a set of files to 104 *ignore* when watching for changes. `^` and `$` are implied and should 105 not be specified manually. See the explanation above for all details. 106 schedule: string with a schedule that describes when to run one iteration 107 of the poller. See [Defining cron schedules](#schedules-doc) for the 108 expected format of this field. Note that it is rare to use custom 109 schedules for pollers. By default, the poller will run each 30 sec. 110 triggers: builders to trigger whenever the poller detects a new git commit 111 on any ref in the watched ref set. 112 """ 113 name = validate.string("name", name) 114 bucket_key = keys.bucket(bucket) 115 116 refs = validate.list("refs", refs) or ["refs/heads/main"] 117 for r in refs: 118 validate.string("refs", r) 119 120 path_regexps = validate.list("path_regexps", path_regexps) 121 for p in path_regexps: 122 validate.string("path_regexps", p) 123 124 path_regexps_exclude = validate.list("path_regexps_exclude", path_regexps_exclude) 125 for p in path_regexps_exclude: 126 validate.string("path_regexps_exclude", p) 127 128 # Node that carries the full definition of the poller. 129 poller_key = keys.gitiles_poller(bucket_key.id, name) 130 graph.add_node(poller_key, idempotent = True, props = { 131 "name": name, 132 "bucket": bucket_key.id, 133 "realm": bucket_key.id, 134 "repo": validate.repo_url("repo", repo), 135 "refs": refs, 136 "path_regexps": path_regexps, 137 "path_regexps_exclude": path_regexps_exclude, 138 "schedule": validate.string("schedule", schedule, required = False), 139 }) 140 graph.add_edge(bucket_key, poller_key) 141 142 # Setup nodes that indicate this poller can be referenced in 'triggered_by' 143 # relations (either via its bucket-scoped name or via its global name). 144 triggerer_key = triggerer.add(poller_key, idempotent = True) 145 146 # Link to builders triggered by this builder. 147 for t in validate.list("triggers", triggers): 148 graph.add_edge( 149 parent = triggerer_key, 150 child = keys.builder_ref(t), 151 title = "triggers", 152 ) 153 154 return graph.keyset(poller_key, triggerer_key) 155 156 gitiles_poller = lucicfg.rule(impl = _gitiles_poller)