blob: 0ef497cedc28173175cba05acbe4fef959474d00 [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 Peng39a42582018-11-09 10:59:47 +0100160 "CLion Plugin": {
161 "git_repository": "https://github.com/bazelbuild/intellij.git",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100162 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/clion.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100163 "pipeline_slug": "clion-plugin",
Yun Peng39a42582018-11-09 10:59:47 +0100164 },
Mai Hussien0731b4d2022-06-28 11:16:07 -0700165 "CLion Plugin Google": {
166 "git_repository": "https://github.com/bazelbuild/intellij.git",
167 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/google/.bazelci/clion.yml",
168 "pipeline_slug": "clion-plugin-google",
169 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200170 "Cartographer": {
171 "git_repository": "https://github.com/googlecartographer/cartographer.git",
172 "http_config": "https://raw.githubusercontent.com/googlecartographer/cartographer/master/.bazelci/presubmit.yml",
173 "pipeline_slug": "cartographer",
174 },
Philipp Wollermannee850782019-02-05 22:56:04 +0100175 "Cloud Robotics Core": {
Stefan Sauerb4dd3f92019-02-05 22:44:28 +0100176 "git_repository": "https://github.com/googlecloudrobotics/core.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200177 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/cloud-robotics.yml",
Stefan Sauerb4dd3f92019-02-05 22:44:28 +0100178 "pipeline_slug": "cloud-robotics-core",
179 },
Keith Smiley3b0ba602019-05-15 04:42:19 -0700180 "Envoy": {
181 "git_repository": "https://github.com/envoyproxy/envoy.git",
Yun Peng7ea4bc82022-12-01 12:58:08 +0100182 "http_config": "https://raw.githubusercontent.com/envoyproxy/envoy/main/.bazelci/presubmit.yml",
Keith Smiley3b0ba602019-05-15 04:42:19 -0700183 "pipeline_slug": "envoy",
184 },
Florian Weikert1fe28b72019-07-02 12:47:55 +0200185 "FlatBuffers": {
186 "git_repository": "https://github.com/google/flatbuffers.git",
187 "http_config": "https://raw.githubusercontent.com/google/flatbuffers/master/.bazelci/presubmit.yml",
188 "pipeline_slug": "flatbuffers",
Gowroji Sunil7192ed02023-10-05 18:06:02 +0530189 "disabled_reason": "https://github.com/google/flatbuffers/issues/7992",
Florian Weikert1fe28b72019-07-02 12:47:55 +0200190 },
Philipp Wollermannf3750fa2019-05-21 17:11:59 +0200191 "Flogger": {
192 "git_repository": "https://github.com/google/flogger.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200193 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/flogger.yml",
Philipp Wollermannf3750fa2019-05-21 17:11:59 +0200194 "pipeline_slug": "flogger",
195 },
Marcel Hlopkoc8840772018-10-23 12:51:46 +0200196 "Gerrit": {
197 "git_repository": "https://gerrit.googlesource.com/gerrit.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200198 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/gerrit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100199 "pipeline_slug": "gerrit",
Marcel Hlopkoc8840772018-10-23 12:51:46 +0200200 },
Yun Pengd6622022018-11-05 13:10:26 +0100201 "Google Logging": {
202 "git_repository": "https://github.com/google/glog.git",
Philipp Wollermann17e5fc62021-02-15 14:48:36 +0100203 "http_config": "https://raw.githubusercontent.com/google/glog/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100204 "pipeline_slug": "google-logging",
Yun Pengd6622022018-11-05 13:10:26 +0100205 },
Yun Peng9586db52018-11-02 10:48:40 +0100206 "IntelliJ Plugin": {
207 "git_repository": "https://github.com/bazelbuild/intellij.git",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100208 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/intellij.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100209 "pipeline_slug": "intellij-plugin",
Yun Peng9586db52018-11-02 10:48:40 +0100210 },
Mai Hussien0731b4d2022-06-28 11:16:07 -0700211 "IntelliJ Plugin Google": {
212 "git_repository": "https://github.com/bazelbuild/intellij.git",
213 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/google/.bazelci/intellij.yml",
214 "pipeline_slug": "intellij-plugin-google",
215 },
216 "IntelliJ UE Plugin": {
217 "git_repository": "https://github.com/bazelbuild/intellij.git",
218 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/intellij-ue.yml",
219 "pipeline_slug": "intellij-ue-plugin",
220 },
221 "IntelliJ UE Plugin Google": {
222 "git_repository": "https://github.com/bazelbuild/intellij.git",
223 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/google/.bazelci/intellij-ue.yml",
224 "pipeline_slug": "intellij-ue-plugin-google",
225 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100226 "IntelliJ Plugin Aspect": {
227 "git_repository": "https://github.com/bazelbuild/intellij.git",
228 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/aspect.yml",
229 "pipeline_slug": "intellij-plugin-aspect",
230 },
Mai Hussien0731b4d2022-06-28 11:16:07 -0700231 "IntelliJ Plugin Aspect Google": {
232 "git_repository": "https://github.com/bazelbuild/intellij.git",
233 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/google/.bazelci/aspect.yml",
234 "pipeline_slug": "intellij-plugin-aspect-google",
235 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200236 "Kythe": {
237 "git_repository": "https://github.com/kythe/kythe.git",
238 "http_config": "https://raw.githubusercontent.com/kythe/kythe/master/.bazelci/presubmit.yml",
239 "pipeline_slug": "kythe",
240 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100241 "Protobuf": {
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200242 "git_repository": "https://github.com/google/protobuf.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200243 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/protobuf.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100244 "pipeline_slug": "protobuf",
Yun Peng667750b2020-02-20 14:06:43 +0100245 "owned_by_bazel": True,
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200246 },
Laurent Le Brunf6326d62020-07-28 18:24:10 +0200247 "Stardoc": {
248 "git_repository": "https://github.com/bazelbuild/stardoc.git",
249 "http_config": "https://raw.githubusercontent.com/bazelbuild/stardoc/master/.bazelci/presubmit.yml",
250 "pipeline_slug": "stardoc",
Yun Peng667750b2020-02-20 14:06:43 +0100251 "owned_by_bazel": True,
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200252 },
253 "Subpar": {
254 "git_repository": "https://github.com/google/subpar.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200255 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/subpar.yml",
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200256 "pipeline_slug": "subpar",
Yun Peng667750b2020-02-20 14:06:43 +0100257 "owned_by_bazel": True,
Xùdōng Yáng26e280f2021-07-20 23:33:07 +1000258 "disabled_reason": "https://github.com/google/subpar/issues/133",
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200259 },
260 "TensorFlow": {
261 "git_repository": "https://github.com/tensorflow/tensorflow.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200262 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/tensorflow.yml",
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200263 "pipeline_slug": "tensorflow",
Yun Pengab700d52023-05-08 13:16:44 +0200264 "disabled_reason": "https://github.com/tensorflow/tensorflow/issues/60508",
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200265 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200266 "re2": {
267 "git_repository": "https://github.com/google/re2.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200268 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/re2.yml",
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200269 "pipeline_slug": "re2",
270 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100271 "rules_android": {
272 "git_repository": "https://github.com/bazelbuild/rules_android.git",
Yun Pengabb3b292023-08-16 17:08:31 +0200273 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_android/main/.bazelci/presubmit.yml",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100274 "pipeline_slug": "rules-android",
275 },
Keith Smiley2e3d7c82022-09-09 00:47:51 -0700276 "rules_android_ndk": {
Yun Peng687ad6b2022-09-15 11:00:02 +0200277 "git_repository": "https://github.com/bazelbuild/rules_android_ndk.git",
Keith Smiley2e3d7c82022-09-09 00:47:51 -0700278 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_android_ndk/main/.bazelci/presubmit.yml",
279 "pipeline_slug": "rules-android-ndk",
280 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200281 "rules_appengine": {
282 "git_repository": "https://github.com/bazelbuild/rules_appengine.git",
Yun Peng996efad2018-11-27 17:19:44 +0100283 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_appengine/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100284 "pipeline_slug": "rules-appengine-appengine",
Yun Penge4816d72022-05-04 15:33:40 -0700285 "disabled_reason": "https://github.com/bazelbuild/rules_appengine/issues/127",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200286 },
Yun Peng809f27b2018-11-13 10:15:39 +0100287 "rules_apple": {
288 "git_repository": "https://github.com/bazelbuild/rules_apple.git",
Yun Peng996efad2018-11-27 17:19:44 +0100289 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_apple/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100290 "pipeline_slug": "rules-apple-darwin",
Yun Peng809f27b2018-11-13 10:15:39 +0100291 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100292 "rules_cc": {
293 "git_repository": "https://github.com/bazelbuild/rules_cc.git",
aiuto560809f2021-08-17 14:51:32 -0400294 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_cc/main/.bazelci/presubmit.yml",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100295 "pipeline_slug": "rules-cc",
Yun Peng667750b2020-02-20 14:06:43 +0100296 "owned_by_bazel": True,
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100297 },
Marcel Hlopko340dfd22018-10-19 11:33:01 +0200298 "rules_closure": {
299 "git_repository": "https://github.com/bazelbuild/rules_closure.git",
Yun Peng996efad2018-11-27 17:19:44 +0100300 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_closure/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100301 "pipeline_slug": "rules-closure-closure-compiler",
Yun Peng667750b2020-02-20 14:06:43 +0100302 "owned_by_bazel": True,
Marcel Hlopko340dfd22018-10-19 11:33:01 +0200303 },
Florian Weikert5569c112021-04-01 14:04:33 +0200304 "rules_dotnet": {
305 "git_repository": "https://github.com/bazelbuild/rules_dotnet.git",
306 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_dotnet/master/.bazelci/presubmit.yml",
307 "pipeline_slug": "rules-dotnet-edge",
308 },
Yun Peng996efad2018-11-27 17:19:44 +0100309 "rules_foreign_cc": {
310 "git_repository": "https://github.com/bazelbuild/rules_foreign_cc.git",
mai932d494522021-03-30 18:34:05 +0200311 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_foreign_cc/main/.bazelci/config.yaml",
Yun Peng996efad2018-11-27 17:19:44 +0100312 "pipeline_slug": "rules-foreign-cc",
Yun Peng667750b2020-02-20 14:06:43 +0100313 "owned_by_bazel": True,
Yun Peng996efad2018-11-27 17:19:44 +0100314 },
Xindb02c012018-11-07 14:10:54 -0500315 "rules_go": {
316 "git_repository": "https://github.com/bazelbuild/rules_go.git",
Yun Peng996efad2018-11-27 17:19:44 +0100317 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_go/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100318 "pipeline_slug": "rules-go-golang",
Yun Pengb7247ff2018-11-15 13:52:39 +0100319 },
Yun Peng7deea572018-11-05 10:47:45 +0100320 "rules_groovy": {
Yun Peng996efad2018-11-27 17:19:44 +0100321 "git_repository": "https://github.com/bazelbuild/rules_groovy.git",
322 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_groovy/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100323 "pipeline_slug": "rules-groovy",
Yun Peng996efad2018-11-27 17:19:44 +0100324 },
325 "rules_gwt": {
326 "git_repository": "https://github.com/bazelbuild/rules_gwt.git",
327 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_gwt/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100328 "pipeline_slug": "rules-gwt",
Xùdōng Yáng99b86b32021-08-18 23:42:05 +1000329 "disabled_reason": "https://github.com/bazelbuild/continuous-integration/issues/1202",
Philipp Wollermann2a160432019-09-19 15:57:28 +0200330 },
Florian Weikertff6444e2019-09-16 16:08:57 +0200331 "rules_haskell": {
332 "git_repository": "https://github.com/tweag/rules_haskell.git",
333 "http_config": "https://raw.githubusercontent.com/tweag/rules_haskell/master/.bazelci/presubmit.yml",
334 "pipeline_slug": "rules-haskell-haskell",
Philipp Wollermann2a160432019-09-19 15:57:28 +0200335 },
Yun Peng996efad2018-11-27 17:19:44 +0100336 "rules_jsonnet": {
337 "git_repository": "https://github.com/bazelbuild/rules_jsonnet.git",
338 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_jsonnet/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100339 "pipeline_slug": "rules-jsonnet",
Yun Peng996efad2018-11-27 17:19:44 +0100340 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200341 "rules_jvm_external": {
342 "git_repository": "https://github.com/bazelbuild/rules_jvm_external.git",
343 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_jvm_external/master/.bazelci/presubmit.yml",
344 "pipeline_slug": "rules-jvm-external",
Yun Peng667750b2020-02-20 14:06:43 +0100345 "owned_by_bazel": True,
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200346 },
347 "rules_jvm_external - examples": {
348 "git_repository": "https://github.com/bazelbuild/rules_jvm_external.git",
349 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_jvm_external/master/.bazelci/examples.yml",
350 "pipeline_slug": "rules-jvm-external-examples",
Yun Peng667750b2020-02-20 14:06:43 +0100351 "owned_by_bazel": True,
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200352 },
Yun Peng996efad2018-11-27 17:19:44 +0100353 "rules_k8s": {
354 "git_repository": "https://github.com/bazelbuild/rules_k8s.git",
355 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_k8s/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100356 "pipeline_slug": "rules-k8s-k8s",
Yun Peng9b1d3432021-12-07 10:40:45 +0100357 "disabled_reason": "https://github.com/bazelbuild/rules_k8s/issues/668",
Yun Peng996efad2018-11-27 17:19:44 +0100358 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100359 "rules_kotlin": {
360 "git_repository": "https://github.com/bazelbuild/rules_kotlin.git",
361 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_kotlin/master/.bazelci/presubmit.yml",
362 "pipeline_slug": "rules-kotlin-kotlin",
363 },
Yun Penga5650e12018-11-14 10:16:06 +0100364 "rules_nodejs": {
365 "git_repository": "https://github.com/bazelbuild/rules_nodejs.git",
Alex Eagle5ba0e7f2023-04-13 02:04:46 -0700366 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_nodejs/main/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100367 "pipeline_slug": "rules-nodejs-nodejs",
Yun Penga5650e12018-11-14 10:16:06 +0100368 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200369 "rules_perl": {
370 "git_repository": "https://github.com/bazelbuild/rules_perl.git",
Philipp Wollermanndf8afd52022-02-08 16:36:10 +0100371 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_perl/main/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100372 "pipeline_slug": "rules-perl",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200373 },
Yannic6110b3c2019-08-12 15:09:37 +0000374 "rules_proto": {
375 "git_repository": "https://github.com/bazelbuild/rules_proto.git",
376 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_proto/master/.bazelci/presubmit.yml",
377 "pipeline_slug": "rules-proto",
Yun Peng667750b2020-02-20 14:06:43 +0100378 "owned_by_bazel": True,
Yannic6110b3c2019-08-12 15:09:37 +0000379 },
Yun Peng3d5a8a62018-11-19 11:42:01 +0100380 "rules_python": {
381 "git_repository": "https://github.com/bazelbuild/rules_python.git",
Florian Weikertf126dfc2021-07-05 15:39:24 +0200382 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_python/main/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100383 "pipeline_slug": "rules-python-python",
Yun Peng667750b2020-02-20 14:06:43 +0100384 "owned_by_bazel": True,
Yun Peng3d5a8a62018-11-19 11:42:01 +0100385 },
Xindb02c012018-11-07 14:10:54 -0500386 "rules_rust": {
387 "git_repository": "https://github.com/bazelbuild/rules_rust.git",
Yun Peng1e56ce82022-11-04 16:31:49 +0100388 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_rust/main/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100389 "pipeline_slug": "rules-rust-rustlang",
Xindb02c012018-11-07 14:10:54 -0500390 },
Yun Pengca62fff2018-10-31 11:22:03 +0100391 "rules_sass": {
392 "git_repository": "https://github.com/bazelbuild/rules_sass.git",
Paul Gschwendtner63ed21b2022-03-22 14:42:42 +0100393 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_sass/main/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100394 "pipeline_slug": "rules-sass",
Yun Pengca62fff2018-10-31 11:22:03 +0100395 },
Xindb02c012018-11-07 14:10:54 -0500396 "rules_scala": {
397 "git_repository": "https://github.com/bazelbuild/rules_scala.git",
Yun Peng996efad2018-11-27 17:19:44 +0100398 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_scala/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100399 "pipeline_slug": "rules-scala-scala",
Xùdōng Yáng79deb042022-09-15 12:26:36 +0200400 "disabled_reason": "waiting on https://github.com/bazelbuild/rules_scala/pull/1422",
Xindb02c012018-11-07 14:10:54 -0500401 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100402 "rules_swift": {
403 "git_repository": "https://github.com/bazelbuild/rules_swift.git",
404 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_swift/master/.bazelci/presubmit.yml",
405 "pipeline_slug": "rules-swift-swift",
406 },
Richard Levasseura9690c62023-03-06 08:39:36 -0800407 "rules_testing": {
408 "git_repository": "https://github.com/bazelbuild/rules_testing.git",
409 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_testing/master/.bazelci/presubmit.yml",
410 "pipeline_slug": "rules-testing",
411 "owned_by_bazel": True,
412 },
Yun Peng996efad2018-11-27 17:19:44 +0100413 "rules_webtesting": {
414 "git_repository": "https://github.com/bazelbuild/rules_webtesting.git",
Yun Pengc2fab332019-01-04 10:53:49 +0100415 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_webtesting/master/.bazelci/presubmit.yml",
Yun Peng996efad2018-11-27 17:19:44 +0100416 "pipeline_slug": "rules-webtesting-saucelabs",
Yun Peng996efad2018-11-27 17:19:44 +0100417 },
Philipp Wollermann389acd82019-05-21 17:41:48 +0200418 "upb": {
419 "git_repository": "https://github.com/protocolbuffers/upb.git",
420 "http_config": "https://raw.githubusercontent.com/protocolbuffers/upb/master/.bazelci/presubmit.yml",
421 "pipeline_slug": "upb",
Yun Pengab700d52023-05-08 13:16:44 +0200422 "disabled_reason": "https://github.com/protocolbuffers/upb/issues/1290",
Philipp Wollermann389acd82019-05-21 17:41:48 +0200423 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200424}
425
Philipp Wollermanne67eec42019-05-24 15:18:20 +0200426DOWNSTREAM_PROJECTS_TESTING = {
Philipp Wollermannbed211d2019-06-07 11:38:59 +0200427 "Bazel": DOWNSTREAM_PROJECTS_PRODUCTION["Bazel"],
428 "Bazelisk": DOWNSTREAM_PROJECTS_PRODUCTION["Bazelisk"],
Philipp Wollermannbed211d2019-06-07 11:38:59 +0200429 "rules_go": DOWNSTREAM_PROJECTS_PRODUCTION["rules_go"],
430 "rules_groovy": DOWNSTREAM_PROJECTS_PRODUCTION["rules_groovy"],
431 "rules_kotlin": DOWNSTREAM_PROJECTS_PRODUCTION["rules_kotlin"],
432 "rules_nodejs": DOWNSTREAM_PROJECTS_PRODUCTION["rules_nodejs"],
433 "rules_rust": DOWNSTREAM_PROJECTS_PRODUCTION["rules_rust"],
434 "rules_scala": DOWNSTREAM_PROJECTS_PRODUCTION["rules_scala"],
Philipp Wollermanne67eec42019-05-24 15:18:20 +0200435}
436
437DOWNSTREAM_PROJECTS = {
438 "bazel-testing": DOWNSTREAM_PROJECTS_TESTING,
439 "bazel-trusted": {},
440 "bazel": DOWNSTREAM_PROJECTS_PRODUCTION,
441}[BUILDKITE_ORG]
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100442
Philipp Wollermann81a88412019-07-12 10:34:33 +0200443DOCKER_REGISTRY_PREFIX = {
444 "bazel-testing": "bazel-public/testing",
445 "bazel-trusted": "bazel-public",
446 "bazel": "bazel-public",
447}[BUILDKITE_ORG]
448
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200449# A map containing all supported platform names as keys, with the values being
450# the platform name in a human readable format, and a the buildkite-agent's
451# working directory.
452PLATFORMS = {
Philipp Wollermanneffcd6e2019-06-21 18:30:34 +0200453 "centos7": {
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200454 "name": "CentOS 7 (OpenJDK 8, gcc 4.8.5)",
455 "emoji-name": ":centos: 7 (OpenJDK 8, gcc 4.8.5)",
Philipp Wollermanneffcd6e2019-06-21 18:30:34 +0200456 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann28978712021-10-21 19:09:29 +0200457 "publish_binary": [],
Philipp Wollermann5d6765d2020-02-17 17:12:02 +0100458 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/centos7-java8",
Philipp Wollermanneffcd6e2019-06-21 18:30:34 +0200459 "python": "python3.6",
460 },
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200461 "centos7_java11": {
462 "name": "CentOS 7 (OpenJDK 11, gcc 4.8.5)",
463 "emoji-name": ":centos: 7 (OpenJDK 11, gcc 4.8.5)",
464 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
465 "publish_binary": [],
466 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/centos7-java11",
467 "python": "python3.6",
468 },
469 "centos7_java11_devtoolset10": {
470 "name": "CentOS 7 (OpenJDK 11, gcc 10.2.1)",
471 "emoji-name": ":centos: 7 (OpenJDK 11, gcc 10.2.1)",
472 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann28978712021-10-21 19:09:29 +0200473 "publish_binary": ["ubuntu1404", "centos7", "linux"],
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200474 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/centos7-java11-devtoolset10",
475 "python": "python3.6",
476 },
Philipp Wollermann67fc3712019-06-12 15:39:21 +0200477 "debian10": {
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200478 "name": "Debian 10 Buster (OpenJDK 11, gcc 8.3.0)",
479 "emoji-name": ":debian: 10 Buster (OpenJDK 11, gcc 8.3.0)",
Philipp Wollermann67fc3712019-06-12 15:39:21 +0200480 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
481 "publish_binary": [],
Philipp Wollermann5d6765d2020-02-17 17:12:02 +0100482 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/debian10-java11",
Philipp Wollermann67fc3712019-06-12 15:39:21 +0200483 "python": "python3.7",
484 },
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200485 "debian11": {
486 "name": "Debian 11 Bullseye (OpenJDK 17, gcc 10.2.1)",
Zhongpeng Lin1377b622023-07-04 09:19:08 -0700487 "emoji-name": ":debian: 11 Bullseye (OpenJDK 17, gcc 10.2.1)",
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200488 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
489 "publish_binary": [],
490 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/debian11-java17",
491 "python": "python3.9",
492 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200493 "ubuntu1604": {
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200494 "name": "Ubuntu 16.04 LTS (OpenJDK 8, gcc 5.4.0)",
495 "emoji-name": ":ubuntu: 16.04 LTS (OpenJDK 8, gcc 5.4.0)",
Philipp Wollermannd551bf62019-05-18 22:04:35 +0200496 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann64047082021-10-21 21:26:25 +0200497 "publish_binary": [],
Philipp Wollermann5d6765d2020-02-17 17:12:02 +0100498 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu1604-java8",
Philipp Wollermann57b32682019-05-18 22:09:27 +0200499 "python": "python3.6",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200500 },
501 "ubuntu1804": {
Florian Weikertd02ea362022-09-15 13:51:17 +0200502 "name": "Ubuntu 18.04 LTS (OpenJDK 11, gcc 7.5.0)",
503 "emoji-name": ":ubuntu: 18.04 LTS (OpenJDK 11, gcc 7.5.0)",
Philipp Wollermannd551bf62019-05-18 22:04:35 +0200504 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Yun Peng539b17f2023-10-18 10:36:58 +0200505 "publish_binary": [],
Philipp Wollermann5d6765d2020-02-17 17:12:02 +0100506 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu1804-java11",
Philipp Wollermann57b32682019-05-18 22:09:27 +0200507 "python": "python3.6",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200508 },
Mostyn Bramley-Mooreab4599e2020-06-23 20:31:01 +0200509 "ubuntu2004": {
Florian Weikertd02ea362022-09-15 13:51:17 +0200510 "name": "Ubuntu 20.04 LTS (OpenJDK 11, gcc 9.4.0)",
511 "emoji-name": ":ubuntu: 20.04 LTS (OpenJDK 11, gcc 9.4.0)",
Mostyn Bramley-Mooreab4599e2020-06-23 20:31:01 +0200512 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann55f72ac2020-09-21 22:22:05 +0200513 "publish_binary": [],
Mostyn Bramley-Mooreab4599e2020-06-23 20:31:01 +0200514 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu2004-java11",
515 "python": "python3.8",
516 },
Yun Peng07dafc52022-03-16 13:23:35 +0100517 "ubuntu2004_arm64": {
Florian Weikertd02ea362022-09-15 13:51:17 +0200518 "name": "Ubuntu 20.04 LTS ARM64 (OpenJDK 11, gcc 9.4.0)",
519 "emoji-name": ":ubuntu: 20.04 LTS ARM64 (OpenJDK 11, gcc 9.4.0)",
Yun Peng07dafc52022-03-16 13:23:35 +0100520 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
521 "publish_binary": [],
522 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu2004-java11",
523 "python": "python3.8",
524 "queue": "arm64",
525 # TODO: Re-enable always-pull if we also publish docker containers for Linux ARM64
526 "always-pull": False,
527 },
Chi Wang6357efe2020-08-25 16:23:38 +0800528 "kythe_ubuntu2004": {
Florian Weikertd02ea362022-09-15 13:51:17 +0200529 "name": "Kythe (Ubuntu 20.04 LTS, OpenJDK 11, gcc 9.4.0)",
530 "emoji-name": "Kythe (:ubuntu: 20.04 LTS, OpenJDK 11, gcc 9.4.0)",
Chi Wang6357efe2020-08-25 16:23:38 +0800531 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
532 "publish_binary": [],
533 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu2004-java11-kythe",
534 "python": "python3.8",
535 },
Florian Weikertdcc75202022-09-06 16:34:04 +0200536 "ubuntu2204": {
537 "name": "Ubuntu 22.04 (OpenJDK 17, gcc 11.2.0)",
538 "emoji-name": ":ubuntu: 22.04 (OpenJDK 17, gcc 11.2.0)",
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200539 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
540 "publish_binary": [],
Florian Weikertdcc75202022-09-06 16:34:04 +0200541 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu2204-java17",
Philipp Wollermannb6a399a2021-10-22 07:57:26 +0200542 "python": "python3",
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200543 },
David Ostrovskyba4478f2023-05-08 16:24:04 +0200544 "fedora39": {
545 "name": "Fedora 39 (OpenJDK 17, gcc 13.1.1)",
546 "emoji-name": ":fedora: 39 (OpenJDK 17, gcc 13.1.1)",
547 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
548 "publish_binary": [],
549 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/fedora39-java17",
550 "python": "python3",
551 },
Philipp Wollermann438ec242018-09-05 14:39:24 +0200552 "macos": {
Philipp Wollermann5e3d09f2021-10-21 01:03:01 +0200553 "name": "macOS (OpenJDK 11, Xcode)",
554 "emoji-name": ":darwin: (OpenJDK 11, Xcode)",
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200555 "downstream-root": "/Users/buildkite/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann783d1672019-06-06 13:35:30 +0200556 "publish_binary": ["macos"],
Philipp Wollermann7a185322019-05-18 22:15:48 +0200557 "queue": "macos",
Philipp Wollermann89d36492021-02-16 11:59:09 +0100558 "python": "python3",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200559 },
Florian Weikerta87e6f32023-04-14 19:58:32 +0200560 "macos_qa": {
561 "name": "macOS QA (OpenJDK 11, Xcode)",
562 "emoji-name": ":darwin: :fire_extinguisher: (OpenJDK 11, Xcode)",
563 "downstream-root": "/Users/buildkite/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
564 "publish_binary": [],
565 "queue": "macos_qa",
566 "python": "python3",
567 },
Florian Weikertf4ad0922023-07-10 20:26:12 +0200568 "macos_arm64_qa": {
569 "name": "macOS arm64 QA (OpenJDK 8, Xcode)",
570 "emoji-name": ":darwin: arm64 :fire_extinguisher: (OpenJDK 8, Xcode)",
571 "downstream-root": "/Users/buildkite/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
572 "publish_binary": [],
573 "queue": "macos_arm64_qa",
574 "python": "python3",
575 },
Yun Peng46d43912021-04-21 09:49:53 +0200576 "macos_arm64": {
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200577 "name": "macOS arm64 (OpenJDK 8, Xcode)",
578 "emoji-name": ":darwin: arm64 (OpenJDK 8, Xcode)",
Yun Peng46d43912021-04-21 09:49:53 +0200579 "downstream-root": "/Users/buildkite/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Yun Peng83f32772021-04-21 11:22:35 +0200580 "publish_binary": ["macos_arm64"],
Yun Pengab922132022-11-18 20:28:02 +0100581 "queue": "macos_arm64",
Yun Peng46d43912021-04-21 09:49:53 +0200582 "python": "python3",
583 },
Philipp Wollermann438ec242018-09-05 14:39:24 +0200584 "windows": {
Yun Peng8d7a2a52022-09-09 14:56:49 +0200585 "name": "Windows (OpenJDK 11, VS2019)",
586 "emoji-name": ":windows: (OpenJDK 11, VS2019)",
Philipp Wollermannd5ab3d92020-02-05 16:55:13 +0100587 "downstream-root": "c:/b/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann783d1672019-06-06 13:35:30 +0200588 "publish_binary": ["windows"],
Philipp Wollermann7a185322019-05-18 22:15:48 +0200589 "queue": "windows",
Philipp Wollermann57b32682019-05-18 22:09:27 +0200590 "python": "python.exe",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200591 },
Yun Peng6a7a6702022-02-02 15:02:47 +0100592 "windows_arm64": {
Yun Peng8d7a2a52022-09-09 14:56:49 +0200593 "name": "Windows ARM64 (OpenJDK 11, VS2019)",
594 "emoji-name": ":windows: arm64 (OpenJDK 11, VS2019)",
Yun Peng6a7a6702022-02-02 15:02:47 +0100595 "downstream-root": "c:/b/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Yun Penge024eb72023-07-25 10:18:39 +0200596 "publish_binary": ["windows_arm64"],
Yun Peng6a7a6702022-02-02 15:02:47 +0100597 # TODO(pcloudy): Switch to windows_arm64 queue when Windows ARM64 machines are available,
598 # current we just use x86_64 machines to do cross compile.
599 "queue": "windows",
600 "python": "python.exe",
Florian Weikert7f21ca42022-02-02 17:35:23 +0100601 },
Philipp Wollermann438ec242018-09-05 14:39:24 +0200602 "rbe_ubuntu1604": {
Philipp Wollermanndb877332019-04-23 17:58:01 +0200603 "name": "RBE (Ubuntu 16.04, OpenJDK 8)",
Jakob Buchgraber1f37fbd2019-07-17 17:08:28 +0200604 "emoji-name": "RBE (:ubuntu: 16.04, OpenJDK 8)",
Philipp Wollermannd551bf62019-05-18 22:04:35 +0200605 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann783d1672019-06-06 13:35:30 +0200606 "publish_binary": [],
Philipp Wollermann5d6765d2020-02-17 17:12:02 +0100607 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu1604-java8",
Philipp Wollermann57b32682019-05-18 22:09:27 +0200608 "python": "python3.6",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100609 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200610}
611
Philipp Wollermannfce92bf2019-05-22 15:14:32 +0200612BUILDIFIER_DOCKER_IMAGE = "gcr.io/bazel-public/buildifier"
Florian Weikertf20ae6f2019-01-16 14:32:09 +0100613
Philipp Wollermann1403d2c2019-01-10 13:15:51 +0100614# The platform used for various steps (e.g. stuff that formerly ran on the "pipeline" workers).
615DEFAULT_PLATFORM = "ubuntu1804"
616
Philipp Wollermannf4aabb72019-06-25 15:59:00 +0200617# In order to test that "the one Linux binary" that we build for our official releases actually
618# works on all Linux distributions that we test on, we use the Linux binary built on our official
619# release platform for all Linux downstream tests.
Yun Pengdae5a7d2022-01-11 16:08:58 +0100620LINUX_BINARY_PLATFORM = "centos7_java11_devtoolset10"
Philipp Wollermannf4aabb72019-06-25 15:59:00 +0200621
Florian Weikertf11f2bf2023-01-31 19:11:52 +0100622# Maps major MacOS version numbers to the Xcode version that should be activated on that particular OS
Florian Weikert7fac1302023-05-17 11:57:52 +0200623DEFAULT_XCODE_VERSIONS_PER_OS = {12: ["13.0"], 13: ["14.2", "14.3"]}
Philipp Wollermann380f1e62019-04-12 16:45:27 +0200624XCODE_VERSION_REGEX = re.compile(r"^\d+\.\d+(\.\d+)?$")
Florian Weikertdb832a02020-11-19 19:14:48 +0100625XCODE_VERSION_OVERRIDES = {"10.2.1": "10.3", "11.2": "11.2.1", "11.3": "11.3.1"}
Philipp Wollermann380f1e62019-04-12 16:45:27 +0200626
Florian Weikertc8642af2019-02-03 23:58:51 +0100627BUILD_LABEL_PATTERN = re.compile(r"^Build label: (\S+)$", re.MULTILINE)
628
Florian Weikertde96a6f2019-03-07 14:57:50 +0100629BUILDIFIER_STEP_NAME = "Buildifier"
630
Florian Weikert5f5d3cb2019-04-15 15:36:27 +0200631SKIP_TASKS_ENV_VAR = "CI_SKIP_TASKS"
632
Florian Weikertecf091c2023-04-28 10:22:23 +0200633# TODO: change to USE_BAZEL_DIFF once the feature has been tested in QA
Florian Weikert7012a522023-05-04 16:49:40 +0200634USE_BAZEL_DIFF_ENV_VAR = "USE_BAZEL_DIFF"
635
Florian Weikert77d20062023-05-08 16:32:48 +0200636BAZEL_DIFF_ANNOTATION_CTX = "'diff'"
637
Florian Weikert7012a522023-05-04 16:49:40 +0200638# TODO(fweikert): Install bazel-diff on the Docker images and on the Mac machines
639BAZEL_DIFF_URL = (
640 "https://github.com/Tinder/bazel-diff/releases/download/4.5.0/bazel-diff_deploy.jar"
641)
Florian Weikertecf091c2023-04-28 10:22:23 +0200642
643AUTO_DIFFBASE_VALUES = frozenset(["1", "true", "auto"])
644
Florian Weikerte417f9f2023-05-05 17:33:46 +0200645# Always run all test targets if any of the paths here are modified by the current commit.
646# Values can be directory paths (with a trailing slash) or file paths.
647DISABLE_BAZEL_DIFF_IF_MODIFIED = (".bazelci/", ".bazelversion")
648
Florian Weikertecf091c2023-04-28 10:22:23 +0200649COMMIT_RE = re.compile(r"[0-9a-z]{40}")
650
Philipp Wollermannce986af2019-07-18 14:46:05 +0200651CONFIG_FILE_EXTENSIONS = {".yml", ".yaml"}
Florian Weikert778251c2019-04-25 15:14:44 +0200652
Chi Wang6357efe2020-08-25 16:23:38 +0800653KYTHE_DIR = "/usr/local/kythe"
654
655INDEX_UPLOAD_POLICY_ALWAYS = "Always"
656
657INDEX_UPLOAD_POLICY_IF_BUILD_SUCCESS = "IfBuildSuccess"
658
659INDEX_UPLOAD_POLICY_NEVER = "Never"
Florian Weikert13215a82019-05-10 12:42:21 +0200660
Yun Peng686f4592022-01-17 15:38:48 +0100661# The maximum number of tasks allowed in one pipeline yaml config file.
662# This is to prevent accidentally creating too many tasks with the martix testing feature.
Yun Peng68e8a4c2022-06-15 18:31:41 +0200663MAX_TASK_NUMBER = 80
Yun Peng686f4592022-01-17 15:38:48 +0100664
Florian Weikert8cba2be2023-07-12 17:39:56 +0200665LAB_AGENT_PATTERNS = [
666 re.compile(r"^bk-imacpro-\d+$"),
667 re.compile(r"^bk-(trusted|testing)-macpro-\d+$"),
668 re.compile(r"^bk-(trusted-)?macstudio-\d+$"),
669]
670
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
Florian Weikert8cba2be2023-07-12 17:39:56 +0200960def is_lab_machine():
961 agent = os.getenv("BUILDKITE_AGENT_NAME")
962 return any(p.match(agent) for p in LAB_AGENT_PATTERNS)
963
964
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100965def gsutil_command():
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200966 return "gsutil.cmd" if is_windows() else "gsutil"
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100967
Jakob Buchgrabere6de16b2018-02-28 12:42:12 +0100968
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100969def gcloud_command():
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200970 return "gcloud.cmd" if is_windows() else "gcloud"
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100971
Jakob Buchgrabere6de16b2018-02-28 12:42:12 +0100972
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100973def downstream_projects_root(platform):
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200974 downstream_root = os.path.expandvars(PLATFORMS[platform]["downstream-root"])
Philipp Wollermannd5ab3d92020-02-05 16:55:13 +0100975 if platform == "windows" and os.path.exists("d:/b"):
976 # If this is a Windows machine with a local SSD, the build directory is
977 # on drive D.
978 downstream_root = downstream_root.replace("c:/b/", "d:/b/")
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200979 if not os.path.exists(downstream_root):
980 os.makedirs(downstream_root)
981 return downstream_root
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100982
983
Yun Peng5a1a9442022-01-11 14:26:48 +0100984def match_matrix_attr_pattern(s):
985 return re.match("^\${{\s*(\w+)\s*}}$", s)
986
987
988def get_matrix_attributes(task):
989 """Get unexpanded matrix attributes from the given task.
990
991 If a value of field matches "${{<name>}}", then <name> is a wanted matrix attribute.
992 eg. platform: ${{ platform }}
993 """
994 attributes = []
995 for key, value in task.items():
996 if type(value) is str:
997 res = match_matrix_attr_pattern(value)
998 if res:
999 attributes.append(res.groups()[0])
1000 return list(set(attributes))
1001
1002
1003def get_combinations(matrix, attributes):
1004 """Given a matrix and the wanted attributes, return all possible combinations.
1005
1006 eg.
1007 With matrix = {'a': [1, 2], 'b': [1], 'c': [1]},
1008 if attributes = ['a', 'b'], then returns [[('a', 1), ('b', 1)], [('a', 2), ('b', 1)]]
1009 if attributes = ['b', 'c'], then returns [[('b', 1), ('c', 1)]]
1010 if attributes = ['c'], then returns [[('c', 1)]]
1011 """
Yun Peng2b59cde2023-05-08 15:44:38 +02001012 # Sort the attributes to make the output deterministic.
1013 attributes.sort()
Yun Peng5a1a9442022-01-11 14:26:48 +01001014 for attr in attributes:
1015 if attr not in matrix:
1016 raise BuildkiteException("${{ %s }} is not defined in `matrix` section." % attr)
1017 pairs = [[(attr, value) for value in matrix[attr]] for attr in attributes]
Yun Peng237309f2023-04-25 15:30:43 +02001018 return sorted(itertools.product(*pairs))
Yun Peng5a1a9442022-01-11 14:26:48 +01001019
1020
1021def get_expanded_task(task, combination):
1022 """Expand a task with the given combination of values of attributes."""
1023 combination = dict(combination)
1024 expanded_task = copy.deepcopy(task)
1025 for key, value in task.items():
1026 if type(value) is str:
1027 res = match_matrix_attr_pattern(value)
1028 if res:
1029 attr = res.groups()[0]
1030 expanded_task[key] = combination[attr]
1031 return expanded_task
1032
1033
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01001034def fetch_configs(http_url, file_config):
Philipp Wollermanndb024862018-02-19 17:16:56 +01001035 """
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01001036 If specified fetches the build configuration from file_config or http_url, else tries to
Jakob Buchgraber25bb50f2018-02-22 18:06:21 +01001037 read it from .bazelci/presubmit.yml.
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001038 Returns the json configuration as a python data structure.
Philipp Wollermanndb024862018-02-19 17:16:56 +01001039 """
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01001040 if file_config is not None and http_url is not None:
1041 raise BuildkiteException("file_config and http_url cannot be set at the same time")
1042
Florian Weikertc8b3ed22019-05-31 16:14:12 +02001043 return load_config(http_url, file_config)
1044
1045
Yun Pengfde48582022-01-11 14:37:47 +01001046def expand_task_config(config):
Yun Peng5a1a9442022-01-11 14:26:48 +01001047 # Expand tasks that uses attributes defined in the matrix section.
1048 # The original task definition expands to multiple tasks for each possible combination.
1049 tasks_to_expand = []
1050 expanded_tasks = {}
1051 matrix = config.pop("matrix", {})
1052 for key, value in matrix.items():
1053 if type(key) is not str or type(value) is not list:
1054 raise BuildkiteException("Expect `matrix` is a map of str -> list")
1055
1056 for task in config["tasks"]:
1057 attributes = get_matrix_attributes(config["tasks"][task])
1058 if attributes:
1059 tasks_to_expand.append(task)
1060 count = 1
1061 for combination in get_combinations(matrix, attributes):
1062 expanded_task_name = "%s_config_%.2d" % (task, count)
1063 count += 1
Florian Weikert7f21ca42022-02-02 17:35:23 +01001064 expanded_tasks[expanded_task_name] = get_expanded_task(
1065 config["tasks"][task], combination
1066 )
Yun Peng5a1a9442022-01-11 14:26:48 +01001067
1068 for task in tasks_to_expand:
1069 config["tasks"].pop(task)
1070 config["tasks"].update(expanded_tasks)
1071
Yun Pengfde48582022-01-11 14:37:47 +01001072
1073def load_config(http_url, file_config, allow_imports=True):
1074 if http_url:
1075 config = load_remote_yaml_file(http_url)
1076 else:
1077 file_config = file_config or ".bazelci/presubmit.yml"
1078 with open(file_config, "r") as fd:
1079 config = yaml.safe_load(fd)
1080
1081 # Legacy mode means that there is exactly one task per platform (e.g. ubuntu1604_nojdk),
1082 # which means that we can get away with using the platform name as task ID.
1083 # No other updates are needed since get_platform_for_task() falls back to using the
1084 # task ID as platform if there is no explicit "platforms" field.
1085 if "platforms" in config:
1086 config["tasks"] = config.pop("platforms")
1087
1088 if "tasks" not in config:
1089 config["tasks"] = {}
1090
1091 expand_task_config(config)
1092
Florian Weikertc8b3ed22019-05-31 16:14:12 +02001093 imports = config.pop("imports", None)
1094 if imports:
1095 if not allow_imports:
1096 raise BuildkiteException("Nested imports are not allowed")
1097
1098 for i in imports:
1099 imported_tasks = load_imported_tasks(i, http_url, file_config)
1100 config["tasks"].update(imported_tasks)
1101
Yun Peng686f4592022-01-17 15:38:48 +01001102 if len(config["tasks"]) > MAX_TASK_NUMBER:
Florian Weikert7f21ca42022-02-02 17:35:23 +01001103 raise BuildkiteException(
1104 "The number of tasks in one config file is limited to %s!" % MAX_TASK_NUMBER
1105 )
Yun Peng686f4592022-01-17 15:38:48 +01001106
Florian Weikert843d7a02019-02-03 17:24:50 +01001107 return config
1108
1109
Florian Weikert13215a82019-05-10 12:42:21 +02001110def load_remote_yaml_file(http_url):
1111 with urllib.request.urlopen(http_url) as resp:
1112 reader = codecs.getreader("utf-8")
Philipp Wollermannd00107e2019-05-18 23:50:59 +02001113 return yaml.safe_load(reader(resp))
Florian Weikert13215a82019-05-10 12:42:21 +02001114
1115
Florian Weikertc8b3ed22019-05-31 16:14:12 +02001116def load_imported_tasks(import_name, http_url, file_config):
1117 if "/" in import_name:
1118 raise BuildkiteException("Invalid import '%s'" % import_name)
1119
1120 old_path = http_url or file_config
1121 new_path = "%s%s" % (old_path[: old_path.rfind("/") + 1], import_name)
1122 if http_url:
1123 http_url = new_path
1124 else:
1125 file_config = new_path
1126
1127 imported_config = load_config(http_url=http_url, file_config=file_config, allow_imports=False)
1128
1129 namespace = import_name.partition(".")[0]
1130 tasks = {}
1131 for task_name, task_config in imported_config["tasks"].items():
Florian Weikert61f29b82019-08-12 16:56:56 +02001132 fix_imported_task_platform(task_name, task_config)
1133 fix_imported_task_name(namespace, task_config)
1134 fix_imported_task_working_directory(namespace, task_config)
Florian Weikertc8b3ed22019-05-31 16:14:12 +02001135 tasks["%s_%s" % (namespace, task_name)] = task_config
1136
1137 return tasks
1138
1139
Florian Weikert61f29b82019-08-12 16:56:56 +02001140def fix_imported_task_platform(task_name, task_config):
1141 if "platform" not in task_config:
1142 task_config["platform"] = task_name
1143
1144
1145def fix_imported_task_name(namespace, task_config):
1146 old_name = task_config.get("name")
1147 task_config["name"] = "%s (%s)" % (namespace, old_name) if old_name else namespace
1148
1149
1150def fix_imported_task_working_directory(namespace, task_config):
1151 old_dir = task_config.get("working_directory")
1152 task_config["working_directory"] = os.path.join(namespace, old_dir) if old_dir else namespace
1153
1154
Jakob Buchgraber3120f7a2018-02-18 13:28:02 +01001155def print_collapsed_group(name):
Jakob Buchgraber5c9b13d2018-02-21 22:28:14 +01001156 eprint("\n\n--- {0}\n\n".format(name))
Jakob Buchgraber3120f7a2018-02-18 13:28:02 +01001157
Jakob Buchgraber9c83de72018-02-18 15:32:44 +01001158
Jakob Buchgraber3120f7a2018-02-18 13:28:02 +01001159def print_expanded_group(name):
Jakob Buchgraber5c9b13d2018-02-21 22:28:14 +01001160 eprint("\n\n+++ {0}\n\n".format(name))
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001161
Yun Peng9b1d3432021-12-07 10:40:45 +01001162
Philipp Wollermannc8b86ac2021-10-25 17:52:07 +02001163def is_trueish(s):
1164 return str(s).lower() in ["true", "1", "t", "y", "yes"]
1165
Jakob Buchgraber9c83de72018-02-18 15:32:44 +01001166
Yun Peng8975c6b2019-02-28 11:55:55 +01001167def use_bazelisk_migrate():
1168 """
1169 If USE_BAZELISK_MIGRATE is set, we use `bazelisk --migrate` to test incompatible flags.
1170 """
Philipp Wollermannc8b86ac2021-10-25 17:52:07 +02001171 return is_trueish(os.environ.get("USE_BAZELISK_MIGRATE"))
Yun Peng8975c6b2019-02-28 11:55:55 +01001172
1173
1174def bazelisk_flags():
1175 return ["--migrate"] if use_bazelisk_migrate() else []
1176
1177
Chi Wang54595a22021-06-11 17:49:58 +08001178def calculate_flags(task_config, task_config_key, action_key, tmpdir, test_env_vars):
Chi Wang6357efe2020-08-25 16:23:38 +08001179 include_json_profile = task_config.get("include_json_profile", [])
Chi Wang54595a22021-06-11 17:49:58 +08001180 capture_corrupted_outputs = task_config.get("capture_corrupted_outputs", [])
Chi Wang6357efe2020-08-25 16:23:38 +08001181
1182 json_profile_flags = []
1183 json_profile_out = None
Chi Wang54595a22021-06-11 17:49:58 +08001184 if action_key in include_json_profile:
1185 json_profile_out = os.path.join(tmpdir, "{}.profile.gz".format(action_key))
Tobias Werthc22e4c42021-10-08 12:03:14 +02001186 json_profile_flags = ["--profile={}".format(json_profile_out)]
1187
Chi Wang54595a22021-06-11 17:49:58 +08001188 capture_corrupted_outputs_flags = []
1189 capture_corrupted_outputs_dir = None
1190 if action_key in capture_corrupted_outputs:
Philipp Wollermannf436e742021-08-11 11:06:55 +02001191 capture_corrupted_outputs_dir = os.path.join(
1192 tmpdir, "{}_corrupted_outputs".format(action_key)
1193 )
1194 capture_corrupted_outputs_flags = [
1195 "--experimental_remote_capture_corrupted_outputs={}".format(
1196 capture_corrupted_outputs_dir
1197 )
1198 ]
Chi Wang6357efe2020-08-25 16:23:38 +08001199
Alexandre Rostovtsev42bbeb52023-08-24 04:08:04 -04001200 flags = list(task_config.get(task_config_key, []))
Chi Wang6357efe2020-08-25 16:23:38 +08001201 flags += json_profile_flags
Chi Wang54595a22021-06-11 17:49:58 +08001202 flags += capture_corrupted_outputs_flags
Chi Wang6357efe2020-08-25 16:23:38 +08001203 # We have to add --test_env flags to `build`, too, otherwise Bazel
1204 # discards its analysis cache between `build` and `test`.
1205 if test_env_vars:
1206 flags += ["--test_env={}".format(v) for v in test_env_vars]
1207
Chi Wang54595a22021-06-11 17:49:58 +08001208 return flags, json_profile_out, capture_corrupted_outputs_dir
Chi Wang6357efe2020-08-25 16:23:38 +08001209
1210
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001211def execute_commands(
Florian Weikertc8642af2019-02-03 23:58:51 +01001212 task_config,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001213 platform,
1214 git_repository,
1215 git_commit,
Yun Peng5012a862021-09-16 16:35:43 +02001216 repo_location,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001217 use_bazel_at_commit,
1218 use_but,
1219 save_but,
Yun Peng4d1d6542019-01-17 18:30:33 +01001220 needs_clean,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001221 build_only,
1222 test_only,
1223 monitor_flaky_tests,
Florian Weikertc8642af2019-02-03 23:58:51 +01001224 bazel_version=None,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001225):
Yun Pengc85cd0e2022-09-02 10:44:29 +02001226 if use_bazelisk_migrate():
1227 # If we are testing incompatible flags with Bazelisk,
1228 # use Bazel@last_green if USE_BAZEL_VERSION env var is not set explicitly.
1229 if "USE_BAZEL_VERSION" not in os.environ:
1230 bazel_version = "last_green"
1231
1232 # Override use_but in case we are in the downstream pipeline so that it doesn't try to
1233 # download Bazel built from previous jobs.
1234 use_but = False
1235
1236 # Set BAZELISK_INCOMPATIBLE_FLAGS to tell Bazelisk which flags to test.
1237 os.environ["BAZELISK_INCOMPATIBLE_FLAGS"] = ",".join(fetch_incompatible_flags().keys())
1238
Florian Weikert13215a82019-05-10 12:42:21 +02001239 if not bazel_version:
1240 # The last good version of Bazel can be specified in an emergency file.
1241 # However, we only use last_good_bazel for pipelines that do not
1242 # explicitly specify a version of Bazel.
1243 try:
1244 emergency_settings = load_remote_yaml_file(EMERGENCY_FILE_URL)
1245 bazel_version = emergency_settings.get("last_good_bazel")
1246 except urllib.error.HTTPError:
1247 # Ignore this error. The Setup step will have already complained about
1248 # it by showing an error message.
1249 pass
Yun Pengf50f7b72019-02-28 19:09:52 +01001250
Jakob Buchgraberfb95a2f2018-02-22 11:46:25 +01001251 if build_only and test_only:
1252 raise BuildkiteException("build_only and test_only cannot be true at the same time")
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001253
Florian Weikertd7cb83d2023-02-24 19:51:52 +01001254 if use_but:
1255 if use_bazel_at_commit:
1256 raise BuildkiteException("use_bazel_at_commit cannot be set when use_but is true")
1257
1258 print_collapsed_group(":printer: Printing task config for downstream job...")
Florian Weikert7d894782023-02-24 20:28:14 +01001259 eprint(json.dumps(task_config, indent=2))
Yun Peng20d45602018-10-18 13:27:05 +02001260
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001261 tmpdir = tempfile.mkdtemp()
1262 sc_process = None
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001263 try:
Florian Weikertda94a102022-10-21 12:24:37 +02001264 if is_mac():
Florian Weikertee84c5c2019-05-28 11:21:51 +02001265 activate_xcode(task_config)
Philipp Wollermann380f1e62019-04-12 16:45:27 +02001266
Florian Weikert4ee0bed2019-02-21 18:03:00 +01001267 # If the CI worker runs Bazelisk, we need to forward all required env variables to the test.
1268 # Otherwise any integration test that invokes Bazel (=Bazelisk in this case) will fail.
Marcel Hlopko198328b2019-02-25 09:19:55 +01001269 test_env_vars = ["LocalAppData"] if platform == "windows" else ["HOME"]
Florian Weikertc12580c2021-07-13 17:09:25 +02001270
1271 # CI should have its own user agent so that we can remove it from Bazel download statistics.
1272 os.environ["BAZELISK_USER_AGENT"] = "Bazelisk/BazelCI"
1273 test_env_vars.append("BAZELISK_USER_AGENT")
1274
Yun Peng5012a862021-09-16 16:35:43 +02001275 if repo_location:
1276 os.chdir(repo_location)
Yun Peng376d2b32018-11-29 10:24:54 +01001277 elif git_repository:
1278 clone_git_repository(git_repository, platform, git_commit)
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001279
Philipp Wollermannf4aabb72019-06-25 15:59:00 +02001280 # We use one binary for all Linux platforms (because we also just release one binary for all
1281 # Linux versions and we have to ensure that it works on all of them).
Florian Weikertda94a102022-10-21 12:24:37 +02001282 binary_platform = platform if is_mac() or is_windows() else LINUX_BINARY_PLATFORM
Philipp Wollermannf4aabb72019-06-25 15:59:00 +02001283
Yun Pengeec2cd92022-07-14 14:44:30 +02001284 bazel_binary = "bazel"
Yun Peng20d45602018-10-18 13:27:05 +02001285 if use_bazel_at_commit:
1286 print_collapsed_group(":gcloud: Downloading Bazel built at " + use_bazel_at_commit)
Yun Pengdae5a7d2022-01-11 16:08:58 +01001287 # Linux binaries are published under platform name "centos7"
1288 if binary_platform == LINUX_BINARY_PLATFORM:
1289 binary_platform = "centos7"
Yun Pengeec2cd92022-07-14 14:44:30 +02001290 os.environ["USE_BAZEL_VERSION"] = download_bazel_binary_at_commit(
Philipp Wollermannf4aabb72019-06-25 15:59:00 +02001291 tmpdir, binary_platform, use_bazel_at_commit
1292 )
Yun Pengeec2cd92022-07-14 14:44:30 +02001293 print_collapsed_group(":bazel: Using Bazel at " + os.environ["USE_BAZEL_VERSION"])
Philipp Wollermann639c0452019-01-03 11:23:54 +01001294 elif use_but:
Jakob Buchgraber92755d72018-02-22 15:33:37 +01001295 print_collapsed_group(":gcloud: Downloading Bazel Under Test")
Yun Pengeec2cd92022-07-14 14:44:30 +02001296 os.environ["USE_BAZEL_VERSION"] = download_bazel_binary(tmpdir, binary_platform)
1297 print_collapsed_group(":bazel: Using Bazel at " + os.environ["USE_BAZEL_VERSION"])
Philipp Wollermann639c0452019-01-03 11:23:54 +01001298 else:
Yun Pengeec2cd92022-07-14 14:44:30 +02001299 print_collapsed_group(":bazel: Using Bazel version " + bazel_version)
Florian Weikertc8642af2019-02-03 23:58:51 +01001300 if bazel_version:
Florian Weikertc8642af2019-02-03 23:58:51 +01001301 os.environ["USE_BAZEL_VERSION"] = bazel_version
Philipp Wollermann87b45252020-01-22 12:43:42 +01001302 if "USE_BAZEL_VERSION" in os.environ and not task_config.get(
1303 "skip_use_bazel_version_for_test", False
1304 ):
Yun Pengf0a66e22019-10-14 12:45:42 +02001305 # This will only work if the bazel binary in $PATH is actually a bazelisk binary
1306 # (https://github.com/bazelbuild/bazelisk).
1307 test_env_vars.append("USE_BAZEL_VERSION")
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001308
Philipp Wollermann5c7ea412019-05-24 15:26:57 +02001309 for key, value in task_config.get("environment", {}).items():
Philipp Wollermann4ad4aac2019-05-24 15:23:09 +02001310 # We have to explicitly convert the value to a string, because sometimes YAML tries to
1311 # be smart and converts strings like "true" and "false" to booleans.
Philipp Wollermann7df2d0d2021-08-11 13:26:04 +02001312 os.environ[key] = os.path.expandvars(str(value))
Philipp Wollermann213ac9d2019-02-06 11:50:05 +01001313
Yun Peng366f04c2020-08-10 16:55:58 +02001314 # Set BAZELISK_SHUTDOWN to 1 when we use bazelisk --migrate on Windows.
1315 # This is a workaround for https://github.com/bazelbuild/continuous-integration/issues/1012
1316 if use_bazelisk_migrate() and platform == "windows":
1317 os.environ["BAZELISK_SHUTDOWN"] = "1"
1318
Florian Weikert9b805ce2023-05-10 18:04:03 +02001319 def PrepareRepoInCwd(print_cmd_groups, initial_setup=False):
Florian Weikert5e70d9d2023-05-08 19:20:23 +02001320 # Allow the config to override the current working directory.
1321 requested_working_dir = task_config.get("working_directory")
1322 if requested_working_dir:
1323 if os.path.isabs(requested_working_dir):
1324 raise BuildkiteException(
1325 f"working_directory must be relative to the repository root, "
1326 "but was {requested_working_dir}"
1327 )
1328
1329 full_requested_working_dir = os.path.abspath(requested_working_dir)
1330 if not os.path.isdir(full_requested_working_dir):
1331 raise BuildkiteException(
1332 f"{full_requested_working_dir} does not exist or is not a directory"
1333 )
1334
1335 os.chdir(full_requested_working_dir)
1336
Florian Weikertb97801e2023-05-10 19:17:08 +02001337 # Dirty workaround for #1660
1338 if initial_setup:
1339 # Set OUTPUT_BASE environment variable
1340 os.environ["OUTPUT_BASE"] = get_output_base(bazel_binary)
Florian Weikert9b805ce2023-05-10 18:04:03 +02001341
Florian Weikertb97801e2023-05-10 19:17:08 +02001342 cmd_exec_func = (
1343 execute_batch_commands if platform == "windows" else execute_shell_commands
1344 )
1345 cmd_exec_func(task_config.get("setup", None))
Yun Peng28a9a532023-05-10 14:19:46 +02001346
Florian Weikert5e70d9d2023-05-08 19:20:23 +02001347 if platform == "windows":
Florian Weikert4141ce92023-05-09 09:45:55 +02001348 execute_batch_commands(task_config.get("batch_commands", None), print_cmd_groups)
Florian Weikert5e70d9d2023-05-08 19:20:23 +02001349 else:
Florian Weikert4141ce92023-05-09 09:45:55 +02001350 execute_shell_commands(task_config.get("shell_commands", None), print_cmd_groups)
Florian Weikert5e70d9d2023-05-08 19:20:23 +02001351
Florian Weikert9b805ce2023-05-10 18:04:03 +02001352 PrepareRepoInCwd(True, initial_setup=True)
Florian Weikerte72d68a2019-03-08 18:56:33 +01001353
Florian Weikertc8642af2019-02-03 23:58:51 +01001354 bazel_version = print_bazel_version_info(bazel_binary, platform)
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001355
Yun Penga5a1ee02018-12-05 15:00:58 +01001356 print_environment_variables_info()
1357
Yun Pengc85cd0e2022-09-02 10:44:29 +02001358 execute_bazel_run(bazel_binary, platform, task_config.get("run_targets", None))
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001359
Yun Peng4d1d6542019-01-17 18:30:33 +01001360 if needs_clean:
Yun Pengea0359e2019-01-17 15:37:47 +01001361 execute_bazel_clean(bazel_binary, platform)
1362
Florian Weikert25e92c42023-04-28 10:56:46 +02001363 # The git_commit paramter only has a value in the downstream pipeline,
1364 # but we need the commit here in order to calculate the correct targets.
1365 git_commit = git_commit or os.getenv("BUILDKITE_COMMIT")
1366 if not git_commit:
1367 raise BuildkiteInfraException("Unable to determine Git commit for this build")
1368
Florian Weikert7dd9f662023-05-04 15:05:42 +02001369 test_flags, json_profile_out_test, capture_corrupted_outputs_dir_test = calculate_flags(
1370 task_config, "test_flags", "test", tmpdir, test_env_vars
1371 )
1372
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01001373 build_targets, test_targets, coverage_targets, index_targets = calculate_targets(
Florian Weikert7dd9f662023-05-04 15:05:42 +02001374 task_config,
1375 bazel_binary,
1376 build_only,
1377 test_only,
Florian Weikert5e70d9d2023-05-08 19:20:23 +02001378 os.getcwd(),
1379 PrepareRepoInCwd,
Florian Weikert7dd9f662023-05-04 15:05:42 +02001380 git_commit,
1381 test_flags,
Florian Weikert736d06e2019-05-08 13:16:42 +02001382 )
Florian Weikert736d06e2019-05-08 13:16:42 +02001383
1384 if build_targets:
Philipp Wollermannf436e742021-08-11 11:06:55 +02001385 (
1386 build_flags,
1387 json_profile_out_build,
1388 capture_corrupted_outputs_dir_build,
1389 ) = calculate_flags(task_config, "build_flags", "build", tmpdir, test_env_vars)
joeleba76887952019-05-16 15:22:17 +02001390 try:
Yun Pengc8bb9e92021-07-28 11:56:53 +02001391 release_name = get_release_name_from_branch_name()
joeleba76887952019-05-16 15:22:17 +02001392 execute_bazel_build(
1393 bazel_version,
1394 bazel_binary,
1395 platform,
Philipp Wollermannf436e742021-08-11 11:06:55 +02001396 build_flags
1397 + (
1398 ["--stamp", "--embed_label=%s" % release_name]
1399 if save_but and release_name
1400 else []
1401 ),
joeleba76887952019-05-16 15:22:17 +02001402 build_targets,
1403 None,
joeleba76887952019-05-16 15:22:17 +02001404 )
1405 if save_but:
1406 upload_bazel_binary(platform)
1407 finally:
Chi Wang6357efe2020-08-25 16:23:38 +08001408 if json_profile_out_build:
Philipp Wollermann92cf51e2019-05-16 15:31:11 +02001409 upload_json_profile(json_profile_out_build, tmpdir)
Chi Wang54595a22021-06-11 17:49:58 +08001410 if capture_corrupted_outputs_dir_build:
1411 upload_corrupted_outputs(capture_corrupted_outputs_dir_build, tmpdir)
Philipp Wollermann639c0452019-01-03 11:23:54 +01001412
Florian Weikert736d06e2019-05-08 13:16:42 +02001413 if test_targets:
Florian Weikert4901c662019-02-26 13:20:11 +01001414 if not is_windows():
1415 # On platforms that support sandboxing (Linux, MacOS) we have
1416 # to allow access to Bazelisk's cache directory.
1417 # However, the flag requires the directory to exist,
1418 # so we create it here in order to not crash when a test
1419 # does not invoke Bazelisk.
Florian Weikertda94a102022-10-21 12:24:37 +02001420 bazelisk_cache_dir = get_bazelisk_cache_directory()
Florian Weikert4901c662019-02-26 13:20:11 +01001421 os.makedirs(bazelisk_cache_dir, mode=0o755, exist_ok=True)
1422 test_flags.append("--sandbox_writable_path={}".format(bazelisk_cache_dir))
Florian Weikert5b890332019-02-25 14:57:43 +01001423
Chi Wang5e3998f2023-05-10 11:51:02 +00001424 # Set BUILDKITE_ANALYTICS_TOKEN so that bazelci-agent can upload test results to Test Analytics
1425 if "ENCRYPTED_BUILDKITE_ANALYTICS_TOKEN" in os.environ:
1426 if THIS_IS_TESTING:
1427 kms_key = "buildkite-testing-api-token"
1428 project = "bazel-untrusted"
1429 elif THIS_IS_TRUSTED:
1430 kms_key = "buildkite-trusted-api-token"
1431 project = "bazel-public"
1432 else:
1433 kms_key = "buildkite-untrusted-api-token"
1434 project = "bazel-untrusted"
1435 os.environ["BUILDKITE_ANALYTICS_TOKEN"] = decrypt_token(
1436 encrypted_token=os.environ["ENCRYPTED_BUILDKITE_ANALYTICS_TOKEN"],
1437 kms_key=kms_key,
1438 project=project,
1439 )
1440
Philipp Wollermannce986af2019-07-18 14:46:05 +02001441 test_bep_file = os.path.join(tmpdir, "test_bep.json")
Philipp Wollermannce986af2019-07-18 14:46:05 +02001442 upload_thread = threading.Thread(
Florian Weikert7f21ca42022-02-02 17:35:23 +01001443 target=upload_test_logs_from_bep,
Florian Weikertda94a102022-10-21 12:24:37 +02001444 args=(test_bep_file, tmpdir, monitor_flaky_tests),
Philipp Wollermannce986af2019-07-18 14:46:05 +02001445 )
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001446 try:
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001447 upload_thread.start()
1448 try:
1449 execute_bazel_test(
1450 bazel_version,
1451 bazel_binary,
1452 platform,
1453 test_flags,
1454 test_targets,
1455 test_bep_file,
1456 monitor_flaky_tests,
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001457 )
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001458 finally:
Chi Wang6357efe2020-08-25 16:23:38 +08001459 if json_profile_out_test:
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001460 upload_json_profile(json_profile_out_test, tmpdir)
Chi Wang54595a22021-06-11 17:49:58 +08001461 if capture_corrupted_outputs_dir_test:
1462 upload_corrupted_outputs(capture_corrupted_outputs_dir_test, tmpdir)
Philipp Wollermann639c0452019-01-03 11:23:54 +01001463 finally:
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001464 upload_thread.join()
Chi Wang6357efe2020-08-25 16:23:38 +08001465
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01001466 if coverage_targets:
Florian Weikert7f21ca42022-02-02 17:35:23 +01001467 (
1468 coverage_flags,
1469 json_profile_out_coverage,
1470 capture_corrupted_outputs_dir_coverage,
1471 ) = calculate_flags(task_config, "coverage_flags", "coverage", tmpdir, test_env_vars)
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01001472 try:
1473 execute_bazel_coverage(
1474 bazel_version,
1475 bazel_binary,
1476 platform,
1477 coverage_flags,
1478 coverage_targets,
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01001479 )
1480 finally:
1481 if json_profile_out_coverage:
1482 upload_json_profile(json_profile_out_coverage, tmpdir)
1483 if capture_corrupted_outputs_dir_coverage:
1484 upload_corrupted_outputs(capture_corrupted_outputs_dir_coverage, tmpdir)
1485
Chi Wang6357efe2020-08-25 16:23:38 +08001486 if index_targets:
Philipp Wollermannf436e742021-08-11 11:06:55 +02001487 (
1488 index_flags,
1489 json_profile_out_index,
1490 capture_corrupted_outputs_dir_index,
1491 ) = calculate_flags(task_config, "index_flags", "index", tmpdir, test_env_vars)
Chi Wang6357efe2020-08-25 16:23:38 +08001492 index_upload_policy = task_config.get("index_upload_policy", "IfBuildSuccess")
Chi Wangb2b65682020-08-27 10:36:15 +08001493 index_upload_gcs = task_config.get("index_upload_gcs", False)
Chi Wang6357efe2020-08-25 16:23:38 +08001494
1495 try:
Florian Weikertdb832a02020-11-19 19:14:48 +01001496 should_upload_kzip = (
1497 True if index_upload_policy == INDEX_UPLOAD_POLICY_ALWAYS else False
1498 )
Chi Wang6357efe2020-08-25 16:23:38 +08001499 try:
1500 execute_bazel_build_with_kythe(
1501 bazel_version,
1502 bazel_binary,
1503 platform,
1504 index_flags,
1505 index_targets,
1506 None,
Chi Wang6357efe2020-08-25 16:23:38 +08001507 )
1508
1509 if index_upload_policy == INDEX_UPLOAD_POLICY_IF_BUILD_SUCCESS:
1510 should_upload_kzip = True
1511 except subprocess.CalledProcessError as e:
1512 # If not running with Always policy, raise the build error.
1513 if index_upload_policy != INDEX_UPLOAD_POLICY_ALWAYS:
1514 handle_bazel_failure(e, "build")
1515
Philipp Wollermanna038b002021-05-05 22:04:38 +02001516 if should_upload_kzip and not is_pull_request():
Chi Wang6357efe2020-08-25 16:23:38 +08001517 try:
Chi Wangb2b65682020-08-27 10:36:15 +08001518 merge_and_upload_kythe_kzip(platform, index_upload_gcs)
Chi Wang6357efe2020-08-25 16:23:38 +08001519 except subprocess.CalledProcessError:
1520 raise BuildkiteException("Failed to upload kythe kzip")
1521 finally:
1522 if json_profile_out_index:
1523 upload_json_profile(json_profile_out_index, tmpdir)
Chi Wang54595a22021-06-11 17:49:58 +08001524 if capture_corrupted_outputs_dir_index:
1525 upload_corrupted_outputs(capture_corrupted_outputs_dir_index, tmpdir)
Chi Wang6357efe2020-08-25 16:23:38 +08001526
UebelAndre2e56c362023-06-13 04:38:15 -07001527 if platform == "windows":
1528 execute_batch_commands(task_config.get("post_batch_commands", None), True, ":batch: Post Processing (Batch Commands)")
1529 else:
1530 execute_shell_commands(task_config.get("post_shell_commands", None), True, ":bash: Post Processing (Shell Commands)")
1531
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001532 finally:
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001533 terminate_background_process(sc_process)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001534 if tmpdir:
1535 shutil.rmtree(tmpdir)
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001536
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02001537
Florian Weikertcee5d1d2023-05-17 00:23:03 +02001538def get_default_xcode_versions():
Florian Weikert9e342592023-02-07 16:32:36 +01001539 # Cannot use platform.mac_ver() since it returns 10.16 on both 12.x and 13.x
1540 macos = execute_command_and_get_output(["sw_vers", "-productVersion"], print_output=False)
Florian Weikertf11f2bf2023-01-31 19:11:52 +01001541 major = int(macos.split(".")[0])
Florian Weikertcee5d1d2023-05-17 00:23:03 +02001542 return DEFAULT_XCODE_VERSIONS_PER_OS.get(major, ["13.0"]) # we use 13.0 due to legacy reasons
Florian Weikertf11f2bf2023-01-31 19:11:52 +01001543
Florian Weikertecf091c2023-04-28 10:22:23 +02001544
Florian Weikertee84c5c2019-05-28 11:21:51 +02001545def activate_xcode(task_config):
Florian Weikertcee5d1d2023-05-17 00:23:03 +02001546 all_default_xcode_versions = get_default_xcode_versions()
1547 supported_versions = sorted(
1548 # Stripping "Xcode" prefix and ".app" suffix from e.g. "Xcode12.0.1.app" leaves just the version number.
1549 [os.path.basename(x)[5:-4] for x in glob("/Applications/Xcode*.app")],
1550 reverse=True,
1551 )
1552
1553 default_xcode_version = "13.0"
1554 for v in all_default_xcode_versions:
1555 if v in supported_versions:
1556 default_xcode_version = v
1557 break
Florian Weikertf11f2bf2023-01-31 19:11:52 +01001558
Florian Weikertee84c5c2019-05-28 11:21:51 +02001559 # Get the Xcode version from the config.
Florian Weikertf11f2bf2023-01-31 19:11:52 +01001560 wanted_xcode_version = task_config.get("xcode_version", default_xcode_version)
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001561 print_collapsed_group(":xcode: Activating Xcode {}...".format(wanted_xcode_version))
Florian Weikertee84c5c2019-05-28 11:21:51 +02001562
1563 # Ensure it's a valid version number.
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001564 if not isinstance(wanted_xcode_version, str):
Florian Weikertee84c5c2019-05-28 11:21:51 +02001565 raise BuildkiteException(
1566 "Version number '{}' is not a string. Did you forget to put it in quotes?".format(
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001567 wanted_xcode_version
Florian Weikertee84c5c2019-05-28 11:21:51 +02001568 )
1569 )
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001570 if not XCODE_VERSION_REGEX.match(wanted_xcode_version):
Florian Weikertee84c5c2019-05-28 11:21:51 +02001571 raise BuildkiteException(
1572 "Invalid Xcode version format '{}', must match the format X.Y[.Z].".format(
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001573 wanted_xcode_version
Florian Weikertee84c5c2019-05-28 11:21:51 +02001574 )
1575 )
1576
Philipp Wollermann06e56972020-01-29 14:46:41 +01001577 # 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 +01001578 xcode_version = XCODE_VERSION_OVERRIDES.get(wanted_xcode_version, wanted_xcode_version)
1579
1580 # This falls back to a default version if the selected version is not available.
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001581 if xcode_version not in supported_versions:
Florian Weikertf11f2bf2023-01-31 19:11:52 +01001582 xcode_version = default_xcode_version
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001583 if xcode_version != wanted_xcode_version:
1584 print_collapsed_group(
1585 ":xcode: Fixed Xcode version: {} -> {}...".format(wanted_xcode_version, xcode_version)
1586 )
1587 lines = [
Florian Weikert9d5e4c02021-05-27 15:10:20 +02001588 "Your selected Xcode version {} was not available on the machine.".format(
1589 wanted_xcode_version
1590 ),
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001591 "Bazel CI automatically picked a fallback version: {}.".format(xcode_version),
1592 "Available versions are: {}.".format(supported_versions),
1593 ]
Florian Weikert9d5e4c02021-05-27 15:10:20 +02001594 execute_command(
1595 [
1596 "buildkite-agent",
1597 "annotate",
1598 "--style=warning",
1599 "\n".join(lines),
1600 "--context",
1601 "ctx-xcode_version_fixed",
1602 ]
1603 )
Philipp Wollermann06e56972020-01-29 14:46:41 +01001604
Florian Weikertee84c5c2019-05-28 11:21:51 +02001605 # Check that the selected Xcode version is actually installed on the host.
1606 xcode_path = "/Applications/Xcode{}.app".format(xcode_version)
1607 if not os.path.exists(xcode_path):
1608 raise BuildkiteException("Xcode not found at '{}'.".format(xcode_path))
1609
1610 # Now activate the specified Xcode version and let it install its required components.
1611 # The CI machines have a sudoers config that allows the 'buildkite' user to run exactly
1612 # these two commands, so don't change them without also modifying the file there.
1613 execute_command(["/usr/bin/sudo", "/usr/bin/xcode-select", "--switch", xcode_path])
1614 execute_command(["/usr/bin/sudo", "/usr/bin/xcodebuild", "-runFirstLaunch"])
1615
1616
Florian Weikertda94a102022-10-21 12:24:37 +02001617def get_bazelisk_cache_directory():
Florian Weikert4901c662019-02-26 13:20:11 +01001618 # The path relies on the behavior of Go's os.UserCacheDir()
1619 # and of the Go version of Bazelisk.
Florian Weikertda94a102022-10-21 12:24:37 +02001620 cache_dir = "Library/Caches" if is_mac() else ".cache"
Philipp Wollermannce986af2019-07-18 14:46:05 +02001621 return os.path.join(os.environ.get("HOME"), cache_dir, "bazelisk")
Florian Weikert4901c662019-02-26 13:20:11 +01001622
Florian Weikert5b890332019-02-25 14:57:43 +01001623
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02001624def current_branch_is_main_branch():
Mai Hussien0731b4d2022-06-28 11:16:07 -07001625 return os.getenv("BUILDKITE_BRANCH") in ("master", "stable", "main", "google")
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02001626
1627
Yun Peng92c0ef82021-07-26 10:41:21 +02001628def get_release_name_from_branch_name():
Yun Peng98948362022-11-08 16:14:20 +01001629 # TODO(pcloudy): Find a better way to do this
1630 if os.getenv("BUILDKITE_PIPELINE_SLUG") == "publish-bazel-binaries":
1631 return None
Yun Peng26e01ff2021-07-26 12:05:53 +02001632 res = re.match(r"release-(\d+\.\d+\.\d+(rc\d+)?).*", os.getenv("BUILDKITE_BRANCH"))
Yun Peng98948362022-11-08 16:14:20 +01001633 return res.group(1) if res else None
Yun Peng92c0ef82021-07-26 10:41:21 +02001634
1635
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001636def is_pull_request():
Jakob Buchgraber67761d32018-02-21 19:00:21 +01001637 third_party_repo = os.getenv("BUILDKITE_PULL_REQUEST_REPO", "")
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001638 return len(third_party_repo) > 0
1639
1640
Yun Penge3cf12d2018-12-05 15:01:09 +01001641def print_bazel_version_info(bazel_binary, platform):
Jakob Buchgraber99c4bbb2018-02-22 11:59:31 +01001642 print_collapsed_group(":information_source: Bazel Info")
Philipp Wollermannf13804b2019-02-05 21:08:30 +01001643 version_output = execute_command_and_get_output(
Florian Weikertb3439b32022-11-09 11:05:16 +01001644 [bazel_binary] + common_startup_flags() + ["--nosystem_rc", "--nohome_rc", "version"]
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001645 )
1646 execute_command(
Florian Weikertb3439b32022-11-09 11:05:16 +01001647 [bazel_binary] + common_startup_flags() + ["--nosystem_rc", "--nohome_rc", "info"]
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001648 )
Jakob Buchgraber7e690a72018-02-18 13:22:15 +01001649
Florian Weikertc8642af2019-02-03 23:58:51 +01001650 match = BUILD_LABEL_PATTERN.search(version_output)
1651 return match.group(1) if match else "unreleased binary"
1652
Jakob Buchgraber7e690a72018-02-18 13:22:15 +01001653
Yun Penga5a1ee02018-12-05 15:00:58 +01001654def print_environment_variables_info():
1655 print_collapsed_group(":information_source: Environment Variables")
1656 for key, value in os.environ.items():
1657 eprint("%s=(%s)" % (key, value))
1658
1659
Jakob Buchgraber426399e2018-03-20 19:45:46 +01001660def upload_bazel_binary(platform):
Jakob Buchgraber7d1d3bb2018-02-21 22:38:22 +01001661 print_collapsed_group(":gcloud: Uploading Bazel Under Test")
Jakob Buchgraber426399e2018-03-20 19:45:46 +01001662 if platform == "windows":
Philipp Wollermann10183212020-02-04 21:54:14 +01001663 binary_dir = r"bazel-bin\src"
1664 binary_name = r"bazel.exe"
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001665 binary_nojdk_name = r"bazel_nojdk.exe"
Philipp Wollermann10183212020-02-04 21:54:14 +01001666 else:
1667 binary_dir = "bazel-bin/src"
1668 binary_name = "bazel"
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001669 binary_nojdk_name = "bazel_nojdk"
Philipp Wollermann10183212020-02-04 21:54:14 +01001670 execute_command(["buildkite-agent", "artifact", "upload", binary_name], cwd=binary_dir)
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001671 execute_command(["buildkite-agent", "artifact", "upload", binary_nojdk_name], cwd=binary_dir)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001672
1673
Chi Wangb2b65682020-08-27 10:36:15 +08001674def merge_and_upload_kythe_kzip(platform, index_upload_gcs):
Chi Wang6357efe2020-08-25 16:23:38 +08001675 print_collapsed_group(":gcloud: Uploading kythe kzip")
1676
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001677 kzips = glob("bazel-out/*/extra_actions/**/*.kzip", recursive=True)
Chi Wang6357efe2020-08-25 16:23:38 +08001678
Chi Wang6357efe2020-08-25 16:23:38 +08001679 build_number = os.getenv("BUILDKITE_BUILD_NUMBER")
Chi Wangb2b65682020-08-27 10:36:15 +08001680 git_commit = os.getenv("BUILDKITE_COMMIT")
1681 final_kzip_name = "{}-{}-{}.kzip".format(build_number, platform, git_commit)
Chi Wang6357efe2020-08-25 16:23:38 +08001682
Chi Wangb2b65682020-08-27 10:36:15 +08001683 execute_command([f"{KYTHE_DIR}/tools/kzip", "merge", "--output", final_kzip_name] + kzips)
Chi Wang6357efe2020-08-25 16:23:38 +08001684 execute_command(["buildkite-agent", "artifact", "upload", final_kzip_name])
1685
Chi Wangb2b65682020-08-27 10:36:15 +08001686 if index_upload_gcs:
1687 pipeline = os.getenv("BUILDKITE_PIPELINE_SLUG")
Chi Wang08aea1c2022-03-21 18:04:52 +08001688 branch = os.getenv("BUILDKITE_BRANCH")
1689 destination = KZIPS_BUCKET + pipeline + "/" + branch + "/" + final_kzip_name
Chi Wangb2b65682020-08-27 10:36:15 +08001690 print("Uploading to GCS {}".format(destination))
Florian Weikertdb832a02020-11-19 19:14:48 +01001691 execute_command([gsutil_command(), "cp", final_kzip_name, destination])
Chi Wangb2b65682020-08-27 10:36:15 +08001692
Chi Wang6357efe2020-08-25 16:23:38 +08001693
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001694def download_binary(dest_dir, platform, binary_name):
Philipp Wollermannc52e26a2019-05-18 22:10:47 +02001695 source_step = create_label(platform, "Bazel", build_only=True)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001696 execute_command(
Philipp Wollermann10183212020-02-04 21:54:14 +01001697 ["buildkite-agent", "artifact", "download", binary_name, dest_dir, "--step", source_step]
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001698 )
Philipp Wollermann10183212020-02-04 21:54:14 +01001699 bazel_binary_path = os.path.join(dest_dir, binary_name)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001700 st = os.stat(bazel_binary_path)
1701 os.chmod(bazel_binary_path, st.st_mode | stat.S_IEXEC)
1702 return bazel_binary_path
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001703
1704
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001705def download_bazel_binary(dest_dir, platform):
1706 binary_name = "bazel.exe" if platform == "windows" else "bazel"
1707 return download_binary(dest_dir, platform, binary_name)
1708
1709
1710def download_bazel_nojdk_binary(dest_dir, platform):
1711 binary_name = "bazel_nojdk.exe" if platform == "windows" else "bazel_nojdk"
1712 return download_binary(dest_dir, platform, binary_name)
1713
1714
Yun Pengd433d4f2022-12-09 10:53:15 +01001715def download_binary_at_commit(bazel_git_commit, bazel_binary_url, bazel_binary_path):
Yun Peng02312732019-01-17 18:17:05 +01001716 try:
Florian Weikertdb832a02020-11-19 19:14:48 +01001717 execute_command([gsutil_command(), "cp", bazel_binary_url, bazel_binary_path])
Yun Peng02312732019-01-17 18:17:05 +01001718 except subprocess.CalledProcessError as e:
Yun Pengd433d4f2022-12-09 10:53:15 +01001719 raise BuildkiteInfraException(
Philipp Wollermannc05ac682019-01-19 12:37:28 +01001720 "Failed to download Bazel binary at %s, error message:\n%s" % (bazel_git_commit, str(e))
1721 )
Yun Peng20d45602018-10-18 13:27:05 +02001722 st = os.stat(bazel_binary_path)
1723 os.chmod(bazel_binary_path, st.st_mode | stat.S_IEXEC)
1724 return bazel_binary_path
1725
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001726
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001727def download_bazel_binary_at_commit(dest_dir, platform, bazel_git_commit):
1728 url = bazelci_builds_gs_url(platform, bazel_git_commit)
1729 path = os.path.join(dest_dir, "bazel.exe" if platform == "windows" else "bazel")
Yun Pengd433d4f2022-12-09 10:53:15 +01001730 return download_binary_at_commit(bazel_git_commit, url, path)
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001731
1732
1733def download_bazel_nojdk_binary_at_commit(dest_dir, platform, bazel_git_commit):
1734 url = bazelci_builds_nojdk_gs_url(platform, bazel_git_commit)
1735 path = os.path.join(dest_dir, "bazel_nojdk.exe" if platform == "windows" else "bazel_nojdk")
Yun Pengd433d4f2022-12-09 10:53:15 +01001736 return download_binary_at_commit(bazel_git_commit, url, path)
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001737
Florian Weikert7f21ca42022-02-02 17:35:23 +01001738
Chi Wangd61eb972023-01-18 11:36:18 +01001739def download_bazelci_agent(dest_dir):
Chi Wangaf6d5b12023-05-10 11:48:05 +00001740 repo = "bazelbuild/continuous-integration"
Chi Wang4412ef12023-05-10 16:29:22 +00001741 if THIS_IS_TESTING and "BAZELCI_AGENT_REPO" in os.environ:
Chi Wangaf6d5b12023-05-10 11:48:05 +00001742 repo = os.environ["BAZELCI_AGENT_REPO"]
Chi Wang8939b692023-06-19 10:14:54 +00001743 version = "0.2.2"
Chi Wang4412ef12023-05-10 16:29:22 +00001744 if THIS_IS_TESTING and "BAZELCI_AGENT_VERSION" in os.environ:
Chi Wangaf6d5b12023-05-10 11:48:05 +00001745 version = os.environ["BAZELCI_AGENT_VERSION"]
Chi Wangd279d582021-09-29 10:59:06 +08001746 postfix = ""
Florian Weikertda94a102022-10-21 12:24:37 +02001747 if is_windows():
Chi Wangd279d582021-09-29 10:59:06 +08001748 postfix = "x86_64-pc-windows-msvc.exe"
Florian Weikertda94a102022-10-21 12:24:37 +02001749 elif is_mac():
Florian Weikertb3439b32022-11-09 11:05:16 +01001750 if platform_module.machine() == "arm64":
Chi Wang74ad6ca2022-10-21 11:20:36 +02001751 postfix = "aarch64-apple-darwin"
1752 else:
1753 postfix = "x86_64-apple-darwin"
Chi Wangd279d582021-09-29 10:59:06 +08001754 else:
Chi Wangaac1ead2023-01-17 11:10:48 +01001755 if platform_module.machine() == "aarch64":
1756 postfix = "aarch64-unknown-linux-musl"
1757 else:
1758 postfix = "x86_64-unknown-linux-musl"
Chi Wangd279d582021-09-29 10:59:06 +08001759
1760 name = "bazelci-agent-{}-{}".format(version, postfix)
Florian Weikert9b805ce2023-05-10 18:04:03 +02001761 url = "https://github.com/{}/releases/download/agent-{}/{}".format(repo, version, name)
Florian Weikertda94a102022-10-21 12:24:37 +02001762 path = os.path.join(dest_dir, "bazelci-agent.exe" if is_windows() else "bazelci-agent")
Chi Wangd279d582021-09-29 10:59:06 +08001763 execute_command(["curl", "-sSL", url, "-o", path])
1764 st = os.stat(path)
1765 os.chmod(path, st.st_mode | stat.S_IEXEC)
1766 return path
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001767
Florian Weikert7f21ca42022-02-02 17:35:23 +01001768
Florian Weikertda94a102022-10-21 12:24:37 +02001769def get_mirror_root():
1770 if is_mac():
1771 return "/usr/local/var/bazelbuild/"
1772 elif is_windows():
1773 return "c:\\buildkite\\bazelbuild\\"
joeleba7050d842019-05-23 17:03:31 +02001774
Florian Weikertda94a102022-10-21 12:24:37 +02001775 return "/var/lib/bazelbuild/"
joeleba7050d842019-05-23 17:03:31 +02001776
1777
Yun Peng376d2b32018-11-29 10:24:54 +01001778def clone_git_repository(git_repository, platform, git_commit=None):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001779 root = downstream_projects_root(platform)
Philipp Wollermannff39ef52018-02-21 14:18:52 +01001780 project_name = re.search(r"/([^/]+)\.git$", git_repository).group(1)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001781 clone_path = os.path.join(root, project_name)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001782 print_collapsed_group(
1783 "Fetching %s sources at %s" % (project_name, git_commit if git_commit else "HEAD")
1784 )
Philipp Wollermann438ec242018-09-05 14:39:24 +02001785
Florian Weikertda94a102022-10-21 12:24:37 +02001786 mirror_path = get_mirror_root() + re.sub(r"[^0-9A-Za-z]", "-", git_repository)
Philipp Wollermannea128282019-05-08 11:56:14 +02001787
Philipp Wollermann414703d2018-08-28 16:40:38 +02001788 if not os.path.exists(clone_path):
Philipp Wollermann62f4a032019-05-08 17:44:14 +02001789 if os.path.exists(mirror_path):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001790 execute_command(
Philipp Wollermann62f4a032019-05-08 17:44:14 +02001791 ["git", "clone", "-v", "--reference", mirror_path, git_repository, clone_path]
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001792 )
Philipp Wollermannd4cd0d82018-05-01 09:56:24 +02001793 else:
Philipp Wollermannea128282019-05-08 11:56:14 +02001794 execute_command(["git", "clone", "-v", git_repository, clone_path])
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001795
Philipp Wollermann414703d2018-08-28 16:40:38 +02001796 os.chdir(clone_path)
1797 execute_command(["git", "remote", "set-url", "origin", git_repository])
1798 execute_command(["git", "clean", "-fdqx"])
Florian Weikertd8f497c2019-06-19 15:44:20 +02001799 execute_command(["git", "submodule", "foreach", "--recursive", "git clean -fdqx"])
Philipp Wollermann414703d2018-08-28 16:40:38 +02001800 execute_command(["git", "fetch", "origin"])
Yun Peng376d2b32018-11-29 10:24:54 +01001801 if git_commit:
1802 # sync to a specific commit of this repository
1803 execute_command(["git", "reset", git_commit, "--hard"])
1804 else:
1805 # sync to the latest commit of HEAD. Unlikely git pull this also works after a force push.
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001806 remote_head = (
1807 subprocess.check_output(["git", "symbolic-ref", "refs/remotes/origin/HEAD"])
1808 .decode("utf-8")
1809 .rstrip()
1810 )
Yun Peng376d2b32018-11-29 10:24:54 +01001811 execute_command(["git", "reset", remote_head, "--hard"])
Philipp Wollermann414703d2018-08-28 16:40:38 +02001812 execute_command(["git", "submodule", "sync", "--recursive"])
1813 execute_command(["git", "submodule", "update", "--init", "--recursive", "--force"])
Florian Weikertd8f497c2019-06-19 15:44:20 +02001814 execute_command(["git", "submodule", "foreach", "--recursive", "git reset --hard"])
Philipp Wollermann414703d2018-08-28 16:40:38 +02001815 execute_command(["git", "clean", "-fdqx"])
Florian Weikertd8f497c2019-06-19 15:44:20 +02001816 execute_command(["git", "submodule", "foreach", "--recursive", "git clean -fdqx"])
Yun Peng20d45602018-10-18 13:27:05 +02001817 return clone_path
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001818
Philipp Wollermann438ec242018-09-05 14:39:24 +02001819
UebelAndre2e56c362023-06-13 04:38:15 -07001820def execute_batch_commands(commands, print_group=True, group_message=":batch: Setup (Batch Commands)"):
Yun Penga935a542018-05-18 15:08:53 +02001821 if not commands:
1822 return
Florian Weikert4141ce92023-05-09 09:45:55 +02001823
1824 if print_group:
UebelAndre2e56c362023-06-13 04:38:15 -07001825 print_collapsed_group(group_message)
Florian Weikert4141ce92023-05-09 09:45:55 +02001826
Yun Penga935a542018-05-18 15:08:53 +02001827 batch_commands = "&".join(commands)
Jakob Buchgraber4a824412018-06-22 12:56:10 +02001828 return subprocess.run(batch_commands, shell=True, check=True, env=os.environ).returncode
Yun Penga935a542018-05-18 15:08:53 +02001829
Philipp Wollermann414703d2018-08-28 16:40:38 +02001830
UebelAndre2e56c362023-06-13 04:38:15 -07001831def execute_shell_commands(commands, print_group=True, group_message=":bash: Setup (Shell Commands)"):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001832 if not commands:
1833 return
Florian Weikert4141ce92023-05-09 09:45:55 +02001834
1835 if print_group:
UebelAndre2e56c362023-06-13 04:38:15 -07001836 print_collapsed_group(group_message)
Florian Weikert4141ce92023-05-09 09:45:55 +02001837
mostynb14440912020-03-17 17:11:47 +01001838 shell_command = "\n".join(["set -e"] + commands)
Philipp Wollermann3e1a7712018-02-19 17:34:24 +01001839 execute_command([shell_command], shell=True)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001840
1841
Yun Peng0a6a98a2019-03-06 13:07:54 +01001842def handle_bazel_failure(exception, action):
1843 msg = "bazel {0} failed with exit code {1}".format(action, exception.returncode)
1844 if use_bazelisk_migrate():
1845 print_collapsed_group(msg)
1846 else:
1847 raise BuildkiteException(msg)
1848
1849
Yun Pengc85cd0e2022-09-02 10:44:29 +02001850def execute_bazel_run(bazel_binary, platform, targets):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001851 if not targets:
1852 return
1853 print_collapsed_group("Setup (Run Targets)")
1854 for target in targets:
Yun Peng0a6a98a2019-03-06 13:07:54 +01001855 try:
1856 execute_command(
1857 [bazel_binary]
1858 + bazelisk_flags()
Florian Weikertda94a102022-10-21 12:24:37 +02001859 + common_startup_flags()
Yun Peng0a6a98a2019-03-06 13:07:54 +01001860 + ["run"]
1861 + common_build_flags(None, platform)
Yun Peng0a6a98a2019-03-06 13:07:54 +01001862 + [target]
1863 )
1864 except subprocess.CalledProcessError as e:
1865 handle_bazel_failure(e, "run")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001866
1867
Philipp Wollermannc4752e42022-02-08 16:35:39 +01001868def remote_caching_flags(platform, accept_cached=True):
Philipp Wollermanne67eec42019-05-24 15:18:20 +02001869 # Only enable caching for untrusted and testing builds.
Florian Weikert8cba2be2023-07-12 17:39:56 +02001870 if CLOUD_PROJECT != "bazel-untrusted":
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001871 return []
Yun Peng07dafc52022-03-16 13:23:35 +01001872 # We don't enable remote caching on the Linux ARM64 machine since it doesn't have access to GCS.
1873 if platform == "ubuntu2004_arm64":
1874 return []
1875
Florian Weikert09012952023-07-12 14:07:39 +02001876 platform_cache_key = [
1877 BUILDKITE_ORG.encode("utf-8"),
1878 # Whenever the remote cache was known to have been poisoned increase the number below
Yun Peng9229e012023-08-03 14:27:56 +02001879 "cache-poisoning-20230803".encode("utf-8"),
Florian Weikert09012952023-07-12 14:07:39 +02001880 platform.encode("utf-8"),
1881 ]
1882
Florian Weikertda94a102022-10-21 12:24:37 +02001883 if is_mac():
Philipp Wollermannfce92bf2019-05-22 15:14:32 +02001884 platform_cache_key += [
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001885 # macOS version:
1886 subprocess.check_output(["/usr/bin/sw_vers", "-productVersion"]),
1887 # Path to Xcode:
1888 subprocess.check_output(["/usr/bin/xcode-select", "-p"]),
1889 # Xcode version:
1890 subprocess.check_output(["/usr/bin/xcodebuild", "-version"]),
1891 ]
Yun Peng1ce55be2023-08-11 16:19:26 +02001892
Florian Weikert8cba2be2023-07-12 17:39:56 +02001893 if is_mac() and is_lab_machine():
1894 # Use a local cache server for our physical macOS machines in the lab.
Philipp Wollermann3d5c0212023-06-13 17:21:57 +09001895 flags = ["--remote_cache=http://100.107.73.147"]
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001896 else:
Philipp Wollermanne74da4e2019-06-07 11:31:02 +02001897 # Use RBE for caching builds running on GCE.
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001898 flags = [
1899 "--google_default_credentials",
Philipp Wollermanne74da4e2019-06-07 11:31:02 +02001900 "--remote_cache=remotebuildexecution.googleapis.com",
1901 "--remote_instance_name=projects/{}/instances/default_instance".format(CLOUD_PROJECT),
Florian Weikert8cba2be2023-07-12 17:39:56 +02001902 # Enable BES / Build Results reporting.
Chi Wang466876d2023-06-12 14:09:20 +00001903 "--bes_backend=buildeventservice.googleapis.com",
1904 "--bes_timeout=360s",
Chi Wang8818f2a2023-06-13 08:41:59 +00001905 "--project_id=bazel-untrusted",
Chi Wang466876d2023-06-12 14:09:20 +00001906 ]
Philipp Wollermann380f1e62019-04-12 16:45:27 +02001907
1908 platform_cache_digest = hashlib.sha256()
1909 for key in platform_cache_key:
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001910 eprint("Adding to platform cache key: {}".format(key))
Philipp Wollermann380f1e62019-04-12 16:45:27 +02001911 platform_cache_digest.update(key)
1912 platform_cache_digest.update(b":")
1913
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001914 flags += [
Philipp Wollermann94937722019-01-11 14:33:18 +01001915 "--remote_timeout=60",
Philipp Wollermann639c0452019-01-03 11:23:54 +01001916 "--remote_max_connections=200",
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001917 '--remote_default_platform_properties=properties:{name:"cache-silo-key" value:"%s"}'
1918 % platform_cache_digest.hexdigest(),
Yun Peng5985f742023-04-17 11:32:42 +02001919 "--remote_download_toplevel",
Philipp Wollermann639c0452019-01-03 11:23:54 +01001920 ]
Jakob Buchgraber4f1d2712018-02-20 10:22:47 +01001921
Yun Pengb2fbce32022-02-04 12:56:34 +01001922 if not accept_cached:
1923 flags += ["--noremote_accept_cached"]
1924
Philipp Wollermannd96d8fa2019-01-11 14:37:47 +01001925 return flags
1926
Jakob Buchgraber4f1d2712018-02-20 10:22:47 +01001927
Jakob Buchgraberb4342cd2018-02-20 16:35:07 +01001928def remote_enabled(flags):
1929 # Detect if the project configuration enabled its own remote caching / execution.
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001930 remote_flags = ["--remote_executor", "--remote_cache", "--remote_http_cache"]
Jakob Buchgraberb4342cd2018-02-20 16:35:07 +01001931 for flag in flags:
1932 for remote_flag in remote_flags:
1933 if flag.startswith(remote_flag):
1934 return True
1935 return False
1936
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001937
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001938def concurrent_jobs(platform):
1939 return "75" if platform.startswith("rbe_") else str(multiprocessing.cpu_count())
Jakob Buchgraber51a83662018-02-22 19:49:24 +01001940
1941
Philipp Wollermann3e28d3b2018-02-23 23:19:37 +01001942def concurrent_test_jobs(platform):
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001943 if platform.startswith("rbe_"):
1944 return "75"
Florian Weikertda94a102022-10-21 12:24:37 +02001945 elif is_windows():
Jakob Buchgrabere3ccda32018-06-22 23:29:48 +02001946 return "8"
Florian Weikertda94a102022-10-21 12:24:37 +02001947 elif is_mac() and THIS_IS_TESTING:
Philipp Wollermann85877cb2021-07-02 19:20:33 +02001948 return "4"
Florian Weikertda94a102022-10-21 12:24:37 +02001949 elif is_mac():
Florian Weikertecf091c2023-04-28 10:22:23 +02001950 # TODO(twerth): This is an experiment, remove.
1951 return str(int(multiprocessing.cpu_count() / 2))
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001952 return "12"
Philipp Wollermann3e28d3b2018-02-23 23:19:37 +01001953
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001954
Florian Weikertda94a102022-10-21 12:24:37 +02001955def common_startup_flags():
1956 if is_windows():
Philipp Wollermannd5ab3d92020-02-05 16:55:13 +01001957 if os.path.exists("D:/b"):
1958 # This machine has a local SSD mounted as drive D.
1959 return ["--output_user_root=D:/b"]
1960 else:
1961 # This machine uses its PD-SSD as the build directory.
1962 return ["--output_user_root=C:/b"]
1963 return []
Yun Peng58977d62018-11-16 12:19:20 +01001964
1965
1966def common_build_flags(bep_file, platform):
Yun Peng088cc932018-11-16 12:11:46 +01001967 flags = [
Yun Pengf51e7842018-11-16 11:35:43 +01001968 "--show_progress_rate_limit=5",
1969 "--curses=yes",
1970 "--color=yes",
Philipp Wollermannd99414c2019-05-28 17:26:09 +02001971 "--terminal_columns=143",
Philipp Wollermann4c8391e2019-05-28 18:03:35 +02001972 "--show_timestamps",
Yun Pengf51e7842018-11-16 11:35:43 +01001973 "--verbose_failures",
Yun Pengf51e7842018-11-16 11:35:43 +01001974 "--jobs=" + concurrent_jobs(platform),
Yun Pengf51e7842018-11-16 11:35:43 +01001975 "--announce_rc",
Philipp Wollermannb97f9102019-04-16 18:05:56 +02001976 "--experimental_repository_cache_hardlinks",
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001977 # Some projects set --disk_cache in their project-specific bazelrc, which we never want on
1978 # CI, so let's just disable it explicitly.
1979 "--disk_cache=",
Yun Peng088cc932018-11-16 12:11:46 +01001980 ]
Philipp Wollermann639c0452019-01-03 11:23:54 +01001981
Florian Weikertda94a102022-10-21 12:24:37 +02001982 if is_windows():
Philipp Wollermannb97f9102019-04-16 18:05:56 +02001983 pass
Florian Weikertda94a102022-10-21 12:24:37 +02001984 elif is_mac():
Philipp Wollermannb97f9102019-04-16 18:05:56 +02001985 flags += [
1986 "--sandbox_writable_path=/var/tmp/_bazel_buildkite/cache/repos/v1",
1987 "--test_env=REPOSITORY_CACHE=/var/tmp/_bazel_buildkite/cache/repos/v1",
1988 ]
1989 else:
Philipp Wollermann639c0452019-01-03 11:23:54 +01001990 flags += ["--sandbox_tmpfs_path=/tmp"]
1991
Yun Peng088cc932018-11-16 12:11:46 +01001992 if bep_file:
Philipp Wollermann639c0452019-01-03 11:23:54 +01001993 flags += [
1994 "--experimental_build_event_json_file_path_conversion=false",
1995 "--build_event_json_file=" + bep_file,
1996 ]
1997
Yun Peng088cc932018-11-16 12:11:46 +01001998 return flags
Philipp Wollermann94bd9e32018-04-30 15:32:28 +02001999
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002000
Yun Pengb7247ff2018-11-15 13:52:39 +01002001def rbe_flags(original_flags, accept_cached):
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02002002 # Enable remote execution via RBE.
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002003 flags = [
2004 "--remote_executor=remotebuildexecution.googleapis.com",
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002005 "--remote_instance_name=projects/bazel-untrusted/instances/default_instance",
Philipp Wollermann2df93482021-06-16 04:39:49 +02002006 "--remote_timeout=3600",
Philipp Wollermann57dadb82020-02-17 14:32:24 +01002007 "--incompatible_strict_action_env",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002008 "--google_default_credentials",
Philipp Wollermann57dadb82020-02-17 14:32:24 +01002009 "--toolchain_resolution_debug",
Yun Peng5985f742023-04-17 11:32:42 +02002010 "--remote_download_toplevel",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002011 ]
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02002012
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02002013 # Enable BES / Build Results reporting.
2014 flags += [
2015 "--bes_backend=buildeventservice.googleapis.com",
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02002016 "--bes_timeout=360s",
Chi Wang8818f2a2023-06-13 08:41:59 +00002017 "--project_id=bazel-untrusted",
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02002018 ]
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02002019
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002020 if not accept_cached:
2021 flags += ["--noremote_accept_cached"]
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02002022
Nicolas Lopez36996222019-05-28 12:21:28 -04002023 # Adapted from https://github.com/bazelbuild/bazel-toolchains/blob/master/bazelrc/.bazelrc
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002024 flags += [
Nicolas Lopez36996222019-05-28 12:21:28 -04002025 # These should NOT longer need to be modified.
2026 # All that is needed is updating the @bazel_toolchains repo pin
2027 # in projects' WORKSPACE files.
Xindb02c012018-11-07 14:10:54 -05002028 #
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002029 # Toolchain related flags to append at the end of your .bazelrc file.
Nicolas Lopez36996222019-05-28 12:21:28 -04002030 "--host_javabase=@buildkite_config//java:jdk",
2031 "--javabase=@buildkite_config//java:jdk",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002032 "--host_java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8",
2033 "--java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8",
Nicolas Lopez36996222019-05-28 12:21:28 -04002034 "--crosstool_top=@buildkite_config//cc:toolchain",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002035 "--action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002036 ]
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02002037
Yun Pengb7247ff2018-11-15 13:52:39 +01002038 # Platform flags:
2039 # The toolchain container used for execution is defined in the target indicated
2040 # by "extra_execution_platforms", "host_platform" and "platforms".
Xin03a88ab2019-03-11 19:18:50 -04002041 # If you are using your own toolchain container, you need to create a platform
2042 # target with "constraint_values" that allow for the toolchain specified with
2043 # "extra_toolchains" to be selected (given constraints defined in
2044 # "exec_compatible_with").
Yun Pengb7247ff2018-11-15 13:52:39 +01002045 # More about platforms: https://docs.bazel.build/versions/master/platforms.html
2046 # Don't add platform flags if they are specified already.
2047 platform_flags = {
Nicolas Lopez36996222019-05-28 12:21:28 -04002048 "--extra_toolchains": "@buildkite_config//config:cc-toolchain",
2049 "--extra_execution_platforms": "@buildkite_config//config:platform",
2050 "--host_platform": "@buildkite_config//config:platform",
2051 "--platforms": "@buildkite_config//config:platform",
Yun Pengb7247ff2018-11-15 13:52:39 +01002052 }
Yun Peng67ab5062018-11-15 13:58:15 +01002053 for platform_flag, value in list(platform_flags.items()):
Yun Pengb7247ff2018-11-15 13:52:39 +01002054 found = False
2055 for original_flag in original_flags:
2056 if original_flag.startswith(platform_flag):
2057 found = True
2058 break
2059 if not found:
2060 flags += [platform_flag + "=" + value]
2061
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002062 return flags
2063
2064
Yun Peng28a9a532023-05-10 14:19:46 +02002065def get_output_base(bazel_binary):
Yun Peng2b6de292022-02-10 14:28:06 +01002066 return execute_command_and_get_output(
Florian Weikertda94a102022-10-21 12:24:37 +02002067 [bazel_binary] + common_startup_flags() + ["info", "output_base"],
Yun Peng2b6de292022-02-10 14:28:06 +01002068 print_output=False,
2069 ).strip()
2070
2071
Florian Weikertb3439b32022-11-09 11:05:16 +01002072def compute_flags(platform, flags, bep_file, bazel_binary, enable_remote_cache=False):
Yun Peng58977d62018-11-16 12:19:20 +01002073 aggregated_flags = common_build_flags(bep_file, platform)
Yun Peng32dbec32018-11-02 12:47:41 +01002074 if not remote_enabled(flags):
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002075 if platform.startswith("rbe_"):
Florian Weikert24a4b482018-11-30 19:05:38 +01002076 aggregated_flags += rbe_flags(flags, accept_cached=enable_remote_cache)
Yun Pengb2fbce32022-02-04 12:56:34 +01002077 else:
2078 aggregated_flags += remote_caching_flags(platform, accept_cached=enable_remote_cache)
Yun Peng75786552018-11-13 15:23:30 +01002079 aggregated_flags += flags
Yun Peng53598002018-12-03 10:42:02 +01002080
Philipp Wollermann87b45252020-01-22 12:43:42 +01002081 for i, flag in enumerate(aggregated_flags):
2082 if "$HOME" in flag:
Florian Weikerta6110a92022-10-20 01:16:09 +02002083 if is_windows():
Philipp Wollermannd5ab3d92020-02-05 16:55:13 +01002084 if os.path.exists("D:/"):
2085 home = "D:"
2086 else:
2087 home = "C:/b"
Florian Weikerta6110a92022-10-20 01:16:09 +02002088 elif is_mac():
Philipp Wollermannd5ab3d92020-02-05 16:55:13 +01002089 home = "/Users/buildkite"
2090 else:
2091 home = "/var/lib/buildkite-agent"
Philipp Wollermann87b45252020-01-22 12:43:42 +01002092 aggregated_flags[i] = flag.replace("$HOME", home)
2093 if "$OUTPUT_BASE" in flag:
Yun Peng28a9a532023-05-10 14:19:46 +02002094 output_base = get_output_base(bazel_binary)
Philipp Wollermann87b45252020-01-22 12:43:42 +01002095 aggregated_flags[i] = flag.replace("$OUTPUT_BASE", output_base)
2096
Florian Weikert24a4b482018-11-30 19:05:38 +01002097 return aggregated_flags
Yun Peng53598002018-12-03 10:42:02 +01002098
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002099
Yun Pengea0359e2019-01-17 15:37:47 +01002100def execute_bazel_clean(bazel_binary, platform):
2101 print_expanded_group(":bazel: Clean")
2102
2103 try:
Florian Weikertda94a102022-10-21 12:24:37 +02002104 execute_command([bazel_binary] + common_startup_flags() + ["clean", "--expunge"])
Yun Pengea0359e2019-01-17 15:37:47 +01002105 except subprocess.CalledProcessError as e:
2106 raise BuildkiteException("bazel clean failed with exit code {}".format(e.returncode))
2107
2108
Chi Wang6357efe2020-08-25 16:23:38 +08002109def kythe_startup_flags():
2110 return [f"--bazelrc={KYTHE_DIR}/extractors.bazelrc"]
2111
2112
2113def kythe_build_flags():
Philipp Wollermannf61a20b2021-05-05 22:04:20 +02002114 return [
2115 "--experimental_convenience_symlinks=normal",
Florian Weikert9d5e4c02021-05-27 15:10:20 +02002116 f"--override_repository=kythe_release={KYTHE_DIR}",
Philipp Wollermannf61a20b2021-05-05 22:04:20 +02002117 ]
Chi Wang6357efe2020-08-25 16:23:38 +08002118
2119
Florian Weikertb3439b32022-11-09 11:05:16 +01002120def execute_bazel_build(bazel_version, bazel_binary, platform, flags, targets, bep_file):
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02002121 print_collapsed_group(":bazel: Computing flags for build step")
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002122 aggregated_flags = compute_flags(
Yun Peng8975c6b2019-02-28 11:55:55 +01002123 platform,
2124 flags,
Yun Peng8975c6b2019-02-28 11:55:55 +01002125 bep_file,
Philipp Wollermann87b45252020-01-22 12:43:42 +01002126 bazel_binary,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002127 enable_remote_cache=True,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002128 )
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02002129
2130 print_expanded_group(":bazel: Build ({})".format(bazel_version))
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01002131 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002132 execute_command(
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002133 [bazel_binary]
2134 + bazelisk_flags()
Florian Weikertda94a102022-10-21 12:24:37 +02002135 + common_startup_flags()
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002136 + ["build"]
2137 + aggregated_flags
Philipp Wollermann2a160432019-09-19 15:57:28 +02002138 + ["--"]
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002139 + targets
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002140 )
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01002141 except subprocess.CalledProcessError as e:
Yun Peng0a6a98a2019-03-06 13:07:54 +01002142 handle_bazel_failure(e, "build")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002143
2144
Florian Weikertb3439b32022-11-09 11:05:16 +01002145def execute_bazel_build_with_kythe(bazel_version, bazel_binary, platform, flags, targets, bep_file):
Chi Wang6357efe2020-08-25 16:23:38 +08002146 print_collapsed_group(":bazel: Computing flags for build step")
2147 aggregated_flags = compute_flags(
2148 platform,
2149 flags,
Chi Wang6357efe2020-08-25 16:23:38 +08002150 bep_file,
2151 bazel_binary,
2152 enable_remote_cache=False,
2153 )
2154
2155 print_expanded_group(":bazel: Build ({})".format(bazel_version))
2156
2157 execute_command(
2158 [bazel_binary]
2159 + bazelisk_flags()
Florian Weikertda94a102022-10-21 12:24:37 +02002160 + common_startup_flags()
Chi Wang6357efe2020-08-25 16:23:38 +08002161 + kythe_startup_flags()
2162 + ["build"]
2163 + kythe_build_flags()
2164 + aggregated_flags
2165 + ["--"]
2166 + targets
2167 )
2168
2169
Florian Weikert7dd9f662023-05-04 15:05:42 +02002170def calculate_targets(
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002171 task_config,
2172 bazel_binary,
2173 build_only,
2174 test_only,
2175 workspace_dir,
2176 ws_setup_func,
2177 git_commit,
2178 test_flags,
Florian Weikert7dd9f662023-05-04 15:05:42 +02002179):
Florian Weikerte417f9f2023-05-05 17:33:46 +02002180 print_collapsed_group(":dart: Calculating targets")
2181
Alexandre Rostovtsev42bbeb52023-08-24 04:08:04 -04002182 build_targets = [] if test_only else list(task_config.get("build_targets", []))
2183 test_targets = [] if build_only else list(task_config.get("test_targets", []))
2184 coverage_targets = [] if (build_only or test_only) else list(task_config.get("coverage_targets", []))
2185 index_targets = [] if (build_only or test_only) else list(task_config.get("index_targets", []))
Chi Wang6357efe2020-08-25 16:23:38 +08002186
Florian Weikertdb832a02020-11-19 19:14:48 +01002187 index_targets_query = (
2188 None if (build_only or test_only) else task_config.get("index_targets_query", None)
2189 )
Chi Wang6357efe2020-08-25 16:23:38 +08002190 if index_targets_query:
2191 output = execute_command_and_get_output(
2192 [bazel_binary]
Florian Weikertda94a102022-10-21 12:24:37 +02002193 + common_startup_flags()
Yun Peng8e8cdcf2022-03-16 13:08:15 +01002194 + ["--nosystem_rc", "--nohome_rc", "query", index_targets_query],
Chi Wang6357efe2020-08-25 16:23:38 +08002195 print_output=False,
2196 )
2197 index_targets += output.strip().split("\n")
Florian Weikert736d06e2019-05-08 13:16:42 +02002198
Philipp Wollermann2a160432019-09-19 15:57:28 +02002199 # Remove the "--" argument splitter from the list that some configs explicitly
2200 # include. We'll add it back again later where needed.
2201 build_targets = [x.strip() for x in build_targets if x.strip() != "--"]
2202 test_targets = [x.strip() for x in test_targets if x.strip() != "--"]
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01002203 coverage_targets = [x.strip() for x in coverage_targets if x.strip() != "--"]
Chi Wang6357efe2020-08-25 16:23:38 +08002204 index_targets = [x.strip() for x in index_targets if x.strip() != "--"]
Philipp Wollermann2a160432019-09-19 15:57:28 +02002205
Florian Weikertdcbbdf32023-05-02 11:58:53 +02002206 diffbase = os.getenv(USE_BAZEL_DIFF_ENV_VAR, "").lower()
2207 shard_id = int(os.getenv("BUILDKITE_PARALLEL_JOB", "-1"))
2208 shard_count = int(os.getenv("BUILDKITE_PARALLEL_JOB_COUNT", "-1"))
2209 sharding_enabled = shard_id > -1 and shard_count > -1
2210
Florian Weikerte417f9f2023-05-05 17:33:46 +02002211 use_bazel_diff = diffbase and can_use_bazel_diff()
2212
Florian Weikertdcbbdf32023-05-02 11:58:53 +02002213 # Skip target expansion if we don't need to calculate test targets
Florian Weikerte417f9f2023-05-05 17:33:46 +02002214 if not use_bazel_diff and not sharding_enabled:
Florian Weikertdcbbdf32023-05-02 11:58:53 +02002215 return build_targets, test_targets, coverage_targets, index_targets
2216
2217 # TODO(#1614): Fix target expansion
Florian Weikert7dd9f662023-05-04 15:05:42 +02002218 expanded_test_targets = expand_test_target_patterns(bazel_binary, test_targets, test_flags)
Florian Weikertecf091c2023-04-28 10:22:23 +02002219
Florian Weikertecf091c2023-04-28 10:22:23 +02002220 actual_test_targets = (
2221 filter_unchanged_targets(
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002222 expanded_test_targets,
2223 workspace_dir,
2224 ws_setup_func,
2225 bazel_binary,
2226 diffbase,
2227 git_commit,
Florian Weikertecf091c2023-04-28 10:22:23 +02002228 )
Florian Weikerte417f9f2023-05-05 17:33:46 +02002229 if use_bazel_diff
Florian Weikertecf091c2023-04-28 10:22:23 +02002230 else expanded_test_targets
2231 )
2232
Florian Weikertdcbbdf32023-05-02 11:58:53 +02002233 if sharding_enabled:
Florian Weikert736d06e2019-05-08 13:16:42 +02002234 print_collapsed_group(
2235 ":female-detective: Calculating targets for shard {}/{}".format(
2236 shard_id + 1, shard_count
2237 )
2238 )
Florian Weikertecf091c2023-04-28 10:22:23 +02002239 actual_test_targets = get_targets_for_shard(actual_test_targets, shard_id, shard_count)
Florian Weikert736d06e2019-05-08 13:16:42 +02002240
Florian Weikertecf091c2023-04-28 10:22:23 +02002241 return build_targets, actual_test_targets, coverage_targets, index_targets
Florian Weikert736d06e2019-05-08 13:16:42 +02002242
2243
Florian Weikerte417f9f2023-05-05 17:33:46 +02002244def can_use_bazel_diff():
2245 matched_files = []
2246 for f in get_modified_files():
2247 for d in DISABLE_BAZEL_DIFF_IF_MODIFIED:
2248 if d.endswith("/") and f.startswith(d) or f == d:
2249 matched_files.append(f)
2250
2251 if matched_files:
2252 eprint(
2253 "Cannot enable bazel-diff since the following files were modified:\n\t{}".format(
2254 "\n\t".join(sorted(matched_files))
2255 )
2256 )
2257
2258 return not matched_files
2259
2260
Florian Weikert7dd9f662023-05-04 15:05:42 +02002261def expand_test_target_patterns(bazel_binary, test_targets, test_flags):
2262 if not test_targets:
2263 return []
Florian Weikert736d06e2019-05-08 13:16:42 +02002264
Florian Weikert7dd9f662023-05-04 15:05:42 +02002265 print_collapsed_group(":ninja: Resolving test targets via bazel query")
Philipp Wollermann2a160432019-09-19 15:57:28 +02002266
Florian Weikert736d06e2019-05-08 13:16:42 +02002267 output = execute_command_and_get_output(
2268 [bazel_binary]
Florian Weikertda94a102022-10-21 12:24:37 +02002269 + common_startup_flags()
Florian Weikert736d06e2019-05-08 13:16:42 +02002270 + [
Yun Peng8e8cdcf2022-03-16 13:08:15 +01002271 "--nosystem_rc",
2272 "--nohome_rc",
Florian Weikert5242a592023-05-04 19:19:28 +02002273 "cquery" if os.getenv("EXP_USE_CQUERY") else "query",
Florian Weikert7dd9f662023-05-04 15:05:42 +02002274 get_test_query(test_targets, test_flags),
Florian Weikert736d06e2019-05-08 13:16:42 +02002275 ],
2276 print_output=False,
Philipp Wollermann54719fe2021-07-02 21:54:08 +02002277 ).strip()
2278 return output.split("\n") if output else []
Florian Weikert736d06e2019-05-08 13:16:42 +02002279
2280
Florian Weikert7dd9f662023-05-04 15:05:42 +02002281def get_test_query(test_targets, test_flags):
2282 included_targets, excluded_targets = partition_list(test_targets)
2283
2284 def FormatTargetList(targets):
2285 return " ".join("'{}'".format(t) for t in targets)
2286
Florian Weikert38a99212023-05-04 15:12:41 +02002287 query = "let t = tests(set({})) in $t".format(FormatTargetList(included_targets))
Florian Weikert7dd9f662023-05-04 15:05:42 +02002288
2289 if excluded_targets:
2290 query += " except tests(set({}))".format(FormatTargetList(excluded_targets))
2291
2292 included_tags, excluded_tags = get_test_tags(test_flags)
2293
2294 for t in excluded_tags:
Florian Weikert38a99212023-05-04 15:12:41 +02002295 query += " except attr('tags', '\\b{}\\b', $t)".format(t)
Florian Weikert7dd9f662023-05-04 15:05:42 +02002296
2297 if included_tags:
Florian Weikert38a99212023-05-04 15:12:41 +02002298 parts = ["attr('tags', '\\b{}\\b', $tt)".format(t) for t in included_tags]
Florian Weikert7dd9f662023-05-04 15:05:42 +02002299 query = "let tt = {} in {}".format(query, " union ".join(parts))
2300
2301 return query
2302
2303
2304def get_test_tags(test_flags):
2305 wanted_prefix = "--test_tag_filters="
2306
2307 for f in test_flags:
2308 if not f.startswith(wanted_prefix):
2309 continue
2310
Florian Weikertc833a7c2023-05-05 21:26:36 +02002311 tags = removeprefix(f, wanted_prefix).split(",")
Florian Weikert7dd9f662023-05-04 15:05:42 +02002312 include, exclude = partition_list(tags)
2313
2314 # Skip tests tagged as "manual" by default, unless explicitly requested
2315 manual_tag = "manual"
2316 if manual_tag not in include and manual_tag not in exclude:
2317 exclude.append(manual_tag)
2318
2319 return include, exclude
2320
Yun Peng01e617e2023-05-04 16:03:46 +02002321 return [], ["manual"]
Florian Weikert7dd9f662023-05-04 15:05:42 +02002322
2323
Florian Weikertc833a7c2023-05-05 21:26:36 +02002324def removeprefix(s, prefix):
2325 def rp(p):
2326 if s.startswith(p):
Florian Weikertb0fcf902023-05-05 22:01:50 +02002327 return s[len(p) :]
Florian Weikertc833a7c2023-05-05 21:26:36 +02002328 return s
2329
2330 func = getattr(s, "removeprefix", rp)
2331 return func(prefix)
2332
2333
Florian Weikertecf091c2023-04-28 10:22:23 +02002334def filter_unchanged_targets(
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002335 expanded_test_targets, workspace_dir, ws_setup_func, bazel_binary, diffbase, git_commit
Florian Weikertecf091c2023-04-28 10:22:23 +02002336):
2337 print_collapsed_group(
2338 f":scissors: Filtering targets that haven't been affected since {diffbase}"
2339 )
2340
2341 tmpdir = tempfile.mkdtemp()
Florian Weikertecf091c2023-04-28 10:22:23 +02002342 try:
Florian Weikertb0fcf902023-05-05 22:01:50 +02002343 resolved_diffbase = resolve_diffbase(diffbase)
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002344 eprint(f"Resolved diffbase to {resolved_diffbase}")
Florian Weikertb0fcf902023-05-05 22:01:50 +02002345
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002346 eprint("Cloning comparison repository...")
2347 diffbase_archive_url = get_commit_archive_url(resolved_diffbase)
2348 local_archive_path = download_file(diffbase_archive_url, tmpdir, "repo.tar.gz")
2349 diffbase_repo_dir = os.path.join(tmpdir, resolved_diffbase)
2350 extract_archive(local_archive_path, diffbase_repo_dir)
2351
2352 eprint("Setting up comparison repository...")
2353 os.chdir(diffbase_repo_dir)
Florian Weikert4141ce92023-05-09 09:45:55 +02002354 ws_setup_func(False)
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002355
2356 eprint(f"Downloading bazel-diff to {tmpdir}")
2357 bazel_diff_path = download_file(BAZEL_DIFF_URL, tmpdir, "bazel-diff.jar")
Florian Weikertb0fcf902023-05-05 22:01:50 +02002358 eprint(f"Running bazel-diff for {resolved_diffbase} and {git_commit}")
2359
Florian Weikertecf091c2023-04-28 10:22:23 +02002360 affected_targets = run_bazel_diff(
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002361 bazel_diff_path, diffbase_repo_dir, workspace_dir, bazel_binary, tmpdir
Florian Weikertecf091c2023-04-28 10:22:23 +02002362 )
Florian Weikertb0fcf902023-05-05 22:01:50 +02002363 except (BuildkiteException, BuildkiteInfraException) as ex:
2364 try:
2365 execute_command(
2366 [
2367 "buildkite-agent",
2368 "annotate",
2369 "--style=warning",
2370 "--context",
2371 "'diff_failed'",
2372 "This build runs all test targets even though `{}` is set "
Florian Weikert9029ccf2023-05-08 17:07:04 +02002373 "since bazel-diff failed with an error:\n```\n{}\n```".format(
Florian Weikertb0fcf902023-05-05 22:01:50 +02002374 USE_BAZEL_DIFF_ENV_VAR, ex
2375 ),
2376 ]
2377 )
Florian Weikert77d20062023-05-08 16:32:48 +02002378 execute_command(
2379 ["buildkite-agent", "annotation", "remove", "--context", BAZEL_DIFF_ANNOTATION_CTX]
2380 )
Florian Weikertb0fcf902023-05-05 22:01:50 +02002381 finally:
2382 return expanded_test_targets
Florian Weikertecf091c2023-04-28 10:22:23 +02002383 finally:
Florian Weikerte747d4f2023-05-09 09:43:47 +02002384 try:
2385 shutil.rmtree(tmpdir)
2386 except:
2387 pass
2388
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002389 os.chdir(workspace_dir)
Florian Weikertecf091c2023-04-28 10:22:23 +02002390
Florian Weikertaa0488f2023-05-03 15:06:13 +02002391 config_target_set = set(expanded_test_targets)
2392 remaining_targets = list(config_target_set.intersection(affected_targets))
2393 if len(remaining_targets) < len(expanded_test_targets):
2394 print_collapsed_group(
2395 ":scissors: Successfully reduced test targets from {} to {}".format(
2396 len(expanded_test_targets), len(remaining_targets)
2397 )
2398 )
2399
2400 skipped_targets = sorted(config_target_set.difference(remaining_targets))
2401 eprint("Skipped targets:\n\t{}".format("\n\t".join(skipped_targets)))
2402
Florian Weikertecf091c2023-04-28 10:22:23 +02002403 execute_command(
2404 [
2405 "buildkite-agent",
2406 "annotate",
2407 "--style=info",
Florian Weikert20151ab2023-05-04 20:32:36 +02002408 "--context",
Florian Weikert77d20062023-05-08 16:32:48 +02002409 BAZEL_DIFF_ANNOTATION_CTX,
Florian Weikert76736e92023-04-28 11:23:27 +02002410 "This run only contains test targets that have been changed since "
Florian Weikertb0fcf902023-05-05 22:01:50 +02002411 "{} due to the `{}` env variable".format(resolved_diffbase, USE_BAZEL_DIFF_ENV_VAR),
Florian Weikertecf091c2023-04-28 10:22:23 +02002412 ]
2413 )
2414
Florian Weikertaa0488f2023-05-03 15:06:13 +02002415 return remaining_targets
Florian Weikertecf091c2023-04-28 10:22:23 +02002416
2417
2418def resolve_diffbase(diffbase):
2419 if diffbase in AUTO_DIFFBASE_VALUES:
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002420 return resolve_revision("HEAD^")
Florian Weikertecf091c2023-04-28 10:22:23 +02002421 elif COMMIT_RE.fullmatch(diffbase):
2422 return diffbase
2423
2424 raise BuildkiteException(
Florian Weikertb0fcf902023-05-05 22:01:50 +02002425 "Invalid value '{}' for `{}` env variable. Must be a Git commit hash or one of {}".format(
Florian Weikertecf091c2023-04-28 10:22:23 +02002426 diffbase, ", ".join(AUTO_DIFFBASE_VALUES)
2427 )
2428 )
2429
2430
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002431def get_commit_archive_url(resolved_diffbase):
2432 repo_url = os.getenv("BUILDKITE_REPO", "")
2433 prefix = "+" if "googlesource" in repo_url else ""
2434 return repo_url.replace(".git", "/{}archive/{}.tar.gz".format(prefix, resolved_diffbase))
2435
2436
2437def extract_archive(archive_url, dest_dir):
2438 if not os.path.isdir(dest_dir):
2439 os.mkdir(dest_dir)
2440
Florian Weikertecf091c2023-04-28 10:22:23 +02002441 try:
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002442 with tarfile.open(archive_url, mode="r:gz") as archive:
2443 archive.extractall(dest_dir)
2444 except tarfile.TarError as ex:
2445 raise BuildkiteInfraException("Failed to extract repository archive: {}".format(ex)) from ex
2446
2447
2448def download_file(url, dest_dir, dest_filename):
2449 local_path = os.path.join(dest_dir, dest_filename)
2450 try:
Florian Weikertdfd8db42023-05-09 15:41:30 +02002451 execute_command(["curl", "-sSL", url, "-o", local_path], capture_stderr=True)
Florian Weikertecf091c2023-04-28 10:22:23 +02002452 except subprocess.CalledProcessError as ex:
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002453 raise BuildkiteInfraException("Failed to download {}: {}\n{}".format(url, ex, ex.stderr))
Florian Weikertecf091c2023-04-28 10:22:23 +02002454 return local_path
2455
2456
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002457def run_bazel_diff(bazel_diff_path, old_workspace_dir, new_workspace_dir, bazel_binary, data_dir):
Florian Weikertecf091c2023-04-28 10:22:23 +02002458 before_json = os.path.join(data_dir, "before.json")
2459 after_json = os.path.join(data_dir, "after.json")
2460 targets_file = os.path.join(data_dir, "targets.txt")
2461
2462 try:
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002463 for repo_dir, json_path in (
2464 (old_workspace_dir, before_json),
2465 (new_workspace_dir, after_json),
2466 ):
Florian Weikertecf091c2023-04-28 10:22:23 +02002467 execute_command(
2468 [
2469 "java",
2470 "-jar",
2471 bazel_diff_path,
2472 "generate-hashes",
2473 "-w",
Florian Weikert5e70d9d2023-05-08 19:20:23 +02002474 repo_dir,
Florian Weikertecf091c2023-04-28 10:22:23 +02002475 "-b",
2476 bazel_binary,
2477 json_path,
Florian Weikertdfd8db42023-05-09 15:41:30 +02002478 ],
2479 capture_stderr=True,
Florian Weikertecf091c2023-04-28 10:22:23 +02002480 )
2481
2482 execute_command(
2483 [
2484 "java",
2485 "-jar",
2486 bazel_diff_path,
2487 "get-impacted-targets",
2488 "-sh",
2489 before_json,
2490 "-fh",
2491 after_json,
2492 "-o",
2493 targets_file,
Florian Weikertdfd8db42023-05-09 15:41:30 +02002494 ],
2495 capture_stderr=True,
Florian Weikertecf091c2023-04-28 10:22:23 +02002496 )
2497 except subprocess.CalledProcessError as ex:
Florian Weikertb0fcf902023-05-05 22:01:50 +02002498 raise BuildkiteInfraException("Failed to run bazel-diff: {}\n{}".format(ex, ex.stderr))
Florian Weikertecf091c2023-04-28 10:22:23 +02002499
2500 with open(targets_file, "rt") as f:
2501 contents = f.read()
2502
2503 return contents.split("\n")
2504
2505
Florian Weikert7dd9f662023-05-04 15:05:42 +02002506def partition_list(items):
2507 included, excluded = [], []
2508 for i in items:
2509 if i.startswith("-"):
2510 excluded.append(i[1:])
Florian Weikert736d06e2019-05-08 13:16:42 +02002511 else:
Florian Weikert7dd9f662023-05-04 15:05:42 +02002512 included.append(i)
Florian Weikert736d06e2019-05-08 13:16:42 +02002513
Florian Weikert7dd9f662023-05-04 15:05:42 +02002514 return included, excluded
Florian Weikert736d06e2019-05-08 13:16:42 +02002515
2516
Philipp Wollermann87b45252020-01-22 12:43:42 +01002517def get_targets_for_shard(test_targets, shard_id, shard_count):
Florian Weikert736d06e2019-05-08 13:16:42 +02002518 # TODO(fweikert): implement a more sophisticated algorithm
Philipp Wollermann87b45252020-01-22 12:43:42 +01002519 return sorted(test_targets)[shard_id::shard_count]
Florian Weikert736d06e2019-05-08 13:16:42 +02002520
2521
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002522def execute_bazel_test(
Florian Weikertc8642af2019-02-03 23:58:51 +01002523 bazel_version,
2524 bazel_binary,
2525 platform,
2526 flags,
2527 targets,
2528 bep_file,
2529 monitor_flaky_tests,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002530):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002531 aggregated_flags = [
2532 "--flaky_test_attempts=3",
2533 "--build_tests_only",
Tobias Werth08a93832023-04-25 16:29:52 +02002534 "--local_test_jobs=" + concurrent_test_jobs(platform),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002535 ]
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002536 # Don't enable remote caching if the user enabled remote execution / caching themselves
Jakob Buchgraberc340f582018-06-22 13:48:33 +02002537 # or flaky test monitoring is enabled, as remote caching makes tests look less flaky than
2538 # they are.
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02002539 print_collapsed_group(":bazel: Computing flags for test step")
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002540 aggregated_flags += compute_flags(
Yun Peng8975c6b2019-02-28 11:55:55 +01002541 platform,
2542 flags,
Yun Peng8975c6b2019-02-28 11:55:55 +01002543 bep_file,
Philipp Wollermann87b45252020-01-22 12:43:42 +01002544 bazel_binary,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002545 enable_remote_cache=not monitor_flaky_tests,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002546 )
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002547
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02002548 print_expanded_group(":bazel: Test ({})".format(bazel_version))
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002549 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002550 execute_command(
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002551 [bazel_binary]
2552 + bazelisk_flags()
Florian Weikertda94a102022-10-21 12:24:37 +02002553 + common_startup_flags()
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002554 + ["test"]
2555 + aggregated_flags
Philipp Wollermann2a160432019-09-19 15:57:28 +02002556 + ["--"]
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002557 + targets
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002558 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002559 except subprocess.CalledProcessError as e:
Yun Peng0a6a98a2019-03-06 13:07:54 +01002560 handle_bazel_failure(e, "test")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002561
Florian Weikert7f21ca42022-02-02 17:35:23 +01002562
Florian Weikertb3439b32022-11-09 11:05:16 +01002563def execute_bazel_coverage(bazel_version, bazel_binary, platform, flags, targets):
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01002564 aggregated_flags = [
2565 "--build_tests_only",
Tobias Werth08a93832023-04-25 16:29:52 +02002566 "--local_test_jobs=" + concurrent_test_jobs(platform),
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01002567 ]
2568 print_collapsed_group(":bazel: Computing flags for coverage step")
2569 aggregated_flags += compute_flags(
2570 platform,
2571 flags,
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01002572 None,
2573 bazel_binary,
2574 enable_remote_cache=True,
2575 )
2576
2577 print_expanded_group(":bazel: Coverage ({})".format(bazel_version))
2578 try:
2579 execute_command(
2580 [bazel_binary]
2581 + bazelisk_flags()
Florian Weikertda94a102022-10-21 12:24:37 +02002582 + common_startup_flags()
Xavier Bonaventura3755ea02022-02-02 13:56:54 +01002583 + ["coverage"]
2584 + aggregated_flags
2585 + ["--"]
2586 + targets
2587 )
2588 except subprocess.CalledProcessError as e:
2589 handle_bazel_failure(e, "coverage")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002590
Florian Weikert7f21ca42022-02-02 17:35:23 +01002591
Florian Weikertda94a102022-10-21 12:24:37 +02002592def upload_test_logs_from_bep(bep_file, tmpdir, monitor_flaky_tests):
Chi Wangd61eb972023-01-18 11:36:18 +01002593 bazelci_agent_binary = download_bazelci_agent(tmpdir)
Chi Wangd279d582021-09-29 10:59:06 +08002594 execute_command(
Florian Weikert7f21ca42022-02-02 17:35:23 +01002595 [
2596 bazelci_agent_binary,
2597 "artifact",
2598 "upload",
2599 "--delay=5",
2600 "--mode=buildkite",
2601 "--build_event_json_file={}".format(bep_file),
2602 ]
Chi Wangd279d582021-09-29 10:59:06 +08002603 + (["--monitor_flaky_tests"] if monitor_flaky_tests else [])
2604 )
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002605
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02002606
joeleba76887952019-05-16 15:22:17 +02002607def upload_json_profile(json_profile_path, tmpdir):
2608 if not os.path.exists(json_profile_path):
2609 return
2610 print_collapsed_group(":gcloud: Uploading JSON Profile")
Philipp Wollermann92cf51e2019-05-16 15:31:11 +02002611 execute_command(["buildkite-agent", "artifact", "upload", json_profile_path], cwd=tmpdir)
joeleba76887952019-05-16 15:22:17 +02002612
Philipp Wollermannf436e742021-08-11 11:06:55 +02002613
Chi Wang54595a22021-06-11 17:49:58 +08002614def upload_corrupted_outputs(capture_corrupted_outputs_dir, tmpdir):
2615 if not os.path.exists(capture_corrupted_outputs_dir):
2616 return
2617 print_collapsed_group(":gcloud: Uploading corrupted outputs")
Philipp Wollermannf436e742021-08-11 11:06:55 +02002618 execute_command(
2619 ["buildkite-agent", "artifact", "upload", "{}/**/*".format(capture_corrupted_outputs_dir)],
2620 cwd=tmpdir,
2621 )
2622
Philipp Wollermann5b00a702019-07-18 11:21:38 +02002623
Philipp Wollermannaf35abf2019-05-22 17:52:01 +02002624def execute_command_and_get_output(args, shell=False, fail_if_nonzero=True, print_output=True):
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002625 eprint(" ".join(args))
Florian Weikertc8642af2019-02-03 23:58:51 +01002626 process = subprocess.run(
2627 args,
2628 shell=shell,
2629 check=fail_if_nonzero,
2630 env=os.environ,
Florian Weikert9029ccf2023-05-08 17:07:04 +02002631 stdout=subprocess.PIPE, # We cannot use capture_output since some workers run Python <3.7
Philipp Wollermannf13804b2019-02-05 21:08:30 +01002632 errors="replace",
Florian Weikertc8642af2019-02-03 23:58:51 +01002633 universal_newlines=True,
2634 )
Florian Weikert736d06e2019-05-08 13:16:42 +02002635 if print_output:
2636 eprint(process.stdout)
2637
Florian Weikertc8642af2019-02-03 23:58:51 +01002638 return process.stdout
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002639
2640
Florian Weikertdfd8db42023-05-09 15:41:30 +02002641def execute_command(
2642 args, shell=False, fail_if_nonzero=True, cwd=None, print_output=True, capture_stderr=False
2643):
Yun Peng9337bb32020-02-28 13:31:29 +01002644 if print_output:
2645 eprint(" ".join(args))
Philipp Wollermann92cf51e2019-05-16 15:31:11 +02002646 return subprocess.run(
Florian Weikertb0fcf902023-05-05 22:01:50 +02002647 args,
2648 shell=shell,
2649 check=fail_if_nonzero,
2650 env=os.environ,
2651 cwd=cwd,
2652 errors="replace",
Florian Weikertdfd8db42023-05-09 15:41:30 +02002653 stderr=subprocess.PIPE
2654 if capture_stderr
2655 else None, # capture_stderr=True when we want exceptions to contain stderr
Philipp Wollermann92cf51e2019-05-16 15:31:11 +02002656 ).returncode
Philipp Wollermannf13804b2019-02-05 21:08:30 +01002657
2658
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02002659def execute_command_background(args):
2660 eprint(" ".join(args))
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02002661 return subprocess.Popen(args, env=os.environ)
2662
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02002663
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02002664def terminate_background_process(process):
2665 if process:
2666 process.terminate()
2667 try:
2668 process.wait(timeout=10)
2669 except subprocess.TimeoutExpired:
2670 process.kill()
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02002671
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02002672
mai93b49bad72021-05-06 00:50:34 +02002673def create_step(label, commands, platform, shards=1, soft_fail=None):
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002674 if "docker-image" in PLATFORMS[platform]:
Florian Weikert736d06e2019-05-08 13:16:42 +02002675 step = create_docker_step(
Florian Weikertb3439b32022-11-09 11:05:16 +01002676 label,
2677 image=PLATFORMS[platform]["docker-image"],
2678 commands=commands,
2679 queue=PLATFORMS[platform].get("queue", "default"),
2680 always_pull=PLATFORMS[platform].get("always-pull", True),
Philipp Wollermannc05ac682019-01-19 12:37:28 +01002681 )
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002682 else:
Philipp Wollermannf3750fa2019-05-21 17:11:59 +02002683 step = {
2684 "label": label,
2685 "command": commands,
2686 "agents": {"queue": PLATFORMS[platform]["queue"]},
2687 }
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002688
Florian Weikert736d06e2019-05-08 13:16:42 +02002689 if shards > 1:
2690 step["label"] += " (shard %n)"
2691 step["parallelism"] = shards
2692
mai93b49bad72021-05-06 00:50:34 +02002693 if soft_fail is not None:
2694 step["soft_fail"] = soft_fail
2695
Philipp Wollermann5b2f3fc2019-05-18 22:36:17 +02002696 # Enforce a global 8 hour job timeout.
2697 step["timeout_in_minutes"] = 8 * 60
2698
2699 # Automatically retry when an agent got lost (usually due to an infra flake).
Philipp Wollermannf22bba32019-07-18 11:22:50 +02002700 step["retry"] = {
2701 "automatic": [
2702 {"exit_status": -1, "limit": 3}, # Buildkite internal "agent lost" exit code
2703 {"exit_status": 137, "limit": 3}, # SIGKILL
2704 {"exit_status": 143, "limit": 3}, # SIGTERM
2705 ]
2706 }
Philipp Wollermann5b2f3fc2019-05-18 22:36:17 +02002707
Florian Weikert736d06e2019-05-08 13:16:42 +02002708 return step
2709
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002710
Florian Weikertb3439b32022-11-09 11:05:16 +01002711def create_docker_step(
2712 label, image, commands=None, additional_env_vars=None, queue="default", always_pull=True
2713):
Philipp Wollermann0e051dd2019-05-16 11:37:52 +02002714 env = ["ANDROID_HOME", "ANDROID_NDK_HOME", "BUILDKITE_ARTIFACT_UPLOAD_DESTINATION"]
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002715 if additional_env_vars:
2716 env += ["{}={}".format(k, v) for k, v in additional_env_vars.items()]
2717
Philipp Wollermannc05ac682019-01-19 12:37:28 +01002718 step = {
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002719 "label": label,
2720 "command": commands,
Yun Peng07dafc52022-03-16 13:23:35 +01002721 "agents": {"queue": queue},
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002722 "plugins": {
Philipp Wollermann9fa03542021-07-01 23:27:53 +02002723 "docker#v3.8.0": {
Yun Peng07dafc52022-03-16 13:23:35 +01002724 "always-pull": always_pull,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002725 "environment": env,
Philipp Wollermannc05ac682019-01-19 12:37:28 +01002726 "image": image,
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002727 "network": "host",
2728 "privileged": True,
2729 "propagate-environment": True,
Philipp Wollermann7aa95492019-05-18 22:03:24 +02002730 "propagate-uid-gid": True,
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002731 "volumes": [
Philipp Wollermann7aa95492019-05-18 22:03:24 +02002732 "/etc/group:/etc/group:ro",
2733 "/etc/passwd:/etc/passwd:ro",
Philipp Wollermann3dc99b32021-10-12 00:34:30 +02002734 "/etc/shadow:/etc/shadow:ro",
Philipp Wollermann562ef1d2021-10-20 22:15:29 +02002735 "/opt/android-ndk-r15c:/opt/android-ndk-r15c:ro",
Yun Peng72874212022-09-13 19:08:03 +02002736 "/opt/android-ndk-r25b:/opt/android-ndk-r25b:ro",
Philipp Wollermann562ef1d2021-10-20 22:15:29 +02002737 "/opt/android-sdk-linux:/opt/android-sdk-linux:ro",
Philipp Wollermann7aa95492019-05-18 22:03:24 +02002738 "/var/lib/buildkite-agent:/var/lib/buildkite-agent",
Philipp Wollermann338db4a2019-05-18 11:21:04 +02002739 "/var/lib/gitmirrors:/var/lib/gitmirrors:ro",
Philipp Wollermanna65944a2020-02-03 12:45:22 +01002740 "/var/run/docker.sock:/var/run/docker.sock",
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002741 ],
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002742 }
2743 },
2744 }
Philipp Wollermannc05ac682019-01-19 12:37:28 +01002745 if not step["command"]:
2746 del step["command"]
2747 return step
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002748
2749
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002750def print_project_pipeline(
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002751 configs,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002752 project_name,
2753 http_config,
2754 file_config,
2755 git_repository,
2756 monitor_flaky_tests,
2757 use_but,
Florian Weikert60661912019-12-18 15:17:10 +01002758 notify,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002759):
Florian Weikert843d7a02019-02-03 17:24:50 +01002760 task_configs = configs.get("tasks", None)
2761 if not task_configs:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002762 raise BuildkiteException("{0} pipeline configuration is empty.".format(project_name))
2763
Jakob Buchgraberaa2af382018-02-21 19:56:54 +01002764 pipeline_steps = []
mai93f2e116c2020-10-19 09:33:14 +02002765 # If the repository is hosted on Git-on-borg, we show the link to the commit Gerrit review
2766 buildkite_repo = os.getenv("BUILDKITE_REPO")
2767 if is_git_on_borg_repo(buildkite_repo):
2768 show_gerrit_review_link(buildkite_repo, pipeline_steps)
2769
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02002770 task_configs = filter_tasks_that_should_be_skipped(task_configs, pipeline_steps)
Jakob Buchgraberff2bdad2018-02-25 13:06:30 +01002771
Philipp Wollermanndac65512019-02-05 22:14:10 +01002772 # In Bazel Downstream Project pipelines, git_repository and project_name must be specified.
Yun Pengc85cd0e2022-09-02 10:44:29 +02002773 is_downstream_project = use_but and git_repository and project_name
Philipp Wollermanndac65512019-02-05 22:14:10 +01002774
Florian Weikert85208912019-03-07 17:08:39 +01002775 buildifier_config = configs.get("buildifier")
Philipp Wollermanndac65512019-02-05 22:14:10 +01002776 # Skip Buildifier when we test downstream projects.
Florian Weikert85208912019-03-07 17:08:39 +01002777 if buildifier_config and not is_downstream_project:
2778 buildifier_env_vars = {}
2779 if isinstance(buildifier_config, str):
2780 # Simple format:
2781 # ---
2782 # buildifier: latest
Philipp Wollermann22538e72021-10-02 09:43:28 +02002783 buildifier_env_vars["BUILDIFIER_VERSION"] = buildifier_config
Florian Weikert85208912019-03-07 17:08:39 +01002784 else:
2785 # Advanced format:
2786 # ---
2787 # buildifier:
2788 # version: latest
2789 # warnings: all
Philipp Wollermann22538e72021-10-02 09:43:28 +02002790 if "version" in buildifier_config:
2791 buildifier_env_vars["BUILDIFIER_VERSION"] = buildifier_config["version"]
2792 if "warnings" in buildifier_config:
2793 buildifier_env_vars["BUILDIFIER_WARNINGS"] = buildifier_config["warnings"]
Florian Weikert85208912019-03-07 17:08:39 +01002794
2795 if not buildifier_env_vars:
2796 raise BuildkiteException(
2797 'Invalid buildifier configuration entry "{}"'.format(buildifier_config)
2798 )
2799
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002800 pipeline_steps.append(
2801 create_docker_step(
Florian Weikertde96a6f2019-03-07 14:57:50 +01002802 BUILDIFIER_STEP_NAME,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002803 image=BUILDIFIER_DOCKER_IMAGE,
Florian Weikert85208912019-03-07 17:08:39 +01002804 additional_env_vars=buildifier_env_vars,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002805 )
2806 )
Philipp Wollermannc05ac682019-01-19 12:37:28 +01002807
Philipp Wollermanndac65512019-02-05 22:14:10 +01002808 # In Bazel Downstream Project pipelines, we should test the project at the last green commit.
Yun Peng376d2b32018-11-29 10:24:54 +01002809 git_commit = None
Philipp Wollermanndac65512019-02-05 22:14:10 +01002810 if is_downstream_project:
Florian Weikert35906542019-04-01 11:53:53 +02002811 last_green_commit_url = bazelci_last_green_commit_url(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002812 git_repository, DOWNSTREAM_PROJECTS[project_name]["pipeline_slug"]
2813 )
Florian Weikert35906542019-04-01 11:53:53 +02002814 git_commit = get_last_green_commit(last_green_commit_url)
Philipp Wollermanndac65512019-02-05 22:14:10 +01002815
Florian Weikert854fd852019-06-04 16:44:19 +02002816 config_hashes = set()
Yun Penge6b09902023-03-31 17:15:58 +02002817 skipped_downstream_tasks = []
Florian Weikert843d7a02019-02-03 17:24:50 +01002818 for task, task_config in task_configs.items():
Florian Weikertdb832a02020-11-19 19:14:48 +01002819 platform = get_platform_for_task(task, task_config)
2820 task_name = task_config.get("name")
mai93b49bad72021-05-06 00:50:34 +02002821 soft_fail = task_config.get("soft_fail")
Florian Weikertdb832a02020-11-19 19:14:48 +01002822
Florian Weikert854fd852019-06-04 16:44:19 +02002823 # We override the Bazel version in downstream pipelines. This means that two tasks that
2824 # only differ in the value of their explicit "bazel" field will be identical in the
2825 # downstream pipeline, thus leading to duplicate work.
2826 # Consequently, we filter those duplicate tasks here.
2827 if is_downstream_project:
2828 h = hash_task_config(task, task_config)
2829 if h in config_hashes:
Yun Penge6b09902023-03-31 17:15:58 +02002830 skipped_downstream_tasks.append(
Yun Peng9d905fb2023-04-24 14:13:26 +02002831 "{}: {}".format(
Florian Weikertb3439b32022-11-09 11:05:16 +01002832 create_label(platform, project_name, task_name=task_name),
Yun Penge6b09902023-03-31 17:15:58 +02002833 "The same task already exists after ignoring bazel version.",
Florian Weikertb3439b32022-11-09 11:05:16 +01002834 )
2835 )
Florian Weikert11d31432023-02-27 11:33:23 +01002836 continue
2837
Florian Weikert854fd852019-06-04 16:44:19 +02002838 config_hashes.add(h)
2839
Yun Penge6b09902023-03-31 17:15:58 +02002840 # Skip tasks with `skip_in_bazel_downstream_pipeline` specified.
2841 skipped_reason = task_config.get("skip_in_bazel_downstream_pipeline", "")
2842 if skipped_reason:
2843 skipped_downstream_tasks.append(
Yun Peng9d905fb2023-04-24 14:13:26 +02002844 "{}: {}".format(
Yun Penge6b09902023-03-31 17:15:58 +02002845 create_label(platform, project_name, task_name=task_name),
2846 skipped_reason,
2847 )
2848 )
2849 continue
2850
Florian Weikert736d06e2019-05-08 13:16:42 +02002851 shards = task_config.get("shards", "1")
2852 try:
2853 shards = int(shards)
2854 except ValueError:
2855 raise BuildkiteException("Task {} has invalid shard value '{}'".format(task, shards))
2856
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002857 step = runner_step(
Florian Weikertdb832a02020-11-19 19:14:48 +01002858 platform=platform,
Florian Weikert843d7a02019-02-03 17:24:50 +01002859 task=task,
Florian Weikertdb832a02020-11-19 19:14:48 +01002860 task_name=task_name,
Florian Weikert843d7a02019-02-03 17:24:50 +01002861 project_name=project_name,
2862 http_config=http_config,
2863 file_config=file_config,
2864 git_repository=git_repository,
2865 git_commit=git_commit,
2866 monitor_flaky_tests=monitor_flaky_tests,
2867 use_but=use_but,
Florian Weikert736d06e2019-05-08 13:16:42 +02002868 shards=shards,
mai93b49bad72021-05-06 00:50:34 +02002869 soft_fail=soft_fail,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002870 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002871 pipeline_steps.append(step)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002872
Yun Penge6b09902023-03-31 17:15:58 +02002873 if skipped_downstream_tasks:
2874 lines = ["\n- {}".format(s) for s in skipped_downstream_tasks]
Florian Weikertdb832a02020-11-19 19:14:48 +01002875 commands = [
Yun Pengee010872023-04-24 14:48:19 +02002876 "buildkite-agent meta-data exists 'has-skipped-annotation' || buildkite-agent annotate --style=info 'The following tasks were skipped:\n' --context 'ctx-skipped_downstream_tasks'",
2877 "buildkite-agent meta-data set 'has-skipped-annotation' 'true'",
Yun Penge6b09902023-03-31 17:15:58 +02002878 "buildkite-agent annotate --style=info '{}' --append --context 'ctx-skipped_downstream_tasks'".format(
Xùdōng Yáng045c9812021-08-18 01:42:35 +10002879 "".join(lines)
2880 ),
Florian Weikertdb832a02020-11-19 19:14:48 +01002881 ]
2882 pipeline_steps.append(
2883 create_step(
Yun Penge6b09902023-03-31 17:15:58 +02002884 label=":pipeline: Print information about skipped tasks",
Florian Weikertdb832a02020-11-19 19:14:48 +01002885 commands=commands,
2886 platform=DEFAULT_PLATFORM,
2887 )
2888 )
2889
Yun Peng996efad2018-11-27 17:19:44 +01002890 pipeline_slug = os.getenv("BUILDKITE_PIPELINE_SLUG")
2891 all_downstream_pipeline_slugs = []
2892 for _, config in DOWNSTREAM_PROJECTS.items():
2893 all_downstream_pipeline_slugs.append(config["pipeline_slug"])
Ivo List23ce48d2020-11-18 13:15:34 +01002894 # We update last green commit in the following cases:
2895 # 1. This job runs on master, stable or main branch (could be a custom build launched manually)
2896 # 2. We intend to run the same job in downstream with Bazel@HEAD (eg. google-bazel-presubmit)
2897 # 3. This job is not:
2898 # - a GitHub pull request
2899 # - uses a custom built Bazel binary (in Bazel Downstream Projects pipeline)
2900 # - testing incompatible flags
2901 # - running `bazelisk --migrate` in a non-downstream pipeline
Florian Weikertdb832a02020-11-19 19:14:48 +01002902 if (
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02002903 current_branch_is_main_branch()
Ivo List23ce48d2020-11-18 13:15:34 +01002904 and pipeline_slug in all_downstream_pipeline_slugs
Yun Pengc85cd0e2022-09-02 10:44:29 +02002905 and not (is_pull_request() or use_but or use_bazelisk_migrate())
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002906 ):
Florian Weikertde96a6f2019-03-07 14:57:50 +01002907 # We need to call "Try Update Last Green Commit" even if there are failures,
2908 # since we don't want a failing Buildifier step to block the update of
2909 # the last green commit for this project.
2910 # try_update_last_green_commit() ensures that we don't update the commit
2911 # if any build or test steps fail.
2912 pipeline_steps.append({"wait": None, "continue_on_failure": True})
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002913 pipeline_steps.append(
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002914 create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002915 label="Try Update Last Green Commit",
2916 commands=[
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002917 fetch_bazelcipy_command(),
Philipp Wollermann57b32682019-05-18 22:09:27 +02002918 PLATFORMS[DEFAULT_PLATFORM]["python"]
2919 + " bazelci.py try_update_last_green_commit",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002920 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002921 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002922 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002923 )
Yun Peng43239b02018-11-23 13:57:34 +01002924
Florian Weikert778251c2019-04-25 15:14:44 +02002925 if "validate_config" in configs:
Florian Weikertf52f91a2019-05-08 15:19:30 +02002926 pipeline_steps += create_config_validation_steps()
Florian Weikert778251c2019-04-25 15:14:44 +02002927
Florian Weikert09813a02019-10-26 19:34:33 +02002928 if use_bazelisk_migrate() and not is_downstream_project:
2929 # Print results of bazelisk --migrate in project pipelines that explicitly set
2930 # the USE_BAZELISK_MIGRATE env var, but that are not being run as part of a
2931 # downstream pipeline.
2932 number = os.getenv("BUILDKITE_BUILD_NUMBER")
Florian Weikert60661912019-12-18 15:17:10 +01002933 pipeline_steps += get_steps_for_aggregating_migration_results(number, notify)
Florian Weikert09813a02019-10-26 19:34:33 +02002934
Florian Weikertd79dc502019-05-13 09:51:05 +02002935 print_pipeline_steps(pipeline_steps, handle_emergencies=not is_downstream_project)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002936
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002937
mai93f2e116c2020-10-19 09:33:14 +02002938def show_gerrit_review_link(git_repository, pipeline_steps):
2939 host = re.search(r"https://(.+?)\.googlesource", git_repository).group(1)
2940 if not host:
2941 raise BuildkiteException("Couldn't get host name from %s" % git_repository)
Florian Weikertdb832a02020-11-19 19:14:48 +01002942 text = "The transformed code used in this pipeline can be found under https://{}-review.googlesource.com/q/{}".format(
2943 host, os.getenv("BUILDKITE_COMMIT")
2944 )
Florian Weikertc6cc6172023-05-04 20:20:55 +02002945 commands = ["buildkite-agent annotate --style=info --context 'gerrit' '{}'".format(text)]
mai93f2e116c2020-10-19 09:33:14 +02002946 pipeline_steps.append(
2947 create_step(
2948 label=":pipeline: Print information about Gerrit Review Link",
2949 commands=commands,
2950 platform=DEFAULT_PLATFORM,
2951 )
2952 )
2953
2954
2955def is_git_on_borg_repo(git_repository):
2956 return git_repository and "googlesource.com" in git_repository
2957
2958
Florian Weikert854fd852019-06-04 16:44:19 +02002959def hash_task_config(task_name, task_config):
2960 # Two task configs c1 and c2 have the same hash iff they lead to two functionally identical jobs
2961 # in the downstream pipeline. This function discards the "bazel" field (since it's being
Philipp Wollermannce986af2019-07-18 14:46:05 +02002962 # overridden) and the "name" field (since it has no effect on the actual work).
Florian Weikert854fd852019-06-04 16:44:19 +02002963 # Moreover, it adds an explicit "platform" field if that's missing.
2964 cpy = task_config.copy()
2965 cpy.pop("bazel", None)
2966 cpy.pop("name", None)
2967 if "platform" not in cpy:
2968 cpy["platform"] = task_name
2969
2970 m = hashlib.md5()
Florian Weikertb3439b32022-11-09 11:05:16 +01002971 # Technically we should sort cpy[key] if it's a list of entries
2972 # whose order does not matter (e.g. targets).
2973 # However, this seems to be overkill for the current use cases.
Florian Weikert854fd852019-06-04 16:44:19 +02002974 for key in sorted(cpy):
Florian Weikert8186c392019-06-05 12:53:39 +02002975 value = "%s:%s;" % (key, cpy[key])
2976 m.update(value.encode("utf-8"))
Florian Weikert854fd852019-06-04 16:44:19 +02002977
2978 return m.digest()
2979
2980
Florian Weikert843d7a02019-02-03 17:24:50 +01002981def get_platform_for_task(task, task_config):
2982 # Most pipeline configurations have exactly one task per platform, which makes it
2983 # convenient to use the platform name as task ID. Consequently, we use the
2984 # task ID as platform if there is no explicit "platform" field.
2985 return task_config.get("platform", task)
2986
2987
Florian Weikertf52f91a2019-05-08 15:19:30 +02002988def create_config_validation_steps():
Florian Weikertf52f91a2019-05-08 15:19:30 +02002989 config_files = [
Philipp Wollermann67225ec2021-08-11 11:12:51 +02002990 path
Florian Weikerte417f9f2023-05-05 17:33:46 +02002991 for path in get_modified_files()
Philipp Wollermann67225ec2021-08-11 11:12:51 +02002992 if path.startswith(".bazelci/") and os.path.splitext(path)[1] in CONFIG_FILE_EXTENSIONS
Florian Weikertf52f91a2019-05-08 15:19:30 +02002993 ]
Florian Weikertf52f91a2019-05-08 15:19:30 +02002994 return [
2995 create_step(
2996 label=":cop: Validate {}".format(f),
2997 commands=[
2998 fetch_bazelcipy_command(),
2999 "{} bazelci.py project_pipeline --file_config={}".format(
Philipp Wollermann57b32682019-05-18 22:09:27 +02003000 PLATFORMS[DEFAULT_PLATFORM]["python"], f
Florian Weikertf52f91a2019-05-08 15:19:30 +02003001 ),
3002 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02003003 platform=DEFAULT_PLATFORM,
Florian Weikertf52f91a2019-05-08 15:19:30 +02003004 )
3005 for f in config_files
3006 ]
3007
3008
Florian Weikerte417f9f2023-05-05 17:33:46 +02003009def get_modified_files():
3010 output = execute_command_and_get_output(
3011 ["git", "diff-tree", "--no-commit-id", "--name-only", "-r", os.getenv("BUILDKITE_COMMIT")]
3012 )
3013 return output.split("\n")
3014
3015
Florian Weikertd79dc502019-05-13 09:51:05 +02003016def print_pipeline_steps(pipeline_steps, handle_emergencies=True):
3017 if handle_emergencies:
3018 emergency_step = create_emergency_announcement_step_if_necessary()
3019 if emergency_step:
3020 pipeline_steps.insert(0, emergency_step)
Florian Weikert13215a82019-05-10 12:42:21 +02003021
3022 print(yaml.dump({"steps": pipeline_steps}))
3023
3024
3025def create_emergency_announcement_step_if_necessary():
3026 style = "error"
3027 message, issue_url, last_good_bazel = None, None, None
3028 try:
3029 emergency_settings = load_remote_yaml_file(EMERGENCY_FILE_URL)
3030 message = emergency_settings.get("message")
3031 issue_url = emergency_settings.get("issue_url")
3032 last_good_bazel = emergency_settings.get("last_good_bazel")
3033 except urllib.error.HTTPError as ex:
3034 message = str(ex)
3035 style = "warning"
3036
3037 if not any([message, issue_url, last_good_bazel]):
3038 return
3039
3040 text = '<span class="h1">:rotating_light: Emergency :rotating_light:</span>\n'
3041 if message:
3042 text += "- {}\n".format(message)
3043 if issue_url:
3044 text += '- Please check this <a href="{}">issue</a> for more details.\n'.format(issue_url)
3045 if last_good_bazel:
3046 text += (
3047 "- Default Bazel version is *{}*, "
3048 "unless the pipeline configuration specifies an explicit version."
3049 ).format(last_good_bazel)
3050
3051 return create_step(
3052 label=":rotating_light: Emergency :rotating_light:",
Philipp Wollermann7590b962019-05-16 11:35:03 +02003053 commands=[
3054 'buildkite-agent annotate --append --style={} --context "omg" "{}"'.format(style, text)
3055 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02003056 platform=DEFAULT_PLATFORM,
Florian Weikert13215a82019-05-10 12:42:21 +02003057 )
3058
3059
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003060def runner_step(
3061 platform,
Florian Weikert843d7a02019-02-03 17:24:50 +01003062 task,
3063 task_name=None,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003064 project_name=None,
3065 http_config=None,
3066 file_config=None,
3067 git_repository=None,
3068 git_commit=None,
3069 monitor_flaky_tests=False,
3070 use_but=False,
Florian Weikert736d06e2019-05-08 13:16:42 +02003071 shards=1,
mai93b49bad72021-05-06 00:50:34 +02003072 soft_fail=None,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003073):
Philipp Wollermann57b32682019-05-18 22:09:27 +02003074 command = PLATFORMS[platform]["python"] + " bazelci.py runner --task=" + task
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003075 if http_config:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003076 command += " --http_config=" + http_config
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003077 if file_config:
3078 command += " --file_config=" + file_config
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003079 if git_repository:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003080 command += " --git_repository=" + git_repository
Yun Peng376d2b32018-11-29 10:24:54 +01003081 if git_commit:
3082 command += " --git_commit=" + git_commit
Jakob Buchgraberc340f582018-06-22 13:48:33 +02003083 if monitor_flaky_tests:
3084 command += " --monitor_flaky_tests"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003085 if use_but:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003086 command += " --use_but"
Florian Weikert843d7a02019-02-03 17:24:50 +01003087 label = create_label(platform, project_name, task_name=task_name)
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01003088 return create_step(
Florian Weikert9d5e4c02021-05-27 15:10:20 +02003089 label=label,
3090 commands=[fetch_bazelcipy_command(), command],
3091 platform=platform,
3092 shards=shards,
3093 soft_fail=soft_fail,
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01003094 )
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003095
3096
3097def fetch_bazelcipy_command():
Philipp Wollermanne67eec42019-05-24 15:18:20 +02003098 return "curl -sS {0} -o bazelci.py".format(SCRIPT_URL)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003099
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003100
Yun Peng8975c6b2019-02-28 11:55:55 +01003101def fetch_aggregate_incompatible_flags_test_result_command():
3102 return "curl -sS {0} -o aggregate_incompatible_flags_test_result.py".format(
Philipp Wollermanne67eec42019-05-24 15:18:20 +02003103 AGGREGATE_INCOMPATIBLE_TEST_RESULT_URL
Yun Peng8975c6b2019-02-28 11:55:55 +01003104 )
3105
3106
Florian Weikertb3439b32022-11-09 11:05:16 +01003107def upload_project_pipeline_step(project_name, git_repository, http_config, file_config):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003108 pipeline_command = (
3109 '{0} bazelci.py project_pipeline --project_name="{1}" ' + "--git_repository={2}"
Philipp Wollermann57b32682019-05-18 22:09:27 +02003110 ).format(PLATFORMS[DEFAULT_PLATFORM]["python"], project_name, git_repository)
Yun Pengc85cd0e2022-09-02 10:44:29 +02003111 pipeline_command += " --use_but"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003112 if http_config:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003113 pipeline_command += " --http_config=" + http_config
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003114 if file_config:
3115 pipeline_command += " --file_config=" + file_config
Chi Wangf1f20362022-02-01 13:44:45 +01003116 pipeline_command += " | tee /dev/tty | buildkite-agent pipeline upload"
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003117
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01003118 return create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01003119 label="Setup {0}".format(project_name),
3120 commands=[fetch_bazelcipy_command(), pipeline_command],
Philipp Wollermann7a185322019-05-18 22:15:48 +02003121 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01003122 )
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003123
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003124
Florian Weikert843d7a02019-02-03 17:24:50 +01003125def create_label(platform, project_name, build_only=False, test_only=False, task_name=None):
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003126 if build_only and test_only:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003127 raise BuildkiteException("build_only and test_only cannot be true at the same time")
Florian Weikert843d7a02019-02-03 17:24:50 +01003128 platform_display_name = PLATFORMS[platform]["emoji-name"]
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003129
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003130 if build_only:
3131 label = "Build "
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003132 elif test_only:
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003133 label = "Test "
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003134 else:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003135 label = ""
3136
Florian Weikert843d7a02019-02-03 17:24:50 +01003137 platform_label = (
3138 "{0} on {1}".format(task_name, platform_display_name)
3139 if task_name
3140 else platform_display_name
3141 )
3142
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003143 if project_name:
Florian Weikert843d7a02019-02-03 17:24:50 +01003144 label += "{0} ({1})".format(project_name, platform_label)
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003145 else:
Florian Weikert843d7a02019-02-03 17:24:50 +01003146 label += platform_label
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003147
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003148 return label
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003149
3150
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003151def bazel_build_step(
Florian Weikert843d7a02019-02-03 17:24:50 +01003152 task,
3153 platform,
3154 project_name,
3155 http_config=None,
3156 file_config=None,
3157 build_only=False,
3158 test_only=False,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003159):
Philipp Wollermann57b32682019-05-18 22:09:27 +02003160 pipeline_command = PLATFORMS[platform]["python"] + " bazelci.py runner"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003161 if build_only:
Philipp Wollermannc52e26a2019-05-18 22:10:47 +02003162 pipeline_command += " --build_only --save_but"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003163 if test_only:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003164 pipeline_command += " --test_only"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003165 if http_config:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01003166 pipeline_command += " --http_config=" + http_config
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003167 if file_config:
3168 pipeline_command += " --file_config=" + file_config
Florian Weikert843d7a02019-02-03 17:24:50 +01003169 pipeline_command += " --task=" + task
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003170
Yun Pengbe4e2eb2022-09-16 11:42:50 +02003171 step = create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01003172 label=create_label(platform, project_name, build_only, test_only),
3173 commands=[fetch_bazelcipy_command(), pipeline_command],
3174 platform=platform,
3175 )
Yun Pengbe4e2eb2022-09-16 11:42:50 +02003176 # Always try to automatically retry the bazel build step, this will make
3177 # the publish bazel binaries pipeline more reliable.
3178 step["retry"] = {
3179 "automatic": [
3180 {"exit_status": "*", "limit": 3},
3181 ]
3182 }
3183 return step
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003184
3185
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02003186def filter_tasks_that_should_be_skipped(task_configs, pipeline_steps):
3187 skip_tasks = get_skip_tasks()
3188 if not skip_tasks:
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02003189 return task_configs
3190
3191 actually_skipped = []
3192 skip_tasks = set(skip_tasks)
3193 for task in list(task_configs.keys()):
3194 if task in skip_tasks:
3195 actually_skipped.append(task)
3196 del task_configs[task]
3197 skip_tasks.remove(task)
3198
3199 if not task_configs:
3200 raise BuildkiteException(
3201 "Nothing to do since all tasks in the configuration should be skipped."
3202 )
3203
3204 annotations = []
3205 if actually_skipped:
3206 annotations.append(
3207 ("info", "Skipping the following task(s): {}".format(", ".join(actually_skipped)))
3208 )
3209
3210 if skip_tasks:
3211 annotations.append(
3212 (
3213 "warning",
3214 (
3215 "The following tasks should have been skipped, "
3216 "but were not part of the configuration: {}"
3217 ).format(", ".join(skip_tasks)),
3218 )
3219 )
3220
3221 if annotations:
3222 print_skip_task_annotations(annotations, pipeline_steps)
3223
3224 return task_configs
3225
3226
3227def get_skip_tasks():
3228 value = os.getenv(SKIP_TASKS_ENV_VAR, "")
3229 return [v for v in value.split(",") if v]
3230
3231
3232def print_skip_task_annotations(annotations, pipeline_steps):
3233 commands = [
3234 "buildkite-agent annotate --style={} '{}' --context 'ctx-{}'".format(s, t, hash(t))
3235 for s, t in annotations
3236 ]
3237 pipeline_steps.append(
Philipp Wollermann7a185322019-05-18 22:15:48 +02003238 create_step(
3239 label=":pipeline: Print information about skipped tasks",
3240 commands=commands,
3241 platform=DEFAULT_PLATFORM,
3242 )
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02003243 )
3244
3245
Florian Weikert843d7a02019-02-03 17:24:50 +01003246def print_bazel_publish_binaries_pipeline(task_configs, http_config, file_config):
3247 if not task_configs:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003248 raise BuildkiteException("Bazel publish binaries pipeline configuration is empty.")
3249
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02003250 pipeline_steps = []
3251 task_configs = filter_tasks_that_should_be_skipped(task_configs, pipeline_steps)
3252
Florian Weikert843d7a02019-02-03 17:24:50 +01003253 platforms = [get_platform_for_task(t, tc) for t, tc in task_configs.items()]
Philipp Wollermann783d1672019-06-06 13:35:30 +02003254
3255 # These are the platforms that the bazel_publish_binaries.yml config is actually building.
3256 configured_platforms = set(filter(should_publish_binaries_for_platform, platforms))
Philipp Wollermanna2ea5d82018-08-27 14:12:10 +02003257
Philipp Wollermann783d1672019-06-06 13:35:30 +02003258 # These are the platforms that we want to build and publish according to this script.
3259 expected_platforms = set(filter(should_publish_binaries_for_platform, PLATFORMS))
Florian Weikert843d7a02019-02-03 17:24:50 +01003260
Philipp Wollermann30f314d2021-06-11 10:51:39 +02003261 # We can skip this check if we're not on the main branch, because then we're probably
3262 # building a one-off custom debugging binary anyway.
Florian Weikert7f21ca42022-02-02 17:35:23 +01003263 if current_branch_is_main_branch():
3264 missing = expected_platforms.difference(configured_platforms)
3265 if missing:
3266 raise BuildkiteException(
3267 (
3268 "Bazel publish binaries pipeline needs to build Bazel for every commit on all publish_binary-enabled platforms. "
3269 "Please add jobs for the missing platform(s) to the pipeline config: {}".format(
3270 ", ".join(missing)
3271 )
3272 )
3273 )
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01003274
Yun Pengd352b6d2018-10-17 13:28:39 +02003275 # Build Bazel
Florian Weikert843d7a02019-02-03 17:24:50 +01003276 for task, task_config in task_configs.items():
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003277 pipeline_steps.append(
Florian Weikert843d7a02019-02-03 17:24:50 +01003278 bazel_build_step(
3279 task,
3280 get_platform_for_task(task, task_config),
3281 "Bazel",
3282 http_config,
3283 file_config,
3284 build_only=True,
3285 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003286 )
Jakob Buchgraber4631a032018-03-22 17:12:46 +01003287
Yun Peng1ce55be2023-08-11 16:19:26 +02003288 pipeline_steps.append({"wait": None, "continue_on_failure": True})
Jakob Buchgraber9d6ca8a2018-03-22 17:30:09 +01003289
Yun Pengc2dd6522018-10-17 12:58:35 +02003290 # If all builds succeed, publish the Bazel binaries to GCS.
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003291 pipeline_steps.append(
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01003292 create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01003293 label="Publish Bazel Binaries",
Philipp Wollermann57b32682019-05-18 22:09:27 +02003294 commands=[
3295 fetch_bazelcipy_command(),
3296 PLATFORMS[DEFAULT_PLATFORM]["python"] + " bazelci.py publish_binaries",
3297 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02003298 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01003299 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003300 )
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01003301
Florian Weikert13215a82019-05-10 12:42:21 +02003302 print_pipeline_steps(pipeline_steps)
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01003303
3304
Florian Weikert843d7a02019-02-03 17:24:50 +01003305def should_publish_binaries_for_platform(platform):
3306 if platform not in PLATFORMS:
3307 raise BuildkiteException("Unknown platform '{}'".format(platform))
3308
3309 return PLATFORMS[platform]["publish_binary"]
3310
3311
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01003312def print_disabled_projects_info_box_step():
3313 info_text = ["Downstream testing is disabled for the following projects :sadpanda:"]
3314 for project, config in DOWNSTREAM_PROJECTS.items():
3315 disabled_reason = config.get("disabled_reason", None)
3316 if disabled_reason:
3317 info_text.append("* **%s**: %s" % (project, disabled_reason))
3318
3319 if len(info_text) == 1:
3320 return None
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01003321 return create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01003322 label=":sadpanda:",
3323 commands=[
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003324 'buildkite-agent annotate --append --style=info "\n' + "\n".join(info_text) + '\n"'
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01003325 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02003326 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01003327 )
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01003328
Yun Peng6528e652019-01-02 14:41:07 +01003329
3330def print_incompatible_flags_info_box_step(incompatible_flags_map):
3331 info_text = ["Build and test with the following incompatible flags:"]
3332
3333 for flag in incompatible_flags_map:
3334 info_text.append("* **%s**: %s" % (flag, incompatible_flags_map[flag]))
3335
3336 if len(info_text) == 1:
3337 return None
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01003338 return create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01003339 label="Incompatible flags info",
3340 commands=[
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003341 'buildkite-agent annotate --append --style=info "\n' + "\n".join(info_text) + '\n"'
Yun Peng6528e652019-01-02 14:41:07 +01003342 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02003343 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01003344 )
Yun Peng6528e652019-01-02 14:41:07 +01003345
3346
Yun Peng7d302f62019-01-10 16:56:15 +01003347def fetch_incompatible_flags():
Yun Peng6528e652019-01-02 14:41:07 +01003348 """
Yun Pengc85cd0e2022-09-02 10:44:29 +02003349 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 +01003350 """
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003351 output = subprocess.check_output(
3352 [
Yun Pengc85cd0e2022-09-02 10:44:29 +02003353 # Query for open issues with "incompatible-change" and "migration-ready" label.
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003354 "curl",
Yun Pengc85cd0e2022-09-02 10:44:29 +02003355 "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 +01003356 ]
3357 ).decode("utf-8")
Yun Peng6528e652019-01-02 14:41:07 +01003358 issue_info = json.loads(output)
3359
Yun Pengc85cd0e2022-09-02 10:44:29 +02003360 FLAG_PATTERN = re.compile(r"^--[a-z][a-z0-9_]*$")
3361 incompatible_flags = {}
Yun Peng6528e652019-01-02 14:41:07 +01003362 for issue in issue_info["items"]:
Yun Peng6528e652019-01-02 14:41:07 +01003363 name = "--" + issue["title"].split(":")[0]
3364 url = issue["html_url"]
Yun Pengc85cd0e2022-09-02 10:44:29 +02003365 if FLAG_PATTERN.match(name):
Yun Peng6528e652019-01-02 14:41:07 +01003366 incompatible_flags[name] = url
3367 else:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003368 eprint(
Philipp Wollermann639c0452019-01-03 11:23:54 +01003369 f"{name} is not recognized as an incompatible flag, please modify the issue title "
3370 f'of {url} to "<incompatible flag name (without --)>:..."'
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003371 )
Yun Peng6528e652019-01-02 14:41:07 +01003372
Yun Pengc85cd0e2022-09-02 10:44:29 +02003373 # If INCOMPATIBLE_FLAGS is set manually, we test those flags, try to keep the URL info if possible.
3374 if "INCOMPATIBLE_FLAGS" in os.environ:
3375 given_incompatible_flags = {}
3376 for flag in os.environ["INCOMPATIBLE_FLAGS"].split(","):
3377 given_incompatible_flags[flag] = incompatible_flags.get(flag, "")
3378 return given_incompatible_flags
3379
Yun Peng6528e652019-01-02 14:41:07 +01003380 return incompatible_flags
3381
3382
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003383def print_bazel_downstream_pipeline(
Yun Pengc85cd0e2022-09-02 10:44:29 +02003384 task_configs, http_config, file_config, test_disabled_projects, notify
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003385):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003386 pipeline_steps = []
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003387
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01003388 info_box_step = print_disabled_projects_info_box_step()
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01003389 if info_box_step is not None:
3390 pipeline_steps.append(info_box_step)
3391
Yun Pengc85cd0e2022-09-02 10:44:29 +02003392 if not use_bazelisk_migrate():
3393 if not task_configs:
3394 raise BuildkiteException("Bazel downstream pipeline configuration is empty.")
Florian Weikert843d7a02019-02-03 17:24:50 +01003395 for task, task_config in task_configs.items():
Yun Peng5599ca22019-01-16 12:32:41 +01003396 pipeline_steps.append(
Florian Weikert843d7a02019-02-03 17:24:50 +01003397 bazel_build_step(
3398 task,
3399 get_platform_for_task(task, task_config),
3400 "Bazel",
3401 http_config,
3402 file_config,
3403 build_only=True,
3404 )
Yun Peng5599ca22019-01-16 12:32:41 +01003405 )
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003406
Yun Peng5599ca22019-01-16 12:32:41 +01003407 pipeline_steps.append("wait")
Yun Pengc85cd0e2022-09-02 10:44:29 +02003408 else:
Yun Peng7d302f62019-01-10 16:56:15 +01003409 incompatible_flags_map = fetch_incompatible_flags()
Yun Peng3c1d7d12020-06-30 14:58:34 +02003410 if not incompatible_flags_map:
Florian Weikert9d5e4c02021-05-27 15:10:20 +02003411 step = create_step(
3412 label="No Incompatible flags info",
3413 commands=[
Florian Weikert42738ac2021-05-27 15:54:14 +02003414 '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 +02003415 ],
3416 platform=DEFAULT_PLATFORM,
Florian Weikertdb832a02020-11-19 19:14:48 +01003417 )
Florian Weikert9d5e4c02021-05-27 15:10:20 +02003418 pipeline_steps.append(step)
3419 print_pipeline_steps(pipeline_steps)
3420 return
3421
Yun Peng6528e652019-01-02 14:41:07 +01003422 info_box_step = print_incompatible_flags_info_box_step(incompatible_flags_map)
3423 if info_box_step is not None:
3424 pipeline_steps.append(info_box_step)
Yun Peng7a539ef2018-11-30 15:07:24 +01003425
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003426 for project, config in DOWNSTREAM_PROJECTS.items():
Yun Peng996efad2018-11-27 17:19:44 +01003427 disabled_reason = config.get("disabled_reason", None)
Yun Pengfb759fa2018-12-13 11:35:39 +01003428 # If test_disabled_projects is true, we add configs for disabled projects.
Florian Weikert7b3f17e2019-03-14 13:52:42 +01003429 # If test_disabled_projects is false, we add configs for not disabled projects.
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003430 if (test_disabled_projects and disabled_reason) or (
3431 not test_disabled_projects and not disabled_reason
3432 ):
Yun Peng996efad2018-11-27 17:19:44 +01003433 pipeline_steps.append(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003434 upload_project_pipeline_step(
3435 project_name=project,
3436 git_repository=config["git_repository"],
3437 http_config=config.get("http_config", None),
3438 file_config=config.get("file_config", None),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003439 )
3440 )
Yun Peng71c2d9f2022-01-05 10:33:51 +01003441
Yun Pengc85cd0e2022-09-02 10:44:29 +02003442 if use_bazelisk_migrate():
Yun Peng002eab92018-12-17 18:28:14 +01003443 current_build_number = os.environ.get("BUILDKITE_BUILD_NUMBER", None)
3444 if not current_build_number:
3445 raise BuildkiteException("Not running inside Buildkite")
Yun Pengc85cd0e2022-09-02 10:44:29 +02003446
Florian Weikertb3439b32022-11-09 11:05:16 +01003447 pipeline_steps += get_steps_for_aggregating_migration_results(current_build_number, notify)
Yun Peng002eab92018-12-17 18:28:14 +01003448
Florian Weikert2896edb2019-04-04 16:12:47 +02003449 if (
3450 not test_disabled_projects
Yun Pengc85cd0e2022-09-02 10:44:29 +02003451 and not use_bazelisk_migrate()
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02003452 and current_branch_is_main_branch()
Florian Weikert2896edb2019-04-04 16:12:47 +02003453 ):
Florian Weikert35906542019-04-01 11:53:53 +02003454 # Only update the last green downstream commit in the regular Bazel@HEAD + Downstream pipeline.
3455 pipeline_steps.append("wait")
3456 pipeline_steps.append(
3457 create_step(
3458 label="Try Update Last Green Downstream Commit",
3459 commands=[
3460 fetch_bazelcipy_command(),
Philipp Wollermann57b32682019-05-18 22:09:27 +02003461 PLATFORMS[DEFAULT_PLATFORM]["python"]
3462 + " bazelci.py try_update_last_green_downstream_commit",
Florian Weikert35906542019-04-01 11:53:53 +02003463 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02003464 platform=DEFAULT_PLATFORM,
Florian Weikert35906542019-04-01 11:53:53 +02003465 )
3466 )
3467
Florian Weikert13215a82019-05-10 12:42:21 +02003468 print_pipeline_steps(pipeline_steps)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003469
3470
Florian Weikert60661912019-12-18 15:17:10 +01003471def get_steps_for_aggregating_migration_results(current_build_number, notify):
Florian Weikert09813a02019-10-26 19:34:33 +02003472 parts = [
3473 PLATFORMS[DEFAULT_PLATFORM]["python"],
3474 "aggregate_incompatible_flags_test_result.py",
3475 "--build_number=%s" % current_build_number,
Florian Weikert09813a02019-10-26 19:34:33 +02003476 ]
Florian Weikert60661912019-12-18 15:17:10 +01003477 if notify:
3478 parts.append("--notify")
Florian Weikert09813a02019-10-26 19:34:33 +02003479 return [
3480 {"wait": "~", "continue_on_failure": "true"},
3481 create_step(
3482 label="Aggregate incompatible flags test result",
3483 commands=[
3484 fetch_bazelcipy_command(),
3485 fetch_aggregate_incompatible_flags_test_result_command(),
3486 " ".join(parts),
3487 ],
3488 platform=DEFAULT_PLATFORM,
3489 ),
3490 ]
3491
3492
Yun Pengc2dd6522018-10-17 12:58:35 +02003493def bazelci_builds_download_url(platform, git_commit):
Philipp Wollermanne67eec42019-05-24 15:18:20 +02003494 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
3495 return "https://storage.googleapis.com/{}/artifacts/{}/{}/bazel".format(
3496 bucket_name, platform, git_commit
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003497 )
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003498
3499
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003500def bazelci_builds_nojdk_download_url(platform, git_commit):
3501 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
3502 return "https://storage.googleapis.com/{}/artifacts/{}/{}/bazel_nojdk".format(
3503 bucket_name, platform, git_commit
3504 )
3505
3506
Yun Peng20d45602018-10-18 13:27:05 +02003507def bazelci_builds_gs_url(platform, git_commit):
Philipp Wollermanne67eec42019-05-24 15:18:20 +02003508 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
3509 return "gs://{}/artifacts/{}/{}/bazel".format(bucket_name, platform, git_commit)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003510
3511
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003512def bazelci_builds_nojdk_gs_url(platform, git_commit):
3513 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
3514 return "gs://{}/artifacts/{}/{}/bazel_nojdk".format(bucket_name, platform, git_commit)
3515
3516
mai93f04f9482020-10-20 17:22:30 +02003517def bazelci_latest_build_metadata_url():
Philipp Wollermanne67eec42019-05-24 15:18:20 +02003518 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
3519 return "gs://{}/metadata/latest.json".format(bucket_name)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003520
3521
mai93f04f9482020-10-20 17:22:30 +02003522def bazelci_builds_metadata_url(git_commit):
3523 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
3524 return "gs://{}/metadata/{}.json".format(bucket_name, git_commit)
3525
3526
Yun Peng996efad2018-11-27 17:19:44 +01003527def bazelci_last_green_commit_url(git_repository, pipeline_slug):
Philipp Wollermanne67eec42019-05-24 15:18:20 +02003528 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-untrusted-builds"
3529 return "gs://{}/last_green_commit/{}/{}".format(
3530 bucket_name, git_repository[len("https://") :], pipeline_slug
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003531 )
Yun Pengafe67d42018-11-23 17:06:43 +01003532
3533
Florian Weikert35906542019-04-01 11:53:53 +02003534def bazelci_last_green_downstream_commit_url():
Philipp Wollermanne67eec42019-05-24 15:18:20 +02003535 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-untrusted-builds"
3536 return "gs://{}/last_green_commit/downstream_pipeline".format(bucket_name)
Florian Weikert35906542019-04-01 11:53:53 +02003537
3538
3539def get_last_green_commit(last_green_commit_url):
Yun Peng61a448f2018-11-23 17:11:46 +01003540 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003541 return (
3542 subprocess.check_output(
3543 [gsutil_command(), "cat", last_green_commit_url], env=os.environ
3544 )
3545 .decode("utf-8")
3546 .strip()
3547 )
Yun Peng61a448f2018-11-23 17:11:46 +01003548 except subprocess.CalledProcessError:
3549 return None
Yun Peng43239b02018-11-23 13:57:34 +01003550
3551
Yun Peng358cd882018-11-29 10:25:18 +01003552def try_update_last_green_commit():
Florian Weikertde96a6f2019-03-07 14:57:50 +01003553 org_slug = os.getenv("BUILDKITE_ORGANIZATION_SLUG")
Yun Peng358cd882018-11-29 10:25:18 +01003554 pipeline_slug = os.getenv("BUILDKITE_PIPELINE_SLUG")
Florian Weikertde96a6f2019-03-07 14:57:50 +01003555 build_number = os.getenv("BUILDKITE_BUILD_NUMBER")
3556 current_job_id = os.getenv("BUILDKITE_JOB_ID")
3557
3558 client = BuildkiteClient(org=org_slug, pipeline=pipeline_slug)
3559 build_info = client.get_build_info(build_number)
3560
mai9302a609c2021-05-20 10:36:46 +02003561 # 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 +02003562 def has_failed(job):
Florian Weikertbd40a272019-03-08 10:20:18 +01003563 state = job.get("state")
3564 # Ignore steps that don't have a state (like "wait").
Florian Weikertde96a6f2019-03-07 14:57:50 +01003565 return (
Florian Weikert35906542019-04-01 11:53:53 +02003566 state is not None
3567 and state != "passed"
mai9302a609c2021-05-20 10:36:46 +02003568 and not job.get("soft_failed")
Florian Weikertde96a6f2019-03-07 14:57:50 +01003569 and job["id"] != current_job_id
3570 and job["name"] != BUILDIFIER_STEP_NAME
3571 )
3572
Philipp Wollermannce986af2019-07-18 14:46:05 +02003573 failing_jobs = [j["name"] for j in build_info["jobs"] if has_failed(j)]
Florian Weikertde96a6f2019-03-07 14:57:50 +01003574 if failing_jobs:
3575 raise BuildkiteException(
3576 "Cannot update last green commit due to {} failing step(s): {}".format(
3577 len(failing_jobs), ", ".join(failing_jobs)
3578 )
3579 )
3580
Yun Peng358cd882018-11-29 10:25:18 +01003581 git_repository = os.getenv("BUILDKITE_REPO")
Florian Weikert35906542019-04-01 11:53:53 +02003582 last_green_commit_url = bazelci_last_green_commit_url(git_repository, pipeline_slug)
3583 update_last_green_commit_if_newer(last_green_commit_url)
3584
3585
3586def update_last_green_commit_if_newer(last_green_commit_url):
3587 last_green_commit = get_last_green_commit(last_green_commit_url)
Florian Weikert5e70d9d2023-05-08 19:20:23 +02003588 current_commit = resolve_revision("HEAD")
Yun Peng358cd882018-11-29 10:25:18 +01003589 if last_green_commit:
Jakob Buchgraber7c7ceee2019-10-28 10:28:58 +01003590 success = False
3591 try:
3592 execute_command(["git", "fetch", "-v", "origin", last_green_commit])
3593 success = True
3594 except subprocess.CalledProcessError:
3595 # If there was an error fetching the commit it typically means
3596 # that the commit does not exist anymore - due to a force push. In
3597 # order to recover from that assume that the current commit is the
3598 # newest commit.
3599 result = [current_commit]
3600 finally:
3601 if success:
3602 result = (
3603 subprocess.check_output(
3604 ["git", "rev-list", "%s..%s" % (last_green_commit, current_commit)]
3605 )
3606 .decode("utf-8")
3607 .strip()
3608 )
Philipp Wollermannce986af2019-07-18 14:46:05 +02003609 else:
3610 result = None
Yun Peng358cd882018-11-29 10:25:18 +01003611
Philipp Wollermann639c0452019-01-03 11:23:54 +01003612 # If current_commit is newer that last_green_commit, `git rev-list A..B` will output a bunch of
3613 # commits, otherwise the output should be empty.
Yun Peng358cd882018-11-29 10:25:18 +01003614 if not last_green_commit or result:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003615 execute_command(
Philipp Wollermann76a7eac2020-02-17 18:29:52 +01003616 [
3617 "echo %s | %s -h 'Cache-Control: no-store' cp - %s"
3618 % (current_commit, gsutil_command(), last_green_commit_url)
3619 ],
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003620 shell=True,
3621 )
Yun Peng358cd882018-11-29 10:25:18 +01003622 else:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003623 eprint(
3624 "Updating abandoned: last green commit (%s) is not older than current commit (%s)."
3625 % (last_green_commit, current_commit)
3626 )
3627
Yun Peng358cd882018-11-29 10:25:18 +01003628
Florian Weikert5e70d9d2023-05-08 19:20:23 +02003629def resolve_revision(rev):
3630 return subprocess.check_output(["git", "rev-parse", rev]).decode("utf-8").strip()
3631
3632
Florian Weikert35906542019-04-01 11:53:53 +02003633def try_update_last_green_downstream_commit():
3634 last_green_commit_url = bazelci_last_green_downstream_commit_url()
3635 update_last_green_commit_if_newer(last_green_commit_url)
3636
3637
Jakob Buchgraber76381e02018-02-19 16:19:56 +01003638def latest_generation_and_build_number():
Philipp Wollermannce986af2019-07-18 14:46:05 +02003639 generation = None
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003640 output = None
Philipp Wollermannce986af2019-07-18 14:46:05 +02003641 for attempt in range(5):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003642 output = subprocess.check_output(
mai93f04f9482020-10-20 17:22:30 +02003643 [gsutil_command(), "stat", bazelci_latest_build_metadata_url()], env=os.environ
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003644 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003645 match = re.search("Generation:[ ]*([0-9]+)", output.decode("utf-8"))
3646 if not match:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003647 raise BuildkiteException("Couldn't parse generation. gsutil output format changed?")
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003648 generation = match.group(1)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003649
Philipp Wollermannff39ef52018-02-21 14:18:52 +01003650 match = re.search(r"Hash \(md5\):[ ]*([^\s]+)", output.decode("utf-8"))
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003651 if not match:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003652 raise BuildkiteException("Couldn't parse md5 hash. gsutil output format changed?")
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003653 expected_md5hash = base64.b64decode(match.group(1))
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003654
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003655 output = subprocess.check_output(
mai93f04f9482020-10-20 17:22:30 +02003656 [gsutil_command(), "cat", bazelci_latest_build_metadata_url()], env=os.environ
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003657 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003658 hasher = hashlib.md5()
3659 hasher.update(output)
3660 actual_md5hash = hasher.digest()
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003661
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003662 if expected_md5hash == actual_md5hash:
3663 break
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003664 info = json.loads(output.decode("utf-8"))
Philipp Wollermannce986af2019-07-18 14:46:05 +02003665 return generation, info["build_number"]
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003666
Jakob Buchgraber699aece2018-02-19 12:49:30 +01003667
Jakob Buchgraber88083fd2018-02-18 17:23:35 +01003668def sha256_hexdigest(filename):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003669 sha256 = hashlib.sha256()
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003670 with open(filename, "rb") as f:
3671 for block in iter(lambda: f.read(65536), b""):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003672 sha256.update(block)
3673 return sha256.hexdigest()
Jakob Buchgraber699aece2018-02-19 12:49:30 +01003674
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003675
Philipp Wollermann02955272019-04-18 18:00:48 +02003676def upload_bazel_binaries():
3677 """
3678 Uploads all Bazel binaries to a deterministic URL based on the current Git commit.
3679
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003680 Returns maps of platform names to sha256 hashes of the corresponding bazel and bazel_nojdk binaries.
Philipp Wollermann02955272019-04-18 18:00:48 +02003681 """
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003682 bazel_hashes = {}
3683 bazel_nojdk_hashes = {}
Yun Peng1ce55be2023-08-11 16:19:26 +02003684 error = None
Philipp Wollermannbdd4bf92019-06-06 14:43:50 +02003685 for platform_name, platform in PLATFORMS.items():
Philipp Wollermann783d1672019-06-06 13:35:30 +02003686 if not should_publish_binaries_for_platform(platform_name):
3687 continue
Jakob Buchgraberb13a9a82018-03-27 18:37:09 +02003688 tmpdir = tempfile.mkdtemp()
3689 try:
Philipp Wollermann783d1672019-06-06 13:35:30 +02003690 bazel_binary_path = download_bazel_binary(tmpdir, platform_name)
3691 # One platform that we build on can generate binaries for multiple platforms, e.g.
Philipp Wollermannf4aabb72019-06-25 15:59:00 +02003692 # the centos7 platform generates binaries for the "centos7" platform, but also
Philipp Wollermann783d1672019-06-06 13:35:30 +02003693 # for the generic "linux" platform.
3694 for target_platform_name in platform["publish_binary"]:
3695 execute_command(
3696 [
3697 gsutil_command(),
3698 "cp",
3699 bazel_binary_path,
3700 bazelci_builds_gs_url(target_platform_name, os.environ["BUILDKITE_COMMIT"]),
3701 ]
3702 )
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003703 bazel_hashes[target_platform_name] = sha256_hexdigest(bazel_binary_path)
3704
3705 # Also publish bazel_nojdk binaries.
3706 bazel_nojdk_binary_path = download_bazel_nojdk_binary(tmpdir, platform_name)
3707 for target_platform_name in platform["publish_binary"]:
3708 execute_command(
3709 [
3710 gsutil_command(),
3711 "cp",
3712 bazel_nojdk_binary_path,
Florian Weikertdb832a02020-11-19 19:14:48 +01003713 bazelci_builds_nojdk_gs_url(
3714 target_platform_name, os.environ["BUILDKITE_COMMIT"]
3715 ),
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003716 ]
3717 )
3718 bazel_nojdk_hashes[target_platform_name] = sha256_hexdigest(bazel_nojdk_binary_path)
Philipp Wollermann30f314d2021-06-11 10:51:39 +02003719 except subprocess.CalledProcessError as e:
Yun Peng1ce55be2023-08-11 16:19:26 +02003720 eprint(
3721 "Failured to download and publish Bazel binary for platform {}: {}".format(
3722 platform_name, e
Philipp Wollermann30f314d2021-06-11 10:51:39 +02003723 )
Yun Peng1ce55be2023-08-11 16:19:26 +02003724 )
3725 error = e
Jakob Buchgraberb13a9a82018-03-27 18:37:09 +02003726 finally:
3727 shutil.rmtree(tmpdir)
Yun Peng1ce55be2023-08-11 16:19:26 +02003728 # If we're not on the main branch, we're probably building a custom one-off binary and
3729 # ignore failures for individual platforms (it's possible that we didn't build binaries
3730 # for all platforms).
3731 if error and current_branch_is_main_branch():
3732 raise error
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003733 return bazel_hashes, bazel_nojdk_hashes
Philipp Wollermann02955272019-04-18 18:00:48 +02003734
3735
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003736def try_publish_binaries(bazel_hashes, bazel_nojdk_hashes, build_number, expected_generation):
Philipp Wollermann02955272019-04-18 18:00:48 +02003737 """
3738 Uploads the info.json file that contains information about the latest Bazel commit that was
3739 successfully built on CI.
3740 """
3741 now = datetime.datetime.now()
3742 git_commit = os.environ["BUILDKITE_COMMIT"]
3743 info = {
3744 "build_number": build_number,
3745 "build_time": now.strftime("%d-%m-%Y %H:%M"),
3746 "git_commit": git_commit,
3747 "platforms": {},
3748 }
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003749 for platform, sha256 in bazel_hashes.items():
Philipp Wollermann02955272019-04-18 18:00:48 +02003750 info["platforms"][platform] = {
3751 "url": bazelci_builds_download_url(platform, git_commit),
Philipp Wollermann783d1672019-06-06 13:35:30 +02003752 "sha256": sha256,
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003753 "nojdk_url": bazelci_builds_nojdk_download_url(platform, git_commit),
3754 "nojdk_sha256": bazel_nojdk_hashes[platform],
Philipp Wollermann02955272019-04-18 18:00:48 +02003755 }
Jakob Buchgraberb13a9a82018-03-27 18:37:09 +02003756 tmpdir = tempfile.mkdtemp()
3757 try:
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003758 info_file = os.path.join(tmpdir, "info.json")
3759 with open(info_file, mode="w", encoding="utf-8") as fp:
Jakob Buchgraber609a20e2018-02-25 17:06:51 +01003760 json.dump(info, fp, indent=2, sort_keys=True)
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003761
3762 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003763 execute_command(
3764 [
3765 gsutil_command(),
3766 "-h",
3767 "x-goog-if-generation-match:" + expected_generation,
3768 "-h",
3769 "Content-Type:application/json",
3770 "cp",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003771 info_file,
mai93f04f9482020-10-20 17:22:30 +02003772 bazelci_latest_build_metadata_url(),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003773 ]
3774 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003775 except subprocess.CalledProcessError:
3776 raise BinaryUploadRaceException()
mai93f04f9482020-10-20 17:22:30 +02003777
3778 execute_command(
3779 [
3780 gsutil_command(),
3781 "cp",
3782 bazelci_latest_build_metadata_url(),
3783 bazelci_builds_metadata_url(git_commit),
3784 ]
3785 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003786 finally:
Philipp Wollermann3e1a7712018-02-19 17:34:24 +01003787 shutil.rmtree(tmpdir)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003788
3789
Jakob Buchgraber76381e02018-02-19 16:19:56 +01003790def publish_binaries():
Philipp Wollermanndb024862018-02-19 17:16:56 +01003791 """
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003792 Publish Bazel binaries to GCS.
Philipp Wollermanndb024862018-02-19 17:16:56 +01003793 """
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003794 current_build_number = os.environ.get("BUILDKITE_BUILD_NUMBER", None)
3795 if not current_build_number:
3796 raise BuildkiteException("Not running inside Buildkite")
3797 current_build_number = int(current_build_number)
3798
Philipp Wollermann02955272019-04-18 18:00:48 +02003799 # Upload the Bazel binaries for this commit.
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003800 bazel_hashes, bazel_nojdk_hashes = upload_bazel_binaries()
Philipp Wollermann02955272019-04-18 18:00:48 +02003801
3802 # 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 +02003803 # not the latest build. Only do this if we're building binaries from the main branch to avoid
3804 # accidentally publishing a custom debug build as the "latest" Bazel binary.
3805 if current_branch_is_main_branch():
3806 for _ in range(5):
3807 latest_generation, latest_build_number = latest_generation_and_build_number()
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003808
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02003809 if current_build_number <= latest_build_number:
3810 eprint(
3811 (
3812 "Current build '{0}' is not newer than latest published '{1}'. "
3813 + "Skipping publishing of binaries."
3814 ).format(current_build_number, latest_build_number)
3815 )
3816 break
3817
3818 try:
3819 try_publish_binaries(
3820 bazel_hashes, bazel_nojdk_hashes, current_build_number, latest_generation
3821 )
3822 except BinaryUploadRaceException:
3823 # Retry.
3824 continue
3825
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003826 eprint(
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02003827 "Successfully updated '{0}' to binaries from build {1}.".format(
3828 bazelci_latest_build_metadata_url(), current_build_number
3829 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003830 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003831 break
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02003832 else:
3833 raise BuildkiteException("Could not publish binaries, ran out of attempts.")
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003834
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02003835
Philipp Wollermann639c0452019-01-03 11:23:54 +01003836# This is so that multiline python strings are represented as YAML
3837# block strings.
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01003838def str_presenter(dumper, data):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003839 if len(data.splitlines()) > 1: # check for multiline string
3840 return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|")
3841 return dumper.represent_scalar("tag:yaml.org,2002:str", data)
3842
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003843
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003844def main(argv=None):
3845 if argv is None:
Yun Peng20d45602018-10-18 13:27:05 +02003846 argv = sys.argv[1:]
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003847
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01003848 yaml.add_representer(str, str_presenter)
3849
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003850 parser = argparse.ArgumentParser(description="Bazel Continuous Integration Script")
Florian Weikert944209b2019-05-10 12:41:48 +02003851 parser.add_argument("--script", type=str)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003852
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003853 subparsers = parser.add_subparsers(dest="subparsers_name")
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003854
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003855 bazel_publish_binaries_pipeline = subparsers.add_parser("bazel_publish_binaries_pipeline")
3856 bazel_publish_binaries_pipeline.add_argument("--file_config", type=str)
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01003857 bazel_publish_binaries_pipeline.add_argument("--http_config", type=str)
3858 bazel_publish_binaries_pipeline.add_argument("--git_repository", type=str)
3859
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003860 bazel_downstream_pipeline = subparsers.add_parser("bazel_downstream_pipeline")
3861 bazel_downstream_pipeline.add_argument("--file_config", type=str)
3862 bazel_downstream_pipeline.add_argument("--http_config", type=str)
3863 bazel_downstream_pipeline.add_argument("--git_repository", type=str)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003864 bazel_downstream_pipeline.add_argument(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003865 "--test_disabled_projects", type=bool, nargs="?", const=True
3866 )
Florian Weikert60661912019-12-18 15:17:10 +01003867 bazel_downstream_pipeline.add_argument("--notify", type=bool, nargs="?", const=True)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003868
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003869 project_pipeline = subparsers.add_parser("project_pipeline")
3870 project_pipeline.add_argument("--project_name", type=str)
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003871 project_pipeline.add_argument("--file_config", type=str)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003872 project_pipeline.add_argument("--http_config", type=str)
3873 project_pipeline.add_argument("--git_repository", type=str)
Jakob Buchgraber66ba4fe2018-06-22 15:04:14 +02003874 project_pipeline.add_argument("--monitor_flaky_tests", type=bool, nargs="?", const=True)
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003875 project_pipeline.add_argument("--use_but", type=bool, nargs="?", const=True)
Florian Weikert60661912019-12-18 15:17:10 +01003876 project_pipeline.add_argument("--notify", type=bool, nargs="?", const=True)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003877
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003878 runner = subparsers.add_parser("runner")
Florian Weikert843d7a02019-02-03 17:24:50 +01003879 runner.add_argument("--task", action="store", type=str, default="")
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003880 runner.add_argument("--file_config", type=str)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003881 runner.add_argument("--http_config", type=str)
3882 runner.add_argument("--git_repository", type=str)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003883 runner.add_argument(
3884 "--git_commit", type=str, help="Reset the git repository to this commit after cloning it"
3885 )
3886 runner.add_argument(
Yun Peng5012a862021-09-16 16:35:43 +02003887 "--repo_location",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003888 type=str,
3889 help="Use an existing repository instead of cloning from github",
3890 )
3891 runner.add_argument(
Dan Halperinefda1192019-01-16 00:34:09 -08003892 "--use_bazel_at_commit", type=str, help="Use Bazel binary built at a specific commit"
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003893 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003894 runner.add_argument("--use_but", type=bool, nargs="?", const=True)
3895 runner.add_argument("--save_but", type=bool, nargs="?", const=True)
Yun Peng4d1d6542019-01-17 18:30:33 +01003896 runner.add_argument("--needs_clean", type=bool, nargs="?", const=True)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003897 runner.add_argument("--build_only", type=bool, nargs="?", const=True)
3898 runner.add_argument("--test_only", type=bool, nargs="?", const=True)
Jakob Buchgraber66ba4fe2018-06-22 15:04:14 +02003899 runner.add_argument("--monitor_flaky_tests", type=bool, nargs="?", const=True)
Jakob Buchgraberc340f582018-06-22 13:48:33 +02003900
Philipp Wollermannce986af2019-07-18 14:46:05 +02003901 subparsers.add_parser("publish_binaries")
3902 subparsers.add_parser("try_update_last_green_commit")
3903 subparsers.add_parser("try_update_last_green_downstream_commit")
Yun Peng358cd882018-11-29 10:25:18 +01003904
Yun Peng20d45602018-10-18 13:27:05 +02003905 args = parser.parse_args(argv)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003906
Florian Weikert944209b2019-05-10 12:41:48 +02003907 if args.script:
3908 global SCRIPT_URL
3909 SCRIPT_URL = args.script
3910
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003911 try:
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01003912 if args.subparsers_name == "bazel_publish_binaries_pipeline":
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003913 configs = fetch_configs(args.http_config, args.file_config)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003914 print_bazel_publish_binaries_pipeline(
Florian Weikert843d7a02019-02-03 17:24:50 +01003915 task_configs=configs.get("tasks", None),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003916 http_config=args.http_config,
3917 file_config=args.file_config,
3918 )
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003919 elif args.subparsers_name == "bazel_downstream_pipeline":
Yun Pengc85cd0e2022-09-02 10:44:29 +02003920 # If USE_BAZELISK_MIGRATE is true, we don't need to fetch task configs for Bazel
3921 # since we use Bazelisk to fetch Bazel binaries.
Florian Weikertb3439b32022-11-09 11:05:16 +01003922 configs = (
3923 {} if use_bazelisk_migrate() else fetch_configs(args.http_config, args.file_config)
3924 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003925 print_bazel_downstream_pipeline(
Florian Weikert843d7a02019-02-03 17:24:50 +01003926 task_configs=configs.get("tasks", None),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003927 http_config=args.http_config,
3928 file_config=args.file_config,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003929 test_disabled_projects=args.test_disabled_projects,
Florian Weikert60661912019-12-18 15:17:10 +01003930 notify=args.notify,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003931 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003932 elif args.subparsers_name == "project_pipeline":
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003933 configs = fetch_configs(args.http_config, args.file_config)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003934 print_project_pipeline(
Florian Weikertf20ae6f2019-01-16 14:32:09 +01003935 configs=configs,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003936 project_name=args.project_name,
3937 http_config=args.http_config,
3938 file_config=args.file_config,
3939 git_repository=args.git_repository,
3940 monitor_flaky_tests=args.monitor_flaky_tests,
3941 use_but=args.use_but,
Florian Weikert60661912019-12-18 15:17:10 +01003942 notify=args.notify,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003943 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003944 elif args.subparsers_name == "runner":
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003945 configs = fetch_configs(args.http_config, args.file_config)
Florian Weikert843d7a02019-02-03 17:24:50 +01003946 tasks = configs.get("tasks", {})
3947 task_config = tasks.get(args.task)
3948 if not task_config:
3949 raise BuildkiteException(
3950 "No such task '{}' in configuration. Available: {}".format(
3951 args.task, ", ".join(tasks)
3952 )
3953 )
3954
Chi Wangdb965412023-05-10 09:00:46 +00003955 os.environ["BAZELCI_TASK"] = args.task
3956
Florian Weikert843d7a02019-02-03 17:24:50 +01003957 platform = get_platform_for_task(args.task, task_config)
3958
Yun Pengdb76f842021-08-30 18:39:38 +02003959 # The value of `BUILDKITE_MESSAGE` defaults to the commit message, which can be too large
3960 # on Windows, therefore we truncate the value to 1000 characters.
3961 # See https://github.com/bazelbuild/continuous-integration/issues/1218
3962 if "BUILDKITE_MESSAGE" in os.environ:
3963 os.environ["BUILDKITE_MESSAGE"] = os.environ["BUILDKITE_MESSAGE"][:1000]
3964
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003965 execute_commands(
Florian Weikertc8642af2019-02-03 23:58:51 +01003966 task_config=task_config,
Florian Weikert843d7a02019-02-03 17:24:50 +01003967 platform=platform,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003968 git_repository=args.git_repository,
3969 git_commit=args.git_commit,
Yun Peng5012a862021-09-16 16:35:43 +02003970 repo_location=args.repo_location,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003971 use_bazel_at_commit=args.use_bazel_at_commit,
3972 use_but=args.use_but,
3973 save_but=args.save_but,
Yun Peng4d1d6542019-01-17 18:30:33 +01003974 needs_clean=args.needs_clean,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003975 build_only=args.build_only,
3976 test_only=args.test_only,
3977 monitor_flaky_tests=args.monitor_flaky_tests,
Florian Weikertc8642af2019-02-03 23:58:51 +01003978 bazel_version=task_config.get("bazel") or configs.get("bazel"),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003979 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003980 elif args.subparsers_name == "publish_binaries":
3981 publish_binaries()
Yun Peng358cd882018-11-29 10:25:18 +01003982 elif args.subparsers_name == "try_update_last_green_commit":
Florian Weikert35906542019-04-01 11:53:53 +02003983 # Update the last green commit of a project pipeline
Yun Peng358cd882018-11-29 10:25:18 +01003984 try_update_last_green_commit()
Florian Weikert35906542019-04-01 11:53:53 +02003985 elif args.subparsers_name == "try_update_last_green_downstream_commit":
3986 # Update the last green commit of the downstream pipeline
3987 try_update_last_green_downstream_commit()
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003988 else:
3989 parser.print_help()
3990 return 2
3991 except BuildkiteException as e:
3992 eprint(str(e))
3993 return 1
3994 return 0
3995
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01003996
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003997if __name__ == "__main__":
3998 sys.exit(main())