| #!/usr/bin/env lucicfg |
| |
| lucicfg.check_version("1.35.3", "Please update depot_tools") |
| |
| lucicfg.config( |
| config_dir = "generated", |
| tracked_files = ["*.cfg"], |
| fail_on_warnings = True, |
| lint_checks = ["default", "-module-docstring"], |
| ) |
| |
| luci.project( |
| name = "golang", |
| buildbucket = "cr-buildbucket.appspot.com", |
| logdog = "luci-logdog.appspot.com", |
| milo = "luci-milo.appspot.com", |
| notify = "luci-notify.appspot.com", |
| scheduler = "luci-scheduler.appspot.com", |
| swarming = "chromium-swarm.appspot.com", |
| tricium = "tricium-prod.appspot.com", |
| bindings = [ |
| # Admin permissions. |
| luci.binding( |
| roles = [ |
| # Allow owners to submit any task in any pool. |
| "role/swarming.poolOwner", |
| "role/swarming.poolUser", |
| "role/swarming.poolViewer", |
| "role/swarming.taskTriggerer", |
| # Allow owners to trigger and cancel LUCI Scheduler jobs. |
| "role/scheduler.owner", |
| # Allow owners to trigger and cancel any build. |
| "role/buildbucket.owner", |
| # Allow owners to read/validate/reimport the project configs. |
| "role/configs.developer", |
| |
| # Allow owners to create/edit ResultDB invocations (for local result_adapter development). |
| # TODO(dmitshur): Remove or move to AOD after it stops being actively used. |
| "role/resultdb.invocationCreator", |
| ], |
| groups = "mdb/golang-luci-admin", |
| ), |
| |
| # Allow task service accounts to spawn builds. |
| luci.binding( |
| roles = "role/buildbucket.triggerer", |
| users = [ |
| "tricium-prod@appspot.gserviceaccount.com", |
| "coordinator-builder@golang-ci-luci.iam.gserviceaccount.com", |
| "security-coordinator-builder@golang-ci-luci.iam.gserviceaccount.com", |
| ], |
| ), |
| |
| # Allow task service accounts to validate configurations. |
| # |
| # This is fine, since all our configurations for this project (even for internal |
| # builders) are public. |
| luci.binding( |
| roles = "role/configs.validator", |
| users = [ |
| "public-worker-builder@golang-ci-luci.iam.gserviceaccount.com", |
| ], |
| ), |
| |
| # luci-analysis permissions. |
| # |
| # Note on security: this appears to open up reading luci-analysis to everyone |
| # for the entire project, but access to test results and cluster definitions |
| # (test names and failure reasons) is gated by access to the corresponding |
| # realm. What this is actually granting access to is cluster IDs, which are |
| # hashes of cluster definitions. In other words, all users can take a failure |
| # they have access to and find which clusters in the project correspond to it, |
| # but they can only see the details of the cluster if they have access to that |
| # realm. |
| # |
| # Note that this also grants access to rule definitions for the whole project. |
| # This is OK for now since our security realm is just presubmit, and we're unlikely |
| # to write rules corresponding to failures in that realm that aren't public |
| # anyway. (And again, test result details are all still hidden.) |
| # |
| # If in the future we want to change this, there's a role/analysis.limitedReader |
| # role for limiting access to rule definitions as well. |
| luci.binding( |
| roles = [ |
| "role/analysis.reader", |
| ], |
| groups = "all", |
| ), |
| luci.binding( |
| # Allow approvers to mutate luci-analysis state. |
| roles = ["role/analysis.editor"], |
| groups = ["project-golang-approvers"], |
| ), |
| luci.binding( |
| # Allow authenticated users to run analysis queries in public realms. |
| # This policy may seem a bit strange, but the idea is to allow community |
| # members to run failure analyses while still keeping a record of |
| # who did it (by making them log in) to identify misuse. |
| # The Chromium project does this and hasn't had any problems yet. |
| roles = ["role/analysis.queryUser"], |
| groups = ["authenticated-users"], |
| ), |
| ], |
| acls = [ |
| acl.entry( |
| roles = acl.PROJECT_CONFIGS_READER, |
| groups = "all", |
| ), |
| ], |
| ) |
| |
| # Per-service tweaks. |
| luci.logdog(gs_bucket = "logdog-golang-archive") |
| |
| # Realms for public buckets and Swarming pools. |
| PUBLIC_REALMS = [ |
| luci.realm(name = "pools/ci"), |
| luci.realm(name = "pools/ci-workers"), |
| luci.realm(name = "pools/try"), |
| luci.realm(name = "pools/try-workers"), |
| luci.realm(name = "pools/shared-workers"), |
| luci.bucket(name = "try"), |
| luci.bucket(name = "try-workers"), |
| luci.bucket(name = "ci"), |
| luci.bucket(name = "ci-workers"), |
| ] |
| |
| SECURITY_REALMS = [ |
| luci.realm(name = "pools/security-try"), |
| luci.realm(name = "pools/security-try-workers"), |
| luci.bucket(name = "security-try"), |
| luci.bucket(name = "security-try-workers"), |
| ] |
| |
| luci.realm(name = "pools/prod") |
| |
| # Allow everyone to see public builds, pools, bots, and tasks. |
| # WARNING: this doesn't do much for Swarming entities -- chromium-swarm |
| # has a global allow-all ACL that supersedes us. Private realms run in |
| # chrome-swarming. |
| luci.binding( |
| roles = [ |
| "role/swarming.poolViewer", |
| "role/buildbucket.reader", |
| ], |
| realm = PUBLIC_REALMS, |
| groups = "all", |
| ) |
| |
| # may-start-trybots grants the permission to trigger public builds. |
| luci.binding( |
| roles = ["role/buildbucket.triggerer"], |
| realm = PUBLIC_REALMS, |
| groups = ["project-golang-may-start-trybots"], |
| ) |
| |
| # Allow security release participants to see and trigger security builds, etc. |
| # WARNING: similar to above, chrome-swarming is open to all Googlers. |
| luci.binding( |
| roles = ["role/swarming.poolViewer", "role/buildbucket.reader", "role/buildbucket.triggerer"], |
| realm = SECURITY_REALMS, |
| groups = ["mdb/golang-security-policy", "mdb/golang-release-eng-policy"], |
| ) |
| |
| # Allow x/build/cmd/makemac to list security bots. |
| luci.binding( |
| roles = "role/swarming.poolViewer", |
| realm = SECURITY_REALMS, |
| users = "makemac@symbolic-datum-552.iam.gserviceaccount.com", |
| ) |
| |
| # Allow users with the taskTriggerer role to impersonate the service accounts. |
| luci.binding( |
| roles = "role/swarming.taskServiceAccount", |
| realm = PUBLIC_REALMS, |
| users = "coordinator-builder@golang-ci-luci.iam.gserviceaccount.com", |
| ) |
| |
| # Allow gomoteserver to run Swarming tasks and BuildBucket builds in public realms. |
| luci.binding( |
| roles = [ |
| "role/buildbucket.triggerer", |
| "role/swarming.poolUser", |
| "role/swarming.taskTriggerer", |
| ], |
| realm = PUBLIC_REALMS, |
| users = "gomoteserver@symbolic-datum-552.iam.gserviceaccount.com", |
| ) |
| |
| # Allow relui to run Swarming tasks and BuildBucket builds in both security realms |
| # (for Go releases) and public realms (for x repo tagging, etc.) |
| luci.binding( |
| roles = [ |
| "role/swarming.taskTriggerer", |
| "role/swarming.poolUser", |
| "role/buildbucket.triggerer", |
| ], |
| realm = PUBLIC_REALMS + SECURITY_REALMS, |
| users = "relui-prod@symbolic-datum-552.iam.gserviceaccount.com", |
| ) |
| |
| # Define relui-tasks as a LUCI service account. This is normally handled |
| # by a luci.builder call, but this isn't a standard builder account. |
| luci.binding( |
| roles = "role/swarming.taskServiceAccount", |
| realm = PUBLIC_REALMS + SECURITY_REALMS, |
| users = [ |
| "relui-tasks@symbolic-datum-552.iam.gserviceaccount.com", |
| ], |
| ) |
| |
| # This is the cipd package name and version where the recipe bundler will put |
| # the built recipes. This line makes it the default value for all `luci.recipe` |
| # invocations in this configuration. |
| # |
| # The recipe bundler sets CIPD refs equal in name to the git refs that it |
| # processed the recipe code from. |
| # |
| # Note: This will cause all recipe commits to automatically deploy as soon |
| # as the recipe bundler compiles them from your refs/heads/luci-config branch. |
| luci.recipe.defaults.cipd_package.set("golang/recipe_bundles/go.googlesource.com/build") |
| luci.recipe.defaults.cipd_version.set("refs/heads/luci-config") |
| luci.recipe.defaults.use_python3.set(True) |
| |
| def define_environment(gerrit_host, swarming_host, bucket, coordinator_sa, worker_sa, has_shared_pool, low_capacity, known_issue, priority = None): |
| return struct( |
| gerrit_host = gerrit_host, |
| swarming_host = swarming_host + ".appspot.com", |
| bucket = bucket, |
| worker_bucket = bucket + "-workers", |
| shadow_bucket = bucket + ".shadow", |
| worker_shadow_bucket = bucket + "-workers.shadow", |
| coordinator_sa = coordinator_sa + "@golang-ci-luci.iam.gserviceaccount.com", |
| coordinator_pool = "luci.golang.%s" % bucket, |
| worker_sa = worker_sa + "@golang-ci-luci.iam.gserviceaccount.com", |
| worker_pool = "luci.golang.%s-workers" % bucket, |
| shared_worker_pool = "luci.golang.shared-workers" if has_shared_pool else "", |
| low_capacity_hosts = low_capacity, |
| known_issue_builder_types = known_issue, |
| priority = priority, |
| ) |
| |
| # GOOGLE_LOW_CAPACITY_HOSTS are low-capacity hosts that happen to be operated |
| # by Google, so we can rely on them being available. |
| GOOGLE_LOW_CAPACITY_HOSTS = [ |
| "darwin-amd64_10.15", |
| "darwin-amd64_11", |
| "darwin-amd64_12", |
| "darwin-amd64_13", |
| "darwin-amd64_14", |
| "darwin-arm64_11", |
| "darwin-arm64_12", |
| "darwin-arm64_13", |
| "linux-arm", |
| "windows-arm64", |
| ] |
| |
| # TBD_CAPACITY_HOSTS lists "hosts" that whose capacity is yet to be determined. |
| # When the work to add a host is underway, its entry should either move to the |
| # LOW_CAPACITY_HOSTS list below, or removed if it's not low-capacity. |
| TBD_CAPACITY_HOSTS = [ |
| "aix-ppc64", |
| "android-386", |
| "android-amd64", |
| "android-arm", |
| "android-arm64", |
| "dragonfly-amd64", |
| "freebsd-386", |
| "freebsd-amd64", |
| "freebsd-arm", |
| "freebsd-arm64", |
| "illumos-amd64", |
| "ios-amd64", |
| "ios-arm64", |
| "linux-mips", |
| "linux-mips", |
| "linux-mips64", |
| "linux-mips64", |
| "linux-mips64le", |
| "linux-mips64le", |
| "linux-mipsle", |
| "linux-mipsle", |
| "linux-s390x", |
| "netbsd-386", |
| "netbsd-amd64", |
| "openbsd-386", |
| "openbsd-arm", |
| "openbsd-arm64", |
| "windows-arm", |
| ] |
| |
| # LOW_CAPACITY_HOSTS lists "hosts" that have fixed, relatively low capacity. |
| # They need to match the builder type, excluding any run mods. |
| LOW_CAPACITY_HOSTS = GOOGLE_LOW_CAPACITY_HOSTS + TBD_CAPACITY_HOSTS + [ |
| "freebsd-riscv64", |
| "linux-loong64", |
| "linux-ppc64_power10", |
| "linux-ppc64_power8", |
| "linux-ppc64le_power10", |
| "linux-ppc64le_power8", |
| "linux-ppc64le_power9", |
| "linux-riscv64", |
| "netbsd-arm", |
| "netbsd-arm64", |
| "openbsd-ppc64", |
| "openbsd-riscv64", |
| "plan9-386", |
| "plan9-amd64", |
| "plan9-arm", |
| "solaris-amd64", |
| ] |
| |
| # HOST_CONTACT_EMAILS is the contact information for a particular host. |
| # These email addresses will recieve notifications about infra failures |
| # on certain hosts. |
| HOST_CONTACT_EMAILS = { |
| "netbsd-arm": ["bsiegert@google.com"], |
| "netbsd-arm64": ["bsiegert@google.com"], |
| } |
| |
| HOST_NOTIFIERS = { |
| host: luci.notifier( |
| name = host + "-infra", |
| on_new_status = ["INFRA_FAILURE"], |
| notify_emails = emails, |
| ) |
| for host, emails in HOST_CONTACT_EMAILS.items() |
| } |
| |
| # SLOW_HOSTS lists "hosts" who are known to run slower than our typical fast |
| # high-capacity machines. It is a mapping of the host to a test timeout scaling |
| # factor. It also affects the decision of whether to include a builder in |
| # presubmit testing by default (slow high-capacity hosts aren't included). |
| SLOW_HOSTS = { |
| "linux-ppc64_power10": 2, |
| "linux-ppc64_power8": 2, |
| "linux-ppc64le_power10": 2, |
| "linux-ppc64le_power8": 2, |
| "linux-ppc64le_power9": 2, |
| "netbsd-arm64": 2, |
| "openbsd-amd64": 2, |
| } |
| |
| # host_timeout_scale returns the default test timeout scale for a given host. |
| def host_timeout_scale(host): |
| if host in SLOW_HOSTS: |
| return SLOW_HOSTS[host] |
| return 1 |
| |
| # DEFAULT_HOST_SUFFIX defines the default host suffixes for builder types which |
| # do not specify one. |
| DEFAULT_HOST_SUFFIX = { |
| "darwin-amd64": "14", |
| "linux-amd64": "debian11", |
| "linux-arm64": "debian11", |
| "openbsd-amd64": "7.2", |
| "windows-386": "10", |
| "windows-amd64": "10", |
| } |
| |
| # The prod bucket will include builders which work on post-commit code and |
| # generate executable artifacts used by other users or machines. |
| luci.bucket(name = "prod") |
| |
| # A list with builders in "prod" bucket. |
| luci.list_view( |
| name = "prod", |
| ) |
| |
| # BUILDER_TYPES lists possible builder types. |
| # |
| # A builder type is a combination of a GOOS and GOARCH, an optional suffix that |
| # specifies the OS version or CPU version, and a series of run-time modifications |
| # (listed in RUN_MODS). |
| # |
| # The format of a builder type is thus $GOOS-$GOARCH(_suffix)?(-$RUN_MOD)*. |
| BUILDER_TYPES = [ |
| "aix-ppc64", |
| "android-386", |
| "android-amd64", |
| "android-arm", |
| "android-arm64", |
| "darwin-amd64-longtest", |
| "darwin-amd64-nocgo", |
| "darwin-amd64_10.15", |
| "darwin-amd64_11", |
| "darwin-amd64_12", |
| "darwin-amd64_13", |
| "darwin-amd64_14", |
| "darwin-arm64_11", |
| "darwin-arm64_12", |
| "darwin-arm64_13", |
| "dragonfly-amd64", |
| "freebsd-386", |
| "freebsd-amd64", |
| "freebsd-arm", |
| "freebsd-arm64", |
| "freebsd-riscv64", |
| "illumos-amd64", |
| "ios-amd64", |
| "ios-arm64", |
| "js-wasm", |
| "linux-386", |
| "linux-386-clang15", |
| "linux-386-longtest", |
| "linux-386-softfloat", |
| "linux-amd64", |
| "linux-amd64-boringcrypto", |
| "linux-amd64-clang15", |
| "linux-amd64-goamd64v3", |
| "linux-amd64-longtest", |
| "linux-amd64-longtest-race", |
| "linux-amd64-misccompile", |
| "linux-amd64-newinliner", |
| "linux-amd64-nocgo", |
| "linux-amd64-noopt", |
| "linux-amd64-race", |
| "linux-amd64-racecompile", |
| "linux-amd64-ssacheck", |
| "linux-amd64-staticlockranking", |
| "linux-amd64-typesalias", |
| "linux-amd64_c2s16-perf_vs_gopls_0_11", |
| "linux-amd64_c2s16-perf_vs_parent", |
| "linux-amd64_c2s16-perf_vs_release", |
| "linux-amd64_c2s16-perf_vs_tip", |
| "linux-amd64_c3h88-perf_vs_parent", |
| "linux-amd64_c3h88-perf_vs_tip", |
| "linux-arm", |
| "linux-arm64", |
| "linux-arm64-boringcrypto", |
| "linux-arm64-longtest", |
| "linux-arm64-race", |
| "linux-loong64", |
| "linux-mips", |
| "linux-mips64", |
| "linux-mips64le", |
| "linux-mipsle", |
| "linux-ppc64_power10", |
| "linux-ppc64_power8", |
| "linux-ppc64le_power10", |
| "linux-ppc64le_power8", |
| "linux-ppc64le_power9", |
| "linux-riscv64", |
| "linux-s390x", |
| "netbsd-386", |
| "netbsd-amd64", |
| "netbsd-arm", |
| "netbsd-arm64", |
| "openbsd-386", |
| "openbsd-amd64", |
| "openbsd-arm", |
| "openbsd-arm64", |
| "openbsd-ppc64", |
| "openbsd-riscv64", |
| "plan9-386", |
| "plan9-amd64", |
| "plan9-arm", |
| "solaris-amd64", |
| "wasip1-wasm_wasmtime", |
| "wasip1-wasm_wazero", |
| "windows-386", |
| "windows-amd64", |
| "windows-amd64-longtest", |
| "windows-amd64-race", |
| "windows-arm", |
| "windows-arm64", |
| ] |
| |
| def known_issue(issue_number, skip_x_repos = False): |
| return struct( |
| issue_number = issue_number, |
| skip_x_repos = skip_x_repos, # Whether to skip defining builders for x/ repos. |
| ) |
| |
| KNOWN_ISSUE_BUILDER_TYPES = { |
| "freebsd-riscv64": known_issue(issue_number = 63482), |
| "linux-loong64": known_issue(issue_number = 65398), |
| "netbsd-arm": known_issue(issue_number = 63698), |
| "openbsd-ppc64": known_issue(issue_number = 63480), |
| "openbsd-riscv64": known_issue(issue_number = 64176), |
| "plan9-386": known_issue(issue_number = 63599), |
| "plan9-amd64": known_issue(issue_number = 63600), |
| "plan9-arm": known_issue(issue_number = 63601), |
| |
| # The known issue for these builder types tracks the work of starting to add them. |
| # Skip the builder definitions for x/ repos to reduce noise. |
| # Once the builder is added and starts working in the main repo, x/ repos can be unskipped. |
| "aix-ppc64": known_issue(issue_number = 60440, skip_x_repos = True), |
| "android-386": known_issue(issue_number = 61097, skip_x_repos = True), |
| "android-amd64": known_issue(issue_number = 61097, skip_x_repos = True), |
| "android-arm": known_issue(issue_number = 61097, skip_x_repos = True), |
| "android-arm64": known_issue(issue_number = 61097, skip_x_repos = True), |
| "dragonfly-amd64": known_issue(issue_number = 61092, skip_x_repos = True), |
| "freebsd-386": known_issue(issue_number = 60468, skip_x_repos = True), |
| "freebsd-amd64": known_issue(issue_number = 61095, skip_x_repos = True), |
| "freebsd-arm": known_issue(issue_number = 60440, skip_x_repos = True), |
| "freebsd-arm64": known_issue(issue_number = 60440, skip_x_repos = True), |
| "illumos-amd64": known_issue(issue_number = 60440, skip_x_repos = True), |
| "ios-amd64": known_issue(issue_number = 42177, skip_x_repos = True), |
| "ios-arm64": known_issue(issue_number = 60440, skip_x_repos = True), |
| "linux-mips": known_issue(issue_number = 60440, skip_x_repos = True), |
| "linux-mips64": known_issue(issue_number = 60440, skip_x_repos = True), |
| "linux-mips64le": known_issue(issue_number = 60440, skip_x_repos = True), |
| "linux-mipsle": known_issue(issue_number = 60440, skip_x_repos = True), |
| "linux-s390x": known_issue(issue_number = 60440, skip_x_repos = True), |
| "netbsd-386": known_issue(issue_number = 61120, skip_x_repos = True), |
| "netbsd-amd64": known_issue(issue_number = 61121, skip_x_repos = True), |
| "openbsd-386": known_issue(issue_number = 61122, skip_x_repos = True), |
| "openbsd-arm": known_issue(issue_number = 60440, skip_x_repos = True), |
| "openbsd-arm64": known_issue(issue_number = 60440, skip_x_repos = True), |
| "windows-arm": known_issue(issue_number = 60440, skip_x_repos = True), |
| } |
| SECURITY_KNOWN_ISSUE_BUILDER_TYPES = dict(KNOWN_ISSUE_BUILDER_TYPES) |
| SECURITY_KNOWN_ISSUE_BUILDER_TYPES.update({ |
| "darwin-amd64_14": known_issue(issue_number = 67073), |
| }) |
| |
| # NO_NETWORK_BUILDERS are a subset of builder types |
| # where we require the no-network check to run. |
| NO_NETWORK_BUILDERS = [ |
| "linux-386", |
| "linux-amd64", |
| ] |
| |
| # MAIN_BRANCH_NAME is the name of the main branch for every repository. This |
| # exists so we can change it more easily in the future, and avoid propagating |
| # the existing one everywhere. |
| MAIN_BRANCH_NAME = "master" |
| |
| # GO_BRANCHES lists the branches of the "go" project to build and test against. |
| # Keys in this map are shortened aliases while values are the git branch name. |
| GO_BRANCHES = { |
| "gotip": struct(branch = MAIN_BRANCH_NAME, bootstrap = "1.20.6"), |
| "go1.22": struct(branch = "release-branch.go1.22", bootstrap = "1.20.6"), |
| "go1.21": struct(branch = "release-branch.go1.21", bootstrap = "1.17.13"), |
| } |
| |
| # INTERNAL_GO_BRANCHES mirrors GO_BRANCHES, but defines the branches to build |
| # and test against for the go-internal/go repository. |
| INTERNAL_GO_BRANCHES = { |
| "gotip": struct(branch_regexp = MAIN_BRANCH_NAME, bootstrap = "1.20.6"), |
| # The private-release-branches are per-point release, rather than |
| # per-major version, since we create them specially for each point |
| # release, and want to maintain that history. We use a regex to match |
| # all the point branches so that we don't need to manually update the |
| # config each time we issue a point release. |
| "go1.22": struct(branch_regexp = "private-release-branch.go1.22.\\d+", bootstrap = "1.20.6"), |
| "go1.21": struct(branch_regexp = "private-release-branch.go1.21.\\d+", bootstrap = "1.17.13"), |
| } |
| |
| # EXTRA_GO_BRANCHES are Go branches that aren't used for project-wide testing |
| # because they're out of scope per https://go.dev/doc/devel/release#policy, |
| # but are used by specific golang.org/x repositories. |
| EXTRA_GO_BRANCHES = { |
| "go1.20": struct(branch = "release-branch.go1.20", bootstrap = "1.17.13"), |
| "go1.19": struct(branch = "release-branch.go1.19", bootstrap = "1.17.13"), |
| } |
| |
| # We set build priorities by environment. These should always be lower than the |
| # build priority for gomote requests, which is 20 (lower number means higher priority). |
| PRIORITY = struct( |
| GOMOTE = 20, |
| PRESUBMIT = 30, |
| POSTSUBMIT = 40, |
| ) |
| |
| # The try bucket will include builders which work on pre-commit or pre-review |
| # code. |
| PUBLIC_TRY_ENV = define_environment("go", "chromium-swarm", "try", "coordinator-builder", "public-worker-builder", True, LOW_CAPACITY_HOSTS, KNOWN_ISSUE_BUILDER_TYPES, priority = PRIORITY.PRESUBMIT) |
| |
| # The ci bucket will include builders which work on post-commit code. |
| PUBLIC_CI_ENV = define_environment("go", "chromium-swarm", "ci", "coordinator-builder", "public-worker-builder", True, LOW_CAPACITY_HOSTS, KNOWN_ISSUE_BUILDER_TYPES, priority = PRIORITY.POSTSUBMIT) |
| |
| # The security-try bucket is for builders that test unreviewed, embargoed |
| # security fixes. |
| SECURITY_TRY_ENV = define_environment("go-internal", "chrome-swarming", "security-try", "security-coordinator-builder", "security-worker-builder", False, LOW_CAPACITY_HOSTS, SECURITY_KNOWN_ISSUE_BUILDER_TYPES, priority = PRIORITY.PRESUBMIT) |
| |
| def define_public_shadow_buckets(env): |
| if env.swarming_host != "chromium-swarm.appspot.com": |
| fail("only the chromium-swarm instance is known to be intended for public builds, but env.swarming_host is %s" % env.swarming_host) |
| |
| all_pools = [env.coordinator_pool, env.worker_pool] |
| if env.shared_worker_pool: |
| all_pools.append(env.shared_worker_pool) |
| |
| for bucket, shadow_bucket in [(env.bucket, env.shadow_bucket), (env.worker_bucket, env.worker_shadow_bucket)]: |
| luci.bucket( |
| shadows = bucket, |
| name = shadow_bucket, |
| dynamic = True, |
| # Explicitly set bucket constraints for shadow buckets. These are populated |
| # for each real bucket implicitly via luci.builder(...), but not populated at |
| # all for shadow buckets, unfortunately. |
| constraints = luci.bucket_constraints( |
| service_accounts = [env.coordinator_sa, env.worker_sa], |
| pools = all_pools, |
| ), |
| bindings = [ |
| # Allow everyone to see builds in public shadow buckets. |
| luci.binding( |
| roles = ["role/buildbucket.reader"], |
| groups = "all", |
| ), |
| # Allow anyone on the Go team to create builds in public shadow buckets. |
| # Creating builds is more permissive than triggering them: it allows |
| # for arbitrary mutation of the builder definition, whereas triggered |
| # builds may only mutate explicitly mutable fields. These shadow buckets |
| # are used for testing of public builder configurations and behaviors. |
| luci.binding( |
| roles = "role/buildbucket.creator", |
| groups = ["mdb/golang-team"], |
| ), |
| |
| # Allow our service accounts to create ResultDB invocations in shadow buckets. |
| # This permission is necessary to set explicitly according to the shadow bucket |
| # documentation. |
| luci.binding( |
| roles = "role/resultdb.invocationCreator", |
| users = [env.coordinator_sa, env.worker_sa], |
| ), |
| ], |
| ) |
| return env |
| |
| # Create public shadow buckets, for mutating and testing out changes to public builds. |
| define_public_shadow_buckets(PUBLIC_TRY_ENV) |
| define_public_shadow_buckets(PUBLIC_CI_ENV) |
| |
| # PT is Project Type, a classification of a project. |
| PT = struct( |
| CORE = "core", # The Go project or something that it depends on. Needs to be tested everywhere. |
| LIBRARY = "library", # A user-facing library. Needs to be tested on a representative set of platforms. |
| TOOL = "tool", # A developer tool. Typically only run on mainstream platforms such as Linux, MacOS, and Windows. |
| SPECIAL = "special", # None of the above; something that needs a handcrafted set. |
| ) |
| |
| # PROJECTS lists the go.googlesource.com/<project> projects we build and test for. |
| PROJECTS = { |
| "go": PT.CORE, |
| "arch": PT.CORE, |
| "benchmarks": PT.LIBRARY, |
| "build": PT.TOOL, |
| "crypto": PT.CORE, |
| "debug": PT.LIBRARY, |
| "dl": PT.CORE, |
| "exp": PT.SPECIAL, |
| "image": PT.LIBRARY, |
| "mobile": PT.SPECIAL, |
| "mod": PT.CORE, |
| "net": PT.CORE, |
| "oauth2": PT.LIBRARY, |
| "perf": PT.TOOL, |
| "pkgsite": PT.TOOL, |
| "pkgsite-metrics": PT.TOOL, |
| "playground": PT.TOOL, |
| "protobuf": PT.SPECIAL, |
| "review": PT.TOOL, |
| "sync": PT.CORE, |
| "sys": PT.CORE, |
| "telemetry": PT.CORE, |
| "term": PT.CORE, |
| "text": PT.CORE, |
| "time": PT.LIBRARY, |
| "tools": PT.LIBRARY, |
| "vuln": PT.TOOL, |
| "vulndb": PT.TOOL, |
| "website": PT.TOOL, |
| } |
| |
| # projects_of_type returns projects of the given types. |
| def projects_of_type(types): |
| return [ |
| project |
| for project in PROJECTS |
| if PROJECTS[project] in types |
| ] |
| |
| # make_run_mod returns a run_mod that adds the given properties and environment |
| # variables. If set, enabled is a function that returns three booleans to |
| # affect the builder it's being added to: |
| # - exists, whether the builder should be created at all |
| # - presubmit, whether the builder should be run in presubmit by default |
| # - postsubmit, whether the builder should run in postsubmit |
| # - presubmit location filters, any cq.location_filter to apply to presubmit |
| def make_run_mod(add_props = {}, add_env = {}, enabled = None, test_timeout_scale = 1): |
| def apply_mod(props, project): |
| props.update(add_props) |
| |
| # Compose timeout scaling factors by multiplying them. |
| if test_timeout_scale != 1: |
| if "test_timeout_scale" not in props: |
| # Having no test_timeout_scale means that it starts at 1. |
| props["test_timeout_scale"] = test_timeout_scale |
| else: |
| props["test_timeout_scale"] *= test_timeout_scale |
| |
| # Update any environment variables. |
| props["env"].update(add_env) |
| |
| if enabled == None: |
| enabled = lambda port, project, go_branch_short: (True, True, True, []) |
| return struct( |
| enabled = enabled, |
| apply = apply_mod, |
| ) |
| |
| # enable only if project matches one of the provided projects and certain source |
| # locations are modified by the CL, or always for the release branches of the go project. |
| # projects is a dict mapping a project name to filters. |
| def define_for_presubmit_only_for_projs_or_on_release_branches(projects): |
| def f(port, project, go_branch_short): |
| filters = [] |
| if project == "go": |
| presubmit = project in projects or go_branch_short != "gotip" |
| if project in projects and go_branch_short == "gotip": |
| filters = projects[project] |
| else: |
| presubmit = project in projects |
| if presubmit: |
| filters = projects[project] |
| return (True, presubmit, True, filters) |
| |
| return f |
| |
| # enable only if port_of(builder_type) matches one of the provided ports, or |
| # for the release branches in the Go project. |
| def define_for_presubmit_only_for_ports_or_on_release_branches(ports): |
| def f(port, project, go_branch_short): |
| presubmit = port in ports or (project == "go" and go_branch_short != "gotip") |
| return (True, presubmit, True, []) |
| |
| return f |
| |
| # define the builder only for the go project at versions after x, useful for |
| # non-default build modes that were created at x. |
| def define_for_go_starting_at(x): |
| def f(port, project, go_branch_short): |
| run = project == "go" and (go_branch_short == "gotip" or go_branch_short >= x) |
| return (run, run, run, []) |
| |
| return f |
| |
| # define the builder only for postsubmit for the specified projects. |
| # |
| # Note: it will still be defined for optional inclusion in presubmit. |
| def define_for_postsubmit(projects, go_branches = GO_BRANCHES.keys()): |
| def f(port, project, go_branch_short): |
| run = project in projects and go_branch_short in go_branches |
| return (run, False, run, []) |
| |
| return f |
| |
| # define the builder only for postsubmit of the go project, or for presubmit |
| # of the go project if a particular location is touched. |
| def define_for_go_postsubmit_or_presubmit_with_filters(filters): |
| def f(port, project, go_branch_short): |
| run = project == "go" |
| return (run, run, run, filters) |
| |
| return f |
| |
| # define the builder as existing for the go project, so it's includable in presubmit, |
| # but don't run it anywhere by default. |
| def define_for_optional_presubmit_only(projects): |
| def f(port, project, go_branch_short): |
| exists = project in projects |
| return (exists, False, False, []) |
| |
| return f |
| |
| # RUN_MODS is a list of valid run-time modifications to the way we |
| # build and test our various projects. |
| RUN_MODS = dict( |
| # Build and test with the boringcrypto GOEXPERIMENT. |
| boringcrypto = make_run_mod( |
| add_env = {"GOEXPERIMENT": "boringcrypto"}, |
| ), |
| |
| # Build and test clang 15 as the C toolchain. |
| clang15 = make_run_mod( |
| add_props = {"clang_version": "15.0.6"}, |
| enabled = define_for_postsubmit(["go"]), |
| ), |
| |
| # Build and test with GOAMD64=v3, which makes the compiler assume certain amd64 CPU |
| # features are always available. |
| goamd64v3 = make_run_mod( |
| add_env = {"GOAMD64": "v3"}, |
| enabled = define_for_postsubmit(["go"]), |
| ), |
| |
| # Run a larger set of tests. |
| longtest = make_run_mod( |
| add_props = {"long_test": True}, |
| test_timeout_scale = 5, |
| enabled = define_for_presubmit_only_for_projs_or_on_release_branches({ |
| "build": [], |
| "go": [ |
| # Enable longtest builders on go against tip if files related to vendored code are modified. |
| "src/{,cmd/}go[.]{mod,sum}", |
| "src/{,cmd/}vendor/.+", |
| "src/.+_bundle.go", |
| ], |
| "protobuf": [], |
| }), |
| ), |
| |
| # The misccompile mod indicates that the builder should act as a "misc-compile" builder, |
| # that is to cross-compile all non-first-class ports to quickly flag portability issues. |
| misccompile = make_run_mod( |
| add_props = {"compile_only": True, "misc_ports": True}, |
| ), |
| |
| # Build and test with the newinliner GOEXPERIMENT. |
| newinliner = make_run_mod( |
| add_env = {"GOEXPERIMENT": "newinliner"}, |
| enabled = define_for_go_starting_at("go1.22"), |
| ), |
| |
| # Build and test with cgo disabled. |
| nocgo = make_run_mod( |
| add_env = {"CGO_ENABLED": "0"}, |
| enabled = define_for_postsubmit(projects_of_type([PT.CORE, PT.LIBRARY])), |
| ), |
| |
| # Build and test with optimizations disabled. |
| noopt = make_run_mod( |
| add_env = {"GO_GCFLAGS": "-N -l"}, |
| enabled = define_for_postsubmit(["go"]), |
| ), |
| |
| # Run performance tests against the latest Go release as a baseline. Only makes sense |
| # for the main Go repository. |
| # |
| # When run against a commit or change on tip, it will pick the latest overall release. |
| # When run against a commit or change on a release branch, it will pick the latest |
| # release on that release branch. |
| # |
| # Note: This run_mod is incompatible with most other run_mods. Generally, build-time |
| # environment variables will apply, but others like compile_only, race, and longtest |
| # will have no effect. |
| perf_vs_release = make_run_mod( |
| add_props = {"perf_mode": {"baseline": "latest_go_release"}}, |
| enabled = define_for_postsubmit(["go"]), |
| ), |
| |
| # Run performance tests against the tip of the main branch for whatever repository |
| # we're targeting. |
| # |
| # Note: This run_mod is incompatible with most other run_mods. Generally, build-time |
| # environment variables will apply, but others like compile_only, race, and longtest |
| # will have no effect. |
| perf_vs_tip = make_run_mod( |
| add_props = {"perf_mode": {"baseline": "refs/heads/" + MAIN_BRANCH_NAME}}, |
| enabled = define_for_optional_presubmit_only(["go", "tools"]), |
| ), |
| |
| # Run performance tests against the source's parent commit. |
| # |
| # Note: This run_mod is incompatible with most other run_mods. Generally, build-time |
| # environment variables will apply, but others like compile_only, race, and longtest |
| # will have no effect. |
| perf_vs_parent = make_run_mod( |
| add_props = {"perf_mode": {"baseline": "parent"}}, |
| enabled = define_for_optional_presubmit_only(["go", "tools"]), |
| ), |
| |
| # Run performance tests against the gopls-release-branch.0.11 branch as a baseline. Only |
| # makes sense for the x/tools repository. Excludes gotip as a branch for testing since the |
| # same toolchain tool would be chosen as the baseline by golangbuild for gotip and the latest |
| # release branch, making it redundant (and also misleading). |
| # |
| # Note: This run_mod is incompatible with most other run_mods. Generally, build-time |
| # environment variables will apply, but others like compile_only, race, and longtest |
| # will have no effect. |
| perf_vs_gopls_0_11 = make_run_mod( |
| add_props = {"perf_mode": {"baseline": "refs/heads/gopls-release-branch.0.11"}}, |
| enabled = define_for_postsubmit(["tools"], go_branches = [branch for branch in GO_BRANCHES.keys() if branch != "gotip"]), |
| ), |
| |
| # Build and test with race mode enabled. |
| race = make_run_mod( |
| add_props = {"race_mode": True}, |
| test_timeout_scale = 2, |
| enabled = define_for_presubmit_only_for_ports_or_on_release_branches(["linux-amd64"]), |
| ), |
| |
| # Build with a compiler and linker that are built with race mode enabled. |
| racecompile = make_run_mod( |
| add_props = {"compile_only": True, "compiler_linker_race_mode": True}, |
| enabled = define_for_postsubmit(["go"]), |
| ), |
| |
| # Build and test with GO386=softfloat, which makes the compiler emit non-floating-point |
| # CPU instructions to perform floating point operations. |
| softfloat = make_run_mod( |
| add_env = {"GO386": "softfloat"}, |
| enabled = define_for_postsubmit(["go"]), |
| ), |
| |
| # Build with ssacheck mode enabled in the compiler. |
| ssacheck = make_run_mod( |
| add_props = {"compile_only": True}, |
| add_env = {"GO_GCFLAGS": "-d=ssa/check/on"}, |
| enabled = define_for_go_postsubmit_or_presubmit_with_filters(["src/cmd/compile/internal/{ssa,ssagen}/.+"]), |
| ), |
| |
| # Build and test with the staticlockranking GOEXPERIMENT, which validates the runtime's |
| # dynamic lock usage against a static ranking to detect possible deadlocks before they happen. |
| staticlockranking = make_run_mod( |
| add_env = {"GOEXPERIMENT": "staticlockranking"}, |
| enabled = define_for_go_postsubmit_or_presubmit_with_filters(["src/runtime/[^/]+"]), |
| ), |
| |
| # Build and test with the gotypesalias GODEBUG, which enables |
| # explicit representation of type aliases. |
| # |
| # The builder can be removed once gotypesalias=1 is the default. |
| typesalias = make_run_mod( |
| add_env = {"GODEBUG": "gotypesalias=1"}, |
| enabled = define_for_optional_presubmit_only(["go", "tools"]), |
| ), |
| ) |
| |
| # EXTRA_DEPENDENCIES specifies custom additional dependencies |
| # to append when applies(project, port, run_mods) matches. |
| EXTRA_DEPENDENCIES = [ |
| # The protobuf repo needs extra dependencies for its integration test. |
| # See its integration_test.go file and go.dev/issue/64066. |
| struct( |
| applies = lambda project, port, run_mods: project == "protobuf" and port == "linux-amd64" and "longtest" in run_mods, |
| test_deps = """@Subdir bin |
| golang/third_party/protoc_with_conformance/${platform} version:v27.0-rc1 |
| """, |
| ), |
| ] |
| |
| def go_cq_group(project, go_branch_short): |
| """go_cq_group returns the CQ group name and watch for project and |
| go_branch_short.""" |
| |
| # The CQ group "{project}_repo_{go-branch}" is configured to watch |
| # applicable branches in project and test with the Go version that |
| # corresponds to go-branch. |
| # |
| # LUCI's CQ group names must match "^[a-zA-Z][a-zA-Z0-9_-]{0,39}$". |
| # Each branch must be watched by no more than one matched CQ group. |
| cq_group_name = ("%s_repo_%s" % (project, go_branch_short)).replace(".", "-") |
| |
| if project == "go": |
| # Main Go repo trybot branch coverage. |
| if go_branch_short == "gotip": |
| refs, refs_exclude = ["^refs/heads/.+$"], ["^refs/heads/release-branch\\..+$"] |
| else: |
| refs, refs_exclude = ["^refs/heads/release-branch\\.%s$" % go_branch_short.replace(".", "\\.")], None |
| else: |
| # golang.org/x repo trybot branch coverage. |
| # See go.dev/issue/46154. |
| if go_branch_short == "gotip": |
| refs, refs_exclude = ["^refs/heads/.+$"], ["^refs/heads/internal-branch\\..+$"] |
| else: |
| refs, refs_exclude = ["^refs/heads/internal-branch\\.%s-.+$" % go_branch_short.replace(".", "\\.")], None |
| |
| return struct( |
| name = cq_group_name, |
| watch = cq.refset( |
| repo = "https://go.googlesource.com/%s" % project, |
| refs = refs, |
| refs_exclude = refs_exclude, |
| ), |
| ) |
| |
| def split_builder_type(builder_type): |
| """split_builder_type splits a builder type into its pieces. |
| |
| Args: |
| builder_type: the builder type. |
| |
| Returns: |
| The builder type's GOOS, GOARCH, OS version, and run mods. |
| """ |
| parts = builder_type.split("-") |
| os, arch = parts[0], parts[1] |
| suffix = "" |
| if "_" in arch: |
| arch, suffix = arch.split("_", 2) |
| |
| return os, arch, suffix, parts[2:] |
| |
| def port_of(builder_type): |
| """port_of returns the builder_type stripped of OS version and run mods. |
| |
| Args: |
| builder_type: the builder type. |
| |
| Returns: |
| The builder type's GOOS and GOARCH, without OS version and run mods. |
| """ |
| os, arch, _, _ = split_builder_type(builder_type) |
| return "%s-%s" % (os, arch) |
| |
| def host_of(builder_type): |
| """host_of returns the host builder type for builder_type. |
| |
| For example, linux-amd64 is the host for js-wasm as of writing. |
| |
| Args: |
| builder_type: the builder type. |
| |
| Returns: |
| The host builder type. |
| """ |
| goos, goarch, suffix, _ = split_builder_type(builder_type) |
| |
| # We run various builds on a Linux host. |
| if goarch == "wasm": |
| return "linux-amd64" |
| |
| port = "%s-%s" % (goos, goarch) |
| if suffix != "": |
| return port + "_" + suffix |
| return port |
| |
| def dimensions_of(host_type): |
| """dimensions_of returns the bot dimensions for a host type.""" |
| goos, goarch, suffix, _ = split_builder_type(host_type) |
| |
| # We run some 386 ports on amd64 machines. |
| if goarch == "386" and goos in ("linux", "windows"): |
| goarch = "amd64" |
| |
| host = "%s-%s" % (goos, goarch) |
| |
| os, cpu = None, None |
| |
| # Narrow down the dimensions using the suffix. |
| |
| # Set the default suffix, if we don't have one and one exists. |
| if suffix == "" and host in DEFAULT_HOST_SUFFIX: |
| suffix = DEFAULT_HOST_SUFFIX[host] |
| |
| # Fail if we don't have a suffix and this isn't a low capacity host. |
| # |
| # It's really important that we specify an OS version so that |
| # robocrop can correctly and precisely identify task queue length |
| # for different types of machines. This *must* line up with the |
| # expected_dimensions field for the botset in the internal config: |
| # //starlark/common/envs/golang.star |
| # |
| # Low capacity hosts don't require a suffix because the OS versions are |
| # manually managed and we don't always control them, so we want to be |
| # as general as possible to avoid downtime. |
| # |
| # Note: it's a little odd that we don't rely on a low_capacity_hosts |
| # passed down to us from an environment, but that's because we care about |
| # the broadest possible definition of "low capacity" here for OS version |
| # specification. |
| if suffix == "" and host not in LOW_CAPACITY_HOSTS: |
| fail("failed to find required OS version for host %s" % host) |
| |
| if suffix != "": |
| if goos == "linux" and "debian" in suffix: |
| # linux-amd64_debian11 -> Debian-11 |
| os = suffix.replace("debian", "Debian-") |
| elif goos == "linux" and goarch == "amd64" and suffix in ["c2s16", "c3h88"]: |
| # Performance test machines. |
| os = "Debian-12" |
| elif goos == "linux" and goarch in ["ppc64", "ppc64le"]: |
| cpu = goarch + "-64-" + suffix.replace("power", "POWER") |
| elif goos == "darwin": |
| # darwin-amd64_12.6 -> Mac-12.6 |
| os = "Mac-" + suffix |
| elif goos == "windows": |
| os = "Windows-" + suffix |
| elif goos == "openbsd": |
| os = "openbsd-" + suffix |
| else: |
| fail("unhandled suffix %s for host type %s" % (suffix, host_type)) |
| |
| # Request a specific GCE machine type for certain platforms. |
| # |
| # This is very, very important for auto-scaling, it this needs to |
| # match the "expected_dimensions" field that botsets have in the |
| # internal configuration. Take care when updating this in general, |
| # it probably also requires an update to the internal configuration. |
| machine_type = None |
| if goos == "linux": |
| if goarch == "amd64": |
| if suffix == "c2s16": |
| # Performance test machines. |
| machine_type = "c2-standard-16" |
| elif suffix == "c3h88": |
| machine_type = "c3-highcpu-88" |
| else: |
| machine_type = "n1-standard-16" |
| elif goarch == "arm64": |
| machine_type = "t2a-standard-8" |
| |
| # cipd_platform is almost "$GOHOSTOS-$GOHOSTARCH", with some deviations. |
| if goos == "darwin": |
| cipd_platform = "mac-" + goarch # GOHOSTOS=darwin is written as "mac". |
| elif goarch == "arm": |
| cipd_platform = goos + "-armv6l" # GOHOSTARCH=arm is written as "armv6l". |
| else: |
| cipd_platform = host |
| |
| dims = {"cipd_platform": cipd_platform} |
| if os != None: |
| dims["os"] = os |
| if cpu != None: |
| dims["cpu"] = cpu |
| if machine_type != None: |
| dims["machine_type"] = machine_type |
| return dims |
| |
| def is_capacity_constrained(low_capacity_hosts, host_type): |
| dims = dimensions_of(host_type) |
| return any([dimensions_of(x) == dims for x in low_capacity_hosts]) |
| |
| def is_fully_supported(dims): |
| """Reports whether dims identifies a platform fully supported by LUCI. |
| |
| Some packages, notably Python, Go, and Git aren't built into CIPD for |
| all platforms or at all versions we need. We work around their absence |
| on unsupported platforms. |
| |
| Args: |
| dims: The dimensions of a task/bot. |
| """ |
| |
| supported_cipd_platforms = [ |
| "%s-%s" % (os, arch) |
| for os in ["linux", "mac", "windows"] |
| for arch in ["armv6l", "amd64", "arm64"] |
| ] |
| return dims["cipd_platform"] in supported_cipd_platforms |
| |
| # builder_name produces the final builder name. |
| def builder_name(project, go_branch_short, builder_type): |
| """Derives the name for a certain builder. |
| |
| Args: |
| project: A go project defined in `PROJECTS`. |
| go_branch_short: A go repository branch name defined in `GO_BRANCHES`. |
| builder_type: A name defined in `BUILDER_TYPES`. |
| |
| Returns: |
| The full name for the builder with the given specs. |
| """ |
| |
| if project == "go": |
| # Omit the project name for the main Go repository. |
| # The branch short name already has a "go" prefix so |
| # it's clear what the builder is building and testing. |
| return "%s-%s" % (go_branch_short, builder_type) |
| |
| elif project in ["dl", "protobuf"]: |
| # A special, non-golang.org/x/* repository. |
| # Put "z" at the beginning to sort this at the bottom of the builder list. |
| return "z_%s-%s-%s" % (project, go_branch_short, builder_type) |
| |
| # Add an x_ prefix to the project to help make it clear that |
| # we're testing a golang.org/x/* repository. These repositories |
| # do not have an "internal" counterpart. |
| return "x_%s-%s-%s" % (project, go_branch_short, builder_type) |
| |
| # project_title produces a short title for the given project. |
| def project_title(project): |
| if project == "go": |
| fail("project_title doesn't have support for the 'go' project") |
| elif project == "dl": |
| return "golang.org/dl" |
| elif project == "protobuf": |
| return "google.golang.org/protobuf" |
| else: |
| # A golang.org/x/* repository. Since these are very common, |
| # the 'golang.org/' prefix is left out for brevity. |
| return "x/" + project |
| |
| # make_console_gen returns a console generator struct whose gen field |
| # is a function that generates a console. |
| def make_console_gen(project, go_branch_short, builders, by_go_commit = False, known_issue = False, tier = 1): |
| repo = project |
| if project == "go": |
| name = "%s-%s" % (project, go_branch_short) |
| title = go_branch_short |
| ref = "refs/heads/" + GO_BRANCHES[go_branch_short].branch |
| else: |
| if project_title(project).startswith("x/"): |
| name = "x-%s-%s" % (project, go_branch_short) |
| else: |
| name = "z-%s-%s" % (project, go_branch_short) |
| title = project_title(project) + " (" + go_branch_short + ")" |
| ref = "refs/heads/" + MAIN_BRANCH_NAME |
| if by_go_commit: |
| name += "-by-go" |
| title += " by go commit" |
| ref = "refs/heads/" + GO_BRANCHES[go_branch_short].branch |
| repo = "go" |
| header = None |
| if known_issue: |
| title += " (known issue)" |
| name += "-known_issue" |
| links = [] |
| for builder_name, builder_type in builders.items(): |
| builder_name = builder_name.split("/")[1] # Remove the bucket. |
| issue = KNOWN_ISSUE_BUILDER_TYPES[builder_type].issue_number |
| links.append({ |
| "text": "%s: go.dev/issue/%d" % (builder_name, issue), |
| "url": "https://go.dev/issue/%d" % issue, |
| "alt": "Known issue link for %s" % builder_name, |
| }) |
| header = {"links": [{"name": "Known issues", "links": links}]} |
| |
| def gen(): |
| luci.console_view( |
| name = name, |
| repo = "https://go.googlesource.com/%s" % repo, |
| title = title, |
| refs = [ref], |
| entries = [ |
| luci.console_view_entry( |
| builder = name, |
| category = display_for_builder_type(builder_type)[0], |
| short_name = display_for_builder_type(builder_type)[1], |
| ) |
| for name, builder_type in builders.items() |
| ], |
| header = header, |
| ) |
| |
| return struct( |
| name = name, |
| title = title, |
| tier = tier, |
| gen = gen, |
| ) |
| |
| # Enum values for golangbuild's "mode" property. |
| GOLANGBUILD_MODES = { |
| "ALL": 0, |
| "COORDINATOR": 1, |
| "BUILD": 2, |
| "TEST": 3, |
| "PERF": 4, |
| } |
| |
| def define_builder(env, project, go_branch_short, builder_type): |
| """Creates a builder definition. |
| |
| Args: |
| env: the environment the builder runs in. |
| project: A go project defined in `PROJECTS`. |
| go_branch_short: A go repository branch name defined in `GO_BRANCHES` or `EXTRA_GO_BRANCHES`. |
| builder_type: A name defined in `BUILDER_TYPES`. |
| |
| Returns: |
| The full name including a bucket prefix. |
| A list of the builders this builder will trigger (by full name). |
| """ |
| |
| os, arch, suffix, run_mods = split_builder_type(builder_type) |
| host_type = host_of(builder_type) |
| hostos, hostarch, _, _ = split_builder_type(host_type) |
| |
| # Construct the basic properties that will apply to all builders for |
| # this combination. |
| known_go_branches = dict(GO_BRANCHES) |
| known_go_branches.update(EXTRA_GO_BRANCHES) |
| base_props = { |
| "project": project, |
| # NOTE: LUCI will pass in the commit information. This is |
| # extra information that's only necessary for x/ repos. |
| # However, we pass it to all builds for consistency and |
| # convenience. |
| "go_branch": known_go_branches[go_branch_short].branch, |
| "bootstrap_version": known_go_branches[go_branch_short].bootstrap, |
| "host": {"goos": hostos, "goarch": hostarch}, |
| "target": {"goos": os, "goarch": arch}, |
| "env": {}, |
| "is_google": not is_capacity_constrained(LOW_CAPACITY_HOSTS, host_type) or is_capacity_constrained(GOOGLE_LOW_CAPACITY_HOSTS, host_type), |
| } |
| if host_timeout_scale(host_type) != 1: |
| base_props["test_timeout_scale"] = host_timeout_scale(host_type) |
| if builder_type in env.known_issue_builder_types: |
| base_props["known_issue"] = env.known_issue_builder_types[builder_type].issue_number |
| for d in EXTRA_DEPENDENCIES: |
| if not d.applies(project, port_of(builder_type), run_mods): |
| continue |
| if d.test_deps: |
| base_props["tools_extra_test"] = d.test_deps |
| |
| # We run GOARCH=wasm builds on linux/amd64 with GOOS/GOARCH set, |
| # and the applicable Wasm runtime provided as a CIPD dependency. |
| # |
| # The availability of a given version in CIPD can be checked with: |
| # cipd search infra/3pp/tools/{wasm_runtime}/linux-amd64 -tag=version:{version} |
| # Where wasm_runtime is one of nodejs, wasmtime, wazero. |
| if arch == "wasm": |
| if os == "js": |
| if suffix != "": |
| fail("unknown GOOS=js builder suffix: %s" % suffix) |
| base_props["node_version"] = "2@18.8.0" |
| elif os == "wasip1": |
| if suffix == "wasmtime": |
| base_props["env"]["GOWASIRUNTIME"] = "wasmtime" |
| base_props["wasmtime_version"] = "2@14.0.4" |
| if go_branch_short == "go1.21": |
| base_props["wasmtime_version"] = "13.0.1" # See go.dev/issue/63718. |
| elif suffix == "wazero": |
| base_props["env"]["GOWASIRUNTIME"] = "wazero" |
| base_props["wazero_version"] = "2@1.7.0" |
| else: |
| fail("unknown GOOS=wasip1 builder suffix: %s" % suffix) |
| |
| # Set GOPPC64 explicitly when it's specified in the suffix. |
| if arch in ["ppc64", "ppc64le"] and "power" in suffix: |
| base_props["env"]["GOPPC64"] = suffix |
| |
| # TODO(go.dev/issue/65241): Start by mirroring old infra's linux-arm env, |
| # which came from CL 390395 and that came from CL 35501 for issue 18748. |
| # Since then the default for GOARM has changed¹, so these should be unset |
| # to make the builder more representative of a common default environment. |
| # ¹ https://go.dev/doc/go1.22#arm |
| if builder_type == "linux-arm": |
| base_props["env"]["GOARM"] = "6" |
| |
| # Construct the basic dimensions for the build/test running part of the build. |
| # |
| # Note that these should generally live in the worker pools. |
| base_dims = dimensions_of(host_type) |
| base_dims["pool"] = env.worker_pool |
| if is_capacity_constrained(env.low_capacity_hosts, host_type) and env.shared_worker_pool != "": |
| # Scarce resources live in the shared-workers pool when it is available. |
| base_dims["pool"] = env.shared_worker_pool |
| |
| # On less-supported platforms, we may not have bootstraps before 1.21 |
| # started cross-compiling everything. |
| if not is_fully_supported(base_dims) and (base_props["bootstrap_version"].startswith("1.20") or base_props["bootstrap_version"].startswith("1.1")): |
| base_props["bootstrap_version"] = "1.21.0" |
| |
| if os == "darwin": |
| # See available versions with: cipd instances -limit 0 infra_internal/ios/xcode/mac | less |
| xcode_versions = { |
| 10: "11e503a", # released Apr 2020, macOS 10.15 released Oct 2019 |
| 11: "12b45b", # released Nov 2020, macOS 11 released Nov 2020 |
| 12: "13c100", # released Dec 2021, macOS 12 released Oct 2021 |
| 13: "15c500b", # released Jan 2024, macOS 13.5 released Jul 2023 |
| 14: "15e204a", # released Mar 2023, macOS 14 released Sep 2023 |
| } |
| base_props["xcode_version"] = xcode_versions[int(dimensions_of(host_type)["os"].split(".")[0].replace("Mac-", ""))] |
| |
| # Turn on the no-network check. |
| if builder_type in NO_NETWORK_BUILDERS: |
| base_props["no_network"] = True |
| |
| # Leave release branches out of scope, they can't work until some |
| # test fixes are backported, but doing that might not be worth it. |
| # TODO(dmitshur): Delete this after Go 1.21 drops off. |
| if project == "go" and go_branch_short == "go1.21": |
| base_props.pop("no_network") |
| |
| for mod in run_mods: |
| if not mod in RUN_MODS: |
| fail("unknown run mod: %s" % mod) |
| RUN_MODS[mod].apply(base_props, project) |
| |
| # Named cache for git clones. |
| base_props["git_cache"] = "git" |
| |
| # Named cache for cipd tools root. |
| base_props["tools_cache"] = "tools" |
| |
| caches = [ |
| swarming.cache(base_props["git_cache"]), |
| swarming.cache(base_props["tools_cache"]), |
| ] |
| |
| # Determine which experiments to apply. |
| experiments = { |
| "golang.shard_by_weight": 100, |
| } |
| |
| # Construct the executable reference. |
| executable = luci.executable( |
| name = "golangbuild", |
| cipd_package = "infra/experimental/golangbuild/${platform}", |
| cipd_version = "latest", |
| cmd = ["golangbuild"], |
| ) |
| |
| # Determine how long we should wait for a machine to become available before the |
| # build expires. Only applies if there's at least one machine. Builds fail immediately |
| # if there are no machines matching the dimensions, unless the builder's wait_for_capacity |
| # field is set. |
| # |
| # For builders targeting platforms that we have plenty of resources for, wait up to 6 hours. |
| # Robocrop should scale much sooner than that to fill demand, but if we end up with more demand |
| # than our cap we'll have 6 hours for that demand to be filled before we report it as a problem. |
| # We do not wait for capacity on these builders so we can find out immediately out all our |
| # capacity is drained. It is usually indicative of a bigger issue, like an outage. |
| # |
| # For builders that are capacity constrained, wait several times longer. Note |
| # that the time we can wait here is not usually unbounded, since according to triggering_policy there |
| # can only be at most 1 outstanding request per repo+gobranch combination in postsubmit. |
| # Therefore, this constant should generally not need to be bumped up. The only case where it |
| # might need it is a high rate of presubmit builds including such builders, but the fact |
| # that builds expire is good: it acts as a backpressure mechanism. We wait for capacity on |
| # these builders because they frequently go down for maintenance or just because they're flaky. |
| capacity_constrained = is_capacity_constrained(env.low_capacity_hosts, host_type) |
| expiration_timeout = 6 * time.hour |
| wait_for_capacity = False |
| if capacity_constrained: |
| expiration_timeout = time.day |
| wait_for_capacity = True |
| |
| # Define notifications for the builder. |
| notifiers = [] |
| |
| # Add a notification for machine owners on infra failures. |
| if host_type in HOST_NOTIFIERS: |
| notifiers.append(HOST_NOTIFIERS[host_type]) |
| |
| # Create a helper to emit builder definitions, installing common fields from |
| # the current context. |
| def emit_builder(name, bucket, dimensions, properties, service_account, **kwargs): |
| exps = dict(experiments) |
| if not is_fully_supported(dimensions): |
| exps["luci.best_effort_platform"] = 100 |
| luci.builder( |
| name = name, |
| bucket = bucket, |
| executable = executable, |
| dimensions = dimensions, |
| properties = properties, |
| service_account = service_account, |
| swarming_host = env.swarming_host, |
| resultdb_settings = resultdb.settings( |
| enable = True, |
| ), |
| caches = caches, |
| experiments = exps, |
| expiration_timeout = expiration_timeout, |
| wait_for_capacity = wait_for_capacity, |
| priority = env.priority, |
| notifies = notifiers, |
| **kwargs |
| ) |
| |
| name = builder_name(project, go_branch_short, builder_type) |
| |
| # Determine if we should be sharding tests, and how many shards. |
| compile_only = "compile_only" in base_props |
| misccompile = "misccompile" in run_mods |
| perfmode = "perf_mode" in base_props |
| if compile_only: |
| if misccompile: |
| if project == "go": |
| test_shards = 12 |
| else: |
| test_shards = 3 |
| else: |
| # Compile-only builders for a single platform should have just one shard, otherwise |
| # each shard will do repeat work. |
| test_shards = 1 |
| elif perfmode: |
| test_shards = 1 |
| elif project == "go" and not capacity_constrained: |
| test_shards = 4 |
| else: |
| test_shards = 1 |
| |
| # Emit the builder definitions. |
| # |
| # For each builder type we have two possible options for emitting a builder. Either it's going to be |
| # a sharded builder, which actually consists of 3 builders for coordination, build, and test, or a single |
| # builder all-mode which does all 3 on the same machine. |
| # |
| # The sharded builder is mainly used for sharding tests, but it is also useful for sharding misccompile |
| # builds. Even if we have only 1 shard, a sharded builder is still useful because only coordinator builders |
| # are allowed to spawn other builds, and so these coordination builders may spawn downstream builds. |
| # For example, builds of Go cache the toolchain. Triggering subrepo builds once the cache is filled is ideal, |
| # because the subrepo builds can use the cached toolchain. To actually run sharded builds we can't be |
| # capacity constrained, and we must only run for the main Go repo, because that's the only case we support |
| # for test sharding in golangbuild currently. |
| # |
| # The all-mode builder is used for everything else, but we must only select it if test_shards == 1. |
| downstream_builders = [] |
| if perfmode: |
| define_perfmode_builder(env, name, builder_type, base_props, base_dims, emit_builder) |
| elif test_shards > 1 or (project == "go" and not capacity_constrained): |
| downstream_builders = define_sharded_builder(env, project, name, test_shards, go_branch_short, builder_type, run_mods, base_props, base_dims, emit_builder) |
| elif test_shards == 1: |
| define_allmode_builder(env, name, builder_type, base_props, base_dims, emit_builder) |
| else: |
| fail("unhandled builder definition") |
| |
| return env.bucket + "/" + name, downstream_builders |
| |
| def define_sharded_builder(env, project, name, test_shards, go_branch_short, builder_type, run_mods, base_props, base_dims, emit_builder): |
| os, arch, _, _ = split_builder_type(builder_type) |
| |
| # Create 3 builders: the main entrypoint/coordinator builder, |
| # a builder just to run make.bash, and a builder to run tests. |
| # |
| # This separation of builders allows for the coordinator builder to have elevated privileges, |
| # because it will never run code still in code review. Furthermore, this separation allows |
| # for sharding tests, which lets us improve build latency beyond what one machine is able to provide. |
| # |
| # The main/coordinator builder must be the only one with the ability |
| # to schedule new builds. |
| coord_name = name |
| if project == "go": |
| build_name = name + "-build_go" |
| else: |
| build_name = builder_name("go", go_branch_short, builder_type) + "-build_go" |
| test_name = name + "-test_only" |
| |
| # The main repo builder also triggers subrepo builders of the same builder type. |
| # |
| # This is currently only used to trigger CI builders, not trybots, because |
| # a builder triggered this way by default will be considered as optional. |
| # |
| # TODO(mknyszek): This rule will not apply for some ports in the future. Some |
| # ports only apply to the main Go repository and are not supported by all subrepos. |
| # PROJECTS should probably contain a table of supported ports or something. |
| builders_to_trigger = [] |
| if project == "go" and env.bucket == "ci": |
| builders_to_trigger = [ |
| "%s/%s" % (env.bucket, builder_name(project, go_branch_short, builder_type)) |
| for project in PROJECTS |
| if project != "go" and enabled(env.low_capacity_hosts, project, go_branch_short, builder_type, env.known_issue_builder_types)[2] |
| ] |
| |
| # Coordinator builder. |
| # |
| # Specify the dimensions directly. Coordinator builds can have very vague dimensions |
| # because we don't really care what machines they run on. We still need to specify |
| # something for robocrop, but the robocrop config will look for just "Linux." |
| coord_dims = { |
| "pool": env.coordinator_pool, |
| "cipd_platform": "linux-amd64", |
| } |
| |
| coord_props = dict(base_props) |
| coord_props.update({ |
| "mode": GOLANGBUILD_MODES["COORDINATOR"], |
| "coord_mode": { |
| "build_builder": "golang/" + env.worker_bucket + "/" + build_name, |
| "test_builder": "golang/" + env.worker_bucket + "/" + test_name, |
| "num_test_shards": test_shards, |
| "builders_to_trigger_after_toolchain_build": ["golang/%s" % name for name in builders_to_trigger], |
| }, |
| }) |
| emit_builder( |
| name = coord_name, |
| bucket = env.bucket, |
| dimensions = coord_dims, |
| properties = coord_props, |
| triggering_policy = triggering_policy(env, builder_type), |
| service_account = env.coordinator_sa, |
| ) |
| |
| # Build builder. |
| if project == "go": |
| build_dims = dict(base_dims) |
| build_props = dict(base_props) |
| build_props.update({ |
| "mode": GOLANGBUILD_MODES["BUILD"], |
| "build_mode": {}, |
| # For sharded x repo builders, go_commit will be overwritten by the coordinator builder. |
| "go_commit": "", |
| }) |
| emit_builder( |
| name = build_name, |
| bucket = env.worker_bucket, |
| dimensions = build_dims, |
| properties = build_props, |
| service_account = env.worker_sa, |
| allowed_property_overrides = ["go_commit"], |
| ) |
| |
| # Test builder. |
| test_dims = dict(base_dims) |
| test_props = dict(base_props) |
| test_props.update({ |
| "mode": GOLANGBUILD_MODES["TEST"], |
| "test_mode": {}, |
| # For sharded x repo builders, go_commit will be overwritten by the coordinator builder. |
| "go_commit": "", |
| # The default is no sharding. This may be overwritten by the coordinator builder. |
| "test_shard": {"shard_id": 0, "num_shards": 1}, |
| }) |
| emit_builder( |
| name = test_name, |
| bucket = env.worker_bucket, |
| dimensions = test_dims, |
| properties = test_props, |
| service_account = env.worker_sa, |
| allowed_property_overrides = ["go_commit", "test_shard"], |
| ) |
| return builders_to_trigger |
| |
| def define_allmode_builder(env, name, builder_type, base_props, base_dims, emit_builder): |
| # Create an "ALL" mode builder which just performs the full build serially. |
| # |
| # This builder is substantially simpler because it doesn't need to trigger any |
| # downstream builders, and also doesn't need test sharding (most subrepos' tests |
| # run fast enough that it's unnecessary). |
| all_props = dict(base_props) |
| all_props.update({ |
| "mode": GOLANGBUILD_MODES["ALL"], |
| }) |
| emit_builder( |
| name = name, |
| bucket = env.bucket, |
| dimensions = base_dims, |
| properties = all_props, |
| triggering_policy = triggering_policy(env, builder_type), |
| service_account = env.worker_sa, |
| ) |
| |
| def define_perfmode_builder(env, name, builder_type, base_props, base_dims, emit_builder): |
| # Create an "PERF" mode builder which runs benchmarks. Its operation is somewhat |
| # special, usually involving checking out two copies of a repository and possibly |
| # a third containing benchmarks. |
| # |
| # This builder is substantially simpler because it doesn't need to trigger any |
| # downstream builders, and also doesn't currently support sharding. |
| perf_props = dict(base_props) |
| perf_props.update({ |
| "mode": GOLANGBUILD_MODES["PERF"], |
| }) |
| |
| # Request c2-standard-16 machines for linux/amd64. This machine type provides |
| # a much more consistent hardware platform, which is useful for making a less |
| # noisy performance measurement. |
| perf_dims = dict(base_dims) |
| emit_builder( |
| name = name, |
| bucket = env.bucket, |
| dimensions = perf_dims, |
| properties = perf_props, |
| triggering_policy = triggering_policy(env, builder_type), |
| service_account = env.worker_sa, |
| execution_timeout = 12 * time.hour, |
| ) |
| |
| # triggering_policy defines the LUCI Scheduler triggering policy for postsubmit builders. |
| # Returns None for presubmit builders. |
| def triggering_policy(env, builder_type): |
| if env.bucket not in ["ci", "ci-workers"]: |
| return None |
| concurrent_builds = 5 |
| if is_capacity_constrained(env.low_capacity_hosts, host_of(builder_type)): |
| concurrent_builds = 1 |
| return scheduler.newest_first( |
| max_concurrent_invocations = concurrent_builds, |
| pending_timeout = time.week, |
| ) |
| |
| luci.builder( |
| name = "tricium", |
| bucket = "try", |
| executable = luci.recipe( |
| name = "tricium_simple", |
| ), |
| service_account = "luci-task@golang-ci-luci.iam.gserviceaccount.com", |
| dimensions = { |
| "pool": "luci.golang.try", |
| "os": "Linux", |
| "cpu": "x86-64", |
| }, |
| ) |
| |
| def display_for_builder_type(builder_type): |
| """Produces the category and short name for a luci.console_view_entry. |
| |
| Args: |
| builder_type: A name defined in `BUILDER_TYPES`. |
| |
| Returns: |
| The category and the short name. |
| """ |
| components = builder_type.split("-", 2) |
| short_name = components[2] if len(components) > 2 else None |
| category = "|".join(components[:2]) |
| return category, short_name # Produces: "$GOOS|$GOARCH", $HOST_SPECIFIER(-$RUN_MOD)* |
| |
| # enabled returns three boolean values and a list or None. The first boolean value |
| # indicates if this builder_type should exist at all for the given project |
| # and branch, the second whether it should run in presubmit by default, and |
| # the third if it should run in postsubmit. The final list is a list of cq.location_filters |
| # if the builder should run in presubmit by default. |
| def enabled(low_capacity_hosts, project, go_branch_short, builder_type, known_issue_builder_types): |
| pt = PROJECTS[project] |
| os, arch, suffix, run_mods = split_builder_type(builder_type) |
| host_type = host_of(builder_type) |
| |
| if builder_type in known_issue_builder_types and known_issue_builder_types[builder_type] \ |
| .skip_x_repos and project != "go": |
| return False, False, False, [] |
| |
| # Filter out old OS versions from new branches. |
| if os == "darwin" and suffix == "10.15" and go_branch_short not in ["go1.22", "go1.21"]: |
| # Go 1.22 is last to support macOS 10.15. |
| return False, False, False, [] |
| |
| # Filter out new ports on old release branches. |
| if os == "openbsd" and arch == "riscv64" and go_branch_short in ["go1.22", "go1.21"]: |
| # The openbsd/riscv64 port is new to Go 1.23. |
| return False, False, False, [] |
| |
| # Apply basic policies about which projects run on what machine types, |
| # and what we have capacity to run in presubmit. |
| enable_types = None |
| if pt == PT.TOOL: |
| enable_types = ["linux-amd64", "windows-amd64", "darwin-amd64"] |
| elif project == "mobile": |
| enable_types = ["linux-amd64", "android"] |
| elif project == "exp": |
| # Not quite sure what to do with exp/shiny. For now just run on major platforms. |
| enable_types = ["linux-386", "linux-amd64", "linux-arm64", "windows-386", "windows-amd64", "darwin-amd64"] |
| elif project == "protobuf": |
| enable_types = ["linux-amd64"] # See issue go.dev/issue/63597. |
| elif pt == PT.SPECIAL: |
| fail("unhandled SPECIAL project: %s" % project) |
| postsubmit = enable_types == None or any([x == "%s-%s" % (os, arch) for x in enable_types]) |
| presubmit = postsubmit # Default to running in presubmit if and only if running in postsubmit. |
| presubmit = presubmit and not is_capacity_constrained(low_capacity_hosts, host_type) # Capacity. |
| presubmit = presubmit and not host_timeout_scale(host_type) > 1 # Speed. |
| if project != "go": # Some ports run as presubmit only in the main Go repo. |
| presubmit = presubmit and os not in ["js", "wasip1"] |
| |
| # Apply policies for each run mod. |
| presubmit_filters = [] |
| for mod in run_mods: |
| ex, pre, post, prefilt = RUN_MODS[mod].enabled(port_of(builder_type), project, go_branch_short) |
| if not ex: |
| return False, False, False, [] |
| presubmit = presubmit and pre |
| postsubmit = postsubmit and post |
| if prefilt: |
| presubmit_filters.extend(prefilt) |
| |
| return True, presubmit, postsubmit, presubmit_filters |
| |
| # Apply LUCI-TryBot-Result +1 or -1 based on CQ result. |
| # |
| # TODO(prattmic): Switch to TryBot-Result once we are ready to use these for |
| # submit enforcement. |
| POST_ACTIONS = [ |
| cq.post_action_gerrit_label_votes( |
| name = "trybot-success", |
| conditions = [ |
| cq.post_action_triggering_condition( |
| mode = cq.MODE_DRY_RUN, |
| statuses = [cq.STATUS_SUCCEEDED], |
| ), |
| ], |
| labels = {"LUCI-TryBot-Result": 1}, |
| ), |
| cq.post_action_gerrit_label_votes( |
| name = "trybot-failure", |
| conditions = [ |
| cq.post_action_triggering_condition( |
| mode = cq.MODE_DRY_RUN, |
| statuses = [cq.STATUS_FAILED, cq.STATUS_CANCELLED], |
| ), |
| ], |
| labels = {"LUCI-TryBot-Result": -1}, |
| ), |
| ] |
| |
| def _define_go_ci(): |
| # Presubmit. |
| for project in PROJECTS: |
| for go_branch_short, go_branch in GO_BRANCHES.items(): |
| # Set up a CQ group for the builder definitions below. |
| cq_group = go_cq_group(project, go_branch_short) |
| luci.cq_group( |
| name = cq_group.name, |
| acls = [ |
| acl.entry( |
| roles = acl.CQ_DRY_RUNNER, |
| groups = ["project-golang-may-start-trybots"], |
| ), |
| acl.entry( |
| roles = acl.CQ_COMMITTER, |
| groups = ["project-golang-approvers"], |
| ), |
| ], |
| watch = cq_group.watch, |
| allow_submit_with_open_deps = True, |
| trust_dry_runner_deps = True, |
| allow_non_owner_dry_runner = True, |
| verifiers = [ |
| luci.cq_tryjob_verifier( |
| builder = "try/tricium", |
| location_filters = [ |
| cq.location_filter( |
| gerrit_host_regexp = "%s-review.googlesource.com" % host, |
| gerrit_project_regexp = filter_project, |
| path_regexp = ".+", |
| ) |
| for host in ["go", "go-internal"] |
| for filter_project in PROJECTS |
| ], |
| mode_allowlist = [cq.MODE_ANALYZER_RUN], |
| ), |
| ], |
| post_actions = POST_ACTIONS, |
| ) |
| |
| # Define builders. |
| for builder_type in BUILDER_TYPES: |
| exists, presubmit, _, presubmit_filters = enabled(LOW_CAPACITY_HOSTS, project, go_branch_short, builder_type, KNOWN_ISSUE_BUILDER_TYPES) |
| if not exists: |
| continue |
| |
| name, _ = define_builder(PUBLIC_TRY_ENV, project, go_branch_short, builder_type) |
| luci.cq_tryjob_verifier( |
| builder = name, |
| cq_group = cq_group.name, |
| includable_only = not presubmit, |
| disable_reuse = True, |
| location_filters = [ |
| cq.location_filter( |
| gerrit_host_regexp = "go-review.googlesource.com", |
| gerrit_project_regexp = "^%s$" % project, |
| path_regexp = filter, |
| ) |
| for filter in presubmit_filters |
| if presubmit |
| ], |
| ) |
| |
| # For golang.org/x repos, include the ability to run presubmit |
| # against all supported releases in addition to testing with tip. |
| # Make presubmit mandatory for builders deemed "fast". |
| # See go.dev/issue/17626. |
| if project != "go" and go_branch_short != "gotip": |
| x_repo_presubmit = builder_type in ["linux-amd64", "linux-386", "darwin-amd64_14", "windows-amd64"] and \ |
| enabled(LOW_CAPACITY_HOSTS, project, go_branch_short, builder_type, KNOWN_ISSUE_BUILDER_TYPES)[2] |
| luci.cq_tryjob_verifier( |
| builder = name, |
| cq_group = go_cq_group(project, "gotip").name, |
| includable_only = not x_repo_presubmit, |
| disable_reuse = True, |
| ) |
| |
| # Add an x/tools builder to the Go presubmit. |
| if project == "go" and builder_type == "linux-amd64": |
| luci.cq_tryjob_verifier( |
| builder = PUBLIC_TRY_ENV.bucket + "/" + builder_name("tools", go_branch_short, builder_type), |
| cq_group = cq_group.name, |
| disable_reuse = True, |
| ) |
| |
| # For golang.org/x/tools, also include coverage for extra Go versions. |
| if project == "tools" and go_branch_short == "gotip": |
| for extra_go_release, _ in EXTRA_GO_BRANCHES.items(): |
| builder_type = "linux-amd64" # Just one fast and highly available builder is deemed enough. |
| try_builder, _ = define_builder(PUBLIC_TRY_ENV, project, extra_go_release, builder_type) |
| luci.cq_tryjob_verifier( |
| builder = try_builder, |
| cq_group = cq_group.name, |
| disable_reuse = True, |
| ) |
| |
| # Postsubmit. |
| console_generators = [] |
| postsubmit_builders_by_port = {} |
| postsubmit_builders_by_project_and_branch = {} |
| postsubmit_builders_with_go_repo_trigger = {} |
| for project in PROJECTS: |
| for go_branch_short, go_branch in GO_BRANCHES.items(): |
| # Define builders. |
| postsubmit_builders = {} |
| postsubmit_builders_known_issue = {} |
| for builder_type in BUILDER_TYPES: |
| exists, _, postsubmit, _ = enabled(LOW_CAPACITY_HOSTS, project, go_branch_short, builder_type, KNOWN_ISSUE_BUILDER_TYPES) |
| if not exists or not postsubmit: |
| continue |
| |
| name, triggers = define_builder(PUBLIC_CI_ENV, project, go_branch_short, builder_type) |
| if builder_type in KNOWN_ISSUE_BUILDER_TYPES: |
| postsubmit_builders_known_issue[name] = builder_type |
| else: |
| postsubmit_builders[name] = builder_type |
| |
| # Collect all the builders that have triggers from the Go repository. Every builder needs at least one. |
| if project == "go": |
| postsubmit_builders_with_go_repo_trigger[name] = True |
| for name in triggers: |
| postsubmit_builders_with_go_repo_trigger[name] = True |
| |
| # For golang.org/x/tools, also include coverage for extra Go versions. |
| if project == "tools" and go_branch_short == "gotip": |
| for extra_go_release, _ in EXTRA_GO_BRANCHES.items(): |
| builder_type = "linux-amd64" # Just one fast and highly available builder is deemed enough. |
| ci_builder, _ = define_builder(PUBLIC_CI_ENV, project, extra_go_release, builder_type) |
| postsubmit_builders[ci_builder] = builder_type |
| |
| # Collect all the postsubmit builders by port and project. |
| for name, builder_type in postsubmit_builders.items() + postsubmit_builders_known_issue.items(): |
| os, arch, _, _ = split_builder_type(builder_type) |
| port = "%s/%s" % (os, arch) |
| postsubmit_builders_by_port.setdefault(port, []).append(name) |
| postsubmit_builders_by_project_and_branch.setdefault((project, go_branch.branch, go_branch_short), []).append(name) |
| |
| # Create the gitiles_poller last because we need the full set of builders to |
| # trigger at the point of definition. |
| # |
| # This is the poller for commits coming in from the target repo. Subrepo builders are |
| # also triggered by the main Go repo builds in one of two ways. Either the main repo builds |
| # trigger them directly once the toolchain builder is done, or that builder is not added to |
| # list of builders with triggers and we generate pollers for those builders at the end. |
| if project == "go": |
| poller_branch = go_branch.branch |
| else: |
| poller_branch = MAIN_BRANCH_NAME |
| luci.gitiles_poller( |
| name = "%s-%s-trigger" % (project, go_branch_short), |
| bucket = "ci", |
| repo = "https://go.googlesource.com/%s" % project, |
| refs = ["refs/heads/" + poller_branch], |
| triggers = postsubmit_builders.keys() + postsubmit_builders_known_issue.keys(), |
| ) |
| |
| # Create consoles generators. |
| if project == "go": |
| console_generators.extend([ |
| # Main console for go on go_branch_short. |
| make_console_gen(project, go_branch_short, postsubmit_builders), |
| # Known issue builders console for go on go_branch_short. |
| make_console_gen(project, go_branch_short, postsubmit_builders_known_issue, known_issue = True, tier = 3), |
| ]) |
| else: |
| console_generators.extend([ |
| # Main console for project on go_branch_short. |
| make_console_gen(project, go_branch_short, postsubmit_builders), |
| # Console for project on go_branch_short ordered by Go commit. |
| make_console_gen(project, go_branch_short, postsubmit_builders, by_go_commit = True, tier = 2), |
| # Known issue builders console for project on go_branch_short ordered. |
| make_console_gen(project, go_branch_short, postsubmit_builders_known_issue, known_issue = True, tier = 3), |
| # Known issue builders console for project on go_branch_short ordered by Go commit. |
| make_console_gen(project, go_branch_short, postsubmit_builders_known_issue, by_go_commit = True, known_issue = True, tier = 4), |
| ]) |
| |
| # Collect all the postsubmit builders that still need triggers. |
| postsubmit_builders_need_triggers = {} |
| for target, builders in postsubmit_builders_by_project_and_branch.items(): |
| for name in builders: |
| if name not in postsubmit_builders_with_go_repo_trigger: |
| postsubmit_builders_need_triggers.setdefault(target, []).append(name) |
| |
| # Emit gitiles_pollers for all the builders who don't have triggers. |
| for target, builders in postsubmit_builders_need_triggers.items(): |
| project, go_branch, go_branch_short = target |
| if project == "go": |
| fail("discovered main Go repo builders without triggers: %s" % builders) |
| luci.gitiles_poller( |
| name = "%s-%s-go-trigger" % (project, go_branch_short), |
| bucket = "ci", |
| repo = "https://go.googlesource.com/go", |
| refs = ["refs/heads/" + go_branch], |
| triggers = builders, |
| ) |
| |
| # Emit consoles in order of tier, and within each tier, the order in which |
| # we iterated over PROJECTS and GO_BRANCHES. (sorted is a stable sort.) |
| # The order we emit them here will be the display order. |
| for console in sorted(console_generators, key = lambda c: c.tier): |
| console.gen() |
| |
| # Emit builder groups for each port. |
| # These will appear last, since they're emitted last. |
| for port, builders in postsubmit_builders_by_port.items(): |
| luci.list_view( |
| name = "port-%s" % port.replace("/", "-"), |
| title = "all %s" % port, |
| entries = builders, |
| ) |
| |
| def _define_go_internal_ci(): |
| for project_name in ["go", "net", "crypto"]: |
| for go_branch_short, go_branch in INTERNAL_GO_BRANCHES.items(): |
| # TODO(yifany): Simplify cq.location_filter once Tricium to CV |
| # migration (go/luci/tricium) is done. |
| cq_group_name = ("go-internal_%s_%s" % (project_name, go_branch_short)).replace(".", "-") |
| luci.cq_group( |
| name = cq_group_name, |
| acls = [ |
| acl.entry( |
| roles = acl.CQ_DRY_RUNNER, |
| groups = ["mdb/golang-security-policy", "mdb/golang-release-eng-policy"], |
| ), |
| acl.entry( |
| roles = acl.CQ_COMMITTER, |
| groups = ["mdb/golang-security-policy", "mdb/golang-release-eng-policy"], |
| ), |
| ], |
| watch = cq.refset( |
| repo = "https://go-internal.googlesource.com/%s" % project_name, |
| refs = ["refs/heads/%s" % go_branch.branch_regexp], |
| ), |
| allow_submit_with_open_deps = True, |
| trust_dry_runner_deps = True, |
| allow_non_owner_dry_runner = True, |
| verifiers = [ |
| luci.cq_tryjob_verifier( |
| builder = "try/tricium", |
| location_filters = [ |
| cq.location_filter( |
| gerrit_host_regexp = "%s-review.googlesource.com" % host, |
| gerrit_project_regexp = filter_project, |
| path_regexp = ".+", |
| ) |
| for host in ["go", "go-internal"] |
| for filter_project in PROJECTS |
| ], |
| mode_allowlist = [cq.MODE_ANALYZER_RUN], |
| ), |
| ], |
| # TODO(prattmic): Set post_actions to apply TryBot-Result labels. |
| ) |
| |
| for builder_type in BUILDER_TYPES: |
| exists, presubmit, postsubmit, _ = enabled(LOW_CAPACITY_HOSTS, project_name, go_branch_short, builder_type, SECURITY_KNOWN_ISSUE_BUILDER_TYPES) |
| host_type = host_of(builder_type) |
| |
| # The internal host only has access to some machines. As of |
| # writing, that means all the GCE-hosted (high-capacity) builders |
| # and a select subset of GOOGLE_LOW_CAPACITY_HOSTS, and that's it. |
| if host_type in [ |
| # A select subset of GOOGLE_LOW_CAPACITY_HOSTS that provide |
| # a separate set of VMs that connect to the chrome-swarming |
| # swarming instance. This requires additional resources and |
| # work to set up, hence each such host needs to opt-in here. |
| "linux-arm", |
| "darwin-amd64_14", |
| ]: |
| # The list above is expected to contain only Google low-capacity hosts. |
| # Verify that's the case. |
| if not is_capacity_constrained(GOOGLE_LOW_CAPACITY_HOSTS, host_type): |
| fail("host type %s is listed explicitly but is not a Google low-capacity host", host_type) |
| elif is_capacity_constrained(LOW_CAPACITY_HOSTS, host_type): |
| exists = False |
| |
| if not exists: |
| continue |
| |
| # Define presubmit builders. Since there's no postsubmit to monitor, |
| # all possible completed builders that perform testing are required. |
| name, _ = define_builder(SECURITY_TRY_ENV, project_name, go_branch_short, builder_type) |
| _, _, _, run_mods = split_builder_type(builder_type) |
| luci.cq_tryjob_verifier( |
| builder = name, |
| cq_group = cq_group_name, |
| disable_reuse = True, |
| includable_only = any([r.startswith("perf") for r in run_mods]) or |
| (not presubmit and not postsubmit) or |
| builder_type in SECURITY_KNOWN_ISSUE_BUILDER_TYPES, |
| ) |
| |
| _define_go_ci() |
| _define_go_internal_ci() |
| |
| exec("./recipes.star") |