blob: dea80c87b0241c214374ae38eab2583bd8d97d73 [file] [log] [blame]
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001#!/usr/bin/env python3
2#
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003# Copyright 2018 The Bazel Authors. All rights reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010017import argparse
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +010018import base64
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010019import codecs
Yun Peng5a1a9442022-01-11 14:26:48 +010020import copy
Jakob Buchgraber12807052018-02-25 17:04:56 +010021import datetime
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +010022from glob import glob
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +010023import hashlib
Yun Peng5a1a9442022-01-11 14:26:48 +010024import itertools
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010025import json
Jakob Buchgraber6db0f262018-02-17 15:45:54 +010026import multiprocessing
Philipp Wollermann0a04cf32018-02-21 17:07:22 +010027import os
Philipp Wollermanndcaddd92018-02-21 14:13:43 +010028import os.path
Florian Weikertda94a102022-10-21 12:24:37 +020029import platform as platform_module
Jakob Buchgraber257693b2018-02-20 00:03:56 +010030import random
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010031import re
Yun Peng9337bb32020-02-28 13:31:29 +010032import requests
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010033import shutil
Philipp Wollermanndcaddd92018-02-21 14:13:43 +010034import stat
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010035import subprocess
36import sys
Florian Weikert5e70d9d2023-05-08 19:20:23 +020037import tarfile
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010038import tempfile
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +020039import threading
Philipp Wollermanne1318eb2018-08-13 15:08:01 +020040import time
Philipp Wollermannce986af2019-07-18 14:46:05 +020041import urllib.error
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010042import urllib.request
Jakob Buchgraber25bb50f2018-02-22 18:06:21 +010043import yaml
Philipp Wollermanndcaddd92018-02-21 14:13:43 +010044
45# Initialize the random number generator.
46random.seed()
47
Philipp Wollermanne67eec42019-05-24 15:18:20 +020048BUILDKITE_ORG = os.environ["BUILDKITE_ORGANIZATION_SLUG"]
Florian Weikertc2745512021-02-17 16:13:55 +010049THIS_IS_PRODUCTION = BUILDKITE_ORG == "bazel"
Philipp Wollermanne67eec42019-05-24 15:18:20 +020050THIS_IS_TESTING = BUILDKITE_ORG == "bazel-testing"
51THIS_IS_TRUSTED = BUILDKITE_ORG == "bazel-trusted"
52THIS_IS_SPARTA = True
53
54CLOUD_PROJECT = "bazel-public" if THIS_IS_TRUSTED else "bazel-untrusted"
55
56GITHUB_BRANCH = {"bazel": "master", "bazel-trusted": "master", "bazel-testing": "testing"}[
57 BUILDKITE_ORG
58]
59
60SCRIPT_URL = "https://raw.githubusercontent.com/bazelbuild/continuous-integration/{}/buildkite/bazelci.py?{}".format(
61 GITHUB_BRANCH, int(time.time())
Philipp Wollermannc05ac682019-01-19 12:37:28 +010062)
Jakob Buchgraber95e3d572018-02-21 18:48:49 +010063
Philipp Wollermanne67eec42019-05-24 15:18:20 +020064AGGREGATE_INCOMPATIBLE_TEST_RESULT_URL = "https://raw.githubusercontent.com/bazelbuild/continuous-integration/{}/buildkite/aggregate_incompatible_flags_test_result.py?{}".format(
65 GITHUB_BRANCH, int(time.time())
66)
67
68EMERGENCY_FILE_URL = "https://raw.githubusercontent.com/bazelbuild/continuous-integration/{}/buildkite/emergency.yml?{}".format(
69 GITHUB_BRANCH, int(time.time())
70)
71
72FLAKY_TESTS_BUCKET = {
73 "bazel-testing": "gs://bazel-testing-buildkite-stats/flaky-tests-bep/",
74 "bazel-trusted": "gs://bazel-buildkite-stats/flaky-tests-bep/",
75 "bazel": "gs://bazel-buildkite-stats/flaky-tests-bep/",
76}[BUILDKITE_ORG]
77
Chi Wangb2b65682020-08-27 10:36:15 +080078KZIPS_BUCKET = {
79 "bazel-testing": "gs://bazel-kzips-testing/",
80 "bazel-trusted": "gs://bazel-kzips/",
81 "bazel": "gs://bazel-kzips/",
82}[BUILDKITE_ORG]
83
Florian Weikert797787b2019-12-19 15:33:07 +010084# Projects can opt out of receiving GitHub issues from --notify by adding `"do_not_notify": True` to their respective downstream entry.
Philipp Wollermanne67eec42019-05-24 15:18:20 +020085DOWNSTREAM_PROJECTS_PRODUCTION = {
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +010086 "Android Studio Plugin": {
87 "git_repository": "https://github.com/bazelbuild/intellij.git",
88 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/android-studio.yml",
89 "pipeline_slug": "android-studio-plugin",
90 },
Mai Hussien0731b4d2022-06-28 11:16:07 -070091 "Android Studio Plugin Google": {
92 "git_repository": "https://github.com/bazelbuild/intellij.git",
93 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/google/.bazelci/android-studio.yml",
94 "pipeline_slug": "android-studio-plugin-google",
95 },
Yun Peng996efad2018-11-27 17:19:44 +010096 "Android Testing": {
97 "git_repository": "https://github.com/googlesamples/android-testing.git",
Jingwenbde72602018-12-13 10:57:43 -050098 "http_config": "https://raw.githubusercontent.com/googlesamples/android-testing/master/bazelci/buildkite-pipeline.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +010099 "pipeline_slug": "android-testing",
Yun Peng9b1d3432021-12-07 10:40:45 +0100100 "disabled_reason": "https://github.com/android/testing-samples/issues/417",
Yun Peng996efad2018-11-27 17:19:44 +0100101 },
Yun Peng8910fa32019-01-03 08:58:16 +0100102 "Bazel": {
103 "git_repository": "https://github.com/bazelbuild/bazel.git",
104 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel/master/.bazelci/postsubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100105 "pipeline_slug": "bazel-bazel",
Yun Peng8910fa32019-01-03 08:58:16 +0100106 },
Tobias Werthd848eca2019-05-14 15:08:35 +0200107 "Bazel Bench": {
108 "git_repository": "https://github.com/bazelbuild/bazel-bench.git",
joeleba92ffec82019-05-22 14:50:15 +0200109 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-bench/master/.bazelci/postsubmit.yml",
Tobias Werthd848eca2019-05-14 15:08:35 +0200110 "pipeline_slug": "bazel-bench",
111 },
Philipp Wollermannfefcbf42019-05-28 14:28:40 +0200112 "Bazel Codelabs": {
113 "git_repository": "https://github.com/bazelbuild/codelabs.git",
114 "http_config": "https://raw.githubusercontent.com/bazelbuild/codelabs/master/.bazelci/presubmit.yml",
115 "pipeline_slug": "bazel-codelabs",
Yun Peng88d80ae2020-11-19 16:23:49 +0100116 "disabled_reason": "https://github.com/bazelbuild/codelabs/issues/38",
Philipp Wollermannfefcbf42019-05-28 14:28:40 +0200117 },
Jinfce9b302019-08-08 15:18:26 -0400118 "Bazel Examples": {
119 "git_repository": "https://github.com/bazelbuild/examples.git",
120 "http_config": "https://raw.githubusercontent.com/bazelbuild/examples/master/.bazelci/presubmit.yml",
121 "pipeline_slug": "bazel-bazel-examples",
122 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100123 "Bazel Remote Cache": {
124 "git_repository": "https://github.com/buchgr/bazel-remote.git",
125 "http_config": "https://raw.githubusercontent.com/buchgr/bazel-remote/master/.bazelci/presubmit.yml",
126 "pipeline_slug": "bazel-remote-cache",
Yun Peng996efad2018-11-27 17:19:44 +0100127 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100128 "Bazel skylib": {
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200129 "git_repository": "https://github.com/bazelbuild/bazel-skylib.git",
Alexandre Rostovtsevd414d0d2021-04-16 13:44:35 -0400130 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-skylib/main/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100131 "pipeline_slug": "bazel-skylib",
Yun Peng667750b2020-02-20 14:06:43 +0100132 "owned_by_bazel": True,
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200133 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100134 "Bazel toolchains": {
135 "git_repository": "https://github.com/bazelbuild/bazel-toolchains.git",
136 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-toolchains/master/.bazelci/presubmit.yml",
137 "pipeline_slug": "bazel-toolchains",
138 },
139 "Bazel watcher": {
140 "git_repository": "https://github.com/bazelbuild/bazel-watcher.git",
141 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-watcher/master/.bazelci/presubmit.yml",
142 "pipeline_slug": "bazel-watcher",
Florian Weikertecf091c2023-04-28 10:22:23 +0200143 "disabled_reason": "https://github.com/bazelbuild/bazel-watcher/issues/590",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100144 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200145 "Bazelisk": {
146 "git_repository": "https://github.com/bazelbuild/bazelisk.git",
147 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazelisk/master/.bazelci/config.yml",
148 "pipeline_slug": "bazelisk",
149 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100150 "Buildfarm": {
151 "git_repository": "https://github.com/bazelbuild/bazel-buildfarm.git",
Philipp Wollermanndf1e19b2021-09-09 12:33:37 +0200152 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-buildfarm/main/.bazelci/presubmit.yml",
Philipp Wollermann89e5d882021-09-09 12:44:29 +0200153 "pipeline_slug": "buildfarm-farmer",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100154 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100155 "Buildtools": {
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200156 "git_repository": "https://github.com/bazelbuild/buildtools.git",
Yun Peng996efad2018-11-27 17:19:44 +0100157 "http_config": "https://raw.githubusercontent.com/bazelbuild/buildtools/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100158 "pipeline_slug": "buildtools",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200159 },
Yun Peng175bf3e2021-02-23 16:37:35 +0100160 "Cargo-Raze": {
161 "git_repository": "https://github.com/google/cargo-raze.git",
Yun Peng3ffde1c2021-12-07 10:50:28 +0100162 "http_config": "https://raw.githubusercontent.com/google/cargo-raze/main/.bazelci/presubmit.yml",
Yun Peng175bf3e2021-02-23 16:37:35 +0100163 "pipeline_slug": "cargo-raze",
Yun Pengab700d52023-05-08 13:16:44 +0200164 "disabled_reason": "https://github.com/bazelbuild/continuous-integration/issues/1594 (broken by Xcode 14.2)",
Yun Peng175bf3e2021-02-23 16:37:35 +0100165 },
Yun Peng39a42582018-11-09 10:59:47 +0100166 "CLion Plugin": {
167 "git_repository": "https://github.com/bazelbuild/intellij.git",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100168 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/clion.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100169 "pipeline_slug": "clion-plugin",
Yun Peng39a42582018-11-09 10:59:47 +0100170 },
Mai Hussien0731b4d2022-06-28 11:16:07 -0700171 "CLion Plugin Google": {
172 "git_repository": "https://github.com/bazelbuild/intellij.git",
173 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/google/.bazelci/clion.yml",
174 "pipeline_slug": "clion-plugin-google",
175 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200176 "Cartographer": {
177 "git_repository": "https://github.com/googlecartographer/cartographer.git",
178 "http_config": "https://raw.githubusercontent.com/googlecartographer/cartographer/master/.bazelci/presubmit.yml",
179 "pipeline_slug": "cartographer",
180 },
Philipp Wollermannee850782019-02-05 22:56:04 +0100181 "Cloud Robotics Core": {
Stefan Sauerb4dd3f92019-02-05 22:44:28 +0100182 "git_repository": "https://github.com/googlecloudrobotics/core.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200183 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/cloud-robotics.yml",
Stefan Sauerb4dd3f92019-02-05 22:44:28 +0100184 "pipeline_slug": "cloud-robotics-core",
185 },
Keith Smiley3b0ba602019-05-15 04:42:19 -0700186 "Envoy": {
187 "git_repository": "https://github.com/envoyproxy/envoy.git",
Yun Peng7ea4bc82022-12-01 12:58:08 +0100188 "http_config": "https://raw.githubusercontent.com/envoyproxy/envoy/main/.bazelci/presubmit.yml",
Keith Smiley3b0ba602019-05-15 04:42:19 -0700189 "pipeline_slug": "envoy",
190 },
Florian Weikert1fe28b72019-07-02 12:47:55 +0200191 "FlatBuffers": {
192 "git_repository": "https://github.com/google/flatbuffers.git",
193 "http_config": "https://raw.githubusercontent.com/google/flatbuffers/master/.bazelci/presubmit.yml",
194 "pipeline_slug": "flatbuffers",
195 },
Philipp Wollermannf3750fa2019-05-21 17:11:59 +0200196 "Flogger": {
197 "git_repository": "https://github.com/google/flogger.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200198 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/flogger.yml",
Philipp Wollermannf3750fa2019-05-21 17:11:59 +0200199 "pipeline_slug": "flogger",
200 },
Marcel Hlopkoc8840772018-10-23 12:51:46 +0200201 "Gerrit": {
202 "git_repository": "https://gerrit.googlesource.com/gerrit.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200203 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/gerrit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100204 "pipeline_slug": "gerrit",
Marcel Hlopkoc8840772018-10-23 12:51:46 +0200205 },
Yun Pengd6622022018-11-05 13:10:26 +0100206 "Google Logging": {
207 "git_repository": "https://github.com/google/glog.git",
Philipp Wollermann17e5fc62021-02-15 14:48:36 +0100208 "http_config": "https://raw.githubusercontent.com/google/glog/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100209 "pipeline_slug": "google-logging",
Yun Pengab700d52023-05-08 13:16:44 +0200210 "disabled_reason": "Waiting on https://github.com/google/glog/pull/916",
Yun Pengd6622022018-11-05 13:10:26 +0100211 },
Yun Peng9586db52018-11-02 10:48:40 +0100212 "IntelliJ Plugin": {
213 "git_repository": "https://github.com/bazelbuild/intellij.git",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100214 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/intellij.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100215 "pipeline_slug": "intellij-plugin",
Yun Peng9586db52018-11-02 10:48:40 +0100216 },
Mai Hussien0731b4d2022-06-28 11:16:07 -0700217 "IntelliJ Plugin Google": {
218 "git_repository": "https://github.com/bazelbuild/intellij.git",
219 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/google/.bazelci/intellij.yml",
220 "pipeline_slug": "intellij-plugin-google",
221 },
222 "IntelliJ UE Plugin": {
223 "git_repository": "https://github.com/bazelbuild/intellij.git",
224 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/intellij-ue.yml",
225 "pipeline_slug": "intellij-ue-plugin",
226 },
227 "IntelliJ UE Plugin Google": {
228 "git_repository": "https://github.com/bazelbuild/intellij.git",
229 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/google/.bazelci/intellij-ue.yml",
230 "pipeline_slug": "intellij-ue-plugin-google",
231 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100232 "IntelliJ Plugin Aspect": {
233 "git_repository": "https://github.com/bazelbuild/intellij.git",
234 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/aspect.yml",
235 "pipeline_slug": "intellij-plugin-aspect",
236 },
Mai Hussien0731b4d2022-06-28 11:16:07 -0700237 "IntelliJ Plugin Aspect Google": {
238 "git_repository": "https://github.com/bazelbuild/intellij.git",
239 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/google/.bazelci/aspect.yml",
240 "pipeline_slug": "intellij-plugin-aspect-google",
241 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200242 "Kythe": {
243 "git_repository": "https://github.com/kythe/kythe.git",
244 "http_config": "https://raw.githubusercontent.com/kythe/kythe/master/.bazelci/presubmit.yml",
245 "pipeline_slug": "kythe",
246 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100247 "Protobuf": {
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200248 "git_repository": "https://github.com/google/protobuf.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200249 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/protobuf.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100250 "pipeline_slug": "protobuf",
Yun Peng667750b2020-02-20 14:06:43 +0100251 "owned_by_bazel": True,
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200252 },
Laurent Le Brunf6326d62020-07-28 18:24:10 +0200253 "Stardoc": {
254 "git_repository": "https://github.com/bazelbuild/stardoc.git",
255 "http_config": "https://raw.githubusercontent.com/bazelbuild/stardoc/master/.bazelci/presubmit.yml",
256 "pipeline_slug": "stardoc",
Yun Peng667750b2020-02-20 14:06:43 +0100257 "owned_by_bazel": True,
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200258 },
259 "Subpar": {
260 "git_repository": "https://github.com/google/subpar.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200261 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/subpar.yml",
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200262 "pipeline_slug": "subpar",
Yun Peng667750b2020-02-20 14:06:43 +0100263 "owned_by_bazel": True,
Xùdōng Yáng26e280f2021-07-20 23:33:07 +1000264 "disabled_reason": "https://github.com/google/subpar/issues/133",
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200265 },
266 "TensorFlow": {
267 "git_repository": "https://github.com/tensorflow/tensorflow.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200268 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/tensorflow.yml",
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200269 "pipeline_slug": "tensorflow",
Yun Pengab700d52023-05-08 13:16:44 +0200270 "disabled_reason": "https://github.com/tensorflow/tensorflow/issues/60508",
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200271 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200272 "re2": {
273 "git_repository": "https://github.com/google/re2.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200274 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/re2.yml",
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200275 "pipeline_slug": "re2",
276 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100277 "rules_android": {
278 "git_repository": "https://github.com/bazelbuild/rules_android.git",
279 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_android/master/.bazelci/postsubmit.yml",
280 "pipeline_slug": "rules-android",
Yun Pengc0575c82020-06-03 11:27:45 +0200281 "disabled_reason": "https://github.com/bazelbuild/rules_android/issues/15",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100282 },
Keith Smiley2e3d7c82022-09-09 00:47:51 -0700283 "rules_android_ndk": {
Yun Peng687ad6b2022-09-15 11:00:02 +0200284 "git_repository": "https://github.com/bazelbuild/rules_android_ndk.git",
Keith Smiley2e3d7c82022-09-09 00:47:51 -0700285 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_android_ndk/main/.bazelci/presubmit.yml",
286 "pipeline_slug": "rules-android-ndk",
287 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200288 "rules_appengine": {
289 "git_repository": "https://github.com/bazelbuild/rules_appengine.git",
Yun Peng996efad2018-11-27 17:19:44 +0100290 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_appengine/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100291 "pipeline_slug": "rules-appengine-appengine",
Yun Penge4816d72022-05-04 15:33:40 -0700292 "disabled_reason": "https://github.com/bazelbuild/rules_appengine/issues/127",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200293 },
Yun Peng809f27b2018-11-13 10:15:39 +0100294 "rules_apple": {
295 "git_repository": "https://github.com/bazelbuild/rules_apple.git",
Yun Peng996efad2018-11-27 17:19:44 +0100296 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_apple/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100297 "pipeline_slug": "rules-apple-darwin",
Yun Peng809f27b2018-11-13 10:15:39 +0100298 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100299 "rules_cc": {
300 "git_repository": "https://github.com/bazelbuild/rules_cc.git",
aiuto560809f2021-08-17 14:51:32 -0400301 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_cc/main/.bazelci/presubmit.yml",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100302 "pipeline_slug": "rules-cc",
Yun Peng667750b2020-02-20 14:06:43 +0100303 "owned_by_bazel": True,
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100304 },
Marcel Hlopko340dfd22018-10-19 11:33:01 +0200305 "rules_closure": {
306 "git_repository": "https://github.com/bazelbuild/rules_closure.git",
Yun Peng996efad2018-11-27 17:19:44 +0100307 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_closure/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100308 "pipeline_slug": "rules-closure-closure-compiler",
Yun Peng667750b2020-02-20 14:06:43 +0100309 "owned_by_bazel": True,
Marcel Hlopko340dfd22018-10-19 11:33:01 +0200310 },
Yun Peng996efad2018-11-27 17:19:44 +0100311 "rules_docker": {
312 "git_repository": "https://github.com/bazelbuild/rules_docker.git",
313 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_docker/master/.bazelci/presubmit.yml",
Jakob Buchgrabera6a8ea82018-12-07 13:51:02 +0100314 "pipeline_slug": "rules-docker-docker",
Yun Pengcfbab262021-12-23 13:01:06 +0100315 "disabled_reason": "https://github.com/bazelbuild/rules_docker/issues/1988",
Yun Peng996efad2018-11-27 17:19:44 +0100316 },
Florian Weikert5569c112021-04-01 14:04:33 +0200317 "rules_dotnet": {
318 "git_repository": "https://github.com/bazelbuild/rules_dotnet.git",
319 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_dotnet/master/.bazelci/presubmit.yml",
320 "pipeline_slug": "rules-dotnet-edge",
321 },
Yun Peng996efad2018-11-27 17:19:44 +0100322 "rules_foreign_cc": {
323 "git_repository": "https://github.com/bazelbuild/rules_foreign_cc.git",
mai932d494522021-03-30 18:34:05 +0200324 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_foreign_cc/main/.bazelci/config.yaml",
Yun Peng996efad2018-11-27 17:19:44 +0100325 "pipeline_slug": "rules-foreign-cc",
Yun Peng667750b2020-02-20 14:06:43 +0100326 "owned_by_bazel": True,
Yun Peng996efad2018-11-27 17:19:44 +0100327 },
Xindb02c012018-11-07 14:10:54 -0500328 "rules_go": {
329 "git_repository": "https://github.com/bazelbuild/rules_go.git",
Yun Peng996efad2018-11-27 17:19:44 +0100330 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_go/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100331 "pipeline_slug": "rules-go-golang",
Yun Pengb7247ff2018-11-15 13:52:39 +0100332 },
Yun Peng7deea572018-11-05 10:47:45 +0100333 "rules_groovy": {
Yun Peng996efad2018-11-27 17:19:44 +0100334 "git_repository": "https://github.com/bazelbuild/rules_groovy.git",
335 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_groovy/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100336 "pipeline_slug": "rules-groovy",
Yun Peng996efad2018-11-27 17:19:44 +0100337 },
338 "rules_gwt": {
339 "git_repository": "https://github.com/bazelbuild/rules_gwt.git",
340 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_gwt/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100341 "pipeline_slug": "rules-gwt",
Xùdōng Yáng99b86b32021-08-18 23:42:05 +1000342 "disabled_reason": "https://github.com/bazelbuild/continuous-integration/issues/1202",
Philipp Wollermann2a160432019-09-19 15:57:28 +0200343 },
Florian Weikertff6444e2019-09-16 16:08:57 +0200344 "rules_haskell": {
345 "git_repository": "https://github.com/tweag/rules_haskell.git",
346 "http_config": "https://raw.githubusercontent.com/tweag/rules_haskell/master/.bazelci/presubmit.yml",
347 "pipeline_slug": "rules-haskell-haskell",
Philipp Wollermann2a160432019-09-19 15:57:28 +0200348 },
Yun Peng996efad2018-11-27 17:19:44 +0100349 "rules_jsonnet": {
350 "git_repository": "https://github.com/bazelbuild/rules_jsonnet.git",
351 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_jsonnet/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100352 "pipeline_slug": "rules-jsonnet",
Yun Peng996efad2018-11-27 17:19:44 +0100353 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200354 "rules_jvm_external": {
355 "git_repository": "https://github.com/bazelbuild/rules_jvm_external.git",
356 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_jvm_external/master/.bazelci/presubmit.yml",
357 "pipeline_slug": "rules-jvm-external",
Yun Peng667750b2020-02-20 14:06:43 +0100358 "owned_by_bazel": True,
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200359 },
360 "rules_jvm_external - examples": {
361 "git_repository": "https://github.com/bazelbuild/rules_jvm_external.git",
362 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_jvm_external/master/.bazelci/examples.yml",
363 "pipeline_slug": "rules-jvm-external-examples",
Yun Peng667750b2020-02-20 14:06:43 +0100364 "owned_by_bazel": True,
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200365 },
Yun Peng996efad2018-11-27 17:19:44 +0100366 "rules_k8s": {
367 "git_repository": "https://github.com/bazelbuild/rules_k8s.git",
368 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_k8s/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100369 "pipeline_slug": "rules-k8s-k8s",
Yun Peng9b1d3432021-12-07 10:40:45 +0100370 "disabled_reason": "https://github.com/bazelbuild/rules_k8s/issues/668",
Yun Peng996efad2018-11-27 17:19:44 +0100371 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100372 "rules_kotlin": {
373 "git_repository": "https://github.com/bazelbuild/rules_kotlin.git",
374 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_kotlin/master/.bazelci/presubmit.yml",
375 "pipeline_slug": "rules-kotlin-kotlin",
376 },
Yun Penga5650e12018-11-14 10:16:06 +0100377 "rules_nodejs": {
378 "git_repository": "https://github.com/bazelbuild/rules_nodejs.git",
Alex Eagle5ba0e7f2023-04-13 02:04:46 -0700379 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_nodejs/main/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100380 "pipeline_slug": "rules-nodejs-nodejs",
Yun Penga5650e12018-11-14 10:16:06 +0100381 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200382 "rules_perl": {
383 "git_repository": "https://github.com/bazelbuild/rules_perl.git",
Philipp Wollermanndf8afd52022-02-08 16:36:10 +0100384 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_perl/main/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100385 "pipeline_slug": "rules-perl",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200386 },
Yannic6110b3c2019-08-12 15:09:37 +0000387 "rules_proto": {
388 "git_repository": "https://github.com/bazelbuild/rules_proto.git",
389 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_proto/master/.bazelci/presubmit.yml",
390 "pipeline_slug": "rules-proto",
Yun Peng667750b2020-02-20 14:06:43 +0100391 "owned_by_bazel": True,
Yannic6110b3c2019-08-12 15:09:37 +0000392 },
Yun Peng3d5a8a62018-11-19 11:42:01 +0100393 "rules_python": {
394 "git_repository": "https://github.com/bazelbuild/rules_python.git",
Florian Weikertf126dfc2021-07-05 15:39:24 +0200395 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_python/main/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100396 "pipeline_slug": "rules-python-python",
Yun Peng667750b2020-02-20 14:06:43 +0100397 "owned_by_bazel": True,
Yun Peng3d5a8a62018-11-19 11:42:01 +0100398 },
Xindb02c012018-11-07 14:10:54 -0500399 "rules_rust": {
400 "git_repository": "https://github.com/bazelbuild/rules_rust.git",
Yun Peng1e56ce82022-11-04 16:31:49 +0100401 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_rust/main/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100402 "pipeline_slug": "rules-rust-rustlang",
Xindb02c012018-11-07 14:10:54 -0500403 },
Yun Pengca62fff2018-10-31 11:22:03 +0100404 "rules_sass": {
405 "git_repository": "https://github.com/bazelbuild/rules_sass.git",
Paul Gschwendtner63ed21b2022-03-22 14:42:42 +0100406 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_sass/main/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100407 "pipeline_slug": "rules-sass",
Yun Pengca62fff2018-10-31 11:22:03 +0100408 },
Xindb02c012018-11-07 14:10:54 -0500409 "rules_scala": {
410 "git_repository": "https://github.com/bazelbuild/rules_scala.git",
Yun Peng996efad2018-11-27 17:19:44 +0100411 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_scala/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100412 "pipeline_slug": "rules-scala-scala",
Xùdōng Yáng79deb042022-09-15 12:26:36 +0200413 "disabled_reason": "waiting on https://github.com/bazelbuild/rules_scala/pull/1422",
Xindb02c012018-11-07 14:10:54 -0500414 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100415 "rules_swift": {
416 "git_repository": "https://github.com/bazelbuild/rules_swift.git",
417 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_swift/master/.bazelci/presubmit.yml",
418 "pipeline_slug": "rules-swift-swift",
419 },
Richard Levasseura9690c62023-03-06 08:39:36 -0800420 "rules_testing": {
421 "git_repository": "https://github.com/bazelbuild/rules_testing.git",
422 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_testing/master/.bazelci/presubmit.yml",
423 "pipeline_slug": "rules-testing",
424 "owned_by_bazel": True,
425 },
Yun Peng996efad2018-11-27 17:19:44 +0100426 "rules_webtesting": {
427 "git_repository": "https://github.com/bazelbuild/rules_webtesting.git",
Yun Pengc2fab332019-01-04 10:53:49 +0100428 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_webtesting/master/.bazelci/presubmit.yml",
Yun Peng996efad2018-11-27 17:19:44 +0100429 "pipeline_slug": "rules-webtesting-saucelabs",
Yun Peng996efad2018-11-27 17:19:44 +0100430 },
Philipp Wollermann389acd82019-05-21 17:41:48 +0200431 "upb": {
432 "git_repository": "https://github.com/protocolbuffers/upb.git",
433 "http_config": "https://raw.githubusercontent.com/protocolbuffers/upb/master/.bazelci/presubmit.yml",
434 "pipeline_slug": "upb",
Yun Pengab700d52023-05-08 13:16:44 +0200435 "disabled_reason": "https://github.com/protocolbuffers/upb/issues/1290",
Philipp Wollermann389acd82019-05-21 17:41:48 +0200436 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200437}
438
Philipp Wollermanne67eec42019-05-24 15:18:20 +0200439DOWNSTREAM_PROJECTS_TESTING = {
Philipp Wollermannbed211d2019-06-07 11:38:59 +0200440 "Bazel": DOWNSTREAM_PROJECTS_PRODUCTION["Bazel"],
441 "Bazelisk": DOWNSTREAM_PROJECTS_PRODUCTION["Bazelisk"],
Philipp Wollermannbed211d2019-06-07 11:38:59 +0200442 "rules_docker": DOWNSTREAM_PROJECTS_PRODUCTION["rules_docker"],
443 "rules_go": DOWNSTREAM_PROJECTS_PRODUCTION["rules_go"],
444 "rules_groovy": DOWNSTREAM_PROJECTS_PRODUCTION["rules_groovy"],
445 "rules_kotlin": DOWNSTREAM_PROJECTS_PRODUCTION["rules_kotlin"],
446 "rules_nodejs": DOWNSTREAM_PROJECTS_PRODUCTION["rules_nodejs"],
447 "rules_rust": DOWNSTREAM_PROJECTS_PRODUCTION["rules_rust"],
448 "rules_scala": DOWNSTREAM_PROJECTS_PRODUCTION["rules_scala"],
Philipp Wollermanne67eec42019-05-24 15:18:20 +0200449}
450
451DOWNSTREAM_PROJECTS = {
452 "bazel-testing": DOWNSTREAM_PROJECTS_TESTING,
453 "bazel-trusted": {},
454 "bazel": DOWNSTREAM_PROJECTS_PRODUCTION,
455}[BUILDKITE_ORG]
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100456
Philipp Wollermann81a88412019-07-12 10:34:33 +0200457DOCKER_REGISTRY_PREFIX = {
458 "bazel-testing": "bazel-public/testing",
459 "bazel-trusted": "bazel-public",
460 "bazel": "bazel-public",
461}[BUILDKITE_ORG]
462
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200463# A map containing all supported platform names as keys, with the values being
464# the platform name in a human readable format, and a the buildkite-agent's
465# working directory.
466PLATFORMS = {
Philipp Wollermanneffcd6e2019-06-21 18:30:34 +0200467 "centos7": {
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200468 "name": "CentOS 7 (OpenJDK 8, gcc 4.8.5)",
469 "emoji-name": ":centos: 7 (OpenJDK 8, gcc 4.8.5)",
Philipp Wollermanneffcd6e2019-06-21 18:30:34 +0200470 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann28978712021-10-21 19:09:29 +0200471 "publish_binary": [],
Philipp Wollermann5d6765d2020-02-17 17:12:02 +0100472 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/centos7-java8",
Philipp Wollermanneffcd6e2019-06-21 18:30:34 +0200473 "python": "python3.6",
474 },
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200475 "centos7_java11": {
476 "name": "CentOS 7 (OpenJDK 11, gcc 4.8.5)",
477 "emoji-name": ":centos: 7 (OpenJDK 11, gcc 4.8.5)",
478 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
479 "publish_binary": [],
480 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/centos7-java11",
481 "python": "python3.6",
482 },
483 "centos7_java11_devtoolset10": {
484 "name": "CentOS 7 (OpenJDK 11, gcc 10.2.1)",
485 "emoji-name": ":centos: 7 (OpenJDK 11, gcc 10.2.1)",
486 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann28978712021-10-21 19:09:29 +0200487 "publish_binary": ["ubuntu1404", "centos7", "linux"],
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200488 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/centos7-java11-devtoolset10",
489 "python": "python3.6",
490 },
Philipp Wollermann67fc3712019-06-12 15:39:21 +0200491 "debian10": {
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200492 "name": "Debian 10 Buster (OpenJDK 11, gcc 8.3.0)",
493 "emoji-name": ":debian: 10 Buster (OpenJDK 11, gcc 8.3.0)",
Philipp Wollermann67fc3712019-06-12 15:39:21 +0200494 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
495 "publish_binary": [],
Philipp Wollermann5d6765d2020-02-17 17:12:02 +0100496 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/debian10-java11",
Philipp Wollermann67fc3712019-06-12 15:39:21 +0200497 "python": "python3.7",
498 },
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200499 "debian11": {
500 "name": "Debian 11 Bullseye (OpenJDK 17, gcc 10.2.1)",
501 "emoji-name": ":debian: 11 Buster (OpenJDK 17, gcc 10.2.1)",
502 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
503 "publish_binary": [],
504 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/debian11-java17",
505 "python": "python3.9",
506 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200507 "ubuntu1604": {
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200508 "name": "Ubuntu 16.04 LTS (OpenJDK 8, gcc 5.4.0)",
509 "emoji-name": ":ubuntu: 16.04 LTS (OpenJDK 8, gcc 5.4.0)",
Philipp Wollermannd551bf62019-05-18 22:04:35 +0200510 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann64047082021-10-21 21:26:25 +0200511 "publish_binary": [],
Philipp Wollermann5d6765d2020-02-17 17:12:02 +0100512 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu1604-java8",
Philipp Wollermann57b32682019-05-18 22:09:27 +0200513 "python": "python3.6",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200514 },
515 "ubuntu1804": {
Florian Weikertd02ea362022-09-15 13:51:17 +0200516 "name": "Ubuntu 18.04 LTS (OpenJDK 11, gcc 7.5.0)",
517 "emoji-name": ":ubuntu: 18.04 LTS (OpenJDK 11, gcc 7.5.0)",
Philipp Wollermannd551bf62019-05-18 22:04:35 +0200518 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann783d1672019-06-06 13:35:30 +0200519 "publish_binary": ["ubuntu1804"],
Philipp Wollermann5d6765d2020-02-17 17:12:02 +0100520 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu1804-java11",
Philipp Wollermann57b32682019-05-18 22:09:27 +0200521 "python": "python3.6",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200522 },
Mostyn Bramley-Mooreab4599e2020-06-23 20:31:01 +0200523 "ubuntu2004": {
Florian Weikertd02ea362022-09-15 13:51:17 +0200524 "name": "Ubuntu 20.04 LTS (OpenJDK 11, gcc 9.4.0)",
525 "emoji-name": ":ubuntu: 20.04 LTS (OpenJDK 11, gcc 9.4.0)",
Mostyn Bramley-Mooreab4599e2020-06-23 20:31:01 +0200526 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann55f72ac2020-09-21 22:22:05 +0200527 "publish_binary": [],
Mostyn Bramley-Mooreab4599e2020-06-23 20:31:01 +0200528 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu2004-java11",
529 "python": "python3.8",
530 },
Yun Peng07dafc52022-03-16 13:23:35 +0100531 "ubuntu2004_arm64": {
Florian Weikertd02ea362022-09-15 13:51:17 +0200532 "name": "Ubuntu 20.04 LTS ARM64 (OpenJDK 11, gcc 9.4.0)",
533 "emoji-name": ":ubuntu: 20.04 LTS ARM64 (OpenJDK 11, gcc 9.4.0)",
Yun Peng07dafc52022-03-16 13:23:35 +0100534 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
535 "publish_binary": [],
536 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu2004-java11",
537 "python": "python3.8",
538 "queue": "arm64",
539 # TODO: Re-enable always-pull if we also publish docker containers for Linux ARM64
540 "always-pull": False,
541 },
Chi Wang6357efe2020-08-25 16:23:38 +0800542 "kythe_ubuntu2004": {
Florian Weikertd02ea362022-09-15 13:51:17 +0200543 "name": "Kythe (Ubuntu 20.04 LTS, OpenJDK 11, gcc 9.4.0)",
544 "emoji-name": "Kythe (:ubuntu: 20.04 LTS, OpenJDK 11, gcc 9.4.0)",
Chi Wang6357efe2020-08-25 16:23:38 +0800545 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
546 "publish_binary": [],
547 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu2004-java11-kythe",
548 "python": "python3.8",
549 },
Florian Weikertdcc75202022-09-06 16:34:04 +0200550 "ubuntu2204": {
551 "name": "Ubuntu 22.04 (OpenJDK 17, gcc 11.2.0)",
552 "emoji-name": ":ubuntu: 22.04 (OpenJDK 17, gcc 11.2.0)",
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200553 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
554 "publish_binary": [],
Florian Weikertdcc75202022-09-06 16:34:04 +0200555 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu2204-java17",
Philipp Wollermannb6a399a2021-10-22 07:57:26 +0200556 "python": "python3",
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200557 },
David Ostrovskyba4478f2023-05-08 16:24:04 +0200558 "fedora39": {
559 "name": "Fedora 39 (OpenJDK 17, gcc 13.1.1)",
560 "emoji-name": ":fedora: 39 (OpenJDK 17, gcc 13.1.1)",
561 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
562 "publish_binary": [],
563 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/fedora39-java17",
564 "python": "python3",
565 },
Philipp Wollermann438ec242018-09-05 14:39:24 +0200566 "macos": {
Philipp Wollermann5e3d09f2021-10-21 01:03:01 +0200567 "name": "macOS (OpenJDK 11, Xcode)",
568 "emoji-name": ":darwin: (OpenJDK 11, Xcode)",
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200569 "downstream-root": "/Users/buildkite/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann783d1672019-06-06 13:35:30 +0200570 "publish_binary": ["macos"],
Philipp Wollermann7a185322019-05-18 22:15:48 +0200571 "queue": "macos",
Philipp Wollermann89d36492021-02-16 11:59:09 +0100572 "python": "python3",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200573 },
Florian Weikerta87e6f32023-04-14 19:58:32 +0200574 "macos_qa": {
575 "name": "macOS QA (OpenJDK 11, Xcode)",
576 "emoji-name": ":darwin: :fire_extinguisher: (OpenJDK 11, Xcode)",
577 "downstream-root": "/Users/buildkite/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
578 "publish_binary": [],
579 "queue": "macos_qa",
580 "python": "python3",
581 },
Yun Peng46d43912021-04-21 09:49:53 +0200582 "macos_arm64": {
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200583 "name": "macOS arm64 (OpenJDK 8, Xcode)",
584 "emoji-name": ":darwin: arm64 (OpenJDK 8, Xcode)",
Yun Peng46d43912021-04-21 09:49:53 +0200585 "downstream-root": "/Users/buildkite/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Yun Peng83f32772021-04-21 11:22:35 +0200586 "publish_binary": ["macos_arm64"],
Yun Pengab922132022-11-18 20:28:02 +0100587 "queue": "macos_arm64",
Yun Peng46d43912021-04-21 09:49:53 +0200588 "python": "python3",
589 },
Philipp Wollermann438ec242018-09-05 14:39:24 +0200590 "windows": {
Yun Peng8d7a2a52022-09-09 14:56:49 +0200591 "name": "Windows (OpenJDK 11, VS2019)",
592 "emoji-name": ":windows: (OpenJDK 11, VS2019)",
Philipp Wollermannd5ab3d92020-02-05 16:55:13 +0100593 "downstream-root": "c:/b/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann783d1672019-06-06 13:35:30 +0200594 "publish_binary": ["windows"],
Philipp Wollermann7a185322019-05-18 22:15:48 +0200595 "queue": "windows",
Philipp Wollermann57b32682019-05-18 22:09:27 +0200596 "python": "python.exe",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200597 },
Yun Peng6a7a6702022-02-02 15:02:47 +0100598 "windows_arm64": {
Yun Peng8d7a2a52022-09-09 14:56:49 +0200599 "name": "Windows ARM64 (OpenJDK 11, VS2019)",
600 "emoji-name": ":windows: arm64 (OpenJDK 11, VS2019)",
Yun Peng6a7a6702022-02-02 15:02:47 +0100601 "downstream-root": "c:/b/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Yun Peng0ae9eb72022-02-03 10:24:26 +0100602 "publish_binary": ["windows_arm64"],
Yun Peng6a7a6702022-02-02 15:02:47 +0100603 # TODO(pcloudy): Switch to windows_arm64 queue when Windows ARM64 machines are available,
604 # current we just use x86_64 machines to do cross compile.
605 "queue": "windows",
606 "python": "python.exe",
Florian Weikert7f21ca42022-02-02 17:35:23 +0100607 },
Philipp Wollermann438ec242018-09-05 14:39:24 +0200608 "rbe_ubuntu1604": {
Philipp Wollermanndb877332019-04-23 17:58:01 +0200609 "name": "RBE (Ubuntu 16.04, OpenJDK 8)",
Jakob Buchgraber1f37fbd2019-07-17 17:08:28 +0200610 "emoji-name": "RBE (:ubuntu: 16.04, OpenJDK 8)",
Philipp Wollermannd551bf62019-05-18 22:04:35 +0200611 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann783d1672019-06-06 13:35:30 +0200612 "publish_binary": [],
Philipp Wollermann5d6765d2020-02-17 17:12:02 +0100613 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu1604-java8",
Philipp Wollermann57b32682019-05-18 22:09:27 +0200614 "python": "python3.6",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100615 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200616}
617
Philipp Wollermannfce92bf2019-05-22 15:14:32 +0200618BUILDIFIER_DOCKER_IMAGE = "gcr.io/bazel-public/buildifier"
Florian Weikertf20ae6f2019-01-16 14:32:09 +0100619
Philipp Wollermann1403d2c2019-01-10 13:15:51 +0100620# The platform used for various steps (e.g. stuff that formerly ran on the "pipeline" workers).
621DEFAULT_PLATFORM = "ubuntu1804"
622
Philipp Wollermannf4aabb72019-06-25 15:59:00 +0200623# In order to test that "the one Linux binary" that we build for our official releases actually
624# works on all Linux distributions that we test on, we use the Linux binary built on our official
625# release platform for all Linux downstream tests.
Yun Pengdae5a7d2022-01-11 16:08:58 +0100626LINUX_BINARY_PLATFORM = "centos7_java11_devtoolset10"
Philipp Wollermannf4aabb72019-06-25 15:59:00 +0200627
Florian Weikertf11f2bf2023-01-31 19:11:52 +0100628# Maps major MacOS version numbers to the Xcode version that should be activated on that particular OS
629DEFAULT_XCODE_VERSION_PER_OS = {12: "13.0", 13: "14.2"}
Philipp Wollermann380f1e62019-04-12 16:45:27 +0200630XCODE_VERSION_REGEX = re.compile(r"^\d+\.\d+(\.\d+)?$")
Florian Weikertdb832a02020-11-19 19:14:48 +0100631XCODE_VERSION_OVERRIDES = {"10.2.1": "10.3", "11.2": "11.2.1", "11.3": "11.3.1"}
Philipp Wollermann380f1e62019-04-12 16:45:27 +0200632
Florian Weikertc8642af2019-02-03 23:58:51 +0100633BUILD_LABEL_PATTERN = re.compile(r"^Build label: (\S+)$", re.MULTILINE)
634
Florian Weikertde96a6f2019-03-07 14:57:50 +0100635BUILDIFIER_STEP_NAME = "Buildifier"
636
Florian Weikert5f5d3cb2019-04-15 15:36:27 +0200637SKIP_TASKS_ENV_VAR = "CI_SKIP_TASKS"
638
Florian Weikertecf091c2023-04-28 10:22:23 +0200639# TODO: change to USE_BAZEL_DIFF once the feature has been tested in QA
Florian Weikert7012a522023-05-04 16:49:40 +0200640USE_BAZEL_DIFF_ENV_VAR = "USE_BAZEL_DIFF"
641
Florian Weikert77d20062023-05-08 16:32:48 +0200642BAZEL_DIFF_ANNOTATION_CTX = "'diff'"
643
Florian Weikert7012a522023-05-04 16:49:40 +0200644# TODO(fweikert): Install bazel-diff on the Docker images and on the Mac machines
645BAZEL_DIFF_URL = (
646 "https://github.com/Tinder/bazel-diff/releases/download/4.5.0/bazel-diff_deploy.jar"
647)
Florian Weikertecf091c2023-04-28 10:22:23 +0200648
649AUTO_DIFFBASE_VALUES = frozenset(["1", "true", "auto"])
650
Florian Weikerte417f9f2023-05-05 17:33:46 +0200651# Always run all test targets if any of the paths here are modified by the current commit.
652# Values can be directory paths (with a trailing slash) or file paths.
653DISABLE_BAZEL_DIFF_IF_MODIFIED = (".bazelci/", ".bazelversion")
654
Florian Weikertecf091c2023-04-28 10:22:23 +0200655COMMIT_RE = re.compile(r"[0-9a-z]{40}")
656
Philipp Wollermannce986af2019-07-18 14:46:05 +0200657CONFIG_FILE_EXTENSIONS = {".yml", ".yaml"}
Florian Weikert778251c2019-04-25 15:14:44 +0200658
Chi Wang6357efe2020-08-25 16:23:38 +0800659KYTHE_DIR = "/usr/local/kythe"
660
661INDEX_UPLOAD_POLICY_ALWAYS = "Always"
662
663INDEX_UPLOAD_POLICY_IF_BUILD_SUCCESS = "IfBuildSuccess"
664
665INDEX_UPLOAD_POLICY_NEVER = "Never"
Florian Weikert13215a82019-05-10 12:42:21 +0200666
Yun Peng686f4592022-01-17 15:38:48 +0100667# The maximum number of tasks allowed in one pipeline yaml config file.
668# This is to prevent accidentally creating too many tasks with the martix testing feature.
Yun Peng68e8a4c2022-06-15 18:31:41 +0200669MAX_TASK_NUMBER = 80
Yun Peng686f4592022-01-17 15:38:48 +0100670
Florian Weikertdb832a02020-11-19 19:14:48 +0100671
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100672class BuildkiteException(Exception):
673 """
674 Raised whenever something goes wrong and we should exit with an error.
675 """
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100676
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100677 pass
678
679
Yun Pengd433d4f2022-12-09 10:53:15 +0100680class BuildkiteInfraException(Exception):
681 """
682 Raised whenever something goes wrong with the CI infra and we should immediately exit with an error.
683 """
684
685 pass
686
687
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100688class BinaryUploadRaceException(Exception):
689 """
690 Raised when try_publish_binaries wasn't able to publish a set of binaries,
691 because the generation of the current file didn't match the expected value.
692 """
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100693
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100694 pass
695
696
Florian Weikerta0e74592019-03-07 11:56:12 +0100697class BuildkiteClient(object):
Florian Weikerta0e74592019-03-07 11:56:12 +0100698 _ENCRYPTED_BUILDKITE_API_TOKEN = """
699CiQA4DEB9ldzC+E39KomywtqXfaQ86hhulgeDsicds2BuvbCYzsSUAAqwcvXZPh9IMWlwWh94J2F
700exosKKaWB0tSRJiPKnv2NPDfEqGul0ZwVjtWeASpugwxxKeLhFhPMcgHMPfndH6j2GEIY6nkKRbP
701uwoRMCwe
702""".strip()
703
Philipp Wollermanne67eec42019-05-24 15:18:20 +0200704 _ENCRYPTED_BUILDKITE_API_TESTING_TOKEN = """
705CiQAMTBkWjL1C+F5oon3+cC1vmum5+c1y5+96WQY44p0Lxd0PeASUQAy7iU0c6E3W5EOSFYfD5fA
706MWy/SHaMno1NQSUa4xDOl5yc2kizrtxPPVkX4x9pLNuGUY/xwAn2n1DdiUdWZNWlY1bX2C4ex65e
707P9w8kNhEbw==
708""".strip()
709
Florian Weikertde96a6f2019-03-07 14:57:50 +0100710 _BUILD_STATUS_URL_TEMPLATE = (
711 "https://api.buildkite.com/v2/organizations/{}/pipelines/{}/builds/{}"
712 )
Florian Weikerta0e74592019-03-07 11:56:12 +0100713
Florian Weikertdb832a02020-11-19 19:14:48 +0100714 _NEW_BUILD_URL_TEMPLATE = "https://api.buildkite.com/v2/organizations/{}/pipelines/{}/builds"
Yun Peng9337bb32020-02-28 13:31:29 +0100715
716 _RETRY_JOB_URL_TEMPLATE = (
717 "https://api.buildkite.com/v2/organizations/{}/pipelines/{}/builds/{}/jobs/{}/retry"
718 )
719
Florian Weikertb3439b32022-11-09 11:05:16 +0100720 _PIPELINE_INFO_URL_TEMPLATE = "https://api.buildkite.com/v2/organizations/{}/pipelines/{}"
Mai Hussienfe58c062022-07-07 01:29:46 -0700721
Florian Weikerta0e74592019-03-07 11:56:12 +0100722 def __init__(self, org, pipeline):
723 self._org = org
724 self._pipeline = pipeline
725 self._token = self._get_buildkite_token()
726
727 def _get_buildkite_token(self):
Florian Weikert849afb22019-12-14 12:22:29 -0800728 return decrypt_token(
729 encrypted_token=self._ENCRYPTED_BUILDKITE_API_TESTING_TOKEN
730 if THIS_IS_TESTING
731 else self._ENCRYPTED_BUILDKITE_API_TOKEN,
732 kms_key="buildkite-testing-api-token"
733 if THIS_IS_TESTING
734 else "buildkite-untrusted-api-token",
Florian Weikerta0e74592019-03-07 11:56:12 +0100735 )
736
Florian Weikertdb832a02020-11-19 19:14:48 +0100737 def _open_url(self, url, params=[]):
Florian Weikert60661912019-12-18 15:17:10 +0100738 try:
Yun Peng9337bb32020-02-28 13:31:29 +0100739 params_str = "".join("&{}={}".format(k, v) for k, v in params)
Florian Weikert60661912019-12-18 15:17:10 +0100740 return (
Yun Peng9337bb32020-02-28 13:31:29 +0100741 urllib.request.urlopen("{}?access_token={}{}".format(url, self._token, params_str))
Florian Weikert60661912019-12-18 15:17:10 +0100742 .read()
Yun Pengdbedc122020-02-28 13:32:04 +0100743 .decode("utf-8", "ignore")
Florian Weikert60661912019-12-18 15:17:10 +0100744 )
745 except urllib.error.HTTPError as ex:
746 raise BuildkiteException("Failed to open {}: {} - {}".format(url, ex.code, ex.reason))
Florian Weikerta0e74592019-03-07 11:56:12 +0100747
Mai Hussienfe58c062022-07-07 01:29:46 -0700748 def get_pipeline_info(self):
749 """Get details for a pipeline given its organization slug
750 and pipeline slug.
751 See https://buildkite.com/docs/apis/rest-api/pipelines#get-a-pipeline
752
753 Returns
754 -------
755 dict
756 the metadata for the pipeline
757 """
758 url = self._PIPELINE_INFO_URL_TEMPLATE.format(self._org, self._pipeline)
759 output = self._open_url(url)
760 return json.loads(output)
761
Florian Weikerta0e74592019-03-07 11:56:12 +0100762 def get_build_info(self, build_number):
Yun Peng9337bb32020-02-28 13:31:29 +0100763 """Get build info for a pipeline with a given build number
764 See https://buildkite.com/docs/apis/rest-api/builds#get-a-build
765
766 Parameters
767 ----------
768 build_number : the build number
769
770 Returns
771 -------
772 dict
773 the metadata for the build
774 """
Florian Weikerta0e74592019-03-07 11:56:12 +0100775 url = self._BUILD_STATUS_URL_TEMPLATE.format(self._org, self._pipeline, build_number)
776 output = self._open_url(url)
777 return json.loads(output)
778
Yun Peng9337bb32020-02-28 13:31:29 +0100779 def get_build_info_list(self, params):
780 """Get a list of build infos for this pipeline
781 See https://buildkite.com/docs/apis/rest-api/builds#list-builds-for-a-pipeline
782
783 Parameters
784 ----------
785 params : the parameters to filter the result
786
787 Returns
788 -------
789 list of dict
790 the metadata for a list of builds
791 """
792 url = self._BUILD_STATUS_URL_TEMPLATE.format(self._org, self._pipeline, "")
793 output = self._open_url(url, params)
794 return json.loads(output)
795
Florian Weikerta0e74592019-03-07 11:56:12 +0100796 def get_build_log(self, job):
797 return self._open_url(job["raw_log_url"])
798
Yun Peng9337bb32020-02-28 13:31:29 +0100799 @staticmethod
800 def _check_response(response, expected_status_code):
801 if response.status_code != expected_status_code:
802 eprint("Exit code:", response.status_code)
803 eprint("Response:\n", response.text)
804 response.raise_for_status()
805
Florian Weikertdb832a02020-11-19 19:14:48 +0100806 def trigger_new_build(self, commit, message=None, env={}):
Yun Peng9337bb32020-02-28 13:31:29 +0100807 """Trigger a new build at a given commit and return the build metadata.
808 See https://buildkite.com/docs/apis/rest-api/builds#create-a-build
809
810 Parameters
811 ----------
812 commit : the commit we want to build at
813 message : the message we should as the build titile
814 env : (optional) the environment variables to set
815
816 Returns
817 -------
818 dict
819 the metadata for the build
820 """
Salma Samyf54c75b2022-11-04 16:28:18 +0200821 pipeline_info = self.get_pipeline_info()
822 if not pipeline_info:
823 raise BuildkiteException(f"Cannot find pipeline info for pipeline {self._pipeline}.")
824
Yun Peng9337bb32020-02-28 13:31:29 +0100825 url = self._NEW_BUILD_URL_TEMPLATE.format(self._org, self._pipeline)
826 data = {
827 "commit": commit,
Salma Samyf54c75b2022-11-04 16:28:18 +0200828 "branch": pipeline_info.get("default_branch") or "master",
Yun Peng9337bb32020-02-28 13:31:29 +0100829 "message": message if message else f"Trigger build at {commit}",
830 "env": env,
Yun Peng867b5a52022-01-11 13:59:41 +0100831 "ignore_pipeline_branch_filters": "true",
Yun Peng9337bb32020-02-28 13:31:29 +0100832 }
Florian Weikertdb832a02020-11-19 19:14:48 +0100833 response = requests.post(url + "?access_token=" + self._token, json=data)
Yun Peng9337bb32020-02-28 13:31:29 +0100834 BuildkiteClient._check_response(response, requests.codes.created)
835 return json.loads(response.text)
836
Yun Peng9337bb32020-02-28 13:31:29 +0100837 def trigger_job_retry(self, build_number, job_id):
838 """Trigger a job retry and return the job metadata.
839 See https://buildkite.com/docs/apis/rest-api/jobs#retry-a-job
840
841 Parameters
842 ----------
843 build_number : the number of the build we want to retry
844 job_id : the id of the job we want to retry
845
846 Returns
847 -------
848 dict
849 the metadata for the job
850 """
851 url = self._RETRY_JOB_URL_TEMPLATE.format(self._org, self._pipeline, build_number, job_id)
852 response = requests.put(url + "?access_token=" + self._token)
853 BuildkiteClient._check_response(response, requests.codes.ok)
854 return json.loads(response.text)
855
Yun Peng9337bb32020-02-28 13:31:29 +0100856 def wait_job_to_finish(self, build_number, job_id, interval_time=30, logger=None):
857 """Wait a job to finish and return the job metadata
858
859 Parameters
860 ----------
861 build_number : the number of the build we want to wait
862 job_id : the id of the job we want to wait
863 interval_time : (optional) the interval time to check the build status, default to 30s
864 logger : (optional) a logger to report progress
865
866 Returns
867 -------
868 dict
869 the latest metadata for the job
870 """
871 t = 0
872 build_info = self.get_build_info(build_number)
873 while True:
874 for job in build_info["jobs"]:
875 if job["id"] == job_id:
876 state = job["state"]
877 if state != "scheduled" and state != "running" and state != "assigned":
878 return job
879 break
880 else:
Florian Weikertdb832a02020-11-19 19:14:48 +0100881 raise BuildkiteException(
882 f"job id {job_id} doesn't exist in build " + build_info["web_url"]
883 )
Yun Peng9337bb32020-02-28 13:31:29 +0100884 url = build_info["web_url"]
885 if logger:
886 logger.log(f"Waiting for {url}, waited {t} seconds...")
887 time.sleep(interval_time)
888 t += interval_time
889 build_info = self.get_build_info(build_number)
890
Yun Peng9337bb32020-02-28 13:31:29 +0100891 def wait_build_to_finish(self, build_number, interval_time=30, logger=None):
892 """Wait a build to finish and return the build metadata
893
894 Parameters
895 ----------
896 build_number : the number of the build we want to wait
897 interval_time : (optional) the interval time to check the build status, default to 30s
898 logger : (optional) a logger to report progress
899
900 Returns
901 -------
902 dict
903 the latest metadata for the build
904 """
905 t = 0
906 build_info = self.get_build_info(build_number)
907 while build_info["state"] == "scheduled" or build_info["state"] == "running":
908 url = build_info["web_url"]
909 if logger:
910 logger.log(f"Waiting for {url}, waited {t} seconds...")
911 time.sleep(interval_time)
912 t += interval_time
913 build_info = self.get_build_info(build_number)
914 return build_info
915
916
Chi Wang5e3998f2023-05-10 11:51:02 +0000917def decrypt_token(encrypted_token, kms_key, project="bazel-untrusted"):
Florian Weikert849afb22019-12-14 12:22:29 -0800918 return (
919 subprocess.check_output(
920 [
921 gcloud_command(),
922 "kms",
923 "decrypt",
924 "--project",
Chi Wang5e3998f2023-05-10 11:51:02 +0000925 project,
Florian Weikert849afb22019-12-14 12:22:29 -0800926 "--location",
927 "global",
928 "--keyring",
929 "buildkite",
930 "--key",
931 kms_key,
932 "--ciphertext-file",
933 "-",
934 "--plaintext-file",
935 "-",
936 ],
937 input=base64.b64decode(encrypted_token),
938 env=os.environ,
939 )
940 .decode("utf-8")
941 .strip()
942 )
943
944
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100945def eprint(*args, **kwargs):
946 """
947 Print to stderr and flush (just in case).
948 """
949 print(*args, flush=True, file=sys.stderr, **kwargs)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100950
951
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100952def is_windows():
Jakob Buchgraber09048fa2018-02-27 11:39:39 +0100953 return os.name == "nt"
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100954
Jakob Buchgrabere6de16b2018-02-28 12:42:12 +0100955
Florian Weikerta6110a92022-10-20 01:16:09 +0200956def is_mac():
Florian Weikertda94a102022-10-21 12:24:37 +0200957 return platform_module.system() == "Darwin"
Florian Weikerta6110a92022-10-20 01:16:09 +0200958
959
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100960def gsutil_command():
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200961 return "gsutil.cmd" if is_windows() else "gsutil"
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100962
Jakob Buchgrabere6de16b2018-02-28 12:42:12 +0100963
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100964def gcloud_command():
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200965 return "gcloud.cmd" if is_windows() else "gcloud"
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100966
Jakob Buchgrabere6de16b2018-02-28 12:42:12 +0100967
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100968def downstream_projects_root(platform):
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200969 downstream_root = os.path.expandvars(PLATFORMS[platform]["downstream-root"])
Philipp Wollermannd5ab3d92020-02-05 16:55:13 +0100970 if platform == "windows" and os.path.exists("d:/b"):
971 # If this is a Windows machine with a local SSD, the build directory is
972 # on drive D.
973 downstream_root = downstream_root.replace("c:/b/", "d:/b/")
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200974 if not os.path.exists(downstream_root):
975 os.makedirs(downstream_root)
976 return downstream_root
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100977
978
Yun Peng5a1a9442022-01-11 14:26:48 +0100979def match_matrix_attr_pattern(s):
980 return re.match("^\${{\s*(\w+)\s*}}$", s)
981
982
983def get_matrix_attributes(task):
984 """Get unexpanded matrix attributes from the given task.
985
986 If a value of field matches "${{<name>}}", then <name> is a wanted matrix attribute.
987 eg. platform: ${{ platform }}
988 """
989 attributes = []
990 for key, value in task.items():
991 if type(value) is str:
992 res = match_matrix_attr_pattern(value)
993 if res:
994 attributes.append(res.groups()[0])
995 return list(set(attributes))
996
997
998def get_combinations(matrix, attributes):
999 """Given a matrix and the wanted attributes, return all possible combinations.
1000
1001 eg.
1002 With matrix = {'a': [1, 2], 'b': [1], 'c': [1]},
1003 if attributes = ['a', 'b'], then returns [[('a', 1), ('b', 1)], [('a', 2), ('b', 1)]]
1004 if attributes = ['b', 'c'], then returns [[('b', 1), ('c', 1)]]
1005 if attributes = ['c'], then returns [[('c', 1)]]
1006 """
Yun Peng2b59cde2023-05-08 15:44:38 +02001007 # Sort the attributes to make the output deterministic.
1008 attributes.sort()
Yun Peng5a1a9442022-01-11 14:26:48 +01001009 for attr in attributes:
1010 if attr not in matrix:
1011 raise BuildkiteException("${{ %s }} is not defined in `matrix` section." % attr)
1012 pairs = [[(attr, value) for value in matrix[attr]] for attr in attributes]
Yun Peng237309f2023-04-25 15:30:43 +02001013 return sorted(itertools.product(*pairs))
Yun Peng5a1a9442022-01-11 14:26:48 +01001014
1015
1016def get_expanded_task(task, combination):
1017 """Expand a task with the given combination of values of attributes."""
1018 combination = dict(combination)
1019 expanded_task = copy.deepcopy(task)
1020 for key, value in task.items():
1021 if type(value) is str:
1022 res = match_matrix_attr_pattern(value)
1023 if res:
1024 attr = res.groups()[0]
1025 expanded_task[key] = combination[attr]
1026 return expanded_task
1027
1028
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01001029def fetch_configs(http_url, file_config):
Philipp Wollermanndb024862018-02-19 17:16:56 +01001030 """
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01001031 If specified fetches the build configuration from file_config or http_url, else tries to
Jakob Buchgraber25bb50f2018-02-22 18:06:21 +01001032 read it from .bazelci/presubmit.yml.
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001033 Returns the json configuration as a python data structure.
Philipp Wollermanndb024862018-02-19 17:16:56 +01001034 """
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01001035 if file_config is not None and http_url is not None:
1036 raise BuildkiteException("file_config and http_url cannot be set at the same time")
1037
Florian Weikertc8b3ed22019-05-31 16:14:12 +02001038 return load_config(http_url, file_config)
1039
1040
Yun Pengfde48582022-01-11 14:37:47 +01001041def expand_task_config(config):
Yun Peng5a1a9442022-01-11 14:26:48 +01001042 # Expand tasks that uses attributes defined in the matrix section.
1043 # The original task definition expands to multiple tasks for each possible combination.
1044 tasks_to_expand = []
1045 expanded_tasks = {}
1046 matrix = config.pop("matrix", {})
1047 for key, value in matrix.items():
1048 if type(key) is not str or type(value) is not list:
1049 raise BuildkiteException("Expect `matrix` is a map of str -> list")
1050
1051 for task in config["tasks"]:
1052 attributes = get_matrix_attributes(config["tasks"][task])
1053 if attributes:
1054 tasks_to_expand.append(task)
1055 count = 1
1056 for combination in get_combinations(matrix, attributes):
1057 expanded_task_name = "%s_config_%.2d" % (task, count)
1058 count += 1
Florian Weikert7f21ca42022-02-02 17:35:23 +01001059 expanded_tasks[expanded_task_name] = get_expanded_task(
1060 config["tasks"][task], combination
1061 )
Yun Peng5a1a9442022-01-11 14:26:48 +01001062
1063 for task in tasks_to_expand:
1064 config["tasks"].pop(task)
1065 config["tasks"].update(expanded_tasks)
1066
Yun Pengfde48582022-01-11 14:37:47 +01001067
1068def load_config(http_url, file_config, allow_imports=True):
1069 if http_url:
1070 config = load_remote_yaml_file(http_url)
1071 else:
1072 file_config = file_config or ".bazelci/presubmit.yml"
1073 with open(file_config, "r") as fd:
1074 config = yaml.safe_load(fd)
1075
1076 # Legacy mode means that there is exactly one task per platform (e.g. ubuntu1604_nojdk),
1077 # which means that we can get away with using the platform name as task ID.
1078 # No other updates are needed since get_platform_for_task() falls back to using the
1079 # task ID as platform if there is no explicit "platforms" field.
1080 if "platforms" in config:
1081 config["tasks"] = config.pop("platforms")
1082
1083 if "tasks" not in config:
1084 config["tasks"] = {}
1085
1086 expand_task_config(config)
1087
Florian Weikertc8b3ed22019-05-31 16:14:12 +02001088 imports = config.pop("imports", None)
1089 if imports:
1090 if not allow_imports:
1091 raise BuildkiteException("Nested imports are not allowed")
1092
1093 for i in imports:
1094 imported_tasks = load_imported_tasks(i, http_url, file_config)
1095 config["tasks"].update(imported_tasks)
1096
Yun Peng686f4592022-01-17 15:38:48 +01001097 if len(config["tasks"]) > MAX_TASK_NUMBER:
Florian Weikert7f21ca42022-02-02 17:35:23 +01001098 raise BuildkiteException(
1099 "The number of tasks in one config file is limited to %s!" % MAX_TASK_NUMBER
1100 )
Yun Peng686f4592022-01-17 15:38:48 +01001101
Florian Weikert843d7a02019-02-03 17:24:50 +01001102 return config
1103
1104
Florian Weikert13215a82019-05-10 12:42:21 +02001105def load_remote_yaml_file(http_url):
1106 with urllib.request.urlopen(http_url) as resp:
1107 reader = codecs.getreader("utf-8")
Philipp Wollermannd00107e2019-05-18 23:50:59 +02001108 return yaml.safe_load(reader(resp))
Florian Weikert13215a82019-05-10 12:42:21 +02001109
1110
Florian Weikertc8b3ed22019-05-31 16:14:12 +02001111def load_imported_tasks(import_name, http_url, file_config):
1112 if "/" in import_name:
1113 raise BuildkiteException("Invalid import '%s'" % import_name)
1114
1115 old_path = http_url or file_config
1116 new_path = "%s%s" % (old_path[: old_path.rfind("/") + 1], import_name)
1117 if http_url:
1118 http_url = new_path
1119 else:
1120 file_config = new_path
1121
1122 imported_config = load_config(http_url=http_url, file_config=file_config, allow_imports=False)
1123
1124 namespace = import_name.partition(".")[0]
1125 tasks = {}
1126 for task_name, task_config in imported_config["tasks"].items():
Florian Weikert61f29b82019-08-12 16:56:56 +02001127 fix_imported_task_platform(task_name, task_config)
1128 fix_imported_task_name(namespace, task_config)
1129 fix_imported_task_working_directory(namespace, task_config)
Florian Weikertc8b3ed22019-05-31 16:14:12 +02001130 tasks["%s_%s" % (namespace, task_name)] = task_config
1131
1132 return tasks
1133
1134
Florian Weikert61f29b82019-08-12 16:56:56 +02001135def fix_imported_task_platform(task_name, task_config):
1136 if "platform" not in task_config:
1137 task_config["platform"] = task_name
1138
1139
1140def fix_imported_task_name(namespace, task_config):
1141 old_name = task_config.get("name")
1142 task_config["name"] = "%s (%s)" % (namespace, old_name) if old_name else namespace
1143
1144
1145def fix_imported_task_working_directory(namespace, task_config):
1146 old_dir = task_config.get("working_directory")
1147 task_config["working_directory"] = os.path.join(namespace, old_dir) if old_dir else namespace
1148
1149
Jakob Buchgraber3120f7a2018-02-18 13:28:02 +01001150def print_collapsed_group(name):
Jakob Buchgraber5c9b13d2018-02-21 22:28:14 +01001151 eprint("\n\n--- {0}\n\n".format(name))
Jakob Buchgraber3120f7a2018-02-18 13:28:02 +01001152
Jakob Buchgraber9c83de72018-02-18 15:32:44 +01001153
Jakob Buchgraber3120f7a2018-02-18 13:28:02 +01001154def print_expanded_group(name):
Jakob Buchgraber5c9b13d2018-02-21 22:28:14 +01001155 eprint("\n\n+++ {0}\n\n".format(name))
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001156
Yun Peng9b1d3432021-12-07 10:40:45 +01001157
Philipp Wollermannc8b86ac2021-10-25 17:52:07 +02001158def is_trueish(s):
1159 return str(s).lower() in ["true", "1", "t", "y", "yes"]
1160
Jakob Buchgraber9c83de72018-02-18 15:32:44 +01001161
Yun Peng8975c6b2019-02-28 11:55:55 +01001162def use_bazelisk_migrate():
1163 """
1164 If USE_BAZELISK_MIGRATE is set, we use `bazelisk --migrate` to test incompatible flags.
1165 """
Philipp Wollermannc8b86ac2021-10-25 17:52:07 +02001166 return is_trueish(os.environ.get("USE_BAZELISK_MIGRATE"))
Yun Peng8975c6b2019-02-28 11:55:55 +01001167
1168
1169def bazelisk_flags():
1170 return ["--migrate"] if use_bazelisk_migrate() else []
1171
1172
Chi Wang54595a22021-06-11 17:49:58 +08001173def calculate_flags(task_config, task_config_key, action_key, tmpdir, test_env_vars):
Chi Wang6357efe2020-08-25 16:23:38 +08001174 include_json_profile = task_config.get("include_json_profile", [])
Chi Wang54595a22021-06-11 17:49:58 +08001175 capture_corrupted_outputs = task_config.get("capture_corrupted_outputs", [])
Chi Wang6357efe2020-08-25 16:23:38 +08001176
1177 json_profile_flags = []
1178 json_profile_out = None
Chi Wang54595a22021-06-11 17:49:58 +08001179 if action_key in include_json_profile:
1180 json_profile_out = os.path.join(tmpdir, "{}.profile.gz".format(action_key))
Tobias Werthc22e4c42021-10-08 12:03:14 +02001181 json_profile_flags = ["--profile={}".format(json_profile_out)]
1182
Chi Wang54595a22021-06-11 17:49:58 +08001183 capture_corrupted_outputs_flags = []
1184 capture_corrupted_outputs_dir = None
1185 if action_key in capture_corrupted_outputs:
Philipp Wollermannf436e742021-08-11 11:06:55 +02001186 capture_corrupted_outputs_dir = os.path.join(
1187 tmpdir, "{}_corrupted_outputs".format(action_key)
1188 )
1189 capture_corrupted_outputs_flags = [
1190 "--experimental_remote_capture_corrupted_outputs={}".format(
1191 capture_corrupted_outputs_dir
1192 )
1193 ]
Chi Wang6357efe2020-08-25 16:23:38 +08001194
1195 flags = task_config.get(task_config_key) or []
1196 flags += json_profile_flags
Chi Wang54595a22021-06-11 17:49:58 +08001197 flags += capture_corrupted_outputs_flags
Chi Wang6357efe2020-08-25 16:23:38 +08001198 # We have to add --test_env flags to `build`, too, otherwise Bazel
1199 # discards its analysis cache between `build` and `test`.
1200 if test_env_vars:
1201 flags += ["--test_env={}".format(v) for v in test_env_vars]
1202
Chi Wang54595a22021-06-11 17:49:58 +08001203 return flags, json_profile_out, capture_corrupted_outputs_dir
Chi Wang6357efe2020-08-25 16:23:38 +08001204
1205
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001206def execute_commands(
Florian Weikertc8642af2019-02-03 23:58:51 +01001207 task_config,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001208 platform,
1209 git_repository,
1210 git_commit,
Yun Peng5012a862021-09-16 16:35:43 +02001211 repo_location,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001212 use_bazel_at_commit,
1213 use_but,
1214 save_but,
Yun Peng4d1d6542019-01-17 18:30:33 +01001215 needs_clean,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001216 build_only,
1217 test_only,
1218 monitor_flaky_tests,
Florian Weikertc8642af2019-02-03 23:58:51 +01001219 bazel_version=None,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001220):
Yun Pengc85cd0e2022-09-02 10:44:29 +02001221 if use_bazelisk_migrate():
1222 # If we are testing incompatible flags with Bazelisk,
1223 # use Bazel@last_green if USE_BAZEL_VERSION env var is not set explicitly.
1224 if "USE_BAZEL_VERSION" not in os.environ:
1225 bazel_version = "last_green"
1226
1227 # Override use_but in case we are in the downstream pipeline so that it doesn't try to
1228 # download Bazel built from previous jobs.
1229 use_but = False
1230
1231 # Set BAZELISK_INCOMPATIBLE_FLAGS to tell Bazelisk which flags to test.
1232 os.environ["BAZELISK_INCOMPATIBLE_FLAGS"] = ",".join(fetch_incompatible_flags().keys())
1233
Florian Weikert13215a82019-05-10 12:42:21 +02001234 if not bazel_version:
1235 # The last good version of Bazel can be specified in an emergency file.
1236 # However, we only use last_good_bazel for pipelines that do not
1237 # explicitly specify a version of Bazel.
1238 try:
1239 emergency_settings = load_remote_yaml_file(EMERGENCY_FILE_URL)
1240 bazel_version = emergency_settings.get("last_good_bazel")
1241 except urllib.error.HTTPError:
1242 # Ignore this error. The Setup step will have already complained about
1243 # it by showing an error message.
1244 pass
Yun Pengf50f7b72019-02-28 19:09:52 +01001245
Jakob Buchgraberfb95a2f2018-02-22 11:46:25 +01001246 if build_only and test_only:
1247 raise BuildkiteException("build_only and test_only cannot be true at the same time")
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001248
Florian Weikertd7cb83d2023-02-24 19:51:52 +01001249 if use_but:
1250 if use_bazel_at_commit:
1251 raise BuildkiteException("use_bazel_at_commit cannot be set when use_but is true")
1252
1253 print_collapsed_group(":printer: Printing task config for downstream job...")
Florian Weikert7d894782023-02-24 20:28:14 +01001254 eprint(json.dumps(task_config, indent=2))
Yun Peng20d45602018-10-18 13:27:05 +02001255
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001256 tmpdir = tempfile.mkdtemp()
1257 sc_process = None
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001258 try:
Florian Weikertda94a102022-10-21 12:24:37 +02001259 if is_mac():
Florian Weikertee84c5c2019-05-28 11:21:51 +02001260 activate_xcode(task_config)
Philipp Wollermann380f1e62019-04-12 16:45:27 +02001261
Florian Weikert4ee0bed2019-02-21 18:03:00 +01001262 # If the CI worker runs Bazelisk, we need to forward all required env variables to the test.
1263 # Otherwise any integration test that invokes Bazel (=Bazelisk in this case) will fail.
Marcel Hlopko198328b2019-02-25 09:19:55 +01001264 test_env_vars = ["LocalAppData"] if platform == "windows" else ["HOME"]
Florian Weikertc12580c2021-07-13 17:09:25 +02001265
1266 # CI should have its own user agent so that we can remove it from Bazel download statistics.
1267 os.environ["BAZELISK_USER_AGENT"] = "Bazelisk/BazelCI"
1268 test_env_vars.append("BAZELISK_USER_AGENT")
1269
Yun Peng5012a862021-09-16 16:35:43 +02001270 if repo_location:
1271 os.chdir(repo_location)
Yun Peng376d2b32018-11-29 10:24:54 +01001272 elif git_repository:
1273 clone_git_repository(git_repository, platform, git_commit)
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001274
Philipp Wollermannf4aabb72019-06-25 15:59:00 +02001275 # We use one binary for all Linux platforms (because we also just release one binary for all
1276 # Linux versions and we have to ensure that it works on all of them).
Florian Weikertda94a102022-10-21 12:24:37 +02001277 binary_platform = platform if is_mac() or is_windows() else LINUX_BINARY_PLATFORM
Philipp Wollermannf4aabb72019-06-25 15:59:00 +02001278
Yun Pengeec2cd92022-07-14 14:44:30 +02001279 bazel_binary = "bazel"
Yun Peng20d45602018-10-18 13:27:05 +02001280 if use_bazel_at_commit:
1281 print_collapsed_group(":gcloud: Downloading Bazel built at " + use_bazel_at_commit)
Yun Pengdae5a7d2022-01-11 16:08:58 +01001282 # Linux binaries are published under platform name "centos7"
1283 if binary_platform == LINUX_BINARY_PLATFORM:
1284 binary_platform = "centos7"
Yun Pengeec2cd92022-07-14 14:44:30 +02001285 os.environ["USE_BAZEL_VERSION"] = download_bazel_binary_at_commit(
Philipp Wollermannf4aabb72019-06-25 15:59:00 +02001286 tmpdir, binary_platform, use_bazel_at_commit
1287 )
Yun Pengeec2cd92022-07-14 14:44:30 +02001288 print_collapsed_group(":bazel: Using Bazel at " + os.environ["USE_BAZEL_VERSION"])
Philipp Wollermann639c0452019-01-03 11:23:54 +01001289 elif use_but:
Jakob Buchgraber92755d72018-02-22 15:33:37 +01001290 print_collapsed_group(":gcloud: Downloading Bazel Under Test")
Yun Pengeec2cd92022-07-14 14:44:30 +02001291 os.environ["USE_BAZEL_VERSION"] = download_bazel_binary(tmpdir, binary_platform)
1292 print_collapsed_group(":bazel: Using Bazel at " + os.environ["USE_BAZEL_VERSION"])
Philipp Wollermann639c0452019-01-03 11:23:54 +01001293 else:
Yun Pengeec2cd92022-07-14 14:44:30 +02001294 print_collapsed_group(":bazel: Using Bazel version " + bazel_version)
Florian Weikertc8642af2019-02-03 23:58:51 +01001295 if bazel_version:
Florian Weikertc8642af2019-02-03 23:58:51 +01001296 os.environ["USE_BAZEL_VERSION"] = bazel_version
Philipp Wollermann87b45252020-01-22 12:43:42 +01001297 if "USE_BAZEL_VERSION" in os.environ and not task_config.get(
1298 "skip_use_bazel_version_for_test", False
1299 ):
Yun Pengf0a66e22019-10-14 12:45:42 +02001300 # This will only work if the bazel binary in $PATH is actually a bazelisk binary
1301 # (https://github.com/bazelbuild/bazelisk).
1302 test_env_vars.append("USE_BAZEL_VERSION")
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001303
Philipp Wollermann5c7ea412019-05-24 15:26:57 +02001304 for key, value in task_config.get("environment", {}).items():
Philipp Wollermann4ad4aac2019-05-24 15:23:09 +02001305 # We have to explicitly convert the value to a string, because sometimes YAML tries to
1306 # be smart and converts strings like "true" and "false" to booleans.
Philipp Wollermann7df2d0d2021-08-11 13:26:04 +02001307 os.environ[key] = os.path.expandvars(str(value))
Philipp Wollermann213ac9d2019-02-06 11:50:05 +01001308
Yun Peng366f04c2020-08-10 16:55:58 +02001309 # Set BAZELISK_SHUTDOWN to 1 when we use bazelisk --migrate on Windows.
1310 # This is a workaround for https://github.com/bazelbuild/continuous-integration/issues/1012
1311 if use_bazelisk_migrate() and platform == "windows":
1312 os.environ["BAZELISK_SHUTDOWN"] = "1"
1313
Florian Weikert9b805ce2023-05-10 18:04:03 +02001314 def PrepareRepoInCwd(print_cmd_groups, initial_setup=False):
Florian Weikert5e70d9d2023-05-08 19:20:23 +02001315 # Allow the config to override the current working directory.
1316 requested_working_dir = task_config.get("working_directory")
1317 if requested_working_dir:
1318 if os.path.isabs(requested_working_dir):
1319 raise BuildkiteException(
1320 f"working_directory must be relative to the repository root, "
1321 "but was {requested_working_dir}"
1322 )
1323
1324 full_requested_working_dir = os.path.abspath(requested_working_dir)
1325 if not os.path.isdir(full_requested_working_dir):
1326 raise BuildkiteException(
1327 f"{full_requested_working_dir} does not exist or is not a directory"
1328 )
1329
1330 os.chdir(full_requested_working_dir)
1331
Florian Weikert9b805ce2023-05-10 18:04:03 +02001332 # Dirty workaround for #1660
1333 if initial_setup:
1334 # Set OUTPUT_BASE environment variable
1335 os.environ["OUTPUT_BASE"] = get_output_base(bazel_binary)
1336
1337 cmd_exec_func = (
1338 execute_batch_commands if platform == "windows" else execute_shell_commands
1339 )
1340 cmd_exec_func(task_config.get("setup", None))
Yun Peng28a9a532023-05-10 14:19:46 +02001341
Florian Weikert5e70d9d2023-05-08 19:20:23 +02001342 if platform == "windows":
Florian Weikert4141ce92023-05-09 09:45:55 +02001343 execute_batch_commands(task_config.get("batch_commands", None), print_cmd_groups)
Florian Weikert5e70d9d2023-05-08 19:20:23 +02001344 else:
Florian Weikert4141ce92023-05-09 09:45:55 +02001345 execute_shell_commands(task_config.get("shell_commands", None), print_cmd_groups)
Florian Weikert5e70d9d2023-05-08 19:20:23 +02001346
Florian Weikert9b805ce2023-05-10 18:04:03 +02001347 PrepareRepoInCwd(True, initial_setup=True)
Florian Weikerte72d68a2019-03-08 18:56:33 +01001348
Florian Weikertc8642af2019-02-03 23:58:51 +01001349 bazel_version = print_bazel_version_info(bazel_binary, platform)
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001350
Yun Penga5a1ee02018-12-05 15:00:58 +01001351 print_environment_variables_info()
1352
Yun Pengc85cd0e2022-09-02 10:44:29 +02001353 execute_bazel_run(bazel_binary, platform, task_config.get("run_targets", None))
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001354
Yun Peng4d1d6542019-01-17 18:30:33 +01001355 if needs_clean:
Yun Pengea0359e2019-01-17 15:37:47 +01001356 execute_bazel_clean(bazel_binary, platform)
1357
Florian Weikert25e92c42023-04-28 10:56:46 +02001358 # The git_commit paramter only has a value in the downstream pipeline,
1359 # but we need the commit here in order to calculate the correct targets.
1360 git_commit = git_commit or os.getenv("BUILDKITE_COMMIT")
1361 if not git_commit:
1362 raise BuildkiteInfraException("Unable to determine Git commit for this build")
1363
Florian Weikert7dd9f662023-05-04 15:05:42 +02001364 test_flags, json_profile_out_test, capture_corrupted_outputs_dir_test = calculate_flags(
1365 task_config, "test_flags", "test", tmpdir, test_env_vars
1366 )
1367
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01001368 build_targets, test_targets, coverage_targets, index_targets = calculate_targets(
Florian Weikert7dd9f662023-05-04 15:05:42 +02001369 task_config,
1370 bazel_binary,
1371 build_only,
1372 test_only,
Florian Weikert5e70d9d2023-05-08 19:20:23 +02001373 os.getcwd(),
1374 PrepareRepoInCwd,
Florian Weikert7dd9f662023-05-04 15:05:42 +02001375 git_commit,
1376 test_flags,
Florian Weikert736d06e2019-05-08 13:16:42 +02001377 )
Florian Weikert736d06e2019-05-08 13:16:42 +02001378
1379 if build_targets:
Philipp Wollermannf436e742021-08-11 11:06:55 +02001380 (
1381 build_flags,
1382 json_profile_out_build,
1383 capture_corrupted_outputs_dir_build,
1384 ) = calculate_flags(task_config, "build_flags", "build", tmpdir, test_env_vars)
joeleba76887952019-05-16 15:22:17 +02001385 try:
Yun Pengc8bb9e92021-07-28 11:56:53 +02001386 release_name = get_release_name_from_branch_name()
joeleba76887952019-05-16 15:22:17 +02001387 execute_bazel_build(
1388 bazel_version,
1389 bazel_binary,
1390 platform,
Philipp Wollermannf436e742021-08-11 11:06:55 +02001391 build_flags
1392 + (
1393 ["--stamp", "--embed_label=%s" % release_name]
1394 if save_but and release_name
1395 else []
1396 ),
joeleba76887952019-05-16 15:22:17 +02001397 build_targets,
1398 None,
joeleba76887952019-05-16 15:22:17 +02001399 )
1400 if save_but:
1401 upload_bazel_binary(platform)
1402 finally:
Chi Wang6357efe2020-08-25 16:23:38 +08001403 if json_profile_out_build:
Philipp Wollermann92cf51e2019-05-16 15:31:11 +02001404 upload_json_profile(json_profile_out_build, tmpdir)
Chi Wang54595a22021-06-11 17:49:58 +08001405 if capture_corrupted_outputs_dir_build:
1406 upload_corrupted_outputs(capture_corrupted_outputs_dir_build, tmpdir)
Philipp Wollermann639c0452019-01-03 11:23:54 +01001407
Florian Weikert736d06e2019-05-08 13:16:42 +02001408 if test_targets:
Florian Weikert4901c662019-02-26 13:20:11 +01001409 if not is_windows():
1410 # On platforms that support sandboxing (Linux, MacOS) we have
1411 # to allow access to Bazelisk's cache directory.
1412 # However, the flag requires the directory to exist,
1413 # so we create it here in order to not crash when a test
1414 # does not invoke Bazelisk.
Florian Weikertda94a102022-10-21 12:24:37 +02001415 bazelisk_cache_dir = get_bazelisk_cache_directory()
Florian Weikert4901c662019-02-26 13:20:11 +01001416 os.makedirs(bazelisk_cache_dir, mode=0o755, exist_ok=True)
1417 test_flags.append("--sandbox_writable_path={}".format(bazelisk_cache_dir))
Florian Weikert5b890332019-02-25 14:57:43 +01001418
Chi Wang5e3998f2023-05-10 11:51:02 +00001419 # Set BUILDKITE_ANALYTICS_TOKEN so that bazelci-agent can upload test results to Test Analytics
1420 if "ENCRYPTED_BUILDKITE_ANALYTICS_TOKEN" in os.environ:
1421 if THIS_IS_TESTING:
1422 kms_key = "buildkite-testing-api-token"
1423 project = "bazel-untrusted"
1424 elif THIS_IS_TRUSTED:
1425 kms_key = "buildkite-trusted-api-token"
1426 project = "bazel-public"
1427 else:
1428 kms_key = "buildkite-untrusted-api-token"
1429 project = "bazel-untrusted"
1430 os.environ["BUILDKITE_ANALYTICS_TOKEN"] = decrypt_token(
1431 encrypted_token=os.environ["ENCRYPTED_BUILDKITE_ANALYTICS_TOKEN"],
1432 kms_key=kms_key,
1433 project=project,
1434 )
1435
Philipp Wollermannce986af2019-07-18 14:46:05 +02001436 test_bep_file = os.path.join(tmpdir, "test_bep.json")
Philipp Wollermannce986af2019-07-18 14:46:05 +02001437 upload_thread = threading.Thread(
Florian Weikert7f21ca42022-02-02 17:35:23 +01001438 target=upload_test_logs_from_bep,
Florian Weikertda94a102022-10-21 12:24:37 +02001439 args=(test_bep_file, tmpdir, monitor_flaky_tests),
Philipp Wollermannce986af2019-07-18 14:46:05 +02001440 )
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001441 try:
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001442 upload_thread.start()
1443 try:
1444 execute_bazel_test(
1445 bazel_version,
1446 bazel_binary,
1447 platform,
1448 test_flags,
1449 test_targets,
1450 test_bep_file,
1451 monitor_flaky_tests,
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001452 )
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001453 finally:
Chi Wang6357efe2020-08-25 16:23:38 +08001454 if json_profile_out_test:
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001455 upload_json_profile(json_profile_out_test, tmpdir)
Chi Wang54595a22021-06-11 17:49:58 +08001456 if capture_corrupted_outputs_dir_test:
1457 upload_corrupted_outputs(capture_corrupted_outputs_dir_test, tmpdir)
Philipp Wollermann639c0452019-01-03 11:23:54 +01001458 finally:
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001459 upload_thread.join()
Chi Wang6357efe2020-08-25 16:23:38 +08001460
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01001461 if coverage_targets:
Florian Weikert7f21ca42022-02-02 17:35:23 +01001462 (
1463 coverage_flags,
1464 json_profile_out_coverage,
1465 capture_corrupted_outputs_dir_coverage,
1466 ) = calculate_flags(task_config, "coverage_flags", "coverage", tmpdir, test_env_vars)
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01001467 try:
1468 execute_bazel_coverage(
1469 bazel_version,
1470 bazel_binary,
1471 platform,
1472 coverage_flags,
1473 coverage_targets,
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01001474 )
1475 finally:
1476 if json_profile_out_coverage:
1477 upload_json_profile(json_profile_out_coverage, tmpdir)
1478 if capture_corrupted_outputs_dir_coverage:
1479 upload_corrupted_outputs(capture_corrupted_outputs_dir_coverage, tmpdir)
1480
Chi Wang6357efe2020-08-25 16:23:38 +08001481 if index_targets:
Philipp Wollermannf436e742021-08-11 11:06:55 +02001482 (
1483 index_flags,
1484 json_profile_out_index,
1485 capture_corrupted_outputs_dir_index,
1486 ) = calculate_flags(task_config, "index_flags", "index", tmpdir, test_env_vars)
Chi Wang6357efe2020-08-25 16:23:38 +08001487 index_upload_policy = task_config.get("index_upload_policy", "IfBuildSuccess")
Chi Wangb2b65682020-08-27 10:36:15 +08001488 index_upload_gcs = task_config.get("index_upload_gcs", False)
Chi Wang6357efe2020-08-25 16:23:38 +08001489
1490 try:
Florian Weikertdb832a02020-11-19 19:14:48 +01001491 should_upload_kzip = (
1492 True if index_upload_policy == INDEX_UPLOAD_POLICY_ALWAYS else False
1493 )
Chi Wang6357efe2020-08-25 16:23:38 +08001494 try:
1495 execute_bazel_build_with_kythe(
1496 bazel_version,
1497 bazel_binary,
1498 platform,
1499 index_flags,
1500 index_targets,
1501 None,
Chi Wang6357efe2020-08-25 16:23:38 +08001502 )
1503
1504 if index_upload_policy == INDEX_UPLOAD_POLICY_IF_BUILD_SUCCESS:
1505 should_upload_kzip = True
1506 except subprocess.CalledProcessError as e:
1507 # If not running with Always policy, raise the build error.
1508 if index_upload_policy != INDEX_UPLOAD_POLICY_ALWAYS:
1509 handle_bazel_failure(e, "build")
1510
Philipp Wollermanna038b002021-05-05 22:04:38 +02001511 if should_upload_kzip and not is_pull_request():
Chi Wang6357efe2020-08-25 16:23:38 +08001512 try:
Chi Wangb2b65682020-08-27 10:36:15 +08001513 merge_and_upload_kythe_kzip(platform, index_upload_gcs)
Chi Wang6357efe2020-08-25 16:23:38 +08001514 except subprocess.CalledProcessError:
1515 raise BuildkiteException("Failed to upload kythe kzip")
1516 finally:
1517 if json_profile_out_index:
1518 upload_json_profile(json_profile_out_index, tmpdir)
Chi Wang54595a22021-06-11 17:49:58 +08001519 if capture_corrupted_outputs_dir_index:
1520 upload_corrupted_outputs(capture_corrupted_outputs_dir_index, tmpdir)
Chi Wang6357efe2020-08-25 16:23:38 +08001521
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001522 finally:
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001523 terminate_background_process(sc_process)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001524 if tmpdir:
1525 shutil.rmtree(tmpdir)
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001526
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02001527
Florian Weikertf11f2bf2023-01-31 19:11:52 +01001528def get_default_xcode_version():
Florian Weikert9e342592023-02-07 16:32:36 +01001529 # Cannot use platform.mac_ver() since it returns 10.16 on both 12.x and 13.x
1530 macos = execute_command_and_get_output(["sw_vers", "-productVersion"], print_output=False)
Florian Weikertf11f2bf2023-01-31 19:11:52 +01001531 major = int(macos.split(".")[0])
1532 return DEFAULT_XCODE_VERSION_PER_OS.get(major, "13.0") # we use 13.0 due to legacy reasons
1533
Florian Weikertecf091c2023-04-28 10:22:23 +02001534
Florian Weikertee84c5c2019-05-28 11:21:51 +02001535def activate_xcode(task_config):
Florian Weikertf11f2bf2023-01-31 19:11:52 +01001536 default_xcode_version = get_default_xcode_version()
1537
Florian Weikertee84c5c2019-05-28 11:21:51 +02001538 # Get the Xcode version from the config.
Florian Weikertf11f2bf2023-01-31 19:11:52 +01001539 wanted_xcode_version = task_config.get("xcode_version", default_xcode_version)
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001540 print_collapsed_group(":xcode: Activating Xcode {}...".format(wanted_xcode_version))
Florian Weikertee84c5c2019-05-28 11:21:51 +02001541
1542 # Ensure it's a valid version number.
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001543 if not isinstance(wanted_xcode_version, str):
Florian Weikertee84c5c2019-05-28 11:21:51 +02001544 raise BuildkiteException(
1545 "Version number '{}' is not a string. Did you forget to put it in quotes?".format(
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001546 wanted_xcode_version
Florian Weikertee84c5c2019-05-28 11:21:51 +02001547 )
1548 )
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001549 if not XCODE_VERSION_REGEX.match(wanted_xcode_version):
Florian Weikertee84c5c2019-05-28 11:21:51 +02001550 raise BuildkiteException(
1551 "Invalid Xcode version format '{}', must match the format X.Y[.Z].".format(
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001552 wanted_xcode_version
Florian Weikertee84c5c2019-05-28 11:21:51 +02001553 )
1554 )
1555
Philipp Wollermann06e56972020-01-29 14:46:41 +01001556 # This is used to replace e.g. 11.2 with 11.2.1 without having to update all configs.
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001557 xcode_version = XCODE_VERSION_OVERRIDES.get(wanted_xcode_version, wanted_xcode_version)
1558
1559 # This falls back to a default version if the selected version is not available.
1560 supported_versions = sorted(
1561 # Stripping "Xcode" prefix and ".app" suffix from e.g. "Xcode12.0.1.app" leaves just the version number.
Florian Weikert9d5e4c02021-05-27 15:10:20 +02001562 [os.path.basename(x)[5:-4] for x in glob("/Applications/Xcode*.app")],
1563 reverse=True,
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001564 )
1565 if xcode_version not in supported_versions:
Florian Weikertf11f2bf2023-01-31 19:11:52 +01001566 xcode_version = default_xcode_version
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001567 if xcode_version != wanted_xcode_version:
1568 print_collapsed_group(
1569 ":xcode: Fixed Xcode version: {} -> {}...".format(wanted_xcode_version, xcode_version)
1570 )
1571 lines = [
Florian Weikert9d5e4c02021-05-27 15:10:20 +02001572 "Your selected Xcode version {} was not available on the machine.".format(
1573 wanted_xcode_version
1574 ),
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001575 "Bazel CI automatically picked a fallback version: {}.".format(xcode_version),
1576 "Available versions are: {}.".format(supported_versions),
1577 ]
Florian Weikert9d5e4c02021-05-27 15:10:20 +02001578 execute_command(
1579 [
1580 "buildkite-agent",
1581 "annotate",
1582 "--style=warning",
1583 "\n".join(lines),
1584 "--context",
1585 "ctx-xcode_version_fixed",
1586 ]
1587 )
Philipp Wollermann06e56972020-01-29 14:46:41 +01001588
Florian Weikertee84c5c2019-05-28 11:21:51 +02001589 # Check that the selected Xcode version is actually installed on the host.
1590 xcode_path = "/Applications/Xcode{}.app".format(xcode_version)
1591 if not os.path.exists(xcode_path):
1592 raise BuildkiteException("Xcode not found at '{}'.".format(xcode_path))
1593
1594 # Now activate the specified Xcode version and let it install its required components.
1595 # The CI machines have a sudoers config that allows the 'buildkite' user to run exactly
1596 # these two commands, so don't change them without also modifying the file there.
1597 execute_command(["/usr/bin/sudo", "/usr/bin/xcode-select", "--switch", xcode_path])
1598 execute_command(["/usr/bin/sudo", "/usr/bin/xcodebuild", "-runFirstLaunch"])
1599
1600
Florian Weikertda94a102022-10-21 12:24:37 +02001601def get_bazelisk_cache_directory():
Florian Weikert4901c662019-02-26 13:20:11 +01001602 # The path relies on the behavior of Go's os.UserCacheDir()
1603 # and of the Go version of Bazelisk.
Florian Weikertda94a102022-10-21 12:24:37 +02001604 cache_dir = "Library/Caches" if is_mac() else ".cache"
Philipp Wollermannce986af2019-07-18 14:46:05 +02001605 return os.path.join(os.environ.get("HOME"), cache_dir, "bazelisk")
Florian Weikert4901c662019-02-26 13:20:11 +01001606
Florian Weikert5b890332019-02-25 14:57:43 +01001607
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02001608def current_branch_is_main_branch():
Mai Hussien0731b4d2022-06-28 11:16:07 -07001609 return os.getenv("BUILDKITE_BRANCH") in ("master", "stable", "main", "google")
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02001610
1611
Yun Peng92c0ef82021-07-26 10:41:21 +02001612def get_release_name_from_branch_name():
Yun Peng98948362022-11-08 16:14:20 +01001613 # TODO(pcloudy): Find a better way to do this
1614 if os.getenv("BUILDKITE_PIPELINE_SLUG") == "publish-bazel-binaries":
1615 return None
Yun Peng26e01ff2021-07-26 12:05:53 +02001616 res = re.match(r"release-(\d+\.\d+\.\d+(rc\d+)?).*", os.getenv("BUILDKITE_BRANCH"))
Yun Peng98948362022-11-08 16:14:20 +01001617 return res.group(1) if res else None
Yun Peng92c0ef82021-07-26 10:41:21 +02001618
1619
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001620def is_pull_request():
Jakob Buchgraber67761d32018-02-21 19:00:21 +01001621 third_party_repo = os.getenv("BUILDKITE_PULL_REQUEST_REPO", "")
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001622 return len(third_party_repo) > 0
1623
1624
Yun Penge3cf12d2018-12-05 15:01:09 +01001625def print_bazel_version_info(bazel_binary, platform):
Jakob Buchgraber99c4bbb2018-02-22 11:59:31 +01001626 print_collapsed_group(":information_source: Bazel Info")
Philipp Wollermannf13804b2019-02-05 21:08:30 +01001627 version_output = execute_command_and_get_output(
Florian Weikertb3439b32022-11-09 11:05:16 +01001628 [bazel_binary] + common_startup_flags() + ["--nosystem_rc", "--nohome_rc", "version"]
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001629 )
1630 execute_command(
Florian Weikertb3439b32022-11-09 11:05:16 +01001631 [bazel_binary] + common_startup_flags() + ["--nosystem_rc", "--nohome_rc", "info"]
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001632 )
Jakob Buchgraber7e690a72018-02-18 13:22:15 +01001633
Florian Weikertc8642af2019-02-03 23:58:51 +01001634 match = BUILD_LABEL_PATTERN.search(version_output)
1635 return match.group(1) if match else "unreleased binary"
1636
Jakob Buchgraber7e690a72018-02-18 13:22:15 +01001637
Yun Penga5a1ee02018-12-05 15:00:58 +01001638def print_environment_variables_info():
1639 print_collapsed_group(":information_source: Environment Variables")
1640 for key, value in os.environ.items():
1641 eprint("%s=(%s)" % (key, value))
1642
1643
Jakob Buchgraber426399e2018-03-20 19:45:46 +01001644def upload_bazel_binary(platform):
Jakob Buchgraber7d1d3bb2018-02-21 22:38:22 +01001645 print_collapsed_group(":gcloud: Uploading Bazel Under Test")
Jakob Buchgraber426399e2018-03-20 19:45:46 +01001646 if platform == "windows":
Philipp Wollermann10183212020-02-04 21:54:14 +01001647 binary_dir = r"bazel-bin\src"
1648 binary_name = r"bazel.exe"
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001649 binary_nojdk_name = r"bazel_nojdk.exe"
Philipp Wollermann10183212020-02-04 21:54:14 +01001650 else:
1651 binary_dir = "bazel-bin/src"
1652 binary_name = "bazel"
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001653 binary_nojdk_name = "bazel_nojdk"
Philipp Wollermann10183212020-02-04 21:54:14 +01001654 execute_command(["buildkite-agent", "artifact", "upload", binary_name], cwd=binary_dir)
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001655 execute_command(["buildkite-agent", "artifact", "upload", binary_nojdk_name], cwd=binary_dir)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001656
1657
Chi Wangb2b65682020-08-27 10:36:15 +08001658def merge_and_upload_kythe_kzip(platform, index_upload_gcs):
Chi Wang6357efe2020-08-25 16:23:38 +08001659 print_collapsed_group(":gcloud: Uploading kythe kzip")
1660
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001661 kzips = glob("bazel-out/*/extra_actions/**/*.kzip", recursive=True)
Chi Wang6357efe2020-08-25 16:23:38 +08001662
Chi Wang6357efe2020-08-25 16:23:38 +08001663 build_number = os.getenv("BUILDKITE_BUILD_NUMBER")
Chi Wangb2b65682020-08-27 10:36:15 +08001664 git_commit = os.getenv("BUILDKITE_COMMIT")
1665 final_kzip_name = "{}-{}-{}.kzip".format(build_number, platform, git_commit)
Chi Wang6357efe2020-08-25 16:23:38 +08001666
Chi Wangb2b65682020-08-27 10:36:15 +08001667 execute_command([f"{KYTHE_DIR}/tools/kzip", "merge", "--output", final_kzip_name] + kzips)
Chi Wang6357efe2020-08-25 16:23:38 +08001668 execute_command(["buildkite-agent", "artifact", "upload", final_kzip_name])
1669
Chi Wangb2b65682020-08-27 10:36:15 +08001670 if index_upload_gcs:
1671 pipeline = os.getenv("BUILDKITE_PIPELINE_SLUG")
Chi Wang08aea1c2022-03-21 18:04:52 +08001672 branch = os.getenv("BUILDKITE_BRANCH")
1673 destination = KZIPS_BUCKET + pipeline + "/" + branch + "/" + final_kzip_name
Chi Wangb2b65682020-08-27 10:36:15 +08001674 print("Uploading to GCS {}".format(destination))
Florian Weikertdb832a02020-11-19 19:14:48 +01001675 execute_command([gsutil_command(), "cp", final_kzip_name, destination])
Chi Wangb2b65682020-08-27 10:36:15 +08001676
Chi Wang6357efe2020-08-25 16:23:38 +08001677
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001678def download_binary(dest_dir, platform, binary_name):
Philipp Wollermannc52e26a2019-05-18 22:10:47 +02001679 source_step = create_label(platform, "Bazel", build_only=True)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001680 execute_command(
Philipp Wollermann10183212020-02-04 21:54:14 +01001681 ["buildkite-agent", "artifact", "download", binary_name, dest_dir, "--step", source_step]
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001682 )
Philipp Wollermann10183212020-02-04 21:54:14 +01001683 bazel_binary_path = os.path.join(dest_dir, binary_name)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001684 st = os.stat(bazel_binary_path)
1685 os.chmod(bazel_binary_path, st.st_mode | stat.S_IEXEC)
1686 return bazel_binary_path
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001687
1688
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001689def download_bazel_binary(dest_dir, platform):
1690 binary_name = "bazel.exe" if platform == "windows" else "bazel"
1691 return download_binary(dest_dir, platform, binary_name)
1692
1693
1694def download_bazel_nojdk_binary(dest_dir, platform):
1695 binary_name = "bazel_nojdk.exe" if platform == "windows" else "bazel_nojdk"
1696 return download_binary(dest_dir, platform, binary_name)
1697
1698
Yun Pengd433d4f2022-12-09 10:53:15 +01001699def download_binary_at_commit(bazel_git_commit, bazel_binary_url, bazel_binary_path):
Yun Peng02312732019-01-17 18:17:05 +01001700 try:
Florian Weikertdb832a02020-11-19 19:14:48 +01001701 execute_command([gsutil_command(), "cp", bazel_binary_url, bazel_binary_path])
Yun Peng02312732019-01-17 18:17:05 +01001702 except subprocess.CalledProcessError as e:
Yun Pengd433d4f2022-12-09 10:53:15 +01001703 raise BuildkiteInfraException(
Philipp Wollermannc05ac682019-01-19 12:37:28 +01001704 "Failed to download Bazel binary at %s, error message:\n%s" % (bazel_git_commit, str(e))
1705 )
Yun Peng20d45602018-10-18 13:27:05 +02001706 st = os.stat(bazel_binary_path)
1707 os.chmod(bazel_binary_path, st.st_mode | stat.S_IEXEC)
1708 return bazel_binary_path
1709
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001710
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001711def download_bazel_binary_at_commit(dest_dir, platform, bazel_git_commit):
1712 url = bazelci_builds_gs_url(platform, bazel_git_commit)
1713 path = os.path.join(dest_dir, "bazel.exe" if platform == "windows" else "bazel")
Yun Pengd433d4f2022-12-09 10:53:15 +01001714 return download_binary_at_commit(bazel_git_commit, url, path)
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001715
1716
1717def download_bazel_nojdk_binary_at_commit(dest_dir, platform, bazel_git_commit):
1718 url = bazelci_builds_nojdk_gs_url(platform, bazel_git_commit)
1719 path = os.path.join(dest_dir, "bazel_nojdk.exe" if platform == "windows" else "bazel_nojdk")
Yun Pengd433d4f2022-12-09 10:53:15 +01001720 return download_binary_at_commit(bazel_git_commit, url, path)
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001721
Florian Weikert7f21ca42022-02-02 17:35:23 +01001722
Chi Wangd61eb972023-01-18 11:36:18 +01001723def download_bazelci_agent(dest_dir):
Chi Wangaf6d5b12023-05-10 11:48:05 +00001724 repo = "bazelbuild/continuous-integration"
Chi Wang4412ef12023-05-10 16:29:22 +00001725 if THIS_IS_TESTING and "BAZELCI_AGENT_REPO" in os.environ:
Chi Wangaf6d5b12023-05-10 11:48:05 +00001726 repo = os.environ["BAZELCI_AGENT_REPO"]
Chi Wangd61eb972023-01-18 11:36:18 +01001727 version = "0.1.4"
Chi Wang4412ef12023-05-10 16:29:22 +00001728 if THIS_IS_TESTING and "BAZELCI_AGENT_VERSION" in os.environ:
Chi Wangaf6d5b12023-05-10 11:48:05 +00001729 version = os.environ["BAZELCI_AGENT_VERSION"]
Chi Wangd279d582021-09-29 10:59:06 +08001730 postfix = ""
Florian Weikertda94a102022-10-21 12:24:37 +02001731 if is_windows():
Chi Wangd279d582021-09-29 10:59:06 +08001732 postfix = "x86_64-pc-windows-msvc.exe"
Florian Weikertda94a102022-10-21 12:24:37 +02001733 elif is_mac():
Florian Weikertb3439b32022-11-09 11:05:16 +01001734 if platform_module.machine() == "arm64":
Chi Wang74ad6ca2022-10-21 11:20:36 +02001735 postfix = "aarch64-apple-darwin"
1736 else:
1737 postfix = "x86_64-apple-darwin"
Chi Wangd279d582021-09-29 10:59:06 +08001738 else:
Chi Wangaac1ead2023-01-17 11:10:48 +01001739 if platform_module.machine() == "aarch64":
1740 postfix = "aarch64-unknown-linux-musl"
1741 else:
1742 postfix = "x86_64-unknown-linux-musl"
Chi Wangd279d582021-09-29 10:59:06 +08001743
1744 name = "bazelci-agent-{}-{}".format(version, postfix)
Florian Weikert9b805ce2023-05-10 18:04:03 +02001745 url = "https://github.com/{}/releases/download/agent-{}/{}".format(repo, version, name)
Florian Weikertda94a102022-10-21 12:24:37 +02001746 path = os.path.join(dest_dir, "bazelci-agent.exe" if is_windows() else "bazelci-agent")
Chi Wangd279d582021-09-29 10:59:06 +08001747 execute_command(["curl", "-sSL", url, "-o", path])
1748 st = os.stat(path)
1749 os.chmod(path, st.st_mode | stat.S_IEXEC)
1750 return path
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001751
Florian Weikert7f21ca42022-02-02 17:35:23 +01001752
Florian Weikertda94a102022-10-21 12:24:37 +02001753def get_mirror_root():
1754 if is_mac():
1755 return "/usr/local/var/bazelbuild/"
1756 elif is_windows():
1757 return "c:\\buildkite\\bazelbuild\\"
joeleba7050d842019-05-23 17:03:31 +02001758
Florian Weikertda94a102022-10-21 12:24:37 +02001759 return "/var/lib/bazelbuild/"
joeleba7050d842019-05-23 17:03:31 +02001760
1761
Yun Peng376d2b32018-11-29 10:24:54 +01001762def clone_git_repository(git_repository, platform, git_commit=None):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001763 root = downstream_projects_root(platform)
Philipp Wollermannff39ef52018-02-21 14:18:52 +01001764 project_name = re.search(r"/([^/]+)\.git$", git_repository).group(1)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001765 clone_path = os.path.join(root, project_name)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001766 print_collapsed_group(
1767 "Fetching %s sources at %s" % (project_name, git_commit if git_commit else "HEAD")
1768 )
Philipp Wollermann438ec242018-09-05 14:39:24 +02001769
Florian Weikertda94a102022-10-21 12:24:37 +02001770 mirror_path = get_mirror_root() + re.sub(r"[^0-9A-Za-z]", "-", git_repository)
Philipp Wollermannea128282019-05-08 11:56:14 +02001771
Philipp Wollermann414703d2018-08-28 16:40:38 +02001772 if not os.path.exists(clone_path):
Philipp Wollermann62f4a032019-05-08 17:44:14 +02001773 if os.path.exists(mirror_path):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001774 execute_command(
Philipp Wollermann62f4a032019-05-08 17:44:14 +02001775 ["git", "clone", "-v", "--reference", mirror_path, git_repository, clone_path]
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001776 )
Philipp Wollermannd4cd0d82018-05-01 09:56:24 +02001777 else:
Philipp Wollermannea128282019-05-08 11:56:14 +02001778 execute_command(["git", "clone", "-v", git_repository, clone_path])
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001779
Philipp Wollermann414703d2018-08-28 16:40:38 +02001780 os.chdir(clone_path)
1781 execute_command(["git", "remote", "set-url", "origin", git_repository])
1782 execute_command(["git", "clean", "-fdqx"])
Florian Weikertd8f497c2019-06-19 15:44:20 +02001783 execute_command(["git", "submodule", "foreach", "--recursive", "git clean -fdqx"])
Philipp Wollermann414703d2018-08-28 16:40:38 +02001784 execute_command(["git", "fetch", "origin"])
Yun Peng376d2b32018-11-29 10:24:54 +01001785 if git_commit:
1786 # sync to a specific commit of this repository
1787 execute_command(["git", "reset", git_commit, "--hard"])
1788 else:
1789 # sync to the latest commit of HEAD. Unlikely git pull this also works after a force push.
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001790 remote_head = (
1791 subprocess.check_output(["git", "symbolic-ref", "refs/remotes/origin/HEAD"])
1792 .decode("utf-8")
1793 .rstrip()
1794 )
Yun Peng376d2b32018-11-29 10:24:54 +01001795 execute_command(["git", "reset", remote_head, "--hard"])
Philipp Wollermann414703d2018-08-28 16:40:38 +02001796 execute_command(["git", "submodule", "sync", "--recursive"])
1797 execute_command(["git", "submodule", "update", "--init", "--recursive", "--force"])
Florian Weikertd8f497c2019-06-19 15:44:20 +02001798 execute_command(["git", "submodule", "foreach", "--recursive", "git reset --hard"])
Philipp Wollermann414703d2018-08-28 16:40:38 +02001799 execute_command(["git", "clean", "-fdqx"])
Florian Weikertd8f497c2019-06-19 15:44:20 +02001800 execute_command(["git", "submodule", "foreach", "--recursive", "git clean -fdqx"])
Yun Peng20d45602018-10-18 13:27:05 +02001801 return clone_path
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001802
Philipp Wollermann438ec242018-09-05 14:39:24 +02001803
Florian Weikert4141ce92023-05-09 09:45:55 +02001804def execute_batch_commands(commands, print_group=True):
Yun Penga935a542018-05-18 15:08:53 +02001805 if not commands:
1806 return
Florian Weikert4141ce92023-05-09 09:45:55 +02001807
1808 if print_group:
1809 print_collapsed_group(":batch: Setup (Batch Commands)")
1810
Yun Penga935a542018-05-18 15:08:53 +02001811 batch_commands = "&".join(commands)
Jakob Buchgraber4a824412018-06-22 12:56:10 +02001812 return subprocess.run(batch_commands, shell=True, check=True, env=os.environ).returncode
Yun Penga935a542018-05-18 15:08:53 +02001813
Philipp Wollermann414703d2018-08-28 16:40:38 +02001814
Florian Weikert4141ce92023-05-09 09:45:55 +02001815def execute_shell_commands(commands, print_group=True):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001816 if not commands:
1817 return
Florian Weikert4141ce92023-05-09 09:45:55 +02001818
1819 if print_group:
1820 print_collapsed_group(":bash: Setup (Shell Commands)")
1821
mostynb14440912020-03-17 17:11:47 +01001822 shell_command = "\n".join(["set -e"] + commands)
Philipp Wollermann3e1a7712018-02-19 17:34:24 +01001823 execute_command([shell_command], shell=True)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001824
1825
Yun Peng0a6a98a2019-03-06 13:07:54 +01001826def handle_bazel_failure(exception, action):
1827 msg = "bazel {0} failed with exit code {1}".format(action, exception.returncode)
1828 if use_bazelisk_migrate():
1829 print_collapsed_group(msg)
1830 else:
1831 raise BuildkiteException(msg)
1832
1833
Yun Pengc85cd0e2022-09-02 10:44:29 +02001834def execute_bazel_run(bazel_binary, platform, targets):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001835 if not targets:
1836 return
1837 print_collapsed_group("Setup (Run Targets)")
1838 for target in targets:
Yun Peng0a6a98a2019-03-06 13:07:54 +01001839 try:
1840 execute_command(
1841 [bazel_binary]
1842 + bazelisk_flags()
Florian Weikertda94a102022-10-21 12:24:37 +02001843 + common_startup_flags()
Yun Peng0a6a98a2019-03-06 13:07:54 +01001844 + ["run"]
1845 + common_build_flags(None, platform)
Yun Peng0a6a98a2019-03-06 13:07:54 +01001846 + [target]
1847 )
1848 except subprocess.CalledProcessError as e:
1849 handle_bazel_failure(e, "run")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001850
1851
Philipp Wollermannc4752e42022-02-08 16:35:39 +01001852def remote_caching_flags(platform, accept_cached=True):
Philipp Wollermanne67eec42019-05-24 15:18:20 +02001853 # Only enable caching for untrusted and testing builds.
Philipp Wollermannfce92bf2019-05-22 15:14:32 +02001854 if CLOUD_PROJECT not in ["bazel-untrusted"]:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001855 return []
Philipp Wollermann02955272019-04-18 18:00:48 +02001856
Philipp Wollermanne67eec42019-05-24 15:18:20 +02001857 platform_cache_key = [BUILDKITE_ORG.encode("utf-8")]
Jakob Buchgraber89df3982019-08-06 13:07:02 +02001858 # Whenever the remote cache was known to have been poisoned increase the number below
Yun Pengd7e28c02022-09-12 16:40:36 +02001859 platform_cache_key += ["cache-poisoning-20220912".encode("utf-8")]
Philipp Wollermannfce92bf2019-05-22 15:14:32 +02001860
Yun Peng07dafc52022-03-16 13:23:35 +01001861 # We don't enable remote caching on the Linux ARM64 machine since it doesn't have access to GCS.
1862 if platform == "ubuntu2004_arm64":
1863 return []
1864
Florian Weikertda94a102022-10-21 12:24:37 +02001865 if is_mac():
Philipp Wollermannfce92bf2019-05-22 15:14:32 +02001866 platform_cache_key += [
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001867 # macOS version:
1868 subprocess.check_output(["/usr/bin/sw_vers", "-productVersion"]),
1869 # Path to Xcode:
1870 subprocess.check_output(["/usr/bin/xcode-select", "-p"]),
1871 # Xcode version:
1872 subprocess.check_output(["/usr/bin/xcodebuild", "-version"]),
1873 ]
1874 # Use a local cache server for our macOS machines.
Philipp Wollermannb9e96282020-02-18 13:59:27 +01001875 flags = ["--remote_cache=http://100.107.73.148"]
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001876 else:
Philipp Wollermannfce92bf2019-05-22 15:14:32 +02001877 platform_cache_key += [
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001878 # Platform name:
1879 platform.encode("utf-8")
1880 ]
Philipp Wollermanne74da4e2019-06-07 11:31:02 +02001881 # Use RBE for caching builds running on GCE.
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001882 flags = [
1883 "--google_default_credentials",
Philipp Wollermanne74da4e2019-06-07 11:31:02 +02001884 "--remote_cache=remotebuildexecution.googleapis.com",
1885 "--remote_instance_name=projects/{}/instances/default_instance".format(CLOUD_PROJECT),
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001886 ]
Philipp Wollermann380f1e62019-04-12 16:45:27 +02001887
1888 platform_cache_digest = hashlib.sha256()
1889 for key in platform_cache_key:
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001890 eprint("Adding to platform cache key: {}".format(key))
Philipp Wollermann380f1e62019-04-12 16:45:27 +02001891 platform_cache_digest.update(key)
1892 platform_cache_digest.update(b":")
1893
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001894 flags += [
Philipp Wollermann94937722019-01-11 14:33:18 +01001895 "--remote_timeout=60",
Philipp Wollermann639c0452019-01-03 11:23:54 +01001896 "--remote_max_connections=200",
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001897 '--remote_default_platform_properties=properties:{name:"cache-silo-key" value:"%s"}'
1898 % platform_cache_digest.hexdigest(),
Yun Peng5985f742023-04-17 11:32:42 +02001899 "--remote_download_toplevel",
Philipp Wollermann639c0452019-01-03 11:23:54 +01001900 ]
Jakob Buchgraber4f1d2712018-02-20 10:22:47 +01001901
Yun Pengb2fbce32022-02-04 12:56:34 +01001902 if not accept_cached:
1903 flags += ["--noremote_accept_cached"]
1904
Philipp Wollermannd96d8fa2019-01-11 14:37:47 +01001905 return flags
1906
Jakob Buchgraber4f1d2712018-02-20 10:22:47 +01001907
Jakob Buchgraberb4342cd2018-02-20 16:35:07 +01001908def remote_enabled(flags):
1909 # Detect if the project configuration enabled its own remote caching / execution.
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001910 remote_flags = ["--remote_executor", "--remote_cache", "--remote_http_cache"]
Jakob Buchgraberb4342cd2018-02-20 16:35:07 +01001911 for flag in flags:
1912 for remote_flag in remote_flags:
1913 if flag.startswith(remote_flag):
1914 return True
1915 return False
1916
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001917
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001918def concurrent_jobs(platform):
1919 return "75" if platform.startswith("rbe_") else str(multiprocessing.cpu_count())
Jakob Buchgraber51a83662018-02-22 19:49:24 +01001920
1921
Philipp Wollermann3e28d3b2018-02-23 23:19:37 +01001922def concurrent_test_jobs(platform):
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001923 if platform.startswith("rbe_"):
1924 return "75"
Florian Weikertda94a102022-10-21 12:24:37 +02001925 elif is_windows():
Jakob Buchgrabere3ccda32018-06-22 23:29:48 +02001926 return "8"
Florian Weikertda94a102022-10-21 12:24:37 +02001927 elif is_mac() and THIS_IS_TESTING:
Philipp Wollermann85877cb2021-07-02 19:20:33 +02001928 return "4"
Florian Weikertda94a102022-10-21 12:24:37 +02001929 elif is_mac():
Florian Weikertecf091c2023-04-28 10:22:23 +02001930 # TODO(twerth): This is an experiment, remove.
1931 return str(int(multiprocessing.cpu_count() / 2))
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001932 return "12"
Philipp Wollermann3e28d3b2018-02-23 23:19:37 +01001933
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001934
Florian Weikertda94a102022-10-21 12:24:37 +02001935def common_startup_flags():
1936 if is_windows():
Philipp Wollermannd5ab3d92020-02-05 16:55:13 +01001937 if os.path.exists("D:/b"):
1938 # This machine has a local SSD mounted as drive D.
1939 return ["--output_user_root=D:/b"]
1940 else:
1941 # This machine uses its PD-SSD as the build directory.
1942 return ["--output_user_root=C:/b"]
1943 return []
Yun Peng58977d62018-11-16 12:19:20 +01001944
1945
1946def common_build_flags(bep_file, platform):
Yun Peng088cc932018-11-16 12:11:46 +01001947 flags = [
Yun Pengf51e7842018-11-16 11:35:43 +01001948 "--show_progress_rate_limit=5",
1949 "--curses=yes",
1950 "--color=yes",
Philipp Wollermannd99414c2019-05-28 17:26:09 +02001951 "--terminal_columns=143",
Philipp Wollermann4c8391e2019-05-28 18:03:35 +02001952 "--show_timestamps",
Yun Pengf51e7842018-11-16 11:35:43 +01001953 "--verbose_failures",
Yun Pengf51e7842018-11-16 11:35:43 +01001954 "--jobs=" + concurrent_jobs(platform),
Yun Pengf51e7842018-11-16 11:35:43 +01001955 "--announce_rc",
Philipp Wollermannb97f9102019-04-16 18:05:56 +02001956 "--experimental_repository_cache_hardlinks",
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001957 # Some projects set --disk_cache in their project-specific bazelrc, which we never want on
1958 # CI, so let's just disable it explicitly.
1959 "--disk_cache=",
Yun Peng088cc932018-11-16 12:11:46 +01001960 ]
Philipp Wollermann639c0452019-01-03 11:23:54 +01001961
Florian Weikertda94a102022-10-21 12:24:37 +02001962 if is_windows():
Philipp Wollermannb97f9102019-04-16 18:05:56 +02001963 pass
Florian Weikertda94a102022-10-21 12:24:37 +02001964 elif is_mac():
Philipp Wollermannb97f9102019-04-16 18:05:56 +02001965 flags += [
1966 "--sandbox_writable_path=/var/tmp/_bazel_buildkite/cache/repos/v1",
1967 "--test_env=REPOSITORY_CACHE=/var/tmp/_bazel_buildkite/cache/repos/v1",
1968 ]
1969 else:
Philipp Wollermann639c0452019-01-03 11:23:54 +01001970 flags += ["--sandbox_tmpfs_path=/tmp"]
1971
Yun Peng088cc932018-11-16 12:11:46 +01001972 if bep_file:
Philipp Wollermann639c0452019-01-03 11:23:54 +01001973 flags += [
1974 "--experimental_build_event_json_file_path_conversion=false",
1975 "--build_event_json_file=" + bep_file,
1976 ]
1977
Yun Peng088cc932018-11-16 12:11:46 +01001978 return flags
Philipp Wollermann94bd9e32018-04-30 15:32:28 +02001979
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001980
Yun Pengb7247ff2018-11-15 13:52:39 +01001981def rbe_flags(original_flags, accept_cached):
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001982 # Enable remote execution via RBE.
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001983 flags = [
1984 "--remote_executor=remotebuildexecution.googleapis.com",
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001985 "--remote_instance_name=projects/bazel-untrusted/instances/default_instance",
Philipp Wollermann2df93482021-06-16 04:39:49 +02001986 "--remote_timeout=3600",
Philipp Wollermann57dadb82020-02-17 14:32:24 +01001987 "--incompatible_strict_action_env",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001988 "--google_default_credentials",
Philipp Wollermann57dadb82020-02-17 14:32:24 +01001989 "--toolchain_resolution_debug",
Yun Peng5985f742023-04-17 11:32:42 +02001990 "--remote_download_toplevel",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001991 ]
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001992
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001993 # Enable BES / Build Results reporting.
1994 flags += [
1995 "--bes_backend=buildeventservice.googleapis.com",
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001996 "--bes_timeout=360s",
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001997 "--project_id=bazel-untrusted",
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001998 ]
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001999
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002000 if not accept_cached:
2001 flags += ["--noremote_accept_cached"]
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02002002
Nicolas Lopez36996222019-05-28 12:21:28 -04002003 # Adapted from https://github.com/bazelbuild/bazel-toolchains/blob/master/bazelrc/.bazelrc
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002004 flags += [
Nicolas Lopez36996222019-05-28 12:21:28 -04002005 # These should NOT longer need to be modified.
2006 # All that is needed is updating the @bazel_toolchains repo pin
2007 # in projects' WORKSPACE files.
Xindb02c012018-11-07 14:10:54 -05002008 #
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002009 # Toolchain related flags to append at the end of your .bazelrc file.
Nicolas Lopez36996222019-05-28 12:21:28 -04002010 "--host_javabase=@buildkite_config//java:jdk",
2011 "--javabase=@buildkite_config//java:jdk",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002012 "--host_java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8",
2013 "--java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8",
Nicolas Lopez36996222019-05-28 12:21:28 -04002014 "--crosstool_top=@buildkite_config//cc:toolchain",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002015 "--action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002016 ]
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02002017
Yun Pengb7247ff2018-11-15 13:52:39 +01002018 # Platform flags:
2019 # The toolchain container used for execution is defined in the target indicated
2020 # by "extra_execution_platforms", "host_platform" and "platforms".
Xin03a88ab2019-03-11 19:18:50 -04002021 # If you are using your own toolchain container, you need to create a platform
2022 # target with "constraint_values" that allow for the toolchain specified with
2023 # "extra_toolchains" to be selected (given constraints defined in
2024 # "exec_compatible_with").
Yun Pengb7247ff2018-11-15 13:52:39 +01002025 # More about platforms: https://docs.bazel.build/versions/master/platforms.html
2026 # Don't add platform flags if they are specified already.
2027 platform_flags = {
Nicolas Lopez36996222019-05-28 12:21:28 -04002028 "--extra_toolchains": "@buildkite_config//config:cc-toolchain",
2029 "--extra_execution_platforms": "@buildkite_config//config:platform",
2030 "--host_platform": "@buildkite_config//config:platform",
2031 "--platforms": "@buildkite_config//config:platform",
Yun Pengb7247ff2018-11-15 13:52:39 +01002032 }
Yun Peng67ab5062018-11-15 13:58:15 +01002033 for platform_flag, value in list(platform_flags.items()):
Yun Pengb7247ff2018-11-15 13:52:39 +01002034 found = False
2035 for original_flag in original_flags:
2036 if original_flag.startswith(platform_flag):
2037 found = True
2038 break
2039 if not found:
2040 flags += [platform_flag + "=" + value]
2041
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002042 return flags
2043
2044
Yun Peng28a9a532023-05-10 14:19:46 +02002045def get_output_base(bazel_binary):
Yun Peng2b6de292022-02-10 14:28:06 +01002046 return execute_command_and_get_output(
Florian Weikertda94a102022-10-21 12:24:37 +02002047 [bazel_binary] + common_startup_flags() + ["info", "output_base"],
Yun Peng2b6de292022-02-10 14:28:06 +01002048 print_output=False,
2049 ).strip()
2050
2051
Florian Weikertb3439b32022-11-09 11:05:16 +01002052def compute_flags(platform, flags, bep_file, bazel_binary, enable_remote_cache=False):
Yun Peng58977d62018-11-16 12:19:20 +01002053 aggregated_flags = common_build_flags(bep_file, platform)
Yun Peng32dbec32018-11-02 12:47:41 +01002054 if not remote_enabled(flags):
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002055 if platform.startswith("rbe_"):
Florian Weikert24a4b482018-11-30 19:05:38 +01002056 aggregated_flags += rbe_flags(flags, accept_cached=enable_remote_cache)
Yun Pengb2fbce32022-02-04 12:56:34 +01002057 else:
2058 aggregated_flags += remote_caching_flags(platform, accept_cached=enable_remote_cache)
Yun Peng75786552018-11-13 15:23:30 +01002059 aggregated_flags += flags
Yun Peng53598002018-12-03 10:42:02 +01002060
Philipp Wollermann87b45252020-01-22 12:43:42 +01002061 for i, flag in enumerate(aggregated_flags):
2062 if "$HOME" in flag:
Florian Weikerta6110a92022-10-20 01:16:09 +02002063 if is_windows():
Philipp Wollermannd5ab3d92020-02-05 16:55:13 +01002064 if os.path.exists("D:/"):
2065 home = "D:"
2066 else:
2067 home = "C:/b"
Florian Weikerta6110a92022-10-20 01:16:09 +02002068 elif is_mac():
Philipp Wollermannd5ab3d92020-02-05 16:55:13 +01002069 home = "/Users/buildkite"
2070 else:
2071 home = "/var/lib/buildkite-agent"
Philipp Wollermann87b45252020-01-22 12:43:42 +01002072 aggregated_flags[i] = flag.replace("$HOME", home)
2073 if "$OUTPUT_BASE" in flag:
Yun Peng28a9a532023-05-10 14:19:46 +02002074 output_base = get_output_base(bazel_binary)
Philipp Wollermann87b45252020-01-22 12:43:42 +01002075 aggregated_flags[i] = flag.replace("$OUTPUT_BASE", output_base)
2076
Florian Weikert24a4b482018-11-30 19:05:38 +01002077 return aggregated_flags
Yun Peng53598002018-12-03 10:42:02 +01002078
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002079
Yun Pengea0359e2019-01-17 15:37:47 +01002080def execute_bazel_clean(bazel_binary, platform):
2081 print_expanded_group(":bazel: Clean")
2082
2083 try:
Florian Weikertda94a102022-10-21 12:24:37 +02002084 execute_command([bazel_binary] + common_startup_flags() + ["clean", "--expunge"])
Yun Pengea0359e2019-01-17 15:37:47 +01002085 except subprocess.CalledProcessError as e:
2086 raise BuildkiteException("bazel clean failed with exit code {}".format(e.returncode))
2087
2088
Chi Wang6357efe2020-08-25 16:23:38 +08002089def kythe_startup_flags():
2090 return [f"--bazelrc={KYTHE_DIR}/extractors.bazelrc"]
2091
2092
2093def kythe_build_flags():
Philipp Wollermannf61a20b2021-05-05 22:04:20 +02002094 return [
2095 "--experimental_convenience_symlinks=normal",
Florian Weikert9d5e4c02021-05-27 15:10:20 +02002096 f"--override_repository=kythe_release={KYTHE_DIR}",
Philipp Wollermannf61a20b2021-05-05 22:04:20 +02002097 ]
Chi Wang6357efe2020-08-25 16:23:38 +08002098
2099
Florian Weikertb3439b32022-11-09 11:05:16 +01002100def execute_bazel_build(bazel_version, bazel_binary, platform, flags, targets, bep_file):
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02002101 print_collapsed_group(":bazel: Computing flags for build step")
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002102 aggregated_flags = compute_flags(
Yun Peng8975c6b2019-02-28 11:55:55 +01002103 platform,
2104 flags,
Yun Peng8975c6b2019-02-28 11:55:55 +01002105 bep_file,
Philipp Wollermann87b45252020-01-22 12:43:42 +01002106 bazel_binary,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002107 enable_remote_cache=True,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002108 )
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02002109
2110 print_expanded_group(":bazel: Build ({})".format(bazel_version))
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01002111 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002112 execute_command(
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002113 [bazel_binary]
2114 + bazelisk_flags()
Florian Weikertda94a102022-10-21 12:24:37 +02002115 + common_startup_flags()
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002116 + ["build"]
2117 + aggregated_flags
Philipp Wollermann2a160432019-09-19 15:57:28 +02002118 + ["--"]
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002119 + targets
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002120 )
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01002121 except subprocess.CalledProcessError as e:
Yun Peng0a6a98a2019-03-06 13:07:54 +01002122 handle_bazel_failure(e, "build")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002123
2124
Florian Weikertb3439b32022-11-09 11:05:16 +01002125def execute_bazel_build_with_kythe(bazel_version, bazel_binary, platform, flags, targets, bep_file):
Chi Wang6357efe2020-08-25 16:23:38 +08002126 print_collapsed_group(":bazel: Computing flags for build step")
2127 aggregated_flags = compute_flags(
2128 platform,
2129 flags,
Chi Wang6357efe2020-08-25 16:23:38 +08002130 bep_file,
2131 bazel_binary,
2132 enable_remote_cache=False,
2133 )
2134
2135 print_expanded_group(":bazel: Build ({})".format(bazel_version))
2136
2137 execute_command(
2138 [bazel_binary]
2139 + bazelisk_flags()
Florian Weikertda94a102022-10-21 12:24:37 +02002140 + common_startup_flags()
Chi Wang6357efe2020-08-25 16:23:38 +08002141 + kythe_startup_flags()
2142 + ["build"]
2143 + kythe_build_flags()
2144 + aggregated_flags
2145 + ["--"]
2146 + targets
2147 )
2148
2149
Florian Weikert7dd9f662023-05-04 15:05:42 +02002150def calculate_targets(
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002151 task_config,
2152 bazel_binary,
2153 build_only,
2154 test_only,
2155 workspace_dir,
2156 ws_setup_func,
2157 git_commit,
2158 test_flags,
Florian Weikert7dd9f662023-05-04 15:05:42 +02002159):
Florian Weikerte417f9f2023-05-05 17:33:46 +02002160 print_collapsed_group(":dart: Calculating targets")
2161
Florian Weikert736d06e2019-05-08 13:16:42 +02002162 build_targets = [] if test_only else task_config.get("build_targets", [])
2163 test_targets = [] if build_only else task_config.get("test_targets", [])
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01002164 coverage_targets = [] if (build_only or test_only) else task_config.get("coverage_targets", [])
Chi Wang6357efe2020-08-25 16:23:38 +08002165 index_targets = [] if (build_only or test_only) else task_config.get("index_targets", [])
2166
Florian Weikertdb832a02020-11-19 19:14:48 +01002167 index_targets_query = (
2168 None if (build_only or test_only) else task_config.get("index_targets_query", None)
2169 )
Chi Wang6357efe2020-08-25 16:23:38 +08002170 if index_targets_query:
2171 output = execute_command_and_get_output(
2172 [bazel_binary]
Florian Weikertda94a102022-10-21 12:24:37 +02002173 + common_startup_flags()
Yun Peng8e8cdcf2022-03-16 13:08:15 +01002174 + ["--nosystem_rc", "--nohome_rc", "query", index_targets_query],
Chi Wang6357efe2020-08-25 16:23:38 +08002175 print_output=False,
2176 )
2177 index_targets += output.strip().split("\n")
Florian Weikert736d06e2019-05-08 13:16:42 +02002178
Philipp Wollermann2a160432019-09-19 15:57:28 +02002179 # Remove the "--" argument splitter from the list that some configs explicitly
2180 # include. We'll add it back again later where needed.
2181 build_targets = [x.strip() for x in build_targets if x.strip() != "--"]
2182 test_targets = [x.strip() for x in test_targets if x.strip() != "--"]
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01002183 coverage_targets = [x.strip() for x in coverage_targets if x.strip() != "--"]
Chi Wang6357efe2020-08-25 16:23:38 +08002184 index_targets = [x.strip() for x in index_targets if x.strip() != "--"]
Philipp Wollermann2a160432019-09-19 15:57:28 +02002185
Florian Weikertdcbbdf32023-05-02 11:58:53 +02002186 diffbase = os.getenv(USE_BAZEL_DIFF_ENV_VAR, "").lower()
2187 shard_id = int(os.getenv("BUILDKITE_PARALLEL_JOB", "-1"))
2188 shard_count = int(os.getenv("BUILDKITE_PARALLEL_JOB_COUNT", "-1"))
2189 sharding_enabled = shard_id > -1 and shard_count > -1
2190
Florian Weikerte417f9f2023-05-05 17:33:46 +02002191 use_bazel_diff = diffbase and can_use_bazel_diff()
2192
Florian Weikertdcbbdf32023-05-02 11:58:53 +02002193 # Skip target expansion if we don't need to calculate test targets
Florian Weikerte417f9f2023-05-05 17:33:46 +02002194 if not use_bazel_diff and not sharding_enabled:
Florian Weikertdcbbdf32023-05-02 11:58:53 +02002195 return build_targets, test_targets, coverage_targets, index_targets
2196
2197 # TODO(#1614): Fix target expansion
Florian Weikert7dd9f662023-05-04 15:05:42 +02002198 expanded_test_targets = expand_test_target_patterns(bazel_binary, test_targets, test_flags)
Florian Weikertecf091c2023-04-28 10:22:23 +02002199
Florian Weikertecf091c2023-04-28 10:22:23 +02002200 actual_test_targets = (
2201 filter_unchanged_targets(
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002202 expanded_test_targets,
2203 workspace_dir,
2204 ws_setup_func,
2205 bazel_binary,
2206 diffbase,
2207 git_commit,
Florian Weikertecf091c2023-04-28 10:22:23 +02002208 )
Florian Weikerte417f9f2023-05-05 17:33:46 +02002209 if use_bazel_diff
Florian Weikertecf091c2023-04-28 10:22:23 +02002210 else expanded_test_targets
2211 )
2212
Florian Weikertdcbbdf32023-05-02 11:58:53 +02002213 if sharding_enabled:
Florian Weikert736d06e2019-05-08 13:16:42 +02002214 print_collapsed_group(
2215 ":female-detective: Calculating targets for shard {}/{}".format(
2216 shard_id + 1, shard_count
2217 )
2218 )
Florian Weikertecf091c2023-04-28 10:22:23 +02002219 actual_test_targets = get_targets_for_shard(actual_test_targets, shard_id, shard_count)
Florian Weikert736d06e2019-05-08 13:16:42 +02002220
Florian Weikertecf091c2023-04-28 10:22:23 +02002221 return build_targets, actual_test_targets, coverage_targets, index_targets
Florian Weikert736d06e2019-05-08 13:16:42 +02002222
2223
Florian Weikerte417f9f2023-05-05 17:33:46 +02002224def can_use_bazel_diff():
2225 matched_files = []
2226 for f in get_modified_files():
2227 for d in DISABLE_BAZEL_DIFF_IF_MODIFIED:
2228 if d.endswith("/") and f.startswith(d) or f == d:
2229 matched_files.append(f)
2230
2231 if matched_files:
2232 eprint(
2233 "Cannot enable bazel-diff since the following files were modified:\n\t{}".format(
2234 "\n\t".join(sorted(matched_files))
2235 )
2236 )
2237
2238 return not matched_files
2239
2240
Florian Weikert7dd9f662023-05-04 15:05:42 +02002241def expand_test_target_patterns(bazel_binary, test_targets, test_flags):
2242 if not test_targets:
2243 return []
Florian Weikert736d06e2019-05-08 13:16:42 +02002244
Florian Weikert7dd9f662023-05-04 15:05:42 +02002245 print_collapsed_group(":ninja: Resolving test targets via bazel query")
Philipp Wollermann2a160432019-09-19 15:57:28 +02002246
Florian Weikert736d06e2019-05-08 13:16:42 +02002247 output = execute_command_and_get_output(
2248 [bazel_binary]
Florian Weikertda94a102022-10-21 12:24:37 +02002249 + common_startup_flags()
Florian Weikert736d06e2019-05-08 13:16:42 +02002250 + [
Yun Peng8e8cdcf2022-03-16 13:08:15 +01002251 "--nosystem_rc",
2252 "--nohome_rc",
Florian Weikert5242a592023-05-04 19:19:28 +02002253 "cquery" if os.getenv("EXP_USE_CQUERY") else "query",
Florian Weikert7dd9f662023-05-04 15:05:42 +02002254 get_test_query(test_targets, test_flags),
Florian Weikert736d06e2019-05-08 13:16:42 +02002255 ],
2256 print_output=False,
Philipp Wollermann54719fe2021-07-02 21:54:08 +02002257 ).strip()
2258 return output.split("\n") if output else []
Florian Weikert736d06e2019-05-08 13:16:42 +02002259
2260
Florian Weikert7dd9f662023-05-04 15:05:42 +02002261def get_test_query(test_targets, test_flags):
2262 included_targets, excluded_targets = partition_list(test_targets)
2263
2264 def FormatTargetList(targets):
2265 return " ".join("'{}'".format(t) for t in targets)
2266
Florian Weikert38a99212023-05-04 15:12:41 +02002267 query = "let t = tests(set({})) in $t".format(FormatTargetList(included_targets))
Florian Weikert7dd9f662023-05-04 15:05:42 +02002268
2269 if excluded_targets:
2270 query += " except tests(set({}))".format(FormatTargetList(excluded_targets))
2271
2272 included_tags, excluded_tags = get_test_tags(test_flags)
2273
2274 for t in excluded_tags:
Florian Weikert38a99212023-05-04 15:12:41 +02002275 query += " except attr('tags', '\\b{}\\b', $t)".format(t)
Florian Weikert7dd9f662023-05-04 15:05:42 +02002276
2277 if included_tags:
Florian Weikert38a99212023-05-04 15:12:41 +02002278 parts = ["attr('tags', '\\b{}\\b', $tt)".format(t) for t in included_tags]
Florian Weikert7dd9f662023-05-04 15:05:42 +02002279 query = "let tt = {} in {}".format(query, " union ".join(parts))
2280
2281 return query
2282
2283
2284def get_test_tags(test_flags):
2285 wanted_prefix = "--test_tag_filters="
2286
2287 for f in test_flags:
2288 if not f.startswith(wanted_prefix):
2289 continue
2290
Florian Weikertc833a7c2023-05-05 21:26:36 +02002291 tags = removeprefix(f, wanted_prefix).split(",")
Florian Weikert7dd9f662023-05-04 15:05:42 +02002292 include, exclude = partition_list(tags)
2293
2294 # Skip tests tagged as "manual" by default, unless explicitly requested
2295 manual_tag = "manual"
2296 if manual_tag not in include and manual_tag not in exclude:
2297 exclude.append(manual_tag)
2298
2299 return include, exclude
2300
Yun Peng01e617e2023-05-04 16:03:46 +02002301 return [], ["manual"]
Florian Weikert7dd9f662023-05-04 15:05:42 +02002302
2303
Florian Weikertc833a7c2023-05-05 21:26:36 +02002304def removeprefix(s, prefix):
2305 def rp(p):
2306 if s.startswith(p):
Florian Weikertb0fcf902023-05-05 22:01:50 +02002307 return s[len(p) :]
Florian Weikertc833a7c2023-05-05 21:26:36 +02002308 return s
2309
2310 func = getattr(s, "removeprefix", rp)
2311 return func(prefix)
2312
2313
Florian Weikertecf091c2023-04-28 10:22:23 +02002314def filter_unchanged_targets(
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002315 expanded_test_targets, workspace_dir, ws_setup_func, bazel_binary, diffbase, git_commit
Florian Weikertecf091c2023-04-28 10:22:23 +02002316):
2317 print_collapsed_group(
2318 f":scissors: Filtering targets that haven't been affected since {diffbase}"
2319 )
2320
2321 tmpdir = tempfile.mkdtemp()
Florian Weikertecf091c2023-04-28 10:22:23 +02002322 try:
Florian Weikertb0fcf902023-05-05 22:01:50 +02002323 resolved_diffbase = resolve_diffbase(diffbase)
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002324 eprint(f"Resolved diffbase to {resolved_diffbase}")
Florian Weikertb0fcf902023-05-05 22:01:50 +02002325
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002326 eprint("Cloning comparison repository...")
2327 diffbase_archive_url = get_commit_archive_url(resolved_diffbase)
2328 local_archive_path = download_file(diffbase_archive_url, tmpdir, "repo.tar.gz")
2329 diffbase_repo_dir = os.path.join(tmpdir, resolved_diffbase)
2330 extract_archive(local_archive_path, diffbase_repo_dir)
2331
2332 eprint("Setting up comparison repository...")
2333 os.chdir(diffbase_repo_dir)
Florian Weikert4141ce92023-05-09 09:45:55 +02002334 ws_setup_func(False)
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002335
2336 eprint(f"Downloading bazel-diff to {tmpdir}")
2337 bazel_diff_path = download_file(BAZEL_DIFF_URL, tmpdir, "bazel-diff.jar")
Florian Weikertb0fcf902023-05-05 22:01:50 +02002338 eprint(f"Running bazel-diff for {resolved_diffbase} and {git_commit}")
2339
Florian Weikertecf091c2023-04-28 10:22:23 +02002340 affected_targets = run_bazel_diff(
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002341 bazel_diff_path, diffbase_repo_dir, workspace_dir, bazel_binary, tmpdir
Florian Weikertecf091c2023-04-28 10:22:23 +02002342 )
Florian Weikertb0fcf902023-05-05 22:01:50 +02002343 except (BuildkiteException, BuildkiteInfraException) as ex:
2344 try:
2345 execute_command(
2346 [
2347 "buildkite-agent",
2348 "annotate",
2349 "--style=warning",
2350 "--context",
2351 "'diff_failed'",
2352 "This build runs all test targets even though `{}` is set "
Florian Weikert9029ccf2023-05-08 17:07:04 +02002353 "since bazel-diff failed with an error:\n```\n{}\n```".format(
Florian Weikertb0fcf902023-05-05 22:01:50 +02002354 USE_BAZEL_DIFF_ENV_VAR, ex
2355 ),
2356 ]
2357 )
Florian Weikert77d20062023-05-08 16:32:48 +02002358 execute_command(
2359 ["buildkite-agent", "annotation", "remove", "--context", BAZEL_DIFF_ANNOTATION_CTX]
2360 )
Florian Weikertb0fcf902023-05-05 22:01:50 +02002361 finally:
2362 return expanded_test_targets
Florian Weikertecf091c2023-04-28 10:22:23 +02002363 finally:
Florian Weikerte747d4f2023-05-09 09:43:47 +02002364 try:
2365 shutil.rmtree(tmpdir)
2366 except:
2367 pass
2368
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002369 os.chdir(workspace_dir)
Florian Weikertecf091c2023-04-28 10:22:23 +02002370
Florian Weikertaa0488f2023-05-03 15:06:13 +02002371 config_target_set = set(expanded_test_targets)
2372 remaining_targets = list(config_target_set.intersection(affected_targets))
2373 if len(remaining_targets) < len(expanded_test_targets):
2374 print_collapsed_group(
2375 ":scissors: Successfully reduced test targets from {} to {}".format(
2376 len(expanded_test_targets), len(remaining_targets)
2377 )
2378 )
2379
2380 skipped_targets = sorted(config_target_set.difference(remaining_targets))
2381 eprint("Skipped targets:\n\t{}".format("\n\t".join(skipped_targets)))
2382
Florian Weikertecf091c2023-04-28 10:22:23 +02002383 execute_command(
2384 [
2385 "buildkite-agent",
2386 "annotate",
2387 "--style=info",
Florian Weikert20151ab2023-05-04 20:32:36 +02002388 "--context",
Florian Weikert77d20062023-05-08 16:32:48 +02002389 BAZEL_DIFF_ANNOTATION_CTX,
Florian Weikert76736e92023-04-28 11:23:27 +02002390 "This run only contains test targets that have been changed since "
Florian Weikertb0fcf902023-05-05 22:01:50 +02002391 "{} due to the `{}` env variable".format(resolved_diffbase, USE_BAZEL_DIFF_ENV_VAR),
Florian Weikertecf091c2023-04-28 10:22:23 +02002392 ]
2393 )
2394
Florian Weikertaa0488f2023-05-03 15:06:13 +02002395 return remaining_targets
Florian Weikertecf091c2023-04-28 10:22:23 +02002396
2397
2398def resolve_diffbase(diffbase):
2399 if diffbase in AUTO_DIFFBASE_VALUES:
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002400 return resolve_revision("HEAD^")
Florian Weikertecf091c2023-04-28 10:22:23 +02002401 elif COMMIT_RE.fullmatch(diffbase):
2402 return diffbase
2403
2404 raise BuildkiteException(
Florian Weikertb0fcf902023-05-05 22:01:50 +02002405 "Invalid value '{}' for `{}` env variable. Must be a Git commit hash or one of {}".format(
Florian Weikertecf091c2023-04-28 10:22:23 +02002406 diffbase, ", ".join(AUTO_DIFFBASE_VALUES)
2407 )
2408 )
2409
2410
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002411def get_commit_archive_url(resolved_diffbase):
2412 repo_url = os.getenv("BUILDKITE_REPO", "")
2413 prefix = "+" if "googlesource" in repo_url else ""
2414 return repo_url.replace(".git", "/{}archive/{}.tar.gz".format(prefix, resolved_diffbase))
2415
2416
2417def extract_archive(archive_url, dest_dir):
2418 if not os.path.isdir(dest_dir):
2419 os.mkdir(dest_dir)
2420
Florian Weikertecf091c2023-04-28 10:22:23 +02002421 try:
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002422 with tarfile.open(archive_url, mode="r:gz") as archive:
2423 archive.extractall(dest_dir)
2424 except tarfile.TarError as ex:
2425 raise BuildkiteInfraException("Failed to extract repository archive: {}".format(ex)) from ex
2426
2427
2428def download_file(url, dest_dir, dest_filename):
2429 local_path = os.path.join(dest_dir, dest_filename)
2430 try:
Florian Weikertdfd8db42023-05-09 15:41:30 +02002431 execute_command(["curl", "-sSL", url, "-o", local_path], capture_stderr=True)
Florian Weikertecf091c2023-04-28 10:22:23 +02002432 except subprocess.CalledProcessError as ex:
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002433 raise BuildkiteInfraException("Failed to download {}: {}\n{}".format(url, ex, ex.stderr))
Florian Weikertecf091c2023-04-28 10:22:23 +02002434 return local_path
2435
2436
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002437def run_bazel_diff(bazel_diff_path, old_workspace_dir, new_workspace_dir, bazel_binary, data_dir):
Florian Weikertecf091c2023-04-28 10:22:23 +02002438 before_json = os.path.join(data_dir, "before.json")
2439 after_json = os.path.join(data_dir, "after.json")
2440 targets_file = os.path.join(data_dir, "targets.txt")
2441
2442 try:
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002443 for repo_dir, json_path in (
2444 (old_workspace_dir, before_json),
2445 (new_workspace_dir, after_json),
2446 ):
Florian Weikertecf091c2023-04-28 10:22:23 +02002447 execute_command(
2448 [
2449 "java",
2450 "-jar",
2451 bazel_diff_path,
2452 "generate-hashes",
2453 "-w",
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002454 repo_dir,
Florian Weikertecf091c2023-04-28 10:22:23 +02002455 "-b",
2456 bazel_binary,
2457 json_path,
Florian Weikertdfd8db42023-05-09 15:41:30 +02002458 ],
2459 capture_stderr=True,
Florian Weikertecf091c2023-04-28 10:22:23 +02002460 )
2461
2462 execute_command(
2463 [
2464 "java",
2465 "-jar",
2466 bazel_diff_path,
2467 "get-impacted-targets",
2468 "-sh",
2469 before_json,
2470 "-fh",
2471 after_json,
2472 "-o",
2473 targets_file,
Florian Weikertdfd8db42023-05-09 15:41:30 +02002474 ],
2475 capture_stderr=True,
Florian Weikertecf091c2023-04-28 10:22:23 +02002476 )
2477 except subprocess.CalledProcessError as ex:
Florian Weikertb0fcf902023-05-05 22:01:50 +02002478 raise BuildkiteInfraException("Failed to run bazel-diff: {}\n{}".format(ex, ex.stderr))
Florian Weikertecf091c2023-04-28 10:22:23 +02002479
2480 with open(targets_file, "rt") as f:
2481 contents = f.read()
2482
2483 return contents.split("\n")
2484
2485
Florian Weikert7dd9f662023-05-04 15:05:42 +02002486def partition_list(items):
2487 included, excluded = [], []
2488 for i in items:
2489 if i.startswith("-"):
2490 excluded.append(i[1:])
Florian Weikert736d06e2019-05-08 13:16:42 +02002491 else:
Florian Weikert7dd9f662023-05-04 15:05:42 +02002492 included.append(i)
Florian Weikert736d06e2019-05-08 13:16:42 +02002493
Florian Weikert7dd9f662023-05-04 15:05:42 +02002494 return included, excluded
Florian Weikert736d06e2019-05-08 13:16:42 +02002495
2496
Philipp Wollermann87b45252020-01-22 12:43:42 +01002497def get_targets_for_shard(test_targets, shard_id, shard_count):
Florian Weikert736d06e2019-05-08 13:16:42 +02002498 # TODO(fweikert): implement a more sophisticated algorithm
Philipp Wollermann87b45252020-01-22 12:43:42 +01002499 return sorted(test_targets)[shard_id::shard_count]
Florian Weikert736d06e2019-05-08 13:16:42 +02002500
2501
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002502def execute_bazel_test(
Florian Weikertc8642af2019-02-03 23:58:51 +01002503 bazel_version,
2504 bazel_binary,
2505 platform,
2506 flags,
2507 targets,
2508 bep_file,
2509 monitor_flaky_tests,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002510):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002511 aggregated_flags = [
2512 "--flaky_test_attempts=3",
2513 "--build_tests_only",
Tobias Werth08a93832023-04-25 16:29:52 +02002514 "--local_test_jobs=" + concurrent_test_jobs(platform),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002515 ]
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002516 # Don't enable remote caching if the user enabled remote execution / caching themselves
Jakob Buchgraberc340f582018-06-22 13:48:33 +02002517 # or flaky test monitoring is enabled, as remote caching makes tests look less flaky than
2518 # they are.
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02002519 print_collapsed_group(":bazel: Computing flags for test step")
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002520 aggregated_flags += compute_flags(
Yun Peng8975c6b2019-02-28 11:55:55 +01002521 platform,
2522 flags,
Yun Peng8975c6b2019-02-28 11:55:55 +01002523 bep_file,
Philipp Wollermann87b45252020-01-22 12:43:42 +01002524 bazel_binary,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002525 enable_remote_cache=not monitor_flaky_tests,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002526 )
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002527
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02002528 print_expanded_group(":bazel: Test ({})".format(bazel_version))
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002529 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002530 execute_command(
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002531 [bazel_binary]
2532 + bazelisk_flags()
Florian Weikertda94a102022-10-21 12:24:37 +02002533 + common_startup_flags()
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002534 + ["test"]
2535 + aggregated_flags
Philipp Wollermann2a160432019-09-19 15:57:28 +02002536 + ["--"]
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002537 + targets
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002538 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002539 except subprocess.CalledProcessError as e:
Yun Peng0a6a98a2019-03-06 13:07:54 +01002540 handle_bazel_failure(e, "test")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002541
Florian Weikert7f21ca42022-02-02 17:35:23 +01002542
Florian Weikertb3439b32022-11-09 11:05:16 +01002543def execute_bazel_coverage(bazel_version, bazel_binary, platform, flags, targets):
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01002544 aggregated_flags = [
2545 "--build_tests_only",
Tobias Werth08a93832023-04-25 16:29:52 +02002546 "--local_test_jobs=" + concurrent_test_jobs(platform),
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01002547 ]
2548 print_collapsed_group(":bazel: Computing flags for coverage step")
2549 aggregated_flags += compute_flags(
2550 platform,
2551 flags,
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01002552 None,
2553 bazel_binary,
2554 enable_remote_cache=True,
2555 )
2556
2557 print_expanded_group(":bazel: Coverage ({})".format(bazel_version))
2558 try:
2559 execute_command(
2560 [bazel_binary]
2561 + bazelisk_flags()
Florian Weikertda94a102022-10-21 12:24:37 +02002562 + common_startup_flags()
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01002563 + ["coverage"]
2564 + aggregated_flags
2565 + ["--"]
2566 + targets
2567 )
2568 except subprocess.CalledProcessError as e:
2569 handle_bazel_failure(e, "coverage")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002570
Florian Weikert7f21ca42022-02-02 17:35:23 +01002571
Florian Weikertda94a102022-10-21 12:24:37 +02002572def upload_test_logs_from_bep(bep_file, tmpdir, monitor_flaky_tests):
Chi Wangd61eb972023-01-18 11:36:18 +01002573 bazelci_agent_binary = download_bazelci_agent(tmpdir)
Chi Wangd279d582021-09-29 10:59:06 +08002574 execute_command(
Florian Weikert7f21ca42022-02-02 17:35:23 +01002575 [
2576 bazelci_agent_binary,
2577 "artifact",
2578 "upload",
2579 "--delay=5",
2580 "--mode=buildkite",
2581 "--build_event_json_file={}".format(bep_file),
2582 ]
Chi Wangd279d582021-09-29 10:59:06 +08002583 + (["--monitor_flaky_tests"] if monitor_flaky_tests else [])
2584 )
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002585
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02002586
joeleba76887952019-05-16 15:22:17 +02002587def upload_json_profile(json_profile_path, tmpdir):
2588 if not os.path.exists(json_profile_path):
2589 return
2590 print_collapsed_group(":gcloud: Uploading JSON Profile")
Philipp Wollermann92cf51e2019-05-16 15:31:11 +02002591 execute_command(["buildkite-agent", "artifact", "upload", json_profile_path], cwd=tmpdir)
joeleba76887952019-05-16 15:22:17 +02002592
Philipp Wollermannf436e742021-08-11 11:06:55 +02002593
Chi Wang54595a22021-06-11 17:49:58 +08002594def upload_corrupted_outputs(capture_corrupted_outputs_dir, tmpdir):
2595 if not os.path.exists(capture_corrupted_outputs_dir):
2596 return
2597 print_collapsed_group(":gcloud: Uploading corrupted outputs")
Philipp Wollermannf436e742021-08-11 11:06:55 +02002598 execute_command(
2599 ["buildkite-agent", "artifact", "upload", "{}/**/*".format(capture_corrupted_outputs_dir)],
2600 cwd=tmpdir,
2601 )
2602
Philipp Wollermann5b00a702019-07-18 11:21:38 +02002603
Philipp Wollermannaf35abf2019-05-22 17:52:01 +02002604def execute_command_and_get_output(args, shell=False, fail_if_nonzero=True, print_output=True):
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002605 eprint(" ".join(args))
Florian Weikertc8642af2019-02-03 23:58:51 +01002606 process = subprocess.run(
2607 args,
2608 shell=shell,
2609 check=fail_if_nonzero,
2610 env=os.environ,
Florian Weikert9029ccf2023-05-08 17:07:04 +02002611 stdout=subprocess.PIPE, # We cannot use capture_output since some workers run Python <3.7
Philipp Wollermannf13804b2019-02-05 21:08:30 +01002612 errors="replace",
Florian Weikertc8642af2019-02-03 23:58:51 +01002613 universal_newlines=True,
2614 )
Florian Weikert736d06e2019-05-08 13:16:42 +02002615 if print_output:
2616 eprint(process.stdout)
2617
Florian Weikertc8642af2019-02-03 23:58:51 +01002618 return process.stdout
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002619
2620
Florian Weikertdfd8db42023-05-09 15:41:30 +02002621def execute_command(
2622 args, shell=False, fail_if_nonzero=True, cwd=None, print_output=True, capture_stderr=False
2623):
Yun Peng9337bb32020-02-28 13:31:29 +01002624 if print_output:
2625 eprint(" ".join(args))
Philipp Wollermann92cf51e2019-05-16 15:31:11 +02002626 return subprocess.run(
Florian Weikertb0fcf902023-05-05 22:01:50 +02002627 args,
2628 shell=shell,
2629 check=fail_if_nonzero,
2630 env=os.environ,
2631 cwd=cwd,
2632 errors="replace",
Florian Weikertdfd8db42023-05-09 15:41:30 +02002633 stderr=subprocess.PIPE
2634 if capture_stderr
2635 else None, # capture_stderr=True when we want exceptions to contain stderr
Philipp Wollermann92cf51e2019-05-16 15:31:11 +02002636 ).returncode
Philipp Wollermannf13804b2019-02-05 21:08:30 +01002637
2638
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02002639def execute_command_background(args):
2640 eprint(" ".join(args))
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02002641 return subprocess.Popen(args, env=os.environ)
2642
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02002643
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02002644def terminate_background_process(process):
2645 if process:
2646 process.terminate()
2647 try:
2648 process.wait(timeout=10)
2649 except subprocess.TimeoutExpired:
2650 process.kill()
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02002651
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02002652
mai93b49bad72021-05-06 00:50:34 +02002653def create_step(label, commands, platform, shards=1, soft_fail=None):
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002654 if "docker-image" in PLATFORMS[platform]:
Florian Weikert736d06e2019-05-08 13:16:42 +02002655 step = create_docker_step(
Florian Weikertb3439b32022-11-09 11:05:16 +01002656 label,
2657 image=PLATFORMS[platform]["docker-image"],
2658 commands=commands,
2659 queue=PLATFORMS[platform].get("queue", "default"),
2660 always_pull=PLATFORMS[platform].get("always-pull", True),
Philipp Wollermannc05ac682019-01-19 12:37:28 +01002661 )
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002662 else:
Philipp Wollermannf3750fa2019-05-21 17:11:59 +02002663 step = {
2664 "label": label,
2665 "command": commands,
2666 "agents": {"queue": PLATFORMS[platform]["queue"]},
2667 }
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002668
Florian Weikert736d06e2019-05-08 13:16:42 +02002669 if shards > 1:
2670 step["label"] += " (shard %n)"
2671 step["parallelism"] = shards
2672
mai93b49bad72021-05-06 00:50:34 +02002673 if soft_fail is not None:
2674 step["soft_fail"] = soft_fail
2675
Philipp Wollermann5b2f3fc2019-05-18 22:36:17 +02002676 # Enforce a global 8 hour job timeout.
2677 step["timeout_in_minutes"] = 8 * 60
2678
2679 # Automatically retry when an agent got lost (usually due to an infra flake).
Philipp Wollermannf22bba32019-07-18 11:22:50 +02002680 step["retry"] = {
2681 "automatic": [
2682 {"exit_status": -1, "limit": 3}, # Buildkite internal "agent lost" exit code
2683 {"exit_status": 137, "limit": 3}, # SIGKILL
2684 {"exit_status": 143, "limit": 3}, # SIGTERM
2685 ]
2686 }
Philipp Wollermann5b2f3fc2019-05-18 22:36:17 +02002687
Florian Weikert736d06e2019-05-08 13:16:42 +02002688 return step
2689
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002690
Florian Weikertb3439b32022-11-09 11:05:16 +01002691def create_docker_step(
2692 label, image, commands=None, additional_env_vars=None, queue="default", always_pull=True
2693):
Philipp Wollermann0e051dd2019-05-16 11:37:52 +02002694 env = ["ANDROID_HOME", "ANDROID_NDK_HOME", "BUILDKITE_ARTIFACT_UPLOAD_DESTINATION"]
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002695 if additional_env_vars:
2696 env += ["{}={}".format(k, v) for k, v in additional_env_vars.items()]
2697
Philipp Wollermannc05ac682019-01-19 12:37:28 +01002698 step = {
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002699 "label": label,
2700 "command": commands,
Yun Peng07dafc52022-03-16 13:23:35 +01002701 "agents": {"queue": queue},
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002702 "plugins": {
Philipp Wollermann9fa03542021-07-01 23:27:53 +02002703 "docker#v3.8.0": {
Yun Peng07dafc52022-03-16 13:23:35 +01002704 "always-pull": always_pull,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002705 "environment": env,
Philipp Wollermannc05ac682019-01-19 12:37:28 +01002706 "image": image,
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002707 "network": "host",
2708 "privileged": True,
2709 "propagate-environment": True,
Philipp Wollermann7aa95492019-05-18 22:03:24 +02002710 "propagate-uid-gid": True,
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002711 "volumes": [
Philipp Wollermann7aa95492019-05-18 22:03:24 +02002712 "/etc/group:/etc/group:ro",
2713 "/etc/passwd:/etc/passwd:ro",
Philipp Wollermann3dc99b32021-10-12 00:34:30 +02002714 "/etc/shadow:/etc/shadow:ro",
Philipp Wollermann562ef1d2021-10-20 22:15:29 +02002715 "/opt/android-ndk-r15c:/opt/android-ndk-r15c:ro",
Yun Peng72874212022-09-13 19:08:03 +02002716 "/opt/android-ndk-r25b:/opt/android-ndk-r25b:ro",
Philipp Wollermann562ef1d2021-10-20 22:15:29 +02002717 "/opt/android-sdk-linux:/opt/android-sdk-linux:ro",
Philipp Wollermann7aa95492019-05-18 22:03:24 +02002718 "/var/lib/buildkite-agent:/var/lib/buildkite-agent",
Philipp Wollermann338db4a2019-05-18 11:21:04 +02002719 "/var/lib/gitmirrors:/var/lib/gitmirrors:ro",
Philipp Wollermanna65944a2020-02-03 12:45:22 +01002720 "/var/run/docker.sock:/var/run/docker.sock",
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002721 ],
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002722 }
2723 },
2724 }
Philipp Wollermannc05ac682019-01-19 12:37:28 +01002725 if not step["command"]:
2726 del step["command"]
2727 return step
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002728
2729
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002730def print_project_pipeline(
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002731 configs,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002732 project_name,
2733 http_config,
2734 file_config,
2735 git_repository,
2736 monitor_flaky_tests,
2737 use_but,
Florian Weikert60661912019-12-18 15:17:10 +01002738 notify,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002739):
Florian Weikert843d7a02019-02-03 17:24:50 +01002740 task_configs = configs.get("tasks", None)
2741 if not task_configs:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002742 raise BuildkiteException("{0} pipeline configuration is empty.".format(project_name))
2743
Jakob Buchgraberaa2af382018-02-21 19:56:54 +01002744 pipeline_steps = []
mai93f2e116c2020-10-19 09:33:14 +02002745 # If the repository is hosted on Git-on-borg, we show the link to the commit Gerrit review
2746 buildkite_repo = os.getenv("BUILDKITE_REPO")
2747 if is_git_on_borg_repo(buildkite_repo):
2748 show_gerrit_review_link(buildkite_repo, pipeline_steps)
2749
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02002750 task_configs = filter_tasks_that_should_be_skipped(task_configs, pipeline_steps)
Jakob Buchgraberff2bdad2018-02-25 13:06:30 +01002751
Philipp Wollermanndac65512019-02-05 22:14:10 +01002752 # In Bazel Downstream Project pipelines, git_repository and project_name must be specified.
Yun Pengc85cd0e2022-09-02 10:44:29 +02002753 is_downstream_project = use_but and git_repository and project_name
Philipp Wollermanndac65512019-02-05 22:14:10 +01002754
Florian Weikert85208912019-03-07 17:08:39 +01002755 buildifier_config = configs.get("buildifier")
Philipp Wollermanndac65512019-02-05 22:14:10 +01002756 # Skip Buildifier when we test downstream projects.
Florian Weikert85208912019-03-07 17:08:39 +01002757 if buildifier_config and not is_downstream_project:
2758 buildifier_env_vars = {}
2759 if isinstance(buildifier_config, str):
2760 # Simple format:
2761 # ---
2762 # buildifier: latest
Philipp Wollermann22538e72021-10-02 09:43:28 +02002763 buildifier_env_vars["BUILDIFIER_VERSION"] = buildifier_config
Florian Weikert85208912019-03-07 17:08:39 +01002764 else:
2765 # Advanced format:
2766 # ---
2767 # buildifier:
2768 # version: latest
2769 # warnings: all
Philipp Wollermann22538e72021-10-02 09:43:28 +02002770 if "version" in buildifier_config:
2771 buildifier_env_vars["BUILDIFIER_VERSION"] = buildifier_config["version"]
2772 if "warnings" in buildifier_config:
2773 buildifier_env_vars["BUILDIFIER_WARNINGS"] = buildifier_config["warnings"]
Florian Weikert85208912019-03-07 17:08:39 +01002774
2775 if not buildifier_env_vars:
2776 raise BuildkiteException(
2777 'Invalid buildifier configuration entry "{}"'.format(buildifier_config)
2778 )
2779
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002780 pipeline_steps.append(
2781 create_docker_step(
Florian Weikertde96a6f2019-03-07 14:57:50 +01002782 BUILDIFIER_STEP_NAME,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002783 image=BUILDIFIER_DOCKER_IMAGE,
Florian Weikert85208912019-03-07 17:08:39 +01002784 additional_env_vars=buildifier_env_vars,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002785 )
2786 )
Philipp Wollermannc05ac682019-01-19 12:37:28 +01002787
Philipp Wollermanndac65512019-02-05 22:14:10 +01002788 # In Bazel Downstream Project pipelines, we should test the project at the last green commit.
Yun Peng376d2b32018-11-29 10:24:54 +01002789 git_commit = None
Philipp Wollermanndac65512019-02-05 22:14:10 +01002790 if is_downstream_project:
Florian Weikert35906542019-04-01 11:53:53 +02002791 last_green_commit_url = bazelci_last_green_commit_url(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002792 git_repository, DOWNSTREAM_PROJECTS[project_name]["pipeline_slug"]
2793 )
Florian Weikert35906542019-04-01 11:53:53 +02002794 git_commit = get_last_green_commit(last_green_commit_url)
Philipp Wollermanndac65512019-02-05 22:14:10 +01002795
Florian Weikert854fd852019-06-04 16:44:19 +02002796 config_hashes = set()
Yun Penge6b09902023-03-31 17:15:58 +02002797 skipped_downstream_tasks = []
Florian Weikert843d7a02019-02-03 17:24:50 +01002798 for task, task_config in task_configs.items():
Florian Weikertdb832a02020-11-19 19:14:48 +01002799 platform = get_platform_for_task(task, task_config)
2800 task_name = task_config.get("name")
mai93b49bad72021-05-06 00:50:34 +02002801 soft_fail = task_config.get("soft_fail")
Florian Weikertdb832a02020-11-19 19:14:48 +01002802
Florian Weikert854fd852019-06-04 16:44:19 +02002803 # We override the Bazel version in downstream pipelines. This means that two tasks that
2804 # only differ in the value of their explicit "bazel" field will be identical in the
2805 # downstream pipeline, thus leading to duplicate work.
2806 # Consequently, we filter those duplicate tasks here.
2807 if is_downstream_project:
2808 h = hash_task_config(task, task_config)
2809 if h in config_hashes:
Yun Penge6b09902023-03-31 17:15:58 +02002810 skipped_downstream_tasks.append(
Yun Peng9d905fb2023-04-24 14:13:26 +02002811 "{}: {}".format(
Florian Weikertb3439b32022-11-09 11:05:16 +01002812 create_label(platform, project_name, task_name=task_name),
Yun Penge6b09902023-03-31 17:15:58 +02002813 "The same task already exists after ignoring bazel version.",
Florian Weikertb3439b32022-11-09 11:05:16 +01002814 )
2815 )
Florian Weikert11d31432023-02-27 11:33:23 +01002816 continue
2817
Florian Weikert854fd852019-06-04 16:44:19 +02002818 config_hashes.add(h)
2819
Yun Penge6b09902023-03-31 17:15:58 +02002820 # Skip tasks with `skip_in_bazel_downstream_pipeline` specified.
2821 skipped_reason = task_config.get("skip_in_bazel_downstream_pipeline", "")
2822 if skipped_reason:
2823 skipped_downstream_tasks.append(
Yun Peng9d905fb2023-04-24 14:13:26 +02002824 "{}: {}".format(
Yun Penge6b09902023-03-31 17:15:58 +02002825 create_label(platform, project_name, task_name=task_name),
2826 skipped_reason,
2827 )
2828 )
2829 continue
2830
Florian Weikert736d06e2019-05-08 13:16:42 +02002831 shards = task_config.get("shards", "1")
2832 try:
2833 shards = int(shards)
2834 except ValueError:
2835 raise BuildkiteException("Task {} has invalid shard value '{}'".format(task, shards))
2836
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002837 step = runner_step(
Florian Weikertdb832a02020-11-19 19:14:48 +01002838 platform=platform,
Florian Weikert843d7a02019-02-03 17:24:50 +01002839 task=task,
Florian Weikertdb832a02020-11-19 19:14:48 +01002840 task_name=task_name,
Florian Weikert843d7a02019-02-03 17:24:50 +01002841 project_name=project_name,
2842 http_config=http_config,
2843 file_config=file_config,
2844 git_repository=git_repository,
2845 git_commit=git_commit,
2846 monitor_flaky_tests=monitor_flaky_tests,
2847 use_but=use_but,
Florian Weikert736d06e2019-05-08 13:16:42 +02002848 shards=shards,
mai93b49bad72021-05-06 00:50:34 +02002849 soft_fail=soft_fail,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002850 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002851 pipeline_steps.append(step)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002852
Yun Penge6b09902023-03-31 17:15:58 +02002853 if skipped_downstream_tasks:
2854 lines = ["\n- {}".format(s) for s in skipped_downstream_tasks]
Florian Weikertdb832a02020-11-19 19:14:48 +01002855 commands = [
Yun Pengee010872023-04-24 14:48:19 +02002856 "buildkite-agent meta-data exists 'has-skipped-annotation' || buildkite-agent annotate --style=info 'The following tasks were skipped:\n' --context 'ctx-skipped_downstream_tasks'",
2857 "buildkite-agent meta-data set 'has-skipped-annotation' 'true'",
Yun Penge6b09902023-03-31 17:15:58 +02002858 "buildkite-agent annotate --style=info '{}' --append --context 'ctx-skipped_downstream_tasks'".format(
Xùdōng Yáng045c9812021-08-18 01:42:35 +10002859 "".join(lines)
2860 ),
Florian Weikertdb832a02020-11-19 19:14:48 +01002861 ]
2862 pipeline_steps.append(
2863 create_step(
Yun Penge6b09902023-03-31 17:15:58 +02002864 label=":pipeline: Print information about skipped tasks",
Florian Weikertdb832a02020-11-19 19:14:48 +01002865 commands=commands,
2866 platform=DEFAULT_PLATFORM,
2867 )
2868 )
2869
Yun Peng996efad2018-11-27 17:19:44 +01002870 pipeline_slug = os.getenv("BUILDKITE_PIPELINE_SLUG")
2871 all_downstream_pipeline_slugs = []
2872 for _, config in DOWNSTREAM_PROJECTS.items():
2873 all_downstream_pipeline_slugs.append(config["pipeline_slug"])
Ivo List23ce48d2020-11-18 13:15:34 +01002874 # We update last green commit in the following cases:
2875 # 1. This job runs on master, stable or main branch (could be a custom build launched manually)
2876 # 2. We intend to run the same job in downstream with Bazel@HEAD (eg. google-bazel-presubmit)
2877 # 3. This job is not:
2878 # - a GitHub pull request
2879 # - uses a custom built Bazel binary (in Bazel Downstream Projects pipeline)
2880 # - testing incompatible flags
2881 # - running `bazelisk --migrate` in a non-downstream pipeline
Florian Weikertdb832a02020-11-19 19:14:48 +01002882 if (
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02002883 current_branch_is_main_branch()
Ivo List23ce48d2020-11-18 13:15:34 +01002884 and pipeline_slug in all_downstream_pipeline_slugs
Yun Pengc85cd0e2022-09-02 10:44:29 +02002885 and not (is_pull_request() or use_but or use_bazelisk_migrate())
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002886 ):
Florian Weikertde96a6f2019-03-07 14:57:50 +01002887 # We need to call "Try Update Last Green Commit" even if there are failures,
2888 # since we don't want a failing Buildifier step to block the update of
2889 # the last green commit for this project.
2890 # try_update_last_green_commit() ensures that we don't update the commit
2891 # if any build or test steps fail.
2892 pipeline_steps.append({"wait": None, "continue_on_failure": True})
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002893 pipeline_steps.append(
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002894 create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002895 label="Try Update Last Green Commit",
2896 commands=[
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002897 fetch_bazelcipy_command(),
Philipp Wollermann57b32682019-05-18 22:09:27 +02002898 PLATFORMS[DEFAULT_PLATFORM]["python"]
2899 + " bazelci.py try_update_last_green_commit",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002900 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002901 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002902 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002903 )
Yun Peng43239b02018-11-23 13:57:34 +01002904
Florian Weikert778251c2019-04-25 15:14:44 +02002905 if "validate_config" in configs:
Florian Weikertf52f91a2019-05-08 15:19:30 +02002906 pipeline_steps += create_config_validation_steps()
Florian Weikert778251c2019-04-25 15:14:44 +02002907
Florian Weikert09813a02019-10-26 19:34:33 +02002908 if use_bazelisk_migrate() and not is_downstream_project:
2909 # Print results of bazelisk --migrate in project pipelines that explicitly set
2910 # the USE_BAZELISK_MIGRATE env var, but that are not being run as part of a
2911 # downstream pipeline.
2912 number = os.getenv("BUILDKITE_BUILD_NUMBER")
Florian Weikert60661912019-12-18 15:17:10 +01002913 pipeline_steps += get_steps_for_aggregating_migration_results(number, notify)
Florian Weikert09813a02019-10-26 19:34:33 +02002914
Florian Weikertd79dc502019-05-13 09:51:05 +02002915 print_pipeline_steps(pipeline_steps, handle_emergencies=not is_downstream_project)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002916
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002917
mai93f2e116c2020-10-19 09:33:14 +02002918def show_gerrit_review_link(git_repository, pipeline_steps):
2919 host = re.search(r"https://(.+?)\.googlesource", git_repository).group(1)
2920 if not host:
2921 raise BuildkiteException("Couldn't get host name from %s" % git_repository)
Florian Weikertdb832a02020-11-19 19:14:48 +01002922 text = "The transformed code used in this pipeline can be found under https://{}-review.googlesource.com/q/{}".format(
2923 host, os.getenv("BUILDKITE_COMMIT")
2924 )
Florian Weikertc6cc6172023-05-04 20:20:55 +02002925 commands = ["buildkite-agent annotate --style=info --context 'gerrit' '{}'".format(text)]
mai93f2e116c2020-10-19 09:33:14 +02002926 pipeline_steps.append(
2927 create_step(
2928 label=":pipeline: Print information about Gerrit Review Link",
2929 commands=commands,
2930 platform=DEFAULT_PLATFORM,
2931 )
2932 )
2933
2934
2935def is_git_on_borg_repo(git_repository):
2936 return git_repository and "googlesource.com" in git_repository
2937
2938
Florian Weikert854fd852019-06-04 16:44:19 +02002939def hash_task_config(task_name, task_config):
2940 # Two task configs c1 and c2 have the same hash iff they lead to two functionally identical jobs
2941 # in the downstream pipeline. This function discards the "bazel" field (since it's being
Philipp Wollermannce986af2019-07-18 14:46:05 +02002942 # overridden) and the "name" field (since it has no effect on the actual work).
Florian Weikert854fd852019-06-04 16:44:19 +02002943 # Moreover, it adds an explicit "platform" field if that's missing.
2944 cpy = task_config.copy()
2945 cpy.pop("bazel", None)
2946 cpy.pop("name", None)
2947 if "platform" not in cpy:
2948 cpy["platform"] = task_name
2949
2950 m = hashlib.md5()
Florian Weikertb3439b32022-11-09 11:05:16 +01002951 # Technically we should sort cpy[key] if it's a list of entries
2952 # whose order does not matter (e.g. targets).
2953 # However, this seems to be overkill for the current use cases.
Florian Weikert854fd852019-06-04 16:44:19 +02002954 for key in sorted(cpy):
Florian Weikert8186c392019-06-05 12:53:39 +02002955 value = "%s:%s;" % (key, cpy[key])
2956 m.update(value.encode("utf-8"))
Florian Weikert854fd852019-06-04 16:44:19 +02002957
2958 return m.digest()
2959
2960
Florian Weikert843d7a02019-02-03 17:24:50 +01002961def get_platform_for_task(task, task_config):
2962 # Most pipeline configurations have exactly one task per platform, which makes it
2963 # convenient to use the platform name as task ID. Consequently, we use the
2964 # task ID as platform if there is no explicit "platform" field.
2965 return task_config.get("platform", task)
2966
2967
Florian Weikertf52f91a2019-05-08 15:19:30 +02002968def create_config_validation_steps():
Florian Weikertf52f91a2019-05-08 15:19:30 +02002969 config_files = [
Philipp Wollermann67225ec2021-08-11 11:12:51 +02002970 path
Florian Weikerte417f9f2023-05-05 17:33:46 +02002971 for path in get_modified_files()
Philipp Wollermann67225ec2021-08-11 11:12:51 +02002972 if path.startswith(".bazelci/") and os.path.splitext(path)[1] in CONFIG_FILE_EXTENSIONS
Florian Weikertf52f91a2019-05-08 15:19:30 +02002973 ]
Florian Weikertf52f91a2019-05-08 15:19:30 +02002974 return [
2975 create_step(
2976 label=":cop: Validate {}".format(f),
2977 commands=[
2978 fetch_bazelcipy_command(),
2979 "{} bazelci.py project_pipeline --file_config={}".format(
Philipp Wollermann57b32682019-05-18 22:09:27 +02002980 PLATFORMS[DEFAULT_PLATFORM]["python"], f
Florian Weikertf52f91a2019-05-08 15:19:30 +02002981 ),
2982 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002983 platform=DEFAULT_PLATFORM,
Florian Weikertf52f91a2019-05-08 15:19:30 +02002984 )
2985 for f in config_files
2986 ]
2987
2988
Florian Weikerte417f9f2023-05-05 17:33:46 +02002989def get_modified_files():
2990 output = execute_command_and_get_output(
2991 ["git", "diff-tree", "--no-commit-id", "--name-only", "-r", os.getenv("BUILDKITE_COMMIT")]
2992 )
2993 return output.split("\n")
2994
2995
Florian Weikertd79dc502019-05-13 09:51:05 +02002996def print_pipeline_steps(pipeline_steps, handle_emergencies=True):
2997 if handle_emergencies:
2998 emergency_step = create_emergency_announcement_step_if_necessary()
2999 if emergency_step:
3000 pipeline_steps.insert(0, emergency_step)
Florian Weikert13215a82019-05-10 12:42:21 +02003001
3002 print(yaml.dump({"steps": pipeline_steps}))
3003
3004
3005def create_emergency_announcement_step_if_necessary():
3006 style = "error"
3007 message, issue_url, last_good_bazel = None, None, None
3008 try:
3009 emergency_settings = load_remote_yaml_file(EMERGENCY_FILE_URL)
3010 message = emergency_settings.get("message")
3011 issue_url = emergency_settings.get("issue_url")
3012 last_good_bazel = emergency_settings.get("last_good_bazel")
3013 except urllib.error.HTTPError as ex:
3014 message = str(ex)
3015 style = "warning"
3016
3017 if not any([message, issue_url, last_good_bazel]):
3018 return
3019
3020 text = '<span class="h1">:rotating_light: Emergency :rotating_light:</span>\n'
3021 if message:
3022 text += "- {}\n".format(message)
3023 if issue_url:
3024 text += '- Please check this <a href="{}">issue</a> for more details.\n'.format(issue_url)
3025 if last_good_bazel:
3026 text += (
3027 "- Default Bazel version is *{}*, "
3028 "unless the pipeline configuration specifies an explicit version."
3029 ).format(last_good_bazel)
3030
3031 return create_step(
3032 label=":rotating_light: Emergency :rotating_light:",
Philipp Wollermann7590b962019-05-16 11:35:03 +02003033 commands=[
3034 'buildkite-agent annotate --append --style={} --context "omg" "{}"'.format(style, text)
3035 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02003036 platform=DEFAULT_PLATFORM,
Florian Weikert13215a82019-05-10 12:42:21 +02003037 )
3038
3039
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003040def runner_step(
3041 platform,
Florian Weikert843d7a02019-02-03 17:24:50 +01003042 task,
3043 task_name=None,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003044 project_name=None,
3045 http_config=None,
3046 file_config=None,
3047 git_repository=None,
3048 git_commit=None,
3049 monitor_flaky_tests=False,
3050 use_but=False,
Florian Weikert736d06e2019-05-08 13:16:42 +02003051 shards=1,
mai93b49bad72021-05-06 00:50:34 +02003052 soft_fail=None,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003053):
Philipp Wollermann57b32682019-05-18 22:09:27 +02003054 command = PLATFORMS[platform]["python"] + " bazelci.py runner --task=" + task
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003055 if http_config:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003056 command += " --http_config=" + http_config
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003057 if file_config:
3058 command += " --file_config=" + file_config
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003059 if git_repository:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003060 command += " --git_repository=" + git_repository
Yun Peng376d2b32018-11-29 10:24:54 +01003061 if git_commit:
3062 command += " --git_commit=" + git_commit
Jakob Buchgraberc340f582018-06-22 13:48:33 +02003063 if monitor_flaky_tests:
3064 command += " --monitor_flaky_tests"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003065 if use_but:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003066 command += " --use_but"
Florian Weikert843d7a02019-02-03 17:24:50 +01003067 label = create_label(platform, project_name, task_name=task_name)
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01003068 return create_step(
Florian Weikert9d5e4c02021-05-27 15:10:20 +02003069 label=label,
3070 commands=[fetch_bazelcipy_command(), command],
3071 platform=platform,
3072 shards=shards,
3073 soft_fail=soft_fail,
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01003074 )
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003075
3076
3077def fetch_bazelcipy_command():
Philipp Wollermanne67eec42019-05-24 15:18:20 +02003078 return "curl -sS {0} -o bazelci.py".format(SCRIPT_URL)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003079
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003080
Yun Peng8975c6b2019-02-28 11:55:55 +01003081def fetch_aggregate_incompatible_flags_test_result_command():
3082 return "curl -sS {0} -o aggregate_incompatible_flags_test_result.py".format(
Philipp Wollermanne67eec42019-05-24 15:18:20 +02003083 AGGREGATE_INCOMPATIBLE_TEST_RESULT_URL
Yun Peng8975c6b2019-02-28 11:55:55 +01003084 )
3085
3086
Florian Weikertb3439b32022-11-09 11:05:16 +01003087def upload_project_pipeline_step(project_name, git_repository, http_config, file_config):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003088 pipeline_command = (
3089 '{0} bazelci.py project_pipeline --project_name="{1}" ' + "--git_repository={2}"
Philipp Wollermann57b32682019-05-18 22:09:27 +02003090 ).format(PLATFORMS[DEFAULT_PLATFORM]["python"], project_name, git_repository)
Yun Pengc85cd0e2022-09-02 10:44:29 +02003091 pipeline_command += " --use_but"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003092 if http_config:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003093 pipeline_command += " --http_config=" + http_config
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003094 if file_config:
3095 pipeline_command += " --file_config=" + file_config
Chi Wangf1f20362022-02-01 13:44:45 +01003096 pipeline_command += " | tee /dev/tty | buildkite-agent pipeline upload"
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003097
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01003098 return create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01003099 label="Setup {0}".format(project_name),
3100 commands=[fetch_bazelcipy_command(), pipeline_command],
Philipp Wollermann7a185322019-05-18 22:15:48 +02003101 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01003102 )
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003103
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003104
Florian Weikert843d7a02019-02-03 17:24:50 +01003105def create_label(platform, project_name, build_only=False, test_only=False, task_name=None):
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003106 if build_only and test_only:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003107 raise BuildkiteException("build_only and test_only cannot be true at the same time")
Florian Weikert843d7a02019-02-03 17:24:50 +01003108 platform_display_name = PLATFORMS[platform]["emoji-name"]
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003109
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003110 if build_only:
3111 label = "Build "
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003112 elif test_only:
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003113 label = "Test "
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003114 else:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003115 label = ""
3116
Florian Weikert843d7a02019-02-03 17:24:50 +01003117 platform_label = (
3118 "{0} on {1}".format(task_name, platform_display_name)
3119 if task_name
3120 else platform_display_name
3121 )
3122
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003123 if project_name:
Florian Weikert843d7a02019-02-03 17:24:50 +01003124 label += "{0} ({1})".format(project_name, platform_label)
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003125 else:
Florian Weikert843d7a02019-02-03 17:24:50 +01003126 label += platform_label
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003127
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003128 return label
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003129
3130
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003131def bazel_build_step(
Florian Weikert843d7a02019-02-03 17:24:50 +01003132 task,
3133 platform,
3134 project_name,
3135 http_config=None,
3136 file_config=None,
3137 build_only=False,
3138 test_only=False,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003139):
Philipp Wollermann57b32682019-05-18 22:09:27 +02003140 pipeline_command = PLATFORMS[platform]["python"] + " bazelci.py runner"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003141 if build_only:
Philipp Wollermannc52e26a2019-05-18 22:10:47 +02003142 pipeline_command += " --build_only --save_but"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003143 if test_only:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003144 pipeline_command += " --test_only"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003145 if http_config:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003146 pipeline_command += " --http_config=" + http_config
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003147 if file_config:
3148 pipeline_command += " --file_config=" + file_config
Florian Weikert843d7a02019-02-03 17:24:50 +01003149 pipeline_command += " --task=" + task
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003150
Yun Pengbe4e2eb2022-09-16 11:42:50 +02003151 step = create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01003152 label=create_label(platform, project_name, build_only, test_only),
3153 commands=[fetch_bazelcipy_command(), pipeline_command],
3154 platform=platform,
3155 )
Yun Pengbe4e2eb2022-09-16 11:42:50 +02003156 # Always try to automatically retry the bazel build step, this will make
3157 # the publish bazel binaries pipeline more reliable.
3158 step["retry"] = {
3159 "automatic": [
3160 {"exit_status": "*", "limit": 3},
3161 ]
3162 }
3163 return step
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003164
3165
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02003166def filter_tasks_that_should_be_skipped(task_configs, pipeline_steps):
3167 skip_tasks = get_skip_tasks()
3168 if not skip_tasks:
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02003169 return task_configs
3170
3171 actually_skipped = []
3172 skip_tasks = set(skip_tasks)
3173 for task in list(task_configs.keys()):
3174 if task in skip_tasks:
3175 actually_skipped.append(task)
3176 del task_configs[task]
3177 skip_tasks.remove(task)
3178
3179 if not task_configs:
3180 raise BuildkiteException(
3181 "Nothing to do since all tasks in the configuration should be skipped."
3182 )
3183
3184 annotations = []
3185 if actually_skipped:
3186 annotations.append(
3187 ("info", "Skipping the following task(s): {}".format(", ".join(actually_skipped)))
3188 )
3189
3190 if skip_tasks:
3191 annotations.append(
3192 (
3193 "warning",
3194 (
3195 "The following tasks should have been skipped, "
3196 "but were not part of the configuration: {}"
3197 ).format(", ".join(skip_tasks)),
3198 )
3199 )
3200
3201 if annotations:
3202 print_skip_task_annotations(annotations, pipeline_steps)
3203
3204 return task_configs
3205
3206
3207def get_skip_tasks():
3208 value = os.getenv(SKIP_TASKS_ENV_VAR, "")
3209 return [v for v in value.split(",") if v]
3210
3211
3212def print_skip_task_annotations(annotations, pipeline_steps):
3213 commands = [
3214 "buildkite-agent annotate --style={} '{}' --context 'ctx-{}'".format(s, t, hash(t))
3215 for s, t in annotations
3216 ]
3217 pipeline_steps.append(
Philipp Wollermann7a185322019-05-18 22:15:48 +02003218 create_step(
3219 label=":pipeline: Print information about skipped tasks",
3220 commands=commands,
3221 platform=DEFAULT_PLATFORM,
3222 )
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02003223 )
3224
3225
Florian Weikert843d7a02019-02-03 17:24:50 +01003226def print_bazel_publish_binaries_pipeline(task_configs, http_config, file_config):
3227 if not task_configs:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003228 raise BuildkiteException("Bazel publish binaries pipeline configuration is empty.")
3229
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02003230 pipeline_steps = []
3231 task_configs = filter_tasks_that_should_be_skipped(task_configs, pipeline_steps)
3232
Florian Weikert843d7a02019-02-03 17:24:50 +01003233 platforms = [get_platform_for_task(t, tc) for t, tc in task_configs.items()]
Philipp Wollermann783d1672019-06-06 13:35:30 +02003234
3235 # These are the platforms that the bazel_publish_binaries.yml config is actually building.
3236 configured_platforms = set(filter(should_publish_binaries_for_platform, platforms))
Philipp Wollermanna2ea5d82018-08-27 14:12:10 +02003237
Philipp Wollermann783d1672019-06-06 13:35:30 +02003238 # These are the platforms that we want to build and publish according to this script.
3239 expected_platforms = set(filter(should_publish_binaries_for_platform, PLATFORMS))
Florian Weikert843d7a02019-02-03 17:24:50 +01003240
Philipp Wollermann30f314d2021-06-11 10:51:39 +02003241 # We can skip this check if we're not on the main branch, because then we're probably
3242 # building a one-off custom debugging binary anyway.
Florian Weikert7f21ca42022-02-02 17:35:23 +01003243 if current_branch_is_main_branch():
3244 missing = expected_platforms.difference(configured_platforms)
3245 if missing:
3246 raise BuildkiteException(
3247 (
3248 "Bazel publish binaries pipeline needs to build Bazel for every commit on all publish_binary-enabled platforms. "
3249 "Please add jobs for the missing platform(s) to the pipeline config: {}".format(
3250 ", ".join(missing)
3251 )
3252 )
3253 )
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01003254
Yun Pengd352b6d2018-10-17 13:28:39 +02003255 # Build Bazel
Florian Weikert843d7a02019-02-03 17:24:50 +01003256 for task, task_config in task_configs.items():
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003257 pipeline_steps.append(
Florian Weikert843d7a02019-02-03 17:24:50 +01003258 bazel_build_step(
3259 task,
3260 get_platform_for_task(task, task_config),
3261 "Bazel",
3262 http_config,
3263 file_config,
3264 build_only=True,
3265 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003266 )
Jakob Buchgraber4631a032018-03-22 17:12:46 +01003267
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003268 pipeline_steps.append("wait")
Jakob Buchgraber9d6ca8a2018-03-22 17:30:09 +01003269
Yun Pengc2dd6522018-10-17 12:58:35 +02003270 # If all builds succeed, publish the Bazel binaries to GCS.
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003271 pipeline_steps.append(
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01003272 create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01003273 label="Publish Bazel Binaries",
Philipp Wollermann57b32682019-05-18 22:09:27 +02003274 commands=[
3275 fetch_bazelcipy_command(),
3276 PLATFORMS[DEFAULT_PLATFORM]["python"] + " bazelci.py publish_binaries",
3277 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02003278 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01003279 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003280 )
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01003281
Florian Weikert13215a82019-05-10 12:42:21 +02003282 print_pipeline_steps(pipeline_steps)
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01003283
3284
Florian Weikert843d7a02019-02-03 17:24:50 +01003285def should_publish_binaries_for_platform(platform):
3286 if platform not in PLATFORMS:
3287 raise BuildkiteException("Unknown platform '{}'".format(platform))
3288
3289 return PLATFORMS[platform]["publish_binary"]
3290
3291
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01003292def print_disabled_projects_info_box_step():
3293 info_text = ["Downstream testing is disabled for the following projects :sadpanda:"]
3294 for project, config in DOWNSTREAM_PROJECTS.items():
3295 disabled_reason = config.get("disabled_reason", None)
3296 if disabled_reason:
3297 info_text.append("* **%s**: %s" % (project, disabled_reason))
3298
3299 if len(info_text) == 1:
3300 return None
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01003301 return create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01003302 label=":sadpanda:",
3303 commands=[
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003304 'buildkite-agent annotate --append --style=info "\n' + "\n".join(info_text) + '\n"'
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01003305 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02003306 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01003307 )
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01003308
Yun Peng6528e652019-01-02 14:41:07 +01003309
3310def print_incompatible_flags_info_box_step(incompatible_flags_map):
3311 info_text = ["Build and test with the following incompatible flags:"]
3312
3313 for flag in incompatible_flags_map:
3314 info_text.append("* **%s**: %s" % (flag, incompatible_flags_map[flag]))
3315
3316 if len(info_text) == 1:
3317 return None
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01003318 return create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01003319 label="Incompatible flags info",
3320 commands=[
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003321 'buildkite-agent annotate --append --style=info "\n' + "\n".join(info_text) + '\n"'
Yun Peng6528e652019-01-02 14:41:07 +01003322 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02003323 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01003324 )
Yun Peng6528e652019-01-02 14:41:07 +01003325
3326
Yun Peng7d302f62019-01-10 16:56:15 +01003327def fetch_incompatible_flags():
Yun Peng6528e652019-01-02 14:41:07 +01003328 """
Yun Pengc85cd0e2022-09-02 10:44:29 +02003329 Return a list of incompatible flags to be tested. The key is the flag name and the value is its Github URL.
Yun Peng6528e652019-01-02 14:41:07 +01003330 """
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003331 output = subprocess.check_output(
3332 [
Yun Pengc85cd0e2022-09-02 10:44:29 +02003333 # Query for open issues with "incompatible-change" and "migration-ready" label.
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003334 "curl",
Yun Pengc85cd0e2022-09-02 10:44:29 +02003335 "https://api.github.com/search/issues?per_page=100&q=repo:bazelbuild/bazel+label:incompatible-change+label:migration-ready+state:open",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003336 ]
3337 ).decode("utf-8")
Yun Peng6528e652019-01-02 14:41:07 +01003338 issue_info = json.loads(output)
3339
Yun Pengc85cd0e2022-09-02 10:44:29 +02003340 FLAG_PATTERN = re.compile(r"^--[a-z][a-z0-9_]*$")
3341 incompatible_flags = {}
Yun Peng6528e652019-01-02 14:41:07 +01003342 for issue in issue_info["items"]:
Yun Peng6528e652019-01-02 14:41:07 +01003343 name = "--" + issue["title"].split(":")[0]
3344 url = issue["html_url"]
Yun Pengc85cd0e2022-09-02 10:44:29 +02003345 if FLAG_PATTERN.match(name):
Yun Peng6528e652019-01-02 14:41:07 +01003346 incompatible_flags[name] = url
3347 else:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003348 eprint(
Philipp Wollermann639c0452019-01-03 11:23:54 +01003349 f"{name} is not recognized as an incompatible flag, please modify the issue title "
3350 f'of {url} to "<incompatible flag name (without --)>:..."'
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003351 )
Yun Peng6528e652019-01-02 14:41:07 +01003352
Yun Pengc85cd0e2022-09-02 10:44:29 +02003353 # If INCOMPATIBLE_FLAGS is set manually, we test those flags, try to keep the URL info if possible.
3354 if "INCOMPATIBLE_FLAGS" in os.environ:
3355 given_incompatible_flags = {}
3356 for flag in os.environ["INCOMPATIBLE_FLAGS"].split(","):
3357 given_incompatible_flags[flag] = incompatible_flags.get(flag, "")
3358 return given_incompatible_flags
3359
Yun Peng6528e652019-01-02 14:41:07 +01003360 return incompatible_flags
3361
3362
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003363def print_bazel_downstream_pipeline(
Yun Pengc85cd0e2022-09-02 10:44:29 +02003364 task_configs, http_config, file_config, test_disabled_projects, notify
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003365):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003366 pipeline_steps = []
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003367
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01003368 info_box_step = print_disabled_projects_info_box_step()
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01003369 if info_box_step is not None:
3370 pipeline_steps.append(info_box_step)
3371
Yun Pengc85cd0e2022-09-02 10:44:29 +02003372 if not use_bazelisk_migrate():
3373 if not task_configs:
3374 raise BuildkiteException("Bazel downstream pipeline configuration is empty.")
Florian Weikert843d7a02019-02-03 17:24:50 +01003375 for task, task_config in task_configs.items():
Yun Peng5599ca22019-01-16 12:32:41 +01003376 pipeline_steps.append(
Florian Weikert843d7a02019-02-03 17:24:50 +01003377 bazel_build_step(
3378 task,
3379 get_platform_for_task(task, task_config),
3380 "Bazel",
3381 http_config,
3382 file_config,
3383 build_only=True,
3384 )
Yun Peng5599ca22019-01-16 12:32:41 +01003385 )
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003386
Yun Peng5599ca22019-01-16 12:32:41 +01003387 pipeline_steps.append("wait")
Yun Pengc85cd0e2022-09-02 10:44:29 +02003388 else:
Yun Peng7d302f62019-01-10 16:56:15 +01003389 incompatible_flags_map = fetch_incompatible_flags()
Yun Peng3c1d7d12020-06-30 14:58:34 +02003390 if not incompatible_flags_map:
Florian Weikert9d5e4c02021-05-27 15:10:20 +02003391 step = create_step(
3392 label="No Incompatible flags info",
3393 commands=[
Florian Weikert42738ac2021-05-27 15:54:14 +02003394 'buildkite-agent annotate --style=error "No incompatible flag issue is found on github for current version of Bazel." --context "noinc"'
Florian Weikert9d5e4c02021-05-27 15:10:20 +02003395 ],
3396 platform=DEFAULT_PLATFORM,
Florian Weikertdb832a02020-11-19 19:14:48 +01003397 )
Florian Weikert9d5e4c02021-05-27 15:10:20 +02003398 pipeline_steps.append(step)
3399 print_pipeline_steps(pipeline_steps)
3400 return
3401
Yun Peng6528e652019-01-02 14:41:07 +01003402 info_box_step = print_incompatible_flags_info_box_step(incompatible_flags_map)
3403 if info_box_step is not None:
3404 pipeline_steps.append(info_box_step)
Yun Peng7a539ef2018-11-30 15:07:24 +01003405
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003406 for project, config in DOWNSTREAM_PROJECTS.items():
Yun Peng996efad2018-11-27 17:19:44 +01003407 disabled_reason = config.get("disabled_reason", None)
Yun Pengfb759fa2018-12-13 11:35:39 +01003408 # If test_disabled_projects is true, we add configs for disabled projects.
Florian Weikert7b3f17e2019-03-14 13:52:42 +01003409 # If test_disabled_projects is false, we add configs for not disabled projects.
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003410 if (test_disabled_projects and disabled_reason) or (
3411 not test_disabled_projects and not disabled_reason
3412 ):
Yun Peng996efad2018-11-27 17:19:44 +01003413 pipeline_steps.append(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003414 upload_project_pipeline_step(
3415 project_name=project,
3416 git_repository=config["git_repository"],
3417 http_config=config.get("http_config", None),
3418 file_config=config.get("file_config", None),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003419 )
3420 )
Yun Peng71c2d9f2022-01-05 10:33:51 +01003421
Yun Pengc85cd0e2022-09-02 10:44:29 +02003422 if use_bazelisk_migrate():
Yun Peng002eab92018-12-17 18:28:14 +01003423 current_build_number = os.environ.get("BUILDKITE_BUILD_NUMBER", None)
3424 if not current_build_number:
3425 raise BuildkiteException("Not running inside Buildkite")
Yun Pengc85cd0e2022-09-02 10:44:29 +02003426
Florian Weikertb3439b32022-11-09 11:05:16 +01003427 pipeline_steps += get_steps_for_aggregating_migration_results(current_build_number, notify)
Yun Peng002eab92018-12-17 18:28:14 +01003428
Florian Weikert2896edb2019-04-04 16:12:47 +02003429 if (
3430 not test_disabled_projects
Yun Pengc85cd0e2022-09-02 10:44:29 +02003431 and not use_bazelisk_migrate()
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02003432 and current_branch_is_main_branch()
Florian Weikert2896edb2019-04-04 16:12:47 +02003433 ):
Florian Weikert35906542019-04-01 11:53:53 +02003434 # Only update the last green downstream commit in the regular Bazel@HEAD + Downstream pipeline.
3435 pipeline_steps.append("wait")
3436 pipeline_steps.append(
3437 create_step(
3438 label="Try Update Last Green Downstream Commit",
3439 commands=[
3440 fetch_bazelcipy_command(),
Philipp Wollermann57b32682019-05-18 22:09:27 +02003441 PLATFORMS[DEFAULT_PLATFORM]["python"]
3442 + " bazelci.py try_update_last_green_downstream_commit",
Florian Weikert35906542019-04-01 11:53:53 +02003443 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02003444 platform=DEFAULT_PLATFORM,
Florian Weikert35906542019-04-01 11:53:53 +02003445 )
3446 )
3447
Florian Weikert13215a82019-05-10 12:42:21 +02003448 print_pipeline_steps(pipeline_steps)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003449
3450
Florian Weikert60661912019-12-18 15:17:10 +01003451def get_steps_for_aggregating_migration_results(current_build_number, notify):
Florian Weikert09813a02019-10-26 19:34:33 +02003452 parts = [
3453 PLATFORMS[DEFAULT_PLATFORM]["python"],
3454 "aggregate_incompatible_flags_test_result.py",
3455 "--build_number=%s" % current_build_number,
Florian Weikert09813a02019-10-26 19:34:33 +02003456 ]
Florian Weikert60661912019-12-18 15:17:10 +01003457 if notify:
3458 parts.append("--notify")
Florian Weikert09813a02019-10-26 19:34:33 +02003459 return [
3460 {"wait": "~", "continue_on_failure": "true"},
3461 create_step(
3462 label="Aggregate incompatible flags test result",
3463 commands=[
3464 fetch_bazelcipy_command(),
3465 fetch_aggregate_incompatible_flags_test_result_command(),
3466 " ".join(parts),
3467 ],
3468 platform=DEFAULT_PLATFORM,
3469 ),
3470 ]
3471
3472
Yun Pengc2dd6522018-10-17 12:58:35 +02003473def bazelci_builds_download_url(platform, git_commit):
Philipp Wollermanne67eec42019-05-24 15:18:20 +02003474 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
3475 return "https://storage.googleapis.com/{}/artifacts/{}/{}/bazel".format(
3476 bucket_name, platform, git_commit
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003477 )
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003478
3479
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003480def bazelci_builds_nojdk_download_url(platform, git_commit):
3481 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
3482 return "https://storage.googleapis.com/{}/artifacts/{}/{}/bazel_nojdk".format(
3483 bucket_name, platform, git_commit
3484 )
3485
3486
Yun Peng20d45602018-10-18 13:27:05 +02003487def bazelci_builds_gs_url(platform, git_commit):
Philipp Wollermanne67eec42019-05-24 15:18:20 +02003488 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
3489 return "gs://{}/artifacts/{}/{}/bazel".format(bucket_name, platform, git_commit)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003490
3491
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003492def bazelci_builds_nojdk_gs_url(platform, git_commit):
3493 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
3494 return "gs://{}/artifacts/{}/{}/bazel_nojdk".format(bucket_name, platform, git_commit)
3495
3496
mai93f04f9482020-10-20 17:22:30 +02003497def bazelci_latest_build_metadata_url():
Philipp Wollermanne67eec42019-05-24 15:18:20 +02003498 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
3499 return "gs://{}/metadata/latest.json".format(bucket_name)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003500
3501
mai93f04f9482020-10-20 17:22:30 +02003502def bazelci_builds_metadata_url(git_commit):
3503 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
3504 return "gs://{}/metadata/{}.json".format(bucket_name, git_commit)
3505
3506
Yun Peng996efad2018-11-27 17:19:44 +01003507def bazelci_last_green_commit_url(git_repository, pipeline_slug):
Philipp Wollermanne67eec42019-05-24 15:18:20 +02003508 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-untrusted-builds"
3509 return "gs://{}/last_green_commit/{}/{}".format(
3510 bucket_name, git_repository[len("https://") :], pipeline_slug
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003511 )
Yun Pengafe67d42018-11-23 17:06:43 +01003512
3513
Florian Weikert35906542019-04-01 11:53:53 +02003514def bazelci_last_green_downstream_commit_url():
Philipp Wollermanne67eec42019-05-24 15:18:20 +02003515 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-untrusted-builds"
3516 return "gs://{}/last_green_commit/downstream_pipeline".format(bucket_name)
Florian Weikert35906542019-04-01 11:53:53 +02003517
3518
3519def get_last_green_commit(last_green_commit_url):
Yun Peng61a448f2018-11-23 17:11:46 +01003520 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003521 return (
3522 subprocess.check_output(
3523 [gsutil_command(), "cat", last_green_commit_url], env=os.environ
3524 )
3525 .decode("utf-8")
3526 .strip()
3527 )
Yun Peng61a448f2018-11-23 17:11:46 +01003528 except subprocess.CalledProcessError:
3529 return None
Yun Peng43239b02018-11-23 13:57:34 +01003530
3531
Yun Peng358cd882018-11-29 10:25:18 +01003532def try_update_last_green_commit():
Florian Weikertde96a6f2019-03-07 14:57:50 +01003533 org_slug = os.getenv("BUILDKITE_ORGANIZATION_SLUG")
Yun Peng358cd882018-11-29 10:25:18 +01003534 pipeline_slug = os.getenv("BUILDKITE_PIPELINE_SLUG")
Florian Weikertde96a6f2019-03-07 14:57:50 +01003535 build_number = os.getenv("BUILDKITE_BUILD_NUMBER")
3536 current_job_id = os.getenv("BUILDKITE_JOB_ID")
3537
3538 client = BuildkiteClient(org=org_slug, pipeline=pipeline_slug)
3539 build_info = client.get_build_info(build_number)
3540
mai9302a609c2021-05-20 10:36:46 +02003541 # Find any failing steps other than Buildifier and steps with soft_fail enabled then "try update last green".
Philipp Wollermannce986af2019-07-18 14:46:05 +02003542 def has_failed(job):
Florian Weikertbd40a272019-03-08 10:20:18 +01003543 state = job.get("state")
3544 # Ignore steps that don't have a state (like "wait").
Florian Weikertde96a6f2019-03-07 14:57:50 +01003545 return (
Florian Weikert35906542019-04-01 11:53:53 +02003546 state is not None
3547 and state != "passed"
mai9302a609c2021-05-20 10:36:46 +02003548 and not job.get("soft_failed")
Florian Weikertde96a6f2019-03-07 14:57:50 +01003549 and job["id"] != current_job_id
3550 and job["name"] != BUILDIFIER_STEP_NAME
3551 )
3552
Philipp Wollermannce986af2019-07-18 14:46:05 +02003553 failing_jobs = [j["name"] for j in build_info["jobs"] if has_failed(j)]
Florian Weikertde96a6f2019-03-07 14:57:50 +01003554 if failing_jobs:
3555 raise BuildkiteException(
3556 "Cannot update last green commit due to {} failing step(s): {}".format(
3557 len(failing_jobs), ", ".join(failing_jobs)
3558 )
3559 )
3560
Yun Peng358cd882018-11-29 10:25:18 +01003561 git_repository = os.getenv("BUILDKITE_REPO")
Florian Weikert35906542019-04-01 11:53:53 +02003562 last_green_commit_url = bazelci_last_green_commit_url(git_repository, pipeline_slug)
3563 update_last_green_commit_if_newer(last_green_commit_url)
3564
3565
3566def update_last_green_commit_if_newer(last_green_commit_url):
3567 last_green_commit = get_last_green_commit(last_green_commit_url)
Florian Weikert5e70d9d2023-05-08 19:20:23 +02003568 current_commit = resolve_revision("HEAD")
Yun Peng358cd882018-11-29 10:25:18 +01003569 if last_green_commit:
Jakob Buchgraber7c7ceee2019-10-28 10:28:58 +01003570 success = False
3571 try:
3572 execute_command(["git", "fetch", "-v", "origin", last_green_commit])
3573 success = True
3574 except subprocess.CalledProcessError:
3575 # If there was an error fetching the commit it typically means
3576 # that the commit does not exist anymore - due to a force push. In
3577 # order to recover from that assume that the current commit is the
3578 # newest commit.
3579 result = [current_commit]
3580 finally:
3581 if success:
3582 result = (
3583 subprocess.check_output(
3584 ["git", "rev-list", "%s..%s" % (last_green_commit, current_commit)]
3585 )
3586 .decode("utf-8")
3587 .strip()
3588 )
Philipp Wollermannce986af2019-07-18 14:46:05 +02003589 else:
3590 result = None
Yun Peng358cd882018-11-29 10:25:18 +01003591
Philipp Wollermann639c0452019-01-03 11:23:54 +01003592 # If current_commit is newer that last_green_commit, `git rev-list A..B` will output a bunch of
3593 # commits, otherwise the output should be empty.
Yun Peng358cd882018-11-29 10:25:18 +01003594 if not last_green_commit or result:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003595 execute_command(
Philipp Wollermann76a7eac2020-02-17 18:29:52 +01003596 [
3597 "echo %s | %s -h 'Cache-Control: no-store' cp - %s"
3598 % (current_commit, gsutil_command(), last_green_commit_url)
3599 ],
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003600 shell=True,
3601 )
Yun Peng358cd882018-11-29 10:25:18 +01003602 else:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003603 eprint(
3604 "Updating abandoned: last green commit (%s) is not older than current commit (%s)."
3605 % (last_green_commit, current_commit)
3606 )
3607
Yun Peng358cd882018-11-29 10:25:18 +01003608
Florian Weikert5e70d9d2023-05-08 19:20:23 +02003609def resolve_revision(rev):
3610 return subprocess.check_output(["git", "rev-parse", rev]).decode("utf-8").strip()
3611
3612
Florian Weikert35906542019-04-01 11:53:53 +02003613def try_update_last_green_downstream_commit():
3614 last_green_commit_url = bazelci_last_green_downstream_commit_url()
3615 update_last_green_commit_if_newer(last_green_commit_url)
3616
3617
Jakob Buchgraber76381e02018-02-19 16:19:56 +01003618def latest_generation_and_build_number():
Philipp Wollermannce986af2019-07-18 14:46:05 +02003619 generation = None
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003620 output = None
Philipp Wollermannce986af2019-07-18 14:46:05 +02003621 for attempt in range(5):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003622 output = subprocess.check_output(
mai93f04f9482020-10-20 17:22:30 +02003623 [gsutil_command(), "stat", bazelci_latest_build_metadata_url()], env=os.environ
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003624 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003625 match = re.search("Generation:[ ]*([0-9]+)", output.decode("utf-8"))
3626 if not match:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003627 raise BuildkiteException("Couldn't parse generation. gsutil output format changed?")
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003628 generation = match.group(1)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003629
Philipp Wollermannff39ef52018-02-21 14:18:52 +01003630 match = re.search(r"Hash \(md5\):[ ]*([^\s]+)", output.decode("utf-8"))
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003631 if not match:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003632 raise BuildkiteException("Couldn't parse md5 hash. gsutil output format changed?")
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003633 expected_md5hash = base64.b64decode(match.group(1))
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003634
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003635 output = subprocess.check_output(
mai93f04f9482020-10-20 17:22:30 +02003636 [gsutil_command(), "cat", bazelci_latest_build_metadata_url()], env=os.environ
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003637 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003638 hasher = hashlib.md5()
3639 hasher.update(output)
3640 actual_md5hash = hasher.digest()
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003641
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003642 if expected_md5hash == actual_md5hash:
3643 break
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003644 info = json.loads(output.decode("utf-8"))
Philipp Wollermannce986af2019-07-18 14:46:05 +02003645 return generation, info["build_number"]
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003646
Jakob Buchgraber699aece2018-02-19 12:49:30 +01003647
Jakob Buchgraber88083fd2018-02-18 17:23:35 +01003648def sha256_hexdigest(filename):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003649 sha256 = hashlib.sha256()
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003650 with open(filename, "rb") as f:
3651 for block in iter(lambda: f.read(65536), b""):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003652 sha256.update(block)
3653 return sha256.hexdigest()
Jakob Buchgraber699aece2018-02-19 12:49:30 +01003654
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003655
Philipp Wollermann02955272019-04-18 18:00:48 +02003656def upload_bazel_binaries():
3657 """
3658 Uploads all Bazel binaries to a deterministic URL based on the current Git commit.
3659
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003660 Returns maps of platform names to sha256 hashes of the corresponding bazel and bazel_nojdk binaries.
Philipp Wollermann02955272019-04-18 18:00:48 +02003661 """
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003662 bazel_hashes = {}
3663 bazel_nojdk_hashes = {}
Philipp Wollermannbdd4bf92019-06-06 14:43:50 +02003664 for platform_name, platform in PLATFORMS.items():
Philipp Wollermann783d1672019-06-06 13:35:30 +02003665 if not should_publish_binaries_for_platform(platform_name):
3666 continue
Jakob Buchgraberb13a9a82018-03-27 18:37:09 +02003667 tmpdir = tempfile.mkdtemp()
3668 try:
Philipp Wollermann783d1672019-06-06 13:35:30 +02003669 bazel_binary_path = download_bazel_binary(tmpdir, platform_name)
3670 # One platform that we build on can generate binaries for multiple platforms, e.g.
Philipp Wollermannf4aabb72019-06-25 15:59:00 +02003671 # the centos7 platform generates binaries for the "centos7" platform, but also
Philipp Wollermann783d1672019-06-06 13:35:30 +02003672 # for the generic "linux" platform.
3673 for target_platform_name in platform["publish_binary"]:
3674 execute_command(
3675 [
3676 gsutil_command(),
3677 "cp",
3678 bazel_binary_path,
3679 bazelci_builds_gs_url(target_platform_name, os.environ["BUILDKITE_COMMIT"]),
3680 ]
3681 )
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003682 bazel_hashes[target_platform_name] = sha256_hexdigest(bazel_binary_path)
3683
3684 # Also publish bazel_nojdk binaries.
3685 bazel_nojdk_binary_path = download_bazel_nojdk_binary(tmpdir, platform_name)
3686 for target_platform_name in platform["publish_binary"]:
3687 execute_command(
3688 [
3689 gsutil_command(),
3690 "cp",
3691 bazel_nojdk_binary_path,
Florian Weikertdb832a02020-11-19 19:14:48 +01003692 bazelci_builds_nojdk_gs_url(
3693 target_platform_name, os.environ["BUILDKITE_COMMIT"]
3694 ),
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003695 ]
3696 )
3697 bazel_nojdk_hashes[target_platform_name] = sha256_hexdigest(bazel_nojdk_binary_path)
Philipp Wollermann30f314d2021-06-11 10:51:39 +02003698 except subprocess.CalledProcessError as e:
3699 # If we're not on the main branch, we're probably building a custom one-off binary and
3700 # ignore failures for individual platforms (it's possible that we didn't build binaries
3701 # for all platforms).
3702 if not current_branch_is_main_branch():
3703 eprint(
3704 "Ignoring failure to download and publish Bazel binary for platform {}: {}".format(
3705 platform_name, e
3706 )
3707 )
3708 else:
3709 raise e
Jakob Buchgraberb13a9a82018-03-27 18:37:09 +02003710 finally:
3711 shutil.rmtree(tmpdir)
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003712 return bazel_hashes, bazel_nojdk_hashes
Philipp Wollermann02955272019-04-18 18:00:48 +02003713
3714
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003715def try_publish_binaries(bazel_hashes, bazel_nojdk_hashes, build_number, expected_generation):
Philipp Wollermann02955272019-04-18 18:00:48 +02003716 """
3717 Uploads the info.json file that contains information about the latest Bazel commit that was
3718 successfully built on CI.
3719 """
3720 now = datetime.datetime.now()
3721 git_commit = os.environ["BUILDKITE_COMMIT"]
3722 info = {
3723 "build_number": build_number,
3724 "build_time": now.strftime("%d-%m-%Y %H:%M"),
3725 "git_commit": git_commit,
3726 "platforms": {},
3727 }
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003728 for platform, sha256 in bazel_hashes.items():
Philipp Wollermann02955272019-04-18 18:00:48 +02003729 info["platforms"][platform] = {
3730 "url": bazelci_builds_download_url(platform, git_commit),
Philipp Wollermann783d1672019-06-06 13:35:30 +02003731 "sha256": sha256,
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003732 "nojdk_url": bazelci_builds_nojdk_download_url(platform, git_commit),
3733 "nojdk_sha256": bazel_nojdk_hashes[platform],
Philipp Wollermann02955272019-04-18 18:00:48 +02003734 }
Jakob Buchgraberb13a9a82018-03-27 18:37:09 +02003735 tmpdir = tempfile.mkdtemp()
3736 try:
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003737 info_file = os.path.join(tmpdir, "info.json")
3738 with open(info_file, mode="w", encoding="utf-8") as fp:
Jakob Buchgraber609a20e2018-02-25 17:06:51 +01003739 json.dump(info, fp, indent=2, sort_keys=True)
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003740
3741 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003742 execute_command(
3743 [
3744 gsutil_command(),
3745 "-h",
3746 "x-goog-if-generation-match:" + expected_generation,
3747 "-h",
3748 "Content-Type:application/json",
3749 "cp",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003750 info_file,
mai93f04f9482020-10-20 17:22:30 +02003751 bazelci_latest_build_metadata_url(),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003752 ]
3753 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003754 except subprocess.CalledProcessError:
3755 raise BinaryUploadRaceException()
mai93f04f9482020-10-20 17:22:30 +02003756
3757 execute_command(
3758 [
3759 gsutil_command(),
3760 "cp",
3761 bazelci_latest_build_metadata_url(),
3762 bazelci_builds_metadata_url(git_commit),
3763 ]
3764 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003765 finally:
Philipp Wollermann3e1a7712018-02-19 17:34:24 +01003766 shutil.rmtree(tmpdir)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003767
3768
Jakob Buchgraber76381e02018-02-19 16:19:56 +01003769def publish_binaries():
Philipp Wollermanndb024862018-02-19 17:16:56 +01003770 """
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003771 Publish Bazel binaries to GCS.
Philipp Wollermanndb024862018-02-19 17:16:56 +01003772 """
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003773 current_build_number = os.environ.get("BUILDKITE_BUILD_NUMBER", None)
3774 if not current_build_number:
3775 raise BuildkiteException("Not running inside Buildkite")
3776 current_build_number = int(current_build_number)
3777
Philipp Wollermann02955272019-04-18 18:00:48 +02003778 # Upload the Bazel binaries for this commit.
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003779 bazel_hashes, bazel_nojdk_hashes = upload_bazel_binaries()
Philipp Wollermann02955272019-04-18 18:00:48 +02003780
3781 # Try to update the info.json with data about our build. This will fail (expectedly) if we're
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02003782 # not the latest build. Only do this if we're building binaries from the main branch to avoid
3783 # accidentally publishing a custom debug build as the "latest" Bazel binary.
3784 if current_branch_is_main_branch():
3785 for _ in range(5):
3786 latest_generation, latest_build_number = latest_generation_and_build_number()
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003787
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02003788 if current_build_number <= latest_build_number:
3789 eprint(
3790 (
3791 "Current build '{0}' is not newer than latest published '{1}'. "
3792 + "Skipping publishing of binaries."
3793 ).format(current_build_number, latest_build_number)
3794 )
3795 break
3796
3797 try:
3798 try_publish_binaries(
3799 bazel_hashes, bazel_nojdk_hashes, current_build_number, latest_generation
3800 )
3801 except BinaryUploadRaceException:
3802 # Retry.
3803 continue
3804
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003805 eprint(
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02003806 "Successfully updated '{0}' to binaries from build {1}.".format(
3807 bazelci_latest_build_metadata_url(), current_build_number
3808 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003809 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003810 break
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02003811 else:
3812 raise BuildkiteException("Could not publish binaries, ran out of attempts.")
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003813
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02003814
Philipp Wollermann639c0452019-01-03 11:23:54 +01003815# This is so that multiline python strings are represented as YAML
3816# block strings.
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01003817def str_presenter(dumper, data):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003818 if len(data.splitlines()) > 1: # check for multiline string
3819 return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|")
3820 return dumper.represent_scalar("tag:yaml.org,2002:str", data)
3821
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003822
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003823def main(argv=None):
3824 if argv is None:
Yun Peng20d45602018-10-18 13:27:05 +02003825 argv = sys.argv[1:]
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003826
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01003827 yaml.add_representer(str, str_presenter)
3828
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003829 parser = argparse.ArgumentParser(description="Bazel Continuous Integration Script")
Florian Weikert944209b2019-05-10 12:41:48 +02003830 parser.add_argument("--script", type=str)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003831
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003832 subparsers = parser.add_subparsers(dest="subparsers_name")
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003833
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003834 bazel_publish_binaries_pipeline = subparsers.add_parser("bazel_publish_binaries_pipeline")
3835 bazel_publish_binaries_pipeline.add_argument("--file_config", type=str)
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01003836 bazel_publish_binaries_pipeline.add_argument("--http_config", type=str)
3837 bazel_publish_binaries_pipeline.add_argument("--git_repository", type=str)
3838
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003839 bazel_downstream_pipeline = subparsers.add_parser("bazel_downstream_pipeline")
3840 bazel_downstream_pipeline.add_argument("--file_config", type=str)
3841 bazel_downstream_pipeline.add_argument("--http_config", type=str)
3842 bazel_downstream_pipeline.add_argument("--git_repository", type=str)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003843 bazel_downstream_pipeline.add_argument(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003844 "--test_disabled_projects", type=bool, nargs="?", const=True
3845 )
Florian Weikert60661912019-12-18 15:17:10 +01003846 bazel_downstream_pipeline.add_argument("--notify", type=bool, nargs="?", const=True)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003847
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003848 project_pipeline = subparsers.add_parser("project_pipeline")
3849 project_pipeline.add_argument("--project_name", type=str)
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003850 project_pipeline.add_argument("--file_config", type=str)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003851 project_pipeline.add_argument("--http_config", type=str)
3852 project_pipeline.add_argument("--git_repository", type=str)
Jakob Buchgraber66ba4fe2018-06-22 15:04:14 +02003853 project_pipeline.add_argument("--monitor_flaky_tests", type=bool, nargs="?", const=True)
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003854 project_pipeline.add_argument("--use_but", type=bool, nargs="?", const=True)
Florian Weikert60661912019-12-18 15:17:10 +01003855 project_pipeline.add_argument("--notify", type=bool, nargs="?", const=True)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003856
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003857 runner = subparsers.add_parser("runner")
Florian Weikert843d7a02019-02-03 17:24:50 +01003858 runner.add_argument("--task", action="store", type=str, default="")
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003859 runner.add_argument("--file_config", type=str)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003860 runner.add_argument("--http_config", type=str)
3861 runner.add_argument("--git_repository", type=str)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003862 runner.add_argument(
3863 "--git_commit", type=str, help="Reset the git repository to this commit after cloning it"
3864 )
3865 runner.add_argument(
Yun Peng5012a862021-09-16 16:35:43 +02003866 "--repo_location",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003867 type=str,
3868 help="Use an existing repository instead of cloning from github",
3869 )
3870 runner.add_argument(
Dan Halperinefda1192019-01-16 00:34:09 -08003871 "--use_bazel_at_commit", type=str, help="Use Bazel binary built at a specific commit"
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003872 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003873 runner.add_argument("--use_but", type=bool, nargs="?", const=True)
3874 runner.add_argument("--save_but", type=bool, nargs="?", const=True)
Yun Peng4d1d6542019-01-17 18:30:33 +01003875 runner.add_argument("--needs_clean", type=bool, nargs="?", const=True)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003876 runner.add_argument("--build_only", type=bool, nargs="?", const=True)
3877 runner.add_argument("--test_only", type=bool, nargs="?", const=True)
Jakob Buchgraber66ba4fe2018-06-22 15:04:14 +02003878 runner.add_argument("--monitor_flaky_tests", type=bool, nargs="?", const=True)
Jakob Buchgraberc340f582018-06-22 13:48:33 +02003879
Philipp Wollermannce986af2019-07-18 14:46:05 +02003880 subparsers.add_parser("publish_binaries")
3881 subparsers.add_parser("try_update_last_green_commit")
3882 subparsers.add_parser("try_update_last_green_downstream_commit")
Yun Peng358cd882018-11-29 10:25:18 +01003883
Yun Peng20d45602018-10-18 13:27:05 +02003884 args = parser.parse_args(argv)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003885
Florian Weikert944209b2019-05-10 12:41:48 +02003886 if args.script:
3887 global SCRIPT_URL
3888 SCRIPT_URL = args.script
3889
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003890 try:
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01003891 if args.subparsers_name == "bazel_publish_binaries_pipeline":
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003892 configs = fetch_configs(args.http_config, args.file_config)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003893 print_bazel_publish_binaries_pipeline(
Florian Weikert843d7a02019-02-03 17:24:50 +01003894 task_configs=configs.get("tasks", None),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003895 http_config=args.http_config,
3896 file_config=args.file_config,
3897 )
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003898 elif args.subparsers_name == "bazel_downstream_pipeline":
Yun Pengc85cd0e2022-09-02 10:44:29 +02003899 # If USE_BAZELISK_MIGRATE is true, we don't need to fetch task configs for Bazel
3900 # since we use Bazelisk to fetch Bazel binaries.
Florian Weikertb3439b32022-11-09 11:05:16 +01003901 configs = (
3902 {} if use_bazelisk_migrate() else fetch_configs(args.http_config, args.file_config)
3903 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003904 print_bazel_downstream_pipeline(
Florian Weikert843d7a02019-02-03 17:24:50 +01003905 task_configs=configs.get("tasks", None),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003906 http_config=args.http_config,
3907 file_config=args.file_config,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003908 test_disabled_projects=args.test_disabled_projects,
Florian Weikert60661912019-12-18 15:17:10 +01003909 notify=args.notify,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003910 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003911 elif args.subparsers_name == "project_pipeline":
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003912 configs = fetch_configs(args.http_config, args.file_config)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003913 print_project_pipeline(
Florian Weikertf20ae6f2019-01-16 14:32:09 +01003914 configs=configs,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003915 project_name=args.project_name,
3916 http_config=args.http_config,
3917 file_config=args.file_config,
3918 git_repository=args.git_repository,
3919 monitor_flaky_tests=args.monitor_flaky_tests,
3920 use_but=args.use_but,
Florian Weikert60661912019-12-18 15:17:10 +01003921 notify=args.notify,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003922 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003923 elif args.subparsers_name == "runner":
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003924 configs = fetch_configs(args.http_config, args.file_config)
Florian Weikert843d7a02019-02-03 17:24:50 +01003925 tasks = configs.get("tasks", {})
3926 task_config = tasks.get(args.task)
3927 if not task_config:
3928 raise BuildkiteException(
3929 "No such task '{}' in configuration. Available: {}".format(
3930 args.task, ", ".join(tasks)
3931 )
3932 )
3933
Chi Wangdb965412023-05-10 09:00:46 +00003934 os.environ["BAZELCI_TASK"] = args.task
3935
Florian Weikert843d7a02019-02-03 17:24:50 +01003936 platform = get_platform_for_task(args.task, task_config)
3937
Yun Pengdb76f842021-08-30 18:39:38 +02003938 # The value of `BUILDKITE_MESSAGE` defaults to the commit message, which can be too large
3939 # on Windows, therefore we truncate the value to 1000 characters.
3940 # See https://github.com/bazelbuild/continuous-integration/issues/1218
3941 if "BUILDKITE_MESSAGE" in os.environ:
3942 os.environ["BUILDKITE_MESSAGE"] = os.environ["BUILDKITE_MESSAGE"][:1000]
3943
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003944 execute_commands(
Florian Weikertc8642af2019-02-03 23:58:51 +01003945 task_config=task_config,
Florian Weikert843d7a02019-02-03 17:24:50 +01003946 platform=platform,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003947 git_repository=args.git_repository,
3948 git_commit=args.git_commit,
Yun Peng5012a862021-09-16 16:35:43 +02003949 repo_location=args.repo_location,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003950 use_bazel_at_commit=args.use_bazel_at_commit,
3951 use_but=args.use_but,
3952 save_but=args.save_but,
Yun Peng4d1d6542019-01-17 18:30:33 +01003953 needs_clean=args.needs_clean,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003954 build_only=args.build_only,
3955 test_only=args.test_only,
3956 monitor_flaky_tests=args.monitor_flaky_tests,
Florian Weikertc8642af2019-02-03 23:58:51 +01003957 bazel_version=task_config.get("bazel") or configs.get("bazel"),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003958 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003959 elif args.subparsers_name == "publish_binaries":
3960 publish_binaries()
Yun Peng358cd882018-11-29 10:25:18 +01003961 elif args.subparsers_name == "try_update_last_green_commit":
Florian Weikert35906542019-04-01 11:53:53 +02003962 # Update the last green commit of a project pipeline
Yun Peng358cd882018-11-29 10:25:18 +01003963 try_update_last_green_commit()
Florian Weikert35906542019-04-01 11:53:53 +02003964 elif args.subparsers_name == "try_update_last_green_downstream_commit":
3965 # Update the last green commit of the downstream pipeline
3966 try_update_last_green_downstream_commit()
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003967 else:
3968 parser.print_help()
3969 return 2
3970 except BuildkiteException as e:
3971 eprint(str(e))
3972 return 1
3973 return 0
3974
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01003975
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003976if __name__ == "__main__":
3977 sys.exit(main())