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)