chromium/infra/config/generators/cq-usage.star

# Copyright 2021 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Generator to output information about blocking CQ builders.

This generator copies commit-queue.cfg, removing builders that are experimental
or includable_only and removing other fields that don't impact when the CQ is
triggered or what the CQ triggers. The resultant file is output as
cq-usage/default.cfg. This enables applying limited owners for changes that
would impact the CQ for all users.
"""

load("@stdlib//internal/luci/proto.star", "cq_pb")
load("//lib/try.star", "location_filters_without_defaults")
load("//subprojects/chromium/fallback-cq.star", "fallback_cq")

def _remove_none(l):
    return [e for e in l if e != None]

def _trim_builder(builder, include_path_based):
    if builder.includable_only or builder.experiment_percentage:
        return None

    if builder.mode_allowlist and "FULL_RUN" not in builder.mode_allowlist:
        return None

    # The majority of CQ builders will exclude something because we don't
    # trigger most builders on changes to non-code directories (e.g. docs), so
    # only consider them path-based if they have an include filter
    if not include_path_based and location_filters_without_defaults(builder):
        return None
    trimmed = cq_pb.Verifiers.Tryjob.Builder(
        name = builder.name,
        disable_reuse = builder.disable_reuse,
    )
    if include_path_based:
        trimmed.location_filters = builder.location_filters
    return trimmed

def _trim_tryjob(tryjob, include_path_based):
    builders = _remove_none([_trim_builder(b, include_path_based) for b in tryjob.builders])
    if not builders:
        return None
    tryjob = proto.clone(tryjob)
    tryjob.builders = builders
    return tryjob

def _trim_verifiers(verifiers, include_path_based):
    if not proto.has(verifiers, "tryjob"):
        return None
    tryjob = _trim_tryjob(verifiers.tryjob, include_path_based)
    if not tryjob:
        return None
    return cq_pb.Verifiers(tryjob = tryjob)

def _trim_config_group(config_group, include_path_based):
    verifiers = _trim_verifiers(config_group.verifiers, include_path_based)
    if not verifiers:
        return None
    return cq_pb.ConfigGroup(
        name = config_group.name,
        verifiers = verifiers,
        gerrit = config_group.gerrit,
    )

def _generate_cq_usage(ctx):
    cfg = ctx.output["luci/commit-queue.cfg"]
    ctx.output["cq-usage/default.cfg"] = cq_pb.Config(config_groups = _remove_none(
        [
            _trim_config_group(g, include_path_based = False)
            for g in cfg.config_groups
            if g.name != fallback_cq.GROUP
        ],
    ))
    ctx.output["cq-usage/full.cfg"] = cq_pb.Config(config_groups = _remove_none(
        [
            _trim_config_group(g, include_path_based = True)
            for g in cfg.config_groups
            if g.name != fallback_cq.GROUP
        ],
    ))

lucicfg.generator(_generate_cq_usage)