blob: 7dc6342e686bcd3c45b52394bfef157f311088b9 [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
Jakob Buchgraber12807052018-02-25 17:04:56 +010020import datetime
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +010021from glob import glob
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +010022import hashlib
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010023import json
Jakob Buchgraber6db0f262018-02-17 15:45:54 +010024import multiprocessing
Philipp Wollermann0a04cf32018-02-21 17:07:22 +010025import os
Philipp Wollermanndcaddd92018-02-21 14:13:43 +010026import os.path
Jakob Buchgraber257693b2018-02-20 00:03:56 +010027import random
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010028import re
Yun Peng9337bb32020-02-28 13:31:29 +010029import requests
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010030import shutil
Philipp Wollermanndcaddd92018-02-21 14:13:43 +010031import stat
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010032import subprocess
33import sys
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010034import tempfile
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +020035import threading
Philipp Wollermanne1318eb2018-08-13 15:08:01 +020036import time
Philipp Wollermannce986af2019-07-18 14:46:05 +020037import urllib.error
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010038import urllib.request
Philipp Wollermanne1318eb2018-08-13 15:08:01 +020039import uuid
Jakob Buchgraber25bb50f2018-02-22 18:06:21 +010040import yaml
Philipp Wollermanndcaddd92018-02-21 14:13:43 +010041
42# Initialize the random number generator.
43random.seed()
44
Philipp Wollermanne67eec42019-05-24 15:18:20 +020045BUILDKITE_ORG = os.environ["BUILDKITE_ORGANIZATION_SLUG"]
Florian Weikertc2745512021-02-17 16:13:55 +010046THIS_IS_PRODUCTION = BUILDKITE_ORG == "bazel"
Philipp Wollermanne67eec42019-05-24 15:18:20 +020047THIS_IS_TESTING = BUILDKITE_ORG == "bazel-testing"
48THIS_IS_TRUSTED = BUILDKITE_ORG == "bazel-trusted"
49THIS_IS_SPARTA = True
50
51CLOUD_PROJECT = "bazel-public" if THIS_IS_TRUSTED else "bazel-untrusted"
52
53GITHUB_BRANCH = {"bazel": "master", "bazel-trusted": "master", "bazel-testing": "testing"}[
54 BUILDKITE_ORG
55]
56
57SCRIPT_URL = "https://raw.githubusercontent.com/bazelbuild/continuous-integration/{}/buildkite/bazelci.py?{}".format(
58 GITHUB_BRANCH, int(time.time())
Philipp Wollermannc05ac682019-01-19 12:37:28 +010059)
Jakob Buchgraber95e3d572018-02-21 18:48:49 +010060
Philipp Wollermanne67eec42019-05-24 15:18:20 +020061INCOMPATIBLE_FLAG_VERBOSE_FAILURES_URL = "https://raw.githubusercontent.com/bazelbuild/continuous-integration/{}/buildkite/incompatible_flag_verbose_failures.py?{}".format(
62 GITHUB_BRANCH, int(time.time())
63)
64
65AGGREGATE_INCOMPATIBLE_TEST_RESULT_URL = "https://raw.githubusercontent.com/bazelbuild/continuous-integration/{}/buildkite/aggregate_incompatible_flags_test_result.py?{}".format(
66 GITHUB_BRANCH, int(time.time())
67)
68
69EMERGENCY_FILE_URL = "https://raw.githubusercontent.com/bazelbuild/continuous-integration/{}/buildkite/emergency.yml?{}".format(
70 GITHUB_BRANCH, int(time.time())
71)
72
73FLAKY_TESTS_BUCKET = {
74 "bazel-testing": "gs://bazel-testing-buildkite-stats/flaky-tests-bep/",
75 "bazel-trusted": "gs://bazel-buildkite-stats/flaky-tests-bep/",
76 "bazel": "gs://bazel-buildkite-stats/flaky-tests-bep/",
77}[BUILDKITE_ORG]
78
Chi Wangb2b65682020-08-27 10:36:15 +080079KZIPS_BUCKET = {
80 "bazel-testing": "gs://bazel-kzips-testing/",
81 "bazel-trusted": "gs://bazel-kzips/",
82 "bazel": "gs://bazel-kzips/",
83}[BUILDKITE_ORG]
84
Florian Weikert797787b2019-12-19 15:33:07 +010085# 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 +020086DOWNSTREAM_PROJECTS_PRODUCTION = {
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +010087 "Android Studio Plugin": {
88 "git_repository": "https://github.com/bazelbuild/intellij.git",
89 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/android-studio.yml",
90 "pipeline_slug": "android-studio-plugin",
91 },
Yun Peng996efad2018-11-27 17:19:44 +010092 "Android Testing": {
93 "git_repository": "https://github.com/googlesamples/android-testing.git",
Jingwenbde72602018-12-13 10:57:43 -050094 "http_config": "https://raw.githubusercontent.com/googlesamples/android-testing/master/bazelci/buildkite-pipeline.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +010095 "pipeline_slug": "android-testing",
Yun Peng9b1d3432021-12-07 10:40:45 +010096 "disabled_reason": "https://github.com/android/testing-samples/issues/417",
Yun Peng996efad2018-11-27 17:19:44 +010097 },
Yun Peng8910fa32019-01-03 08:58:16 +010098 "Bazel": {
99 "git_repository": "https://github.com/bazelbuild/bazel.git",
100 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel/master/.bazelci/postsubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100101 "pipeline_slug": "bazel-bazel",
Yun Peng8910fa32019-01-03 08:58:16 +0100102 },
Tobias Werthd848eca2019-05-14 15:08:35 +0200103 "Bazel Bench": {
104 "git_repository": "https://github.com/bazelbuild/bazel-bench.git",
joeleba92ffec82019-05-22 14:50:15 +0200105 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-bench/master/.bazelci/postsubmit.yml",
Tobias Werthd848eca2019-05-14 15:08:35 +0200106 "pipeline_slug": "bazel-bench",
107 },
Philipp Wollermannfefcbf42019-05-28 14:28:40 +0200108 "Bazel Codelabs": {
109 "git_repository": "https://github.com/bazelbuild/codelabs.git",
110 "http_config": "https://raw.githubusercontent.com/bazelbuild/codelabs/master/.bazelci/presubmit.yml",
111 "pipeline_slug": "bazel-codelabs",
Yun Peng88d80ae2020-11-19 16:23:49 +0100112 "disabled_reason": "https://github.com/bazelbuild/codelabs/issues/38",
Philipp Wollermannfefcbf42019-05-28 14:28:40 +0200113 },
Jinfce9b302019-08-08 15:18:26 -0400114 "Bazel Examples": {
115 "git_repository": "https://github.com/bazelbuild/examples.git",
116 "http_config": "https://raw.githubusercontent.com/bazelbuild/examples/master/.bazelci/presubmit.yml",
117 "pipeline_slug": "bazel-bazel-examples",
118 },
Florian Weikert4b3ec672019-08-14 19:05:12 +0200119 "Bazel Federation": {
120 "git_repository": "https://github.com/bazelbuild/bazel-federation.git",
121 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-federation/master/.bazelci/presubmit.yml",
122 "pipeline_slug": "bazel-federation",
Yun Pengc263eff2020-11-19 15:20:15 +0100123 "disabled_reason": "https://github.com/bazelbuild/bazel-federation/issues/126",
Florian Weikert4b3ec672019-08-14 19:05:12 +0200124 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100125 "Bazel Remote Cache": {
126 "git_repository": "https://github.com/buchgr/bazel-remote.git",
127 "http_config": "https://raw.githubusercontent.com/buchgr/bazel-remote/master/.bazelci/presubmit.yml",
128 "pipeline_slug": "bazel-remote-cache",
Yun Peng996efad2018-11-27 17:19:44 +0100129 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200130 "Bazel integration testing": {
131 "git_repository": "https://github.com/bazelbuild/bazel-integration-testing.git",
132 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-integration-testing/master/.bazelci/presubmit.yml",
133 "pipeline_slug": "bazel-integration-testing",
134 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100135 "Bazel skylib": {
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200136 "git_repository": "https://github.com/bazelbuild/bazel-skylib.git",
Alexandre Rostovtsevd414d0d2021-04-16 13:44:35 -0400137 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-skylib/main/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100138 "pipeline_slug": "bazel-skylib",
Yun Peng667750b2020-02-20 14:06:43 +0100139 "owned_by_bazel": True,
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200140 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100141 "Bazel toolchains": {
142 "git_repository": "https://github.com/bazelbuild/bazel-toolchains.git",
143 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-toolchains/master/.bazelci/presubmit.yml",
144 "pipeline_slug": "bazel-toolchains",
145 },
146 "Bazel watcher": {
147 "git_repository": "https://github.com/bazelbuild/bazel-watcher.git",
148 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-watcher/master/.bazelci/presubmit.yml",
149 "pipeline_slug": "bazel-watcher",
150 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200151 "Bazelisk": {
152 "git_repository": "https://github.com/bazelbuild/bazelisk.git",
153 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazelisk/master/.bazelci/config.yml",
154 "pipeline_slug": "bazelisk",
155 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100156 "Buildfarm": {
157 "git_repository": "https://github.com/bazelbuild/bazel-buildfarm.git",
Philipp Wollermanndf1e19b2021-09-09 12:33:37 +0200158 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-buildfarm/main/.bazelci/presubmit.yml",
Philipp Wollermann89e5d882021-09-09 12:44:29 +0200159 "pipeline_slug": "buildfarm-farmer",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100160 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100161 "Buildtools": {
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200162 "git_repository": "https://github.com/bazelbuild/buildtools.git",
Yun Peng996efad2018-11-27 17:19:44 +0100163 "http_config": "https://raw.githubusercontent.com/bazelbuild/buildtools/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100164 "pipeline_slug": "buildtools",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200165 },
Yun Peng175bf3e2021-02-23 16:37:35 +0100166 "Cargo-Raze": {
167 "git_repository": "https://github.com/google/cargo-raze.git",
168 "http_config": "https://raw.githubusercontent.com/google/cargo-raze/master/.bazelci/presubmit.yml",
169 "pipeline_slug": "cargo-raze",
170 },
Yun Peng39a42582018-11-09 10:59:47 +0100171 "CLion Plugin": {
172 "git_repository": "https://github.com/bazelbuild/intellij.git",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100173 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/clion.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100174 "pipeline_slug": "clion-plugin",
Yun Peng39a42582018-11-09 10:59:47 +0100175 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200176 "Cartographer": {
177 "git_repository": "https://github.com/googlecartographer/cartographer.git",
178 "http_config": "https://raw.githubusercontent.com/googlecartographer/cartographer/master/.bazelci/presubmit.yml",
179 "pipeline_slug": "cartographer",
180 },
Philipp Wollermannee850782019-02-05 22:56:04 +0100181 "Cloud Robotics Core": {
Stefan Sauerb4dd3f92019-02-05 22:44:28 +0100182 "git_repository": "https://github.com/googlecloudrobotics/core.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200183 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/cloud-robotics.yml",
Stefan Sauerb4dd3f92019-02-05 22:44:28 +0100184 "pipeline_slug": "cloud-robotics-core",
185 },
Keith Smiley3b0ba602019-05-15 04:42:19 -0700186 "Envoy": {
187 "git_repository": "https://github.com/envoyproxy/envoy.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200188 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/envoy.yml",
Keith Smiley3b0ba602019-05-15 04:42:19 -0700189 "pipeline_slug": "envoy",
190 },
Florian Weikert1fe28b72019-07-02 12:47:55 +0200191 "FlatBuffers": {
192 "git_repository": "https://github.com/google/flatbuffers.git",
193 "http_config": "https://raw.githubusercontent.com/google/flatbuffers/master/.bazelci/presubmit.yml",
194 "pipeline_slug": "flatbuffers",
Florian Weikert1d08af62021-08-07 08:29:20 +0200195 "disabled_reason": "https://github.com/bazelbuild/bazel/issues/13811",
Florian Weikert1fe28b72019-07-02 12:47:55 +0200196 },
Philipp Wollermannf3750fa2019-05-21 17:11:59 +0200197 "Flogger": {
198 "git_repository": "https://github.com/google/flogger.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200199 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/flogger.yml",
Philipp Wollermannf3750fa2019-05-21 17:11:59 +0200200 "pipeline_slug": "flogger",
201 },
Marcel Hlopkoc8840772018-10-23 12:51:46 +0200202 "Gerrit": {
203 "git_repository": "https://gerrit.googlesource.com/gerrit.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200204 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/gerrit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100205 "pipeline_slug": "gerrit",
Florian Weikert8bc0c772021-06-17 10:24:31 +0200206 "disabled_reason": "https://github.com/bazelbuild/continuous-integration/issues/1182",
Marcel Hlopkoc8840772018-10-23 12:51:46 +0200207 },
Yun Pengd6622022018-11-05 13:10:26 +0100208 "Google Logging": {
209 "git_repository": "https://github.com/google/glog.git",
Philipp Wollermann17e5fc62021-02-15 14:48:36 +0100210 "http_config": "https://raw.githubusercontent.com/google/glog/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100211 "pipeline_slug": "google-logging",
Yun Pengd6622022018-11-05 13:10:26 +0100212 },
Yun Peng9586db52018-11-02 10:48:40 +0100213 "IntelliJ Plugin": {
214 "git_repository": "https://github.com/bazelbuild/intellij.git",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100215 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/intellij.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100216 "pipeline_slug": "intellij-plugin",
Yun Peng9586db52018-11-02 10:48:40 +0100217 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100218 "IntelliJ Plugin Aspect": {
219 "git_repository": "https://github.com/bazelbuild/intellij.git",
220 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/aspect.yml",
221 "pipeline_slug": "intellij-plugin-aspect",
222 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200223 "Kythe": {
224 "git_repository": "https://github.com/kythe/kythe.git",
225 "http_config": "https://raw.githubusercontent.com/kythe/kythe/master/.bazelci/presubmit.yml",
226 "pipeline_slug": "kythe",
227 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100228 "Protobuf": {
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200229 "git_repository": "https://github.com/google/protobuf.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200230 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/protobuf.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100231 "pipeline_slug": "protobuf",
Yun Peng667750b2020-02-20 14:06:43 +0100232 "owned_by_bazel": True,
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200233 },
Laurent Le Brunf6326d62020-07-28 18:24:10 +0200234 "Stardoc": {
235 "git_repository": "https://github.com/bazelbuild/stardoc.git",
236 "http_config": "https://raw.githubusercontent.com/bazelbuild/stardoc/master/.bazelci/presubmit.yml",
237 "pipeline_slug": "stardoc",
Yun Peng667750b2020-02-20 14:06:43 +0100238 "owned_by_bazel": True,
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200239 },
240 "Subpar": {
241 "git_repository": "https://github.com/google/subpar.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200242 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/subpar.yml",
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200243 "pipeline_slug": "subpar",
Yun Peng667750b2020-02-20 14:06:43 +0100244 "owned_by_bazel": True,
Xùdōng Yáng26e280f2021-07-20 23:33:07 +1000245 "disabled_reason": "https://github.com/google/subpar/issues/133",
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200246 },
247 "TensorFlow": {
248 "git_repository": "https://github.com/tensorflow/tensorflow.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200249 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/tensorflow.yml",
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200250 "pipeline_slug": "tensorflow",
Florian Weikert1d08af62021-08-07 08:29:20 +0200251 "disabled_reason": "https://github.com/bazelbuild/bazel/issues/13811",
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200252 },
253 "Tulsi": {
254 "git_repository": "https://github.com/bazelbuild/tulsi.git",
255 "http_config": "https://raw.githubusercontent.com/bazelbuild/tulsi/master/.bazelci/presubmit.yml",
256 "pipeline_slug": "tulsi-bazel-darwin",
Yun Peng9b1d3432021-12-07 10:40:45 +0100257 "disabled_reason": "https://github.com/bazelbuild/tulsi/issues/286",
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200258 },
259 "re2": {
260 "git_repository": "https://github.com/google/re2.git",
Philipp Wollermanndd8cf922021-10-01 15:43:33 +0200261 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/pipelines/re2.yml",
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200262 "pipeline_slug": "re2",
263 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100264 "rules_android": {
265 "git_repository": "https://github.com/bazelbuild/rules_android.git",
266 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_android/master/.bazelci/postsubmit.yml",
267 "pipeline_slug": "rules-android",
Yun Pengc0575c82020-06-03 11:27:45 +0200268 "disabled_reason": "https://github.com/bazelbuild/rules_android/issues/15",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100269 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200270 "rules_appengine": {
271 "git_repository": "https://github.com/bazelbuild/rules_appengine.git",
Yun Peng996efad2018-11-27 17:19:44 +0100272 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_appengine/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100273 "pipeline_slug": "rules-appengine-appengine",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200274 },
Yun Peng809f27b2018-11-13 10:15:39 +0100275 "rules_apple": {
276 "git_repository": "https://github.com/bazelbuild/rules_apple.git",
Yun Peng996efad2018-11-27 17:19:44 +0100277 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_apple/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100278 "pipeline_slug": "rules-apple-darwin",
Yun Peng809f27b2018-11-13 10:15:39 +0100279 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100280 "rules_cc": {
281 "git_repository": "https://github.com/bazelbuild/rules_cc.git",
aiuto560809f2021-08-17 14:51:32 -0400282 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_cc/main/.bazelci/presubmit.yml",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100283 "pipeline_slug": "rules-cc",
Yun Peng667750b2020-02-20 14:06:43 +0100284 "owned_by_bazel": True,
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100285 },
Marcel Hlopko340dfd22018-10-19 11:33:01 +0200286 "rules_closure": {
287 "git_repository": "https://github.com/bazelbuild/rules_closure.git",
Yun Peng996efad2018-11-27 17:19:44 +0100288 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_closure/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100289 "pipeline_slug": "rules-closure-closure-compiler",
Yun Peng667750b2020-02-20 14:06:43 +0100290 "owned_by_bazel": True,
Marcel Hlopko340dfd22018-10-19 11:33:01 +0200291 },
Yun Peng996efad2018-11-27 17:19:44 +0100292 "rules_docker": {
293 "git_repository": "https://github.com/bazelbuild/rules_docker.git",
294 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_docker/master/.bazelci/presubmit.yml",
Jakob Buchgrabera6a8ea82018-12-07 13:51:02 +0100295 "pipeline_slug": "rules-docker-docker",
Yun Peng996efad2018-11-27 17:19:44 +0100296 },
Florian Weikert5569c112021-04-01 14:04:33 +0200297 "rules_dotnet": {
298 "git_repository": "https://github.com/bazelbuild/rules_dotnet.git",
299 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_dotnet/master/.bazelci/presubmit.yml",
300 "pipeline_slug": "rules-dotnet-edge",
Yun Peng9b1d3432021-12-07 10:40:45 +0100301 "disabled_reason": "https://github.com/bazelbuild/rules_dotnet/issues/268",
Florian Weikert5569c112021-04-01 14:04:33 +0200302 },
Yun Peng996efad2018-11-27 17:19:44 +0100303 "rules_foreign_cc": {
304 "git_repository": "https://github.com/bazelbuild/rules_foreign_cc.git",
mai932d494522021-03-30 18:34:05 +0200305 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_foreign_cc/main/.bazelci/config.yaml",
Yun Peng996efad2018-11-27 17:19:44 +0100306 "pipeline_slug": "rules-foreign-cc",
Yun Peng667750b2020-02-20 14:06:43 +0100307 "owned_by_bazel": True,
Yun Peng996efad2018-11-27 17:19:44 +0100308 },
Xindb02c012018-11-07 14:10:54 -0500309 "rules_go": {
310 "git_repository": "https://github.com/bazelbuild/rules_go.git",
Yun Peng996efad2018-11-27 17:19:44 +0100311 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_go/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100312 "pipeline_slug": "rules-go-golang",
Yun Pengb7247ff2018-11-15 13:52:39 +0100313 },
Yun Peng7deea572018-11-05 10:47:45 +0100314 "rules_groovy": {
Yun Peng996efad2018-11-27 17:19:44 +0100315 "git_repository": "https://github.com/bazelbuild/rules_groovy.git",
316 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_groovy/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100317 "pipeline_slug": "rules-groovy",
Yun Peng996efad2018-11-27 17:19:44 +0100318 },
319 "rules_gwt": {
320 "git_repository": "https://github.com/bazelbuild/rules_gwt.git",
321 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_gwt/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100322 "pipeline_slug": "rules-gwt",
Xùdōng Yáng99b86b32021-08-18 23:42:05 +1000323 "disabled_reason": "https://github.com/bazelbuild/continuous-integration/issues/1202",
Philipp Wollermann2a160432019-09-19 15:57:28 +0200324 },
Florian Weikertff6444e2019-09-16 16:08:57 +0200325 "rules_haskell": {
326 "git_repository": "https://github.com/tweag/rules_haskell.git",
327 "http_config": "https://raw.githubusercontent.com/tweag/rules_haskell/master/.bazelci/presubmit.yml",
328 "pipeline_slug": "rules-haskell-haskell",
Yun Peng9b1d3432021-12-07 10:40:45 +0100329 "disabled_reason": "https://github.com/tweag/rules_haskell/issues/1650",
Philipp Wollermann2a160432019-09-19 15:57:28 +0200330 },
Yun Peng996efad2018-11-27 17:19:44 +0100331 "rules_jsonnet": {
332 "git_repository": "https://github.com/bazelbuild/rules_jsonnet.git",
333 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_jsonnet/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100334 "pipeline_slug": "rules-jsonnet",
Yun Peng996efad2018-11-27 17:19:44 +0100335 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200336 "rules_jvm_external": {
337 "git_repository": "https://github.com/bazelbuild/rules_jvm_external.git",
338 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_jvm_external/master/.bazelci/presubmit.yml",
339 "pipeline_slug": "rules-jvm-external",
Yun Peng667750b2020-02-20 14:06:43 +0100340 "owned_by_bazel": True,
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200341 },
342 "rules_jvm_external - examples": {
343 "git_repository": "https://github.com/bazelbuild/rules_jvm_external.git",
344 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_jvm_external/master/.bazelci/examples.yml",
345 "pipeline_slug": "rules-jvm-external-examples",
Yun Peng667750b2020-02-20 14:06:43 +0100346 "owned_by_bazel": True,
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200347 },
Yun Peng996efad2018-11-27 17:19:44 +0100348 "rules_k8s": {
349 "git_repository": "https://github.com/bazelbuild/rules_k8s.git",
350 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_k8s/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100351 "pipeline_slug": "rules-k8s-k8s",
Yun Peng9b1d3432021-12-07 10:40:45 +0100352 "disabled_reason": "https://github.com/bazelbuild/rules_k8s/issues/668",
Yun Peng996efad2018-11-27 17:19:44 +0100353 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100354 "rules_kotlin": {
355 "git_repository": "https://github.com/bazelbuild/rules_kotlin.git",
356 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_kotlin/master/.bazelci/presubmit.yml",
357 "pipeline_slug": "rules-kotlin-kotlin",
358 },
Yun Penga5650e12018-11-14 10:16:06 +0100359 "rules_nodejs": {
360 "git_repository": "https://github.com/bazelbuild/rules_nodejs.git",
Ivo List23ce48d2020-11-18 13:15:34 +0100361 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_nodejs/stable/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100362 "pipeline_slug": "rules-nodejs-nodejs",
Yun Penga5650e12018-11-14 10:16:06 +0100363 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200364 "rules_perl": {
365 "git_repository": "https://github.com/bazelbuild/rules_perl.git",
Yun Peng996efad2018-11-27 17:19:44 +0100366 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_perl/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100367 "pipeline_slug": "rules-perl",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200368 },
Yannic6110b3c2019-08-12 15:09:37 +0000369 "rules_proto": {
370 "git_repository": "https://github.com/bazelbuild/rules_proto.git",
371 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_proto/master/.bazelci/presubmit.yml",
372 "pipeline_slug": "rules-proto",
Yun Peng667750b2020-02-20 14:06:43 +0100373 "owned_by_bazel": True,
Yannic6110b3c2019-08-12 15:09:37 +0000374 },
Yun Peng3d5a8a62018-11-19 11:42:01 +0100375 "rules_python": {
376 "git_repository": "https://github.com/bazelbuild/rules_python.git",
Florian Weikertf126dfc2021-07-05 15:39:24 +0200377 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_python/main/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100378 "pipeline_slug": "rules-python-python",
Yun Peng667750b2020-02-20 14:06:43 +0100379 "owned_by_bazel": True,
Yun Peng3d5a8a62018-11-19 11:42:01 +0100380 },
Xindb02c012018-11-07 14:10:54 -0500381 "rules_rust": {
382 "git_repository": "https://github.com/bazelbuild/rules_rust.git",
Yun Peng996efad2018-11-27 17:19:44 +0100383 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_rust/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100384 "pipeline_slug": "rules-rust-rustlang",
Xindb02c012018-11-07 14:10:54 -0500385 },
Yun Pengca62fff2018-10-31 11:22:03 +0100386 "rules_sass": {
387 "git_repository": "https://github.com/bazelbuild/rules_sass.git",
Yun Peng996efad2018-11-27 17:19:44 +0100388 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_sass/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100389 "pipeline_slug": "rules-sass",
Yun Pengca62fff2018-10-31 11:22:03 +0100390 },
Xindb02c012018-11-07 14:10:54 -0500391 "rules_scala": {
392 "git_repository": "https://github.com/bazelbuild/rules_scala.git",
Yun Peng996efad2018-11-27 17:19:44 +0100393 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_scala/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100394 "pipeline_slug": "rules-scala-scala",
Xùdōng Yánga1b883a2021-02-27 03:00:43 +1100395 "disabled_reason": "https://github.com/bazelbuild/rules_scala/issues/1224",
Xindb02c012018-11-07 14:10:54 -0500396 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100397 "rules_swift": {
398 "git_repository": "https://github.com/bazelbuild/rules_swift.git",
399 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_swift/master/.bazelci/presubmit.yml",
400 "pipeline_slug": "rules-swift-swift",
Florian Weikertbaa683f2019-12-27 18:09:58 +0100401 "do_not_notify": "https://github.com/bazelbuild/continuous-integration/issues/915",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100402 },
Yun Peng996efad2018-11-27 17:19:44 +0100403 "rules_webtesting": {
404 "git_repository": "https://github.com/bazelbuild/rules_webtesting.git",
Yun Pengc2fab332019-01-04 10:53:49 +0100405 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_webtesting/master/.bazelci/presubmit.yml",
Yun Peng996efad2018-11-27 17:19:44 +0100406 "pipeline_slug": "rules-webtesting-saucelabs",
Yun Peng996efad2018-11-27 17:19:44 +0100407 },
Philipp Wollermann389acd82019-05-21 17:41:48 +0200408 "upb": {
409 "git_repository": "https://github.com/protocolbuffers/upb.git",
410 "http_config": "https://raw.githubusercontent.com/protocolbuffers/upb/master/.bazelci/presubmit.yml",
411 "pipeline_slug": "upb",
412 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200413}
414
Philipp Wollermanne67eec42019-05-24 15:18:20 +0200415DOWNSTREAM_PROJECTS_TESTING = {
Philipp Wollermannbed211d2019-06-07 11:38:59 +0200416 "Bazel": DOWNSTREAM_PROJECTS_PRODUCTION["Bazel"],
417 "Bazelisk": DOWNSTREAM_PROJECTS_PRODUCTION["Bazelisk"],
Florian Weikert8fda2a72019-05-31 15:21:54 +0200418 "Federation": {
419 "git_repository": "https://github.com/fweikert/bazel-federation.git",
420 "http_config": "https://raw.githubusercontent.com/fweikert/bazel-federation/master/.bazelci/presubmit.yml",
421 "pipeline_slug": "bazel-federation",
422 },
Philipp Wollermannbed211d2019-06-07 11:38:59 +0200423 "rules_docker": DOWNSTREAM_PROJECTS_PRODUCTION["rules_docker"],
424 "rules_go": DOWNSTREAM_PROJECTS_PRODUCTION["rules_go"],
425 "rules_groovy": DOWNSTREAM_PROJECTS_PRODUCTION["rules_groovy"],
426 "rules_kotlin": DOWNSTREAM_PROJECTS_PRODUCTION["rules_kotlin"],
427 "rules_nodejs": DOWNSTREAM_PROJECTS_PRODUCTION["rules_nodejs"],
428 "rules_rust": DOWNSTREAM_PROJECTS_PRODUCTION["rules_rust"],
429 "rules_scala": DOWNSTREAM_PROJECTS_PRODUCTION["rules_scala"],
Philipp Wollermanne67eec42019-05-24 15:18:20 +0200430}
431
432DOWNSTREAM_PROJECTS = {
433 "bazel-testing": DOWNSTREAM_PROJECTS_TESTING,
434 "bazel-trusted": {},
435 "bazel": DOWNSTREAM_PROJECTS_PRODUCTION,
436}[BUILDKITE_ORG]
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100437
Philipp Wollermann81a88412019-07-12 10:34:33 +0200438DOCKER_REGISTRY_PREFIX = {
439 "bazel-testing": "bazel-public/testing",
440 "bazel-trusted": "bazel-public",
441 "bazel": "bazel-public",
442}[BUILDKITE_ORG]
443
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200444# A map containing all supported platform names as keys, with the values being
445# the platform name in a human readable format, and a the buildkite-agent's
446# working directory.
447PLATFORMS = {
Philipp Wollermanneffcd6e2019-06-21 18:30:34 +0200448 "centos7": {
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200449 "name": "CentOS 7 (OpenJDK 8, gcc 4.8.5)",
450 "emoji-name": ":centos: 7 (OpenJDK 8, gcc 4.8.5)",
Philipp Wollermanneffcd6e2019-06-21 18:30:34 +0200451 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann28978712021-10-21 19:09:29 +0200452 "publish_binary": [],
Philipp Wollermann5d6765d2020-02-17 17:12:02 +0100453 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/centos7-java8",
Philipp Wollermanneffcd6e2019-06-21 18:30:34 +0200454 "python": "python3.6",
455 },
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200456 "centos7_java11": {
457 "name": "CentOS 7 (OpenJDK 11, gcc 4.8.5)",
458 "emoji-name": ":centos: 7 (OpenJDK 11, gcc 4.8.5)",
459 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
460 "publish_binary": [],
461 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/centos7-java11",
462 "python": "python3.6",
463 },
464 "centos7_java11_devtoolset10": {
465 "name": "CentOS 7 (OpenJDK 11, gcc 10.2.1)",
466 "emoji-name": ":centos: 7 (OpenJDK 11, gcc 10.2.1)",
467 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann28978712021-10-21 19:09:29 +0200468 "publish_binary": ["ubuntu1404", "centos7", "linux"],
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200469 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/centos7-java11-devtoolset10",
470 "python": "python3.6",
471 },
Philipp Wollermann67fc3712019-06-12 15:39:21 +0200472 "debian10": {
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200473 "name": "Debian 10 Buster (OpenJDK 11, gcc 8.3.0)",
474 "emoji-name": ":debian: 10 Buster (OpenJDK 11, gcc 8.3.0)",
Philipp Wollermann67fc3712019-06-12 15:39:21 +0200475 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
476 "publish_binary": [],
Philipp Wollermann5d6765d2020-02-17 17:12:02 +0100477 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/debian10-java11",
Philipp Wollermann67fc3712019-06-12 15:39:21 +0200478 "python": "python3.7",
479 },
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200480 "debian11": {
481 "name": "Debian 11 Bullseye (OpenJDK 17, gcc 10.2.1)",
482 "emoji-name": ":debian: 11 Buster (OpenJDK 17, gcc 10.2.1)",
483 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
484 "publish_binary": [],
485 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/debian11-java17",
486 "python": "python3.9",
487 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200488 "ubuntu1604": {
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200489 "name": "Ubuntu 16.04 LTS (OpenJDK 8, gcc 5.4.0)",
490 "emoji-name": ":ubuntu: 16.04 LTS (OpenJDK 8, gcc 5.4.0)",
Philipp Wollermannd551bf62019-05-18 22:04:35 +0200491 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann64047082021-10-21 21:26:25 +0200492 "publish_binary": [],
Philipp Wollermann5d6765d2020-02-17 17:12:02 +0100493 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu1604-java8",
Philipp Wollermann57b32682019-05-18 22:09:27 +0200494 "python": "python3.6",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200495 },
496 "ubuntu1804": {
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200497 "name": "Ubuntu 18.04 LTS (OpenJDK 11, gcc 7.4.0)",
498 "emoji-name": ":ubuntu: 18.04 LTS (OpenJDK 11, gcc 7.4.0)",
Philipp Wollermannd551bf62019-05-18 22:04:35 +0200499 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann783d1672019-06-06 13:35:30 +0200500 "publish_binary": ["ubuntu1804"],
Philipp Wollermann5d6765d2020-02-17 17:12:02 +0100501 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu1804-java11",
Philipp Wollermann57b32682019-05-18 22:09:27 +0200502 "python": "python3.6",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200503 },
Mostyn Bramley-Mooreab4599e2020-06-23 20:31:01 +0200504 "ubuntu2004": {
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200505 "name": "Ubuntu 20.04 LTS (OpenJDK 11, gcc 9.3.0)",
506 "emoji-name": ":ubuntu: 20.04 LTS (OpenJDK 11, gcc 9.3.0)",
Mostyn Bramley-Mooreab4599e2020-06-23 20:31:01 +0200507 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann55f72ac2020-09-21 22:22:05 +0200508 "publish_binary": [],
Mostyn Bramley-Mooreab4599e2020-06-23 20:31:01 +0200509 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu2004-java11",
510 "python": "python3.8",
511 },
Chi Wang6357efe2020-08-25 16:23:38 +0800512 "kythe_ubuntu2004": {
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200513 "name": "Kythe (Ubuntu 20.04 LTS, OpenJDK 11, gcc 9.3.0)",
514 "emoji-name": "Kythe (:ubuntu: 20.04 LTS, OpenJDK 11, gcc 9.3.0)",
Chi Wang6357efe2020-08-25 16:23:38 +0800515 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
516 "publish_binary": [],
517 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu2004-java11-kythe",
518 "python": "python3.8",
519 },
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200520 "ubuntu2104": {
521 "name": "Ubuntu 21.04 (OpenJDK 11, gcc 10.3.0)",
522 "emoji-name": ":ubuntu: 21.04 (OpenJDK 11, gcc 10.3.0)",
523 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
524 "publish_binary": [],
525 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu2104-java11",
Philipp Wollermann5c3dbb72021-11-24 17:36:38 +0100526 "python": "python3",
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200527 },
528 "ubuntu2110": {
529 "name": "Ubuntu 21.10 (OpenJDK 17, gcc 11.2.0)",
530 "emoji-name": ":ubuntu: 21.10 (OpenJDK 11, gcc 11.2.0)",
531 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
532 "publish_binary": [],
Philipp Wollermann32341e02021-10-21 23:31:09 +0200533 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu2110-java17",
Philipp Wollermannb6a399a2021-10-22 07:57:26 +0200534 "python": "python3",
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200535 },
Philipp Wollermann438ec242018-09-05 14:39:24 +0200536 "macos": {
Philipp Wollermann5e3d09f2021-10-21 01:03:01 +0200537 "name": "macOS (OpenJDK 11, Xcode)",
538 "emoji-name": ":darwin: (OpenJDK 11, Xcode)",
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200539 "downstream-root": "/Users/buildkite/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann783d1672019-06-06 13:35:30 +0200540 "publish_binary": ["macos"],
Philipp Wollermann7a185322019-05-18 22:15:48 +0200541 "queue": "macos",
Philipp Wollermann89d36492021-02-16 11:59:09 +0100542 "python": "python3",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200543 },
Yun Peng46d43912021-04-21 09:49:53 +0200544 "macos_arm64": {
Philipp Wollermann9af2b432021-10-20 22:37:17 +0200545 "name": "macOS arm64 (OpenJDK 8, Xcode)",
546 "emoji-name": ":darwin: arm64 (OpenJDK 8, Xcode)",
Yun Peng46d43912021-04-21 09:49:53 +0200547 "downstream-root": "/Users/buildkite/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Yun Peng83f32772021-04-21 11:22:35 +0200548 "publish_binary": ["macos_arm64"],
Yun Peng46d43912021-04-21 09:49:53 +0200549 # TODO(pcloudy): Switch to macos_arm64 queue when Apple Silicon machines are available,
550 # current we just use x86_64 machines to do cross compile.
551 "queue": "macos",
552 "python": "python3",
553 },
Philipp Wollermann438ec242018-09-05 14:39:24 +0200554 "windows": {
Philipp Wollermann74911e32021-10-21 19:10:09 +0200555 "name": "Windows (OpenJDK 11, VS2017)",
556 "emoji-name": ":windows: (OpenJDK 11, VS2017)",
Philipp Wollermannd5ab3d92020-02-05 16:55:13 +0100557 "downstream-root": "c:/b/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann783d1672019-06-06 13:35:30 +0200558 "publish_binary": ["windows"],
Philipp Wollermann7a185322019-05-18 22:15:48 +0200559 "queue": "windows",
Philipp Wollermann57b32682019-05-18 22:09:27 +0200560 "python": "python.exe",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200561 },
562 "rbe_ubuntu1604": {
Philipp Wollermanndb877332019-04-23 17:58:01 +0200563 "name": "RBE (Ubuntu 16.04, OpenJDK 8)",
Jakob Buchgraber1f37fbd2019-07-17 17:08:28 +0200564 "emoji-name": "RBE (:ubuntu: 16.04, OpenJDK 8)",
Philipp Wollermannd551bf62019-05-18 22:04:35 +0200565 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann783d1672019-06-06 13:35:30 +0200566 "publish_binary": [],
Philipp Wollermann5d6765d2020-02-17 17:12:02 +0100567 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu1604-java8",
Philipp Wollermann57b32682019-05-18 22:09:27 +0200568 "python": "python3.6",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100569 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200570}
571
Philipp Wollermannfce92bf2019-05-22 15:14:32 +0200572BUILDIFIER_DOCKER_IMAGE = "gcr.io/bazel-public/buildifier"
Florian Weikertf20ae6f2019-01-16 14:32:09 +0100573
Philipp Wollermann1403d2c2019-01-10 13:15:51 +0100574# The platform used for various steps (e.g. stuff that formerly ran on the "pipeline" workers).
575DEFAULT_PLATFORM = "ubuntu1804"
576
Philipp Wollermannf4aabb72019-06-25 15:59:00 +0200577# In order to test that "the one Linux binary" that we build for our official releases actually
578# works on all Linux distributions that we test on, we use the Linux binary built on our official
579# release platform for all Linux downstream tests.
Philipp Wollermann61faafa2021-10-25 15:02:57 +0200580LINUX_BINARY_PLATFORM = "centos7_java11_devtoolset10"
Philipp Wollermannf4aabb72019-06-25 15:59:00 +0200581
Philipp Wollermann05783052021-10-21 21:02:10 +0200582DEFAULT_XCODE_VERSION = "13.0"
Philipp Wollermann380f1e62019-04-12 16:45:27 +0200583XCODE_VERSION_REGEX = re.compile(r"^\d+\.\d+(\.\d+)?$")
Florian Weikertdb832a02020-11-19 19:14:48 +0100584XCODE_VERSION_OVERRIDES = {"10.2.1": "10.3", "11.2": "11.2.1", "11.3": "11.3.1"}
Philipp Wollermann380f1e62019-04-12 16:45:27 +0200585
Florian Weikertc8642af2019-02-03 23:58:51 +0100586BUILD_LABEL_PATTERN = re.compile(r"^Build label: (\S+)$", re.MULTILINE)
587
Florian Weikertde96a6f2019-03-07 14:57:50 +0100588BUILDIFIER_STEP_NAME = "Buildifier"
589
Florian Weikert5f5d3cb2019-04-15 15:36:27 +0200590SKIP_TASKS_ENV_VAR = "CI_SKIP_TASKS"
591
Philipp Wollermannce986af2019-07-18 14:46:05 +0200592CONFIG_FILE_EXTENSIONS = {".yml", ".yaml"}
Florian Weikert778251c2019-04-25 15:14:44 +0200593
Chi Wang6357efe2020-08-25 16:23:38 +0800594KYTHE_DIR = "/usr/local/kythe"
595
596INDEX_UPLOAD_POLICY_ALWAYS = "Always"
597
598INDEX_UPLOAD_POLICY_IF_BUILD_SUCCESS = "IfBuildSuccess"
599
600INDEX_UPLOAD_POLICY_NEVER = "Never"
Florian Weikert13215a82019-05-10 12:42:21 +0200601
Florian Weikertdb832a02020-11-19 19:14:48 +0100602
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100603class BuildkiteException(Exception):
604 """
605 Raised whenever something goes wrong and we should exit with an error.
606 """
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100607
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100608 pass
609
610
611class BinaryUploadRaceException(Exception):
612 """
613 Raised when try_publish_binaries wasn't able to publish a set of binaries,
614 because the generation of the current file didn't match the expected value.
615 """
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100616
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100617 pass
618
619
Florian Weikerta0e74592019-03-07 11:56:12 +0100620class BuildkiteClient(object):
621
622 _ENCRYPTED_BUILDKITE_API_TOKEN = """
623CiQA4DEB9ldzC+E39KomywtqXfaQ86hhulgeDsicds2BuvbCYzsSUAAqwcvXZPh9IMWlwWh94J2F
624exosKKaWB0tSRJiPKnv2NPDfEqGul0ZwVjtWeASpugwxxKeLhFhPMcgHMPfndH6j2GEIY6nkKRbP
625uwoRMCwe
626""".strip()
627
Philipp Wollermanne67eec42019-05-24 15:18:20 +0200628 _ENCRYPTED_BUILDKITE_API_TESTING_TOKEN = """
629CiQAMTBkWjL1C+F5oon3+cC1vmum5+c1y5+96WQY44p0Lxd0PeASUQAy7iU0c6E3W5EOSFYfD5fA
630MWy/SHaMno1NQSUa4xDOl5yc2kizrtxPPVkX4x9pLNuGUY/xwAn2n1DdiUdWZNWlY1bX2C4ex65e
631P9w8kNhEbw==
632""".strip()
633
Florian Weikertde96a6f2019-03-07 14:57:50 +0100634 _BUILD_STATUS_URL_TEMPLATE = (
635 "https://api.buildkite.com/v2/organizations/{}/pipelines/{}/builds/{}"
636 )
Florian Weikerta0e74592019-03-07 11:56:12 +0100637
Florian Weikertdb832a02020-11-19 19:14:48 +0100638 _NEW_BUILD_URL_TEMPLATE = "https://api.buildkite.com/v2/organizations/{}/pipelines/{}/builds"
Yun Peng9337bb32020-02-28 13:31:29 +0100639
640 _RETRY_JOB_URL_TEMPLATE = (
641 "https://api.buildkite.com/v2/organizations/{}/pipelines/{}/builds/{}/jobs/{}/retry"
642 )
643
Florian Weikerta0e74592019-03-07 11:56:12 +0100644 def __init__(self, org, pipeline):
645 self._org = org
646 self._pipeline = pipeline
647 self._token = self._get_buildkite_token()
648
649 def _get_buildkite_token(self):
Florian Weikert849afb22019-12-14 12:22:29 -0800650 return decrypt_token(
651 encrypted_token=self._ENCRYPTED_BUILDKITE_API_TESTING_TOKEN
652 if THIS_IS_TESTING
653 else self._ENCRYPTED_BUILDKITE_API_TOKEN,
654 kms_key="buildkite-testing-api-token"
655 if THIS_IS_TESTING
656 else "buildkite-untrusted-api-token",
Florian Weikerta0e74592019-03-07 11:56:12 +0100657 )
658
Florian Weikertdb832a02020-11-19 19:14:48 +0100659 def _open_url(self, url, params=[]):
Florian Weikert60661912019-12-18 15:17:10 +0100660 try:
Yun Peng9337bb32020-02-28 13:31:29 +0100661 params_str = "".join("&{}={}".format(k, v) for k, v in params)
Florian Weikert60661912019-12-18 15:17:10 +0100662 return (
Yun Peng9337bb32020-02-28 13:31:29 +0100663 urllib.request.urlopen("{}?access_token={}{}".format(url, self._token, params_str))
Florian Weikert60661912019-12-18 15:17:10 +0100664 .read()
Yun Pengdbedc122020-02-28 13:32:04 +0100665 .decode("utf-8", "ignore")
Florian Weikert60661912019-12-18 15:17:10 +0100666 )
667 except urllib.error.HTTPError as ex:
668 raise BuildkiteException("Failed to open {}: {} - {}".format(url, ex.code, ex.reason))
Florian Weikerta0e74592019-03-07 11:56:12 +0100669
670 def get_build_info(self, build_number):
Yun Peng9337bb32020-02-28 13:31:29 +0100671 """Get build info for a pipeline with a given build number
672 See https://buildkite.com/docs/apis/rest-api/builds#get-a-build
673
674 Parameters
675 ----------
676 build_number : the build number
677
678 Returns
679 -------
680 dict
681 the metadata for the build
682 """
Florian Weikerta0e74592019-03-07 11:56:12 +0100683 url = self._BUILD_STATUS_URL_TEMPLATE.format(self._org, self._pipeline, build_number)
684 output = self._open_url(url)
685 return json.loads(output)
686
Yun Peng9337bb32020-02-28 13:31:29 +0100687 def get_build_info_list(self, params):
688 """Get a list of build infos for this pipeline
689 See https://buildkite.com/docs/apis/rest-api/builds#list-builds-for-a-pipeline
690
691 Parameters
692 ----------
693 params : the parameters to filter the result
694
695 Returns
696 -------
697 list of dict
698 the metadata for a list of builds
699 """
700 url = self._BUILD_STATUS_URL_TEMPLATE.format(self._org, self._pipeline, "")
701 output = self._open_url(url, params)
702 return json.loads(output)
703
Florian Weikerta0e74592019-03-07 11:56:12 +0100704 def get_build_log(self, job):
705 return self._open_url(job["raw_log_url"])
706
Yun Peng9337bb32020-02-28 13:31:29 +0100707 @staticmethod
708 def _check_response(response, expected_status_code):
709 if response.status_code != expected_status_code:
710 eprint("Exit code:", response.status_code)
711 eprint("Response:\n", response.text)
712 response.raise_for_status()
713
Florian Weikertdb832a02020-11-19 19:14:48 +0100714 def trigger_new_build(self, commit, message=None, env={}):
Yun Peng9337bb32020-02-28 13:31:29 +0100715 """Trigger a new build at a given commit and return the build metadata.
716 See https://buildkite.com/docs/apis/rest-api/builds#create-a-build
717
718 Parameters
719 ----------
720 commit : the commit we want to build at
721 message : the message we should as the build titile
722 env : (optional) the environment variables to set
723
724 Returns
725 -------
726 dict
727 the metadata for the build
728 """
729 url = self._NEW_BUILD_URL_TEMPLATE.format(self._org, self._pipeline)
730 data = {
731 "commit": commit,
732 "branch": "master",
733 "message": message if message else f"Trigger build at {commit}",
734 "env": env,
735 }
Florian Weikertdb832a02020-11-19 19:14:48 +0100736 response = requests.post(url + "?access_token=" + self._token, json=data)
Yun Peng9337bb32020-02-28 13:31:29 +0100737 BuildkiteClient._check_response(response, requests.codes.created)
738 return json.loads(response.text)
739
Yun Peng9337bb32020-02-28 13:31:29 +0100740 def trigger_job_retry(self, build_number, job_id):
741 """Trigger a job retry and return the job metadata.
742 See https://buildkite.com/docs/apis/rest-api/jobs#retry-a-job
743
744 Parameters
745 ----------
746 build_number : the number of the build we want to retry
747 job_id : the id of the job we want to retry
748
749 Returns
750 -------
751 dict
752 the metadata for the job
753 """
754 url = self._RETRY_JOB_URL_TEMPLATE.format(self._org, self._pipeline, build_number, job_id)
755 response = requests.put(url + "?access_token=" + self._token)
756 BuildkiteClient._check_response(response, requests.codes.ok)
757 return json.loads(response.text)
758
Yun Peng9337bb32020-02-28 13:31:29 +0100759 def wait_job_to_finish(self, build_number, job_id, interval_time=30, logger=None):
760 """Wait a job to finish and return the job metadata
761
762 Parameters
763 ----------
764 build_number : the number of the build we want to wait
765 job_id : the id of the job we want to wait
766 interval_time : (optional) the interval time to check the build status, default to 30s
767 logger : (optional) a logger to report progress
768
769 Returns
770 -------
771 dict
772 the latest metadata for the job
773 """
774 t = 0
775 build_info = self.get_build_info(build_number)
776 while True:
777 for job in build_info["jobs"]:
778 if job["id"] == job_id:
779 state = job["state"]
780 if state != "scheduled" and state != "running" and state != "assigned":
781 return job
782 break
783 else:
Florian Weikertdb832a02020-11-19 19:14:48 +0100784 raise BuildkiteException(
785 f"job id {job_id} doesn't exist in build " + build_info["web_url"]
786 )
Yun Peng9337bb32020-02-28 13:31:29 +0100787 url = build_info["web_url"]
788 if logger:
789 logger.log(f"Waiting for {url}, waited {t} seconds...")
790 time.sleep(interval_time)
791 t += interval_time
792 build_info = self.get_build_info(build_number)
793
Yun Peng9337bb32020-02-28 13:31:29 +0100794 def wait_build_to_finish(self, build_number, interval_time=30, logger=None):
795 """Wait a build to finish and return the build metadata
796
797 Parameters
798 ----------
799 build_number : the number of the build we want to wait
800 interval_time : (optional) the interval time to check the build status, default to 30s
801 logger : (optional) a logger to report progress
802
803 Returns
804 -------
805 dict
806 the latest metadata for the build
807 """
808 t = 0
809 build_info = self.get_build_info(build_number)
810 while build_info["state"] == "scheduled" or build_info["state"] == "running":
811 url = build_info["web_url"]
812 if logger:
813 logger.log(f"Waiting for {url}, waited {t} seconds...")
814 time.sleep(interval_time)
815 t += interval_time
816 build_info = self.get_build_info(build_number)
817 return build_info
818
819
Florian Weikert849afb22019-12-14 12:22:29 -0800820def decrypt_token(encrypted_token, kms_key):
821 return (
822 subprocess.check_output(
823 [
824 gcloud_command(),
825 "kms",
826 "decrypt",
827 "--project",
828 "bazel-untrusted",
829 "--location",
830 "global",
831 "--keyring",
832 "buildkite",
833 "--key",
834 kms_key,
835 "--ciphertext-file",
836 "-",
837 "--plaintext-file",
838 "-",
839 ],
840 input=base64.b64decode(encrypted_token),
841 env=os.environ,
842 )
843 .decode("utf-8")
844 .strip()
845 )
846
847
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100848def eprint(*args, **kwargs):
849 """
850 Print to stderr and flush (just in case).
851 """
852 print(*args, flush=True, file=sys.stderr, **kwargs)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100853
854
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100855def is_windows():
Jakob Buchgraber09048fa2018-02-27 11:39:39 +0100856 return os.name == "nt"
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100857
Jakob Buchgrabere6de16b2018-02-28 12:42:12 +0100858
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100859def gsutil_command():
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200860 return "gsutil.cmd" if is_windows() else "gsutil"
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100861
Jakob Buchgrabere6de16b2018-02-28 12:42:12 +0100862
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100863def gcloud_command():
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200864 return "gcloud.cmd" if is_windows() else "gcloud"
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100865
Jakob Buchgrabere6de16b2018-02-28 12:42:12 +0100866
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100867def downstream_projects_root(platform):
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200868 downstream_root = os.path.expandvars(PLATFORMS[platform]["downstream-root"])
Philipp Wollermannd5ab3d92020-02-05 16:55:13 +0100869 if platform == "windows" and os.path.exists("d:/b"):
870 # If this is a Windows machine with a local SSD, the build directory is
871 # on drive D.
872 downstream_root = downstream_root.replace("c:/b/", "d:/b/")
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200873 if not os.path.exists(downstream_root):
874 os.makedirs(downstream_root)
875 return downstream_root
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100876
877
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +0100878def fetch_configs(http_url, file_config):
Philipp Wollermanndb024862018-02-19 17:16:56 +0100879 """
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +0100880 If specified fetches the build configuration from file_config or http_url, else tries to
Jakob Buchgraber25bb50f2018-02-22 18:06:21 +0100881 read it from .bazelci/presubmit.yml.
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100882 Returns the json configuration as a python data structure.
Philipp Wollermanndb024862018-02-19 17:16:56 +0100883 """
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +0100884 if file_config is not None and http_url is not None:
885 raise BuildkiteException("file_config and http_url cannot be set at the same time")
886
Florian Weikertc8b3ed22019-05-31 16:14:12 +0200887 return load_config(http_url, file_config)
888
889
890def load_config(http_url, file_config, allow_imports=True):
Florian Weikertc8b3ed22019-05-31 16:14:12 +0200891 if http_url:
892 config = load_remote_yaml_file(http_url)
893 else:
894 file_config = file_config or ".bazelci/presubmit.yml"
895 with open(file_config, "r") as fd:
896 config = yaml.safe_load(fd)
897
Florian Weikert843d7a02019-02-03 17:24:50 +0100898 # Legacy mode means that there is exactly one task per platform (e.g. ubuntu1604_nojdk),
899 # which means that we can get away with using the platform name as task ID.
900 # No other updates are needed since get_platform_for_task() falls back to using the
901 # task ID as platform if there is no explicit "platforms" field.
902 if "platforms" in config:
903 config["tasks"] = config.pop("platforms")
904
Florian Weikertc8b3ed22019-05-31 16:14:12 +0200905 if "tasks" not in config:
906 config["tasks"] = {}
907
908 imports = config.pop("imports", None)
909 if imports:
910 if not allow_imports:
911 raise BuildkiteException("Nested imports are not allowed")
912
913 for i in imports:
914 imported_tasks = load_imported_tasks(i, http_url, file_config)
915 config["tasks"].update(imported_tasks)
916
Florian Weikert843d7a02019-02-03 17:24:50 +0100917 return config
918
919
Florian Weikert13215a82019-05-10 12:42:21 +0200920def load_remote_yaml_file(http_url):
921 with urllib.request.urlopen(http_url) as resp:
922 reader = codecs.getreader("utf-8")
Philipp Wollermannd00107e2019-05-18 23:50:59 +0200923 return yaml.safe_load(reader(resp))
Florian Weikert13215a82019-05-10 12:42:21 +0200924
925
Florian Weikertc8b3ed22019-05-31 16:14:12 +0200926def load_imported_tasks(import_name, http_url, file_config):
927 if "/" in import_name:
928 raise BuildkiteException("Invalid import '%s'" % import_name)
929
930 old_path = http_url or file_config
931 new_path = "%s%s" % (old_path[: old_path.rfind("/") + 1], import_name)
932 if http_url:
933 http_url = new_path
934 else:
935 file_config = new_path
936
937 imported_config = load_config(http_url=http_url, file_config=file_config, allow_imports=False)
938
939 namespace = import_name.partition(".")[0]
940 tasks = {}
941 for task_name, task_config in imported_config["tasks"].items():
Florian Weikert61f29b82019-08-12 16:56:56 +0200942 fix_imported_task_platform(task_name, task_config)
943 fix_imported_task_name(namespace, task_config)
944 fix_imported_task_working_directory(namespace, task_config)
Florian Weikertc8b3ed22019-05-31 16:14:12 +0200945 tasks["%s_%s" % (namespace, task_name)] = task_config
946
947 return tasks
948
949
Florian Weikert61f29b82019-08-12 16:56:56 +0200950def fix_imported_task_platform(task_name, task_config):
951 if "platform" not in task_config:
952 task_config["platform"] = task_name
953
954
955def fix_imported_task_name(namespace, task_config):
956 old_name = task_config.get("name")
957 task_config["name"] = "%s (%s)" % (namespace, old_name) if old_name else namespace
958
959
960def fix_imported_task_working_directory(namespace, task_config):
961 old_dir = task_config.get("working_directory")
962 task_config["working_directory"] = os.path.join(namespace, old_dir) if old_dir else namespace
963
964
Jakob Buchgraber3120f7a2018-02-18 13:28:02 +0100965def print_collapsed_group(name):
Jakob Buchgraber5c9b13d2018-02-21 22:28:14 +0100966 eprint("\n\n--- {0}\n\n".format(name))
Jakob Buchgraber3120f7a2018-02-18 13:28:02 +0100967
Jakob Buchgraber9c83de72018-02-18 15:32:44 +0100968
Jakob Buchgraber3120f7a2018-02-18 13:28:02 +0100969def print_expanded_group(name):
Jakob Buchgraber5c9b13d2018-02-21 22:28:14 +0100970 eprint("\n\n+++ {0}\n\n".format(name))
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100971
Yun Peng9b1d3432021-12-07 10:40:45 +0100972
Philipp Wollermannc8b86ac2021-10-25 17:52:07 +0200973def is_trueish(s):
974 return str(s).lower() in ["true", "1", "t", "y", "yes"]
975
Jakob Buchgraber9c83de72018-02-18 15:32:44 +0100976
Yun Peng8975c6b2019-02-28 11:55:55 +0100977def use_bazelisk_migrate():
978 """
979 If USE_BAZELISK_MIGRATE is set, we use `bazelisk --migrate` to test incompatible flags.
980 """
Philipp Wollermannc8b86ac2021-10-25 17:52:07 +0200981 return is_trueish(os.environ.get("USE_BAZELISK_MIGRATE"))
Yun Peng8975c6b2019-02-28 11:55:55 +0100982
983
984def bazelisk_flags():
985 return ["--migrate"] if use_bazelisk_migrate() else []
986
987
Chi Wang54595a22021-06-11 17:49:58 +0800988def calculate_flags(task_config, task_config_key, action_key, tmpdir, test_env_vars):
Chi Wang6357efe2020-08-25 16:23:38 +0800989 include_json_profile = task_config.get("include_json_profile", [])
Chi Wang54595a22021-06-11 17:49:58 +0800990 capture_corrupted_outputs = task_config.get("capture_corrupted_outputs", [])
Chi Wang6357efe2020-08-25 16:23:38 +0800991
992 json_profile_flags = []
993 json_profile_out = None
Chi Wang54595a22021-06-11 17:49:58 +0800994 if action_key in include_json_profile:
995 json_profile_out = os.path.join(tmpdir, "{}.profile.gz".format(action_key))
Tobias Werthc22e4c42021-10-08 12:03:14 +0200996 json_profile_flags = ["--profile={}".format(json_profile_out)]
997
Yun Peng92c0ef82021-07-26 10:41:21 +0200998
Chi Wang54595a22021-06-11 17:49:58 +0800999 capture_corrupted_outputs_flags = []
1000 capture_corrupted_outputs_dir = None
1001 if action_key in capture_corrupted_outputs:
Philipp Wollermannf436e742021-08-11 11:06:55 +02001002 capture_corrupted_outputs_dir = os.path.join(
1003 tmpdir, "{}_corrupted_outputs".format(action_key)
1004 )
1005 capture_corrupted_outputs_flags = [
1006 "--experimental_remote_capture_corrupted_outputs={}".format(
1007 capture_corrupted_outputs_dir
1008 )
1009 ]
Chi Wang6357efe2020-08-25 16:23:38 +08001010
1011 flags = task_config.get(task_config_key) or []
1012 flags += json_profile_flags
Chi Wang54595a22021-06-11 17:49:58 +08001013 flags += capture_corrupted_outputs_flags
Chi Wang6357efe2020-08-25 16:23:38 +08001014 # We have to add --test_env flags to `build`, too, otherwise Bazel
1015 # discards its analysis cache between `build` and `test`.
1016 if test_env_vars:
1017 flags += ["--test_env={}".format(v) for v in test_env_vars]
1018
Chi Wang54595a22021-06-11 17:49:58 +08001019 return flags, json_profile_out, capture_corrupted_outputs_dir
Chi Wang6357efe2020-08-25 16:23:38 +08001020
1021
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001022def execute_commands(
Florian Weikertc8642af2019-02-03 23:58:51 +01001023 task_config,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001024 platform,
1025 git_repository,
1026 git_commit,
Yun Peng5012a862021-09-16 16:35:43 +02001027 repo_location,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001028 use_bazel_at_commit,
1029 use_but,
1030 save_but,
Yun Peng4d1d6542019-01-17 18:30:33 +01001031 needs_clean,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001032 build_only,
1033 test_only,
1034 monitor_flaky_tests,
1035 incompatible_flags,
Florian Weikertc8642af2019-02-03 23:58:51 +01001036 bazel_version=None,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001037):
Yun Pengf50f7b72019-02-28 19:09:52 +01001038 # If we want to test incompatible flags, we ignore bazel_version and always use
1039 # the latest Bazel version through Bazelisk.
1040 if incompatible_flags:
1041 bazel_version = None
Florian Weikert13215a82019-05-10 12:42:21 +02001042 if not bazel_version:
1043 # The last good version of Bazel can be specified in an emergency file.
1044 # However, we only use last_good_bazel for pipelines that do not
1045 # explicitly specify a version of Bazel.
1046 try:
1047 emergency_settings = load_remote_yaml_file(EMERGENCY_FILE_URL)
1048 bazel_version = emergency_settings.get("last_good_bazel")
1049 except urllib.error.HTTPError:
1050 # Ignore this error. The Setup step will have already complained about
1051 # it by showing an error message.
1052 pass
Yun Pengf50f7b72019-02-28 19:09:52 +01001053
Jakob Buchgraberfb95a2f2018-02-22 11:46:25 +01001054 if build_only and test_only:
1055 raise BuildkiteException("build_only and test_only cannot be true at the same time")
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001056
Yun Peng20d45602018-10-18 13:27:05 +02001057 if use_bazel_at_commit and use_but:
1058 raise BuildkiteException("use_bazel_at_commit cannot be set when use_but is true")
1059
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001060 tmpdir = tempfile.mkdtemp()
1061 sc_process = None
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001062 try:
Yun Pengda319b52021-05-20 17:00:36 +02001063 if platform == "macos" or platform == "macos_arm64":
Florian Weikertee84c5c2019-05-28 11:21:51 +02001064 activate_xcode(task_config)
Philipp Wollermann380f1e62019-04-12 16:45:27 +02001065
Florian Weikert4ee0bed2019-02-21 18:03:00 +01001066 # If the CI worker runs Bazelisk, we need to forward all required env variables to the test.
1067 # Otherwise any integration test that invokes Bazel (=Bazelisk in this case) will fail.
Marcel Hlopko198328b2019-02-25 09:19:55 +01001068 test_env_vars = ["LocalAppData"] if platform == "windows" else ["HOME"]
Florian Weikertc12580c2021-07-13 17:09:25 +02001069
1070 # CI should have its own user agent so that we can remove it from Bazel download statistics.
1071 os.environ["BAZELISK_USER_AGENT"] = "Bazelisk/BazelCI"
1072 test_env_vars.append("BAZELISK_USER_AGENT")
1073
Yun Peng5012a862021-09-16 16:35:43 +02001074 if repo_location:
1075 os.chdir(repo_location)
Yun Peng376d2b32018-11-29 10:24:54 +01001076 elif git_repository:
1077 clone_git_repository(git_repository, platform, git_commit)
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001078
Philipp Wollermannf4aabb72019-06-25 15:59:00 +02001079 # We use one binary for all Linux platforms (because we also just release one binary for all
1080 # Linux versions and we have to ensure that it works on all of them).
1081 binary_platform = platform if platform in ["macos", "windows"] else LINUX_BINARY_PLATFORM
1082
Yun Peng20d45602018-10-18 13:27:05 +02001083 if use_bazel_at_commit:
1084 print_collapsed_group(":gcloud: Downloading Bazel built at " + use_bazel_at_commit)
Philipp Wollermannf4aabb72019-06-25 15:59:00 +02001085 bazel_binary = download_bazel_binary_at_commit(
1086 tmpdir, binary_platform, use_bazel_at_commit
1087 )
Yun Pengf0a66e22019-10-14 12:45:42 +02001088 os.environ["USE_BAZEL_VERSION"] = bazel_binary
Philipp Wollermann639c0452019-01-03 11:23:54 +01001089 elif use_but:
Jakob Buchgraber92755d72018-02-22 15:33:37 +01001090 print_collapsed_group(":gcloud: Downloading Bazel Under Test")
Philipp Wollermannf4aabb72019-06-25 15:59:00 +02001091 bazel_binary = download_bazel_binary(tmpdir, binary_platform)
Yun Pengf0a66e22019-10-14 12:45:42 +02001092 os.environ["USE_BAZEL_VERSION"] = bazel_binary
Philipp Wollermann639c0452019-01-03 11:23:54 +01001093 else:
1094 bazel_binary = "bazel"
Florian Weikertc8642af2019-02-03 23:58:51 +01001095 if bazel_version:
Florian Weikertc8642af2019-02-03 23:58:51 +01001096 os.environ["USE_BAZEL_VERSION"] = bazel_version
Philipp Wollermann87b45252020-01-22 12:43:42 +01001097 if "USE_BAZEL_VERSION" in os.environ and not task_config.get(
1098 "skip_use_bazel_version_for_test", False
1099 ):
Yun Pengf0a66e22019-10-14 12:45:42 +02001100 # This will only work if the bazel binary in $PATH is actually a bazelisk binary
1101 # (https://github.com/bazelbuild/bazelisk).
1102 test_env_vars.append("USE_BAZEL_VERSION")
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001103
Philipp Wollermann5c7ea412019-05-24 15:26:57 +02001104 for key, value in task_config.get("environment", {}).items():
Philipp Wollermann4ad4aac2019-05-24 15:23:09 +02001105 # We have to explicitly convert the value to a string, because sometimes YAML tries to
1106 # be smart and converts strings like "true" and "false" to booleans.
Philipp Wollermann7df2d0d2021-08-11 13:26:04 +02001107 os.environ[key] = os.path.expandvars(str(value))
Philipp Wollermann213ac9d2019-02-06 11:50:05 +01001108
Yun Peng366f04c2020-08-10 16:55:58 +02001109 # Set BAZELISK_SHUTDOWN to 1 when we use bazelisk --migrate on Windows.
1110 # This is a workaround for https://github.com/bazelbuild/continuous-integration/issues/1012
1111 if use_bazelisk_migrate() and platform == "windows":
1112 os.environ["BAZELISK_SHUTDOWN"] = "1"
1113
Florian Weikerta8c020b2019-08-12 16:56:38 +02001114 cmd_exec_func = execute_batch_commands if platform == "windows" else execute_shell_commands
1115 cmd_exec_func(task_config.get("setup", None))
1116
Philipp Wollermanna5aee2c2019-02-11 16:55:19 +01001117 # Allow the config to override the current working directory.
1118 required_prefix = os.getcwd()
1119 requested_working_dir = os.path.abspath(task_config.get("working_directory", ""))
1120 if os.path.commonpath([required_prefix, requested_working_dir]) != required_prefix:
1121 raise BuildkiteException("working_directory refers to a path outside the workspace")
1122 os.chdir(requested_working_dir)
1123
Florian Weikerte72d68a2019-03-08 18:56:33 +01001124 if platform == "windows":
1125 execute_batch_commands(task_config.get("batch_commands", None))
1126 else:
1127 execute_shell_commands(task_config.get("shell_commands", None))
1128
Florian Weikertc8642af2019-02-03 23:58:51 +01001129 bazel_version = print_bazel_version_info(bazel_binary, platform)
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001130
Yun Penga5a1ee02018-12-05 15:00:58 +01001131 print_environment_variables_info()
1132
Yun Pengd0217ed2018-11-30 14:51:11 +01001133 if incompatible_flags:
1134 print_expanded_group("Build and test with the following incompatible flags:")
1135 for flag in incompatible_flags:
1136 eprint(flag + "\n")
1137
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001138 execute_bazel_run(
Florian Weikertc8642af2019-02-03 23:58:51 +01001139 bazel_binary, platform, task_config.get("run_targets", None), incompatible_flags
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001140 )
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001141
Yun Peng4d1d6542019-01-17 18:30:33 +01001142 if needs_clean:
Yun Pengea0359e2019-01-17 15:37:47 +01001143 execute_bazel_clean(bazel_binary, platform)
1144
Chi Wang6357efe2020-08-25 16:23:38 +08001145 build_targets, test_targets, index_targets = calculate_targets(
Florian Weikert736d06e2019-05-08 13:16:42 +02001146 task_config, platform, bazel_binary, build_only, test_only
1147 )
Florian Weikert736d06e2019-05-08 13:16:42 +02001148
1149 if build_targets:
Philipp Wollermannf436e742021-08-11 11:06:55 +02001150 (
1151 build_flags,
1152 json_profile_out_build,
1153 capture_corrupted_outputs_dir_build,
1154 ) = calculate_flags(task_config, "build_flags", "build", tmpdir, test_env_vars)
joeleba76887952019-05-16 15:22:17 +02001155 try:
Yun Pengc8bb9e92021-07-28 11:56:53 +02001156 release_name = get_release_name_from_branch_name()
joeleba76887952019-05-16 15:22:17 +02001157 execute_bazel_build(
1158 bazel_version,
1159 bazel_binary,
1160 platform,
Philipp Wollermannf436e742021-08-11 11:06:55 +02001161 build_flags
1162 + (
1163 ["--stamp", "--embed_label=%s" % release_name]
1164 if save_but and release_name
1165 else []
1166 ),
joeleba76887952019-05-16 15:22:17 +02001167 build_targets,
1168 None,
1169 incompatible_flags,
1170 )
1171 if save_but:
1172 upload_bazel_binary(platform)
1173 finally:
Chi Wang6357efe2020-08-25 16:23:38 +08001174 if json_profile_out_build:
Philipp Wollermann92cf51e2019-05-16 15:31:11 +02001175 upload_json_profile(json_profile_out_build, tmpdir)
Chi Wang54595a22021-06-11 17:49:58 +08001176 if capture_corrupted_outputs_dir_build:
1177 upload_corrupted_outputs(capture_corrupted_outputs_dir_build, tmpdir)
Philipp Wollermann639c0452019-01-03 11:23:54 +01001178
Florian Weikert736d06e2019-05-08 13:16:42 +02001179 if test_targets:
Chi Wang54595a22021-06-11 17:49:58 +08001180 test_flags, json_profile_out_test, capture_corrupted_outputs_dir_test = calculate_flags(
Florian Weikertdb832a02020-11-19 19:14:48 +01001181 task_config, "test_flags", "test", tmpdir, test_env_vars
1182 )
Florian Weikert4901c662019-02-26 13:20:11 +01001183 if not is_windows():
1184 # On platforms that support sandboxing (Linux, MacOS) we have
1185 # to allow access to Bazelisk's cache directory.
1186 # However, the flag requires the directory to exist,
1187 # so we create it here in order to not crash when a test
1188 # does not invoke Bazelisk.
1189 bazelisk_cache_dir = get_bazelisk_cache_directory(platform)
1190 os.makedirs(bazelisk_cache_dir, mode=0o755, exist_ok=True)
1191 test_flags.append("--sandbox_writable_path={}".format(bazelisk_cache_dir))
Florian Weikert5b890332019-02-25 14:57:43 +01001192
Philipp Wollermannce986af2019-07-18 14:46:05 +02001193 test_bep_file = os.path.join(tmpdir, "test_bep.json")
Philipp Wollermannce986af2019-07-18 14:46:05 +02001194 upload_thread = threading.Thread(
Chi Wangd279d582021-09-29 10:59:06 +08001195 target=upload_test_logs_from_bep, args=(test_bep_file, tmpdir, binary_platform, monitor_flaky_tests)
Philipp Wollermannce986af2019-07-18 14:46:05 +02001196 )
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001197 try:
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001198 upload_thread.start()
1199 try:
1200 execute_bazel_test(
1201 bazel_version,
1202 bazel_binary,
1203 platform,
1204 test_flags,
1205 test_targets,
1206 test_bep_file,
1207 monitor_flaky_tests,
1208 incompatible_flags,
1209 )
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001210 finally:
Chi Wang6357efe2020-08-25 16:23:38 +08001211 if json_profile_out_test:
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001212 upload_json_profile(json_profile_out_test, tmpdir)
Chi Wang54595a22021-06-11 17:49:58 +08001213 if capture_corrupted_outputs_dir_test:
1214 upload_corrupted_outputs(capture_corrupted_outputs_dir_test, tmpdir)
Philipp Wollermann639c0452019-01-03 11:23:54 +01001215 finally:
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001216 upload_thread.join()
Chi Wang6357efe2020-08-25 16:23:38 +08001217
1218 if index_targets:
Philipp Wollermannf436e742021-08-11 11:06:55 +02001219 (
1220 index_flags,
1221 json_profile_out_index,
1222 capture_corrupted_outputs_dir_index,
1223 ) = calculate_flags(task_config, "index_flags", "index", tmpdir, test_env_vars)
Chi Wang6357efe2020-08-25 16:23:38 +08001224 index_upload_policy = task_config.get("index_upload_policy", "IfBuildSuccess")
Chi Wangb2b65682020-08-27 10:36:15 +08001225 index_upload_gcs = task_config.get("index_upload_gcs", False)
Chi Wang6357efe2020-08-25 16:23:38 +08001226
1227 try:
Florian Weikertdb832a02020-11-19 19:14:48 +01001228 should_upload_kzip = (
1229 True if index_upload_policy == INDEX_UPLOAD_POLICY_ALWAYS else False
1230 )
Chi Wang6357efe2020-08-25 16:23:38 +08001231 try:
1232 execute_bazel_build_with_kythe(
1233 bazel_version,
1234 bazel_binary,
1235 platform,
1236 index_flags,
1237 index_targets,
1238 None,
Florian Weikertdb832a02020-11-19 19:14:48 +01001239 incompatible_flags,
Chi Wang6357efe2020-08-25 16:23:38 +08001240 )
1241
1242 if index_upload_policy == INDEX_UPLOAD_POLICY_IF_BUILD_SUCCESS:
1243 should_upload_kzip = True
1244 except subprocess.CalledProcessError as e:
1245 # If not running with Always policy, raise the build error.
1246 if index_upload_policy != INDEX_UPLOAD_POLICY_ALWAYS:
1247 handle_bazel_failure(e, "build")
1248
Philipp Wollermanna038b002021-05-05 22:04:38 +02001249 if should_upload_kzip and not is_pull_request():
Chi Wang6357efe2020-08-25 16:23:38 +08001250 try:
Chi Wangb2b65682020-08-27 10:36:15 +08001251 merge_and_upload_kythe_kzip(platform, index_upload_gcs)
Chi Wang6357efe2020-08-25 16:23:38 +08001252 except subprocess.CalledProcessError:
1253 raise BuildkiteException("Failed to upload kythe kzip")
1254 finally:
1255 if json_profile_out_index:
1256 upload_json_profile(json_profile_out_index, tmpdir)
Chi Wang54595a22021-06-11 17:49:58 +08001257 if capture_corrupted_outputs_dir_index:
1258 upload_corrupted_outputs(capture_corrupted_outputs_dir_index, tmpdir)
Chi Wang6357efe2020-08-25 16:23:38 +08001259
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001260 finally:
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001261 terminate_background_process(sc_process)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001262 if tmpdir:
1263 shutil.rmtree(tmpdir)
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001264
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02001265
Florian Weikertee84c5c2019-05-28 11:21:51 +02001266def activate_xcode(task_config):
1267 # Get the Xcode version from the config.
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001268 wanted_xcode_version = task_config.get("xcode_version", DEFAULT_XCODE_VERSION)
1269 print_collapsed_group(":xcode: Activating Xcode {}...".format(wanted_xcode_version))
Florian Weikertee84c5c2019-05-28 11:21:51 +02001270
1271 # Ensure it's a valid version number.
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001272 if not isinstance(wanted_xcode_version, str):
Florian Weikertee84c5c2019-05-28 11:21:51 +02001273 raise BuildkiteException(
1274 "Version number '{}' is not a string. Did you forget to put it in quotes?".format(
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001275 wanted_xcode_version
Florian Weikertee84c5c2019-05-28 11:21:51 +02001276 )
1277 )
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001278 if not XCODE_VERSION_REGEX.match(wanted_xcode_version):
Florian Weikertee84c5c2019-05-28 11:21:51 +02001279 raise BuildkiteException(
1280 "Invalid Xcode version format '{}', must match the format X.Y[.Z].".format(
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001281 wanted_xcode_version
Florian Weikertee84c5c2019-05-28 11:21:51 +02001282 )
1283 )
1284
Philipp Wollermann06e56972020-01-29 14:46:41 +01001285 # 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 +01001286 xcode_version = XCODE_VERSION_OVERRIDES.get(wanted_xcode_version, wanted_xcode_version)
1287
1288 # This falls back to a default version if the selected version is not available.
1289 supported_versions = sorted(
1290 # Stripping "Xcode" prefix and ".app" suffix from e.g. "Xcode12.0.1.app" leaves just the version number.
Florian Weikert9d5e4c02021-05-27 15:10:20 +02001291 [os.path.basename(x)[5:-4] for x in glob("/Applications/Xcode*.app")],
1292 reverse=True,
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001293 )
1294 if xcode_version not in supported_versions:
1295 xcode_version = DEFAULT_XCODE_VERSION
1296 if xcode_version != wanted_xcode_version:
1297 print_collapsed_group(
1298 ":xcode: Fixed Xcode version: {} -> {}...".format(wanted_xcode_version, xcode_version)
1299 )
1300 lines = [
Florian Weikert9d5e4c02021-05-27 15:10:20 +02001301 "Your selected Xcode version {} was not available on the machine.".format(
1302 wanted_xcode_version
1303 ),
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001304 "Bazel CI automatically picked a fallback version: {}.".format(xcode_version),
1305 "Available versions are: {}.".format(supported_versions),
1306 ]
Florian Weikert9d5e4c02021-05-27 15:10:20 +02001307 execute_command(
1308 [
1309 "buildkite-agent",
1310 "annotate",
1311 "--style=warning",
1312 "\n".join(lines),
1313 "--context",
1314 "ctx-xcode_version_fixed",
1315 ]
1316 )
Philipp Wollermann06e56972020-01-29 14:46:41 +01001317
Florian Weikertee84c5c2019-05-28 11:21:51 +02001318 # Check that the selected Xcode version is actually installed on the host.
1319 xcode_path = "/Applications/Xcode{}.app".format(xcode_version)
1320 if not os.path.exists(xcode_path):
1321 raise BuildkiteException("Xcode not found at '{}'.".format(xcode_path))
1322
1323 # Now activate the specified Xcode version and let it install its required components.
1324 # The CI machines have a sudoers config that allows the 'buildkite' user to run exactly
1325 # these two commands, so don't change them without also modifying the file there.
1326 execute_command(["/usr/bin/sudo", "/usr/bin/xcode-select", "--switch", xcode_path])
1327 execute_command(["/usr/bin/sudo", "/usr/bin/xcodebuild", "-runFirstLaunch"])
1328
1329
Florian Weikert4901c662019-02-26 13:20:11 +01001330def get_bazelisk_cache_directory(platform):
1331 # The path relies on the behavior of Go's os.UserCacheDir()
1332 # and of the Go version of Bazelisk.
Philipp Wollermannce986af2019-07-18 14:46:05 +02001333 cache_dir = "Library/Caches" if platform == "macos" else ".cache"
1334 return os.path.join(os.environ.get("HOME"), cache_dir, "bazelisk")
Florian Weikert4901c662019-02-26 13:20:11 +01001335
Florian Weikert5b890332019-02-25 14:57:43 +01001336
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02001337def current_branch_is_main_branch():
1338 return os.getenv("BUILDKITE_BRANCH") in ("master", "stable", "main")
1339
1340
Yun Peng92c0ef82021-07-26 10:41:21 +02001341def get_release_name_from_branch_name():
Yun Peng26e01ff2021-07-26 12:05:53 +02001342 res = re.match(r"release-(\d+\.\d+\.\d+(rc\d+)?).*", os.getenv("BUILDKITE_BRANCH"))
Yun Peng92c0ef82021-07-26 10:41:21 +02001343 return res.group(1) if res else ""
1344
1345
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001346def is_pull_request():
Jakob Buchgraber67761d32018-02-21 19:00:21 +01001347 third_party_repo = os.getenv("BUILDKITE_PULL_REQUEST_REPO", "")
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001348 return len(third_party_repo) > 0
1349
1350
Yun Penge3cf12d2018-12-05 15:01:09 +01001351def print_bazel_version_info(bazel_binary, platform):
Jakob Buchgraber99c4bbb2018-02-22 11:59:31 +01001352 print_collapsed_group(":information_source: Bazel Info")
Philipp Wollermannf13804b2019-02-05 21:08:30 +01001353 version_output = execute_command_and_get_output(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001354 [bazel_binary]
1355 + common_startup_flags(platform)
1356 + ["--nomaster_bazelrc", "--bazelrc=/dev/null", "version"]
1357 )
1358 execute_command(
1359 [bazel_binary]
1360 + common_startup_flags(platform)
1361 + ["--nomaster_bazelrc", "--bazelrc=/dev/null", "info"]
1362 )
Jakob Buchgraber7e690a72018-02-18 13:22:15 +01001363
Florian Weikertc8642af2019-02-03 23:58:51 +01001364 match = BUILD_LABEL_PATTERN.search(version_output)
1365 return match.group(1) if match else "unreleased binary"
1366
Jakob Buchgraber7e690a72018-02-18 13:22:15 +01001367
Yun Penga5a1ee02018-12-05 15:00:58 +01001368def print_environment_variables_info():
1369 print_collapsed_group(":information_source: Environment Variables")
1370 for key, value in os.environ.items():
1371 eprint("%s=(%s)" % (key, value))
1372
1373
Jakob Buchgraber426399e2018-03-20 19:45:46 +01001374def upload_bazel_binary(platform):
Jakob Buchgraber7d1d3bb2018-02-21 22:38:22 +01001375 print_collapsed_group(":gcloud: Uploading Bazel Under Test")
Jakob Buchgraber426399e2018-03-20 19:45:46 +01001376 if platform == "windows":
Philipp Wollermann10183212020-02-04 21:54:14 +01001377 binary_dir = r"bazel-bin\src"
1378 binary_name = r"bazel.exe"
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001379 binary_nojdk_name = r"bazel_nojdk.exe"
Philipp Wollermann10183212020-02-04 21:54:14 +01001380 else:
1381 binary_dir = "bazel-bin/src"
1382 binary_name = "bazel"
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001383 binary_nojdk_name = "bazel_nojdk"
Philipp Wollermann10183212020-02-04 21:54:14 +01001384 execute_command(["buildkite-agent", "artifact", "upload", binary_name], cwd=binary_dir)
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001385 execute_command(["buildkite-agent", "artifact", "upload", binary_nojdk_name], cwd=binary_dir)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001386
1387
Chi Wangb2b65682020-08-27 10:36:15 +08001388def merge_and_upload_kythe_kzip(platform, index_upload_gcs):
Chi Wang6357efe2020-08-25 16:23:38 +08001389 print_collapsed_group(":gcloud: Uploading kythe kzip")
1390
Philipp Wollermann2b4ee9f2021-02-11 16:32:35 +01001391 kzips = glob("bazel-out/*/extra_actions/**/*.kzip", recursive=True)
Chi Wang6357efe2020-08-25 16:23:38 +08001392
Chi Wang6357efe2020-08-25 16:23:38 +08001393 build_number = os.getenv("BUILDKITE_BUILD_NUMBER")
Chi Wangb2b65682020-08-27 10:36:15 +08001394 git_commit = os.getenv("BUILDKITE_COMMIT")
1395 final_kzip_name = "{}-{}-{}.kzip".format(build_number, platform, git_commit)
Chi Wang6357efe2020-08-25 16:23:38 +08001396
Chi Wangb2b65682020-08-27 10:36:15 +08001397 execute_command([f"{KYTHE_DIR}/tools/kzip", "merge", "--output", final_kzip_name] + kzips)
Chi Wang6357efe2020-08-25 16:23:38 +08001398 execute_command(["buildkite-agent", "artifact", "upload", final_kzip_name])
1399
Chi Wangb2b65682020-08-27 10:36:15 +08001400 if index_upload_gcs:
1401 pipeline = os.getenv("BUILDKITE_PIPELINE_SLUG")
1402 destination = KZIPS_BUCKET + pipeline + "/" + final_kzip_name
1403 print("Uploading to GCS {}".format(destination))
Florian Weikertdb832a02020-11-19 19:14:48 +01001404 execute_command([gsutil_command(), "cp", final_kzip_name, destination])
Chi Wangb2b65682020-08-27 10:36:15 +08001405
Chi Wang6357efe2020-08-25 16:23:38 +08001406
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001407def download_binary(dest_dir, platform, binary_name):
Philipp Wollermannc52e26a2019-05-18 22:10:47 +02001408 source_step = create_label(platform, "Bazel", build_only=True)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001409 execute_command(
Philipp Wollermann10183212020-02-04 21:54:14 +01001410 ["buildkite-agent", "artifact", "download", binary_name, dest_dir, "--step", source_step]
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001411 )
Philipp Wollermann10183212020-02-04 21:54:14 +01001412 bazel_binary_path = os.path.join(dest_dir, binary_name)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001413 st = os.stat(bazel_binary_path)
1414 os.chmod(bazel_binary_path, st.st_mode | stat.S_IEXEC)
1415 return bazel_binary_path
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001416
1417
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001418def download_bazel_binary(dest_dir, platform):
1419 binary_name = "bazel.exe" if platform == "windows" else "bazel"
1420 return download_binary(dest_dir, platform, binary_name)
1421
1422
1423def download_bazel_nojdk_binary(dest_dir, platform):
1424 binary_name = "bazel_nojdk.exe" if platform == "windows" else "bazel_nojdk"
1425 return download_binary(dest_dir, platform, binary_name)
1426
1427
Florian Weikertdb832a02020-11-19 19:14:48 +01001428def download_binary_at_commit(
1429 dest_dir, platform, bazel_git_commit, bazel_binary_url, bazel_binary_path
1430):
Yun Peng02312732019-01-17 18:17:05 +01001431 try:
Florian Weikertdb832a02020-11-19 19:14:48 +01001432 execute_command([gsutil_command(), "cp", bazel_binary_url, bazel_binary_path])
Yun Peng02312732019-01-17 18:17:05 +01001433 except subprocess.CalledProcessError as e:
Philipp Wollermannc05ac682019-01-19 12:37:28 +01001434 raise BuildkiteException(
1435 "Failed to download Bazel binary at %s, error message:\n%s" % (bazel_git_commit, str(e))
1436 )
Yun Peng20d45602018-10-18 13:27:05 +02001437 st = os.stat(bazel_binary_path)
1438 os.chmod(bazel_binary_path, st.st_mode | stat.S_IEXEC)
1439 return bazel_binary_path
1440
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001441
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001442def download_bazel_binary_at_commit(dest_dir, platform, bazel_git_commit):
1443 url = bazelci_builds_gs_url(platform, bazel_git_commit)
1444 path = os.path.join(dest_dir, "bazel.exe" if platform == "windows" else "bazel")
1445 return download_binary_at_commit(dest_dir, platform, bazel_git_commit, url, path)
1446
1447
1448def download_bazel_nojdk_binary_at_commit(dest_dir, platform, bazel_git_commit):
1449 url = bazelci_builds_nojdk_gs_url(platform, bazel_git_commit)
1450 path = os.path.join(dest_dir, "bazel_nojdk.exe" if platform == "windows" else "bazel_nojdk")
1451 return download_binary_at_commit(dest_dir, platform, bazel_git_commit, url, path)
1452
Chi Wangd279d582021-09-29 10:59:06 +08001453def download_bazelci_agent(dest_dir, platform, version):
1454 postfix = ""
1455 if platform == "windows":
1456 postfix = "x86_64-pc-windows-msvc.exe"
1457 elif platform == "macos":
1458 postfix = "x86_64-apple-darwin"
1459 else:
1460 postfix = "x86_64-unknown-linux-musl"
1461
1462 name = "bazelci-agent-{}-{}".format(version, postfix)
1463 url = "https://github.com/bazelbuild/continuous-integration/releases/download/agent-{}/{}".format(version, name)
1464 path = os.path.join(dest_dir, "bazelci-agent.exe" if platform == "windows" else "bazelci-agent")
1465 execute_command(["curl", "-sSL", url, "-o", path])
1466 st = os.stat(path)
1467 os.chmod(path, st.st_mode | stat.S_IEXEC)
1468 return path
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04001469
joeleba7050d842019-05-23 17:03:31 +02001470def get_mirror_path(git_repository, platform):
1471 mirror_root = {
1472 "macos": "/usr/local/var/bazelbuild/",
1473 "windows": "c:\\buildkite\\bazelbuild\\",
1474 }.get(platform, "/var/lib/bazelbuild/")
1475
1476 return mirror_root + re.sub(r"[^0-9A-Za-z]", "-", git_repository)
1477
1478
Yun Peng376d2b32018-11-29 10:24:54 +01001479def clone_git_repository(git_repository, platform, git_commit=None):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001480 root = downstream_projects_root(platform)
Philipp Wollermannff39ef52018-02-21 14:18:52 +01001481 project_name = re.search(r"/([^/]+)\.git$", git_repository).group(1)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001482 clone_path = os.path.join(root, project_name)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001483 print_collapsed_group(
1484 "Fetching %s sources at %s" % (project_name, git_commit if git_commit else "HEAD")
1485 )
Philipp Wollermann438ec242018-09-05 14:39:24 +02001486
joeleba7050d842019-05-23 17:03:31 +02001487 mirror_path = get_mirror_path(git_repository, platform)
Philipp Wollermannea128282019-05-08 11:56:14 +02001488
Philipp Wollermann414703d2018-08-28 16:40:38 +02001489 if not os.path.exists(clone_path):
Philipp Wollermann62f4a032019-05-08 17:44:14 +02001490 if os.path.exists(mirror_path):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001491 execute_command(
Philipp Wollermann62f4a032019-05-08 17:44:14 +02001492 ["git", "clone", "-v", "--reference", mirror_path, git_repository, clone_path]
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001493 )
Philipp Wollermannd4cd0d82018-05-01 09:56:24 +02001494 else:
Philipp Wollermannea128282019-05-08 11:56:14 +02001495 execute_command(["git", "clone", "-v", git_repository, clone_path])
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001496
Philipp Wollermann414703d2018-08-28 16:40:38 +02001497 os.chdir(clone_path)
1498 execute_command(["git", "remote", "set-url", "origin", git_repository])
1499 execute_command(["git", "clean", "-fdqx"])
Florian Weikertd8f497c2019-06-19 15:44:20 +02001500 execute_command(["git", "submodule", "foreach", "--recursive", "git clean -fdqx"])
Philipp Wollermann414703d2018-08-28 16:40:38 +02001501 execute_command(["git", "fetch", "origin"])
Yun Peng376d2b32018-11-29 10:24:54 +01001502 if git_commit:
1503 # sync to a specific commit of this repository
1504 execute_command(["git", "reset", git_commit, "--hard"])
1505 else:
1506 # sync to the latest commit of HEAD. Unlikely git pull this also works after a force push.
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001507 remote_head = (
1508 subprocess.check_output(["git", "symbolic-ref", "refs/remotes/origin/HEAD"])
1509 .decode("utf-8")
1510 .rstrip()
1511 )
Yun Peng376d2b32018-11-29 10:24:54 +01001512 execute_command(["git", "reset", remote_head, "--hard"])
Philipp Wollermann414703d2018-08-28 16:40:38 +02001513 execute_command(["git", "submodule", "sync", "--recursive"])
1514 execute_command(["git", "submodule", "update", "--init", "--recursive", "--force"])
Florian Weikertd8f497c2019-06-19 15:44:20 +02001515 execute_command(["git", "submodule", "foreach", "--recursive", "git reset --hard"])
Philipp Wollermann414703d2018-08-28 16:40:38 +02001516 execute_command(["git", "clean", "-fdqx"])
Florian Weikertd8f497c2019-06-19 15:44:20 +02001517 execute_command(["git", "submodule", "foreach", "--recursive", "git clean -fdqx"])
Yun Peng20d45602018-10-18 13:27:05 +02001518 return clone_path
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001519
Philipp Wollermann438ec242018-09-05 14:39:24 +02001520
Yun Penga935a542018-05-18 15:08:53 +02001521def execute_batch_commands(commands):
1522 if not commands:
1523 return
1524 print_collapsed_group(":batch: Setup (Batch Commands)")
1525 batch_commands = "&".join(commands)
Jakob Buchgraber4a824412018-06-22 12:56:10 +02001526 return subprocess.run(batch_commands, shell=True, check=True, env=os.environ).returncode
Yun Penga935a542018-05-18 15:08:53 +02001527
Philipp Wollermann414703d2018-08-28 16:40:38 +02001528
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001529def execute_shell_commands(commands):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001530 if not commands:
1531 return
Jakob Buchgraber94d5c212018-02-22 09:57:08 +01001532 print_collapsed_group(":bash: Setup (Shell Commands)")
mostynb14440912020-03-17 17:11:47 +01001533 shell_command = "\n".join(["set -e"] + commands)
Philipp Wollermann3e1a7712018-02-19 17:34:24 +01001534 execute_command([shell_command], shell=True)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001535
1536
Yun Peng0a6a98a2019-03-06 13:07:54 +01001537def handle_bazel_failure(exception, action):
1538 msg = "bazel {0} failed with exit code {1}".format(action, exception.returncode)
1539 if use_bazelisk_migrate():
1540 print_collapsed_group(msg)
1541 else:
1542 raise BuildkiteException(msg)
1543
1544
Yun Peng4be92b32018-11-30 09:48:29 +01001545def execute_bazel_run(bazel_binary, platform, targets, incompatible_flags):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001546 if not targets:
1547 return
1548 print_collapsed_group("Setup (Run Targets)")
Florian Weikert474d7972019-03-01 02:12:01 +01001549 # When using bazelisk --migrate to test incompatible flags,
1550 # incompatible flags set by "INCOMPATIBLE_FLAGS" env var will be ignored.
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001551 incompatible_flags_to_use = (
1552 [] if (use_bazelisk_migrate() or not incompatible_flags) else incompatible_flags
1553 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001554 for target in targets:
Yun Peng0a6a98a2019-03-06 13:07:54 +01001555 try:
1556 execute_command(
1557 [bazel_binary]
1558 + bazelisk_flags()
1559 + common_startup_flags(platform)
1560 + ["run"]
1561 + common_build_flags(None, platform)
1562 + incompatible_flags_to_use
1563 + [target]
1564 )
1565 except subprocess.CalledProcessError as e:
1566 handle_bazel_failure(e, "run")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001567
1568
Jakob Buchgraber4f1d2712018-02-20 10:22:47 +01001569def remote_caching_flags(platform):
Philipp Wollermanne67eec42019-05-24 15:18:20 +02001570 # Only enable caching for untrusted and testing builds.
Philipp Wollermannfce92bf2019-05-22 15:14:32 +02001571 if CLOUD_PROJECT not in ["bazel-untrusted"]:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001572 return []
Philipp Wollermann02955272019-04-18 18:00:48 +02001573
Philipp Wollermanne67eec42019-05-24 15:18:20 +02001574 platform_cache_key = [BUILDKITE_ORG.encode("utf-8")]
Jakob Buchgraber89df3982019-08-06 13:07:02 +02001575 # Whenever the remote cache was known to have been poisoned increase the number below
Yun Penge04dd1d2021-08-11 13:14:42 +02001576 platform_cache_key += ["cache-poisoning-20210811".encode("utf-8")]
Philipp Wollermannfce92bf2019-05-22 15:14:32 +02001577
Philipp Wollermann380f1e62019-04-12 16:45:27 +02001578 if platform == "macos":
Philipp Wollermannfce92bf2019-05-22 15:14:32 +02001579 platform_cache_key += [
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001580 # macOS version:
1581 subprocess.check_output(["/usr/bin/sw_vers", "-productVersion"]),
1582 # Path to Xcode:
1583 subprocess.check_output(["/usr/bin/xcode-select", "-p"]),
1584 # Xcode version:
1585 subprocess.check_output(["/usr/bin/xcodebuild", "-version"]),
1586 ]
1587 # Use a local cache server for our macOS machines.
Philipp Wollermannb9e96282020-02-18 13:59:27 +01001588 flags = ["--remote_cache=http://100.107.73.148"]
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001589 else:
Philipp Wollermannfce92bf2019-05-22 15:14:32 +02001590 platform_cache_key += [
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001591 # Platform name:
1592 platform.encode("utf-8")
1593 ]
Philipp Wollermanne74da4e2019-06-07 11:31:02 +02001594 # Use RBE for caching builds running on GCE.
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001595 flags = [
1596 "--google_default_credentials",
Philipp Wollermanne74da4e2019-06-07 11:31:02 +02001597 "--remote_cache=remotebuildexecution.googleapis.com",
1598 "--remote_instance_name=projects/{}/instances/default_instance".format(CLOUD_PROJECT),
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001599 ]
Philipp Wollermann380f1e62019-04-12 16:45:27 +02001600
1601 platform_cache_digest = hashlib.sha256()
1602 for key in platform_cache_key:
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001603 eprint("Adding to platform cache key: {}".format(key))
Philipp Wollermann380f1e62019-04-12 16:45:27 +02001604 platform_cache_digest.update(key)
1605 platform_cache_digest.update(b":")
1606
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001607 flags += [
Philipp Wollermann94937722019-01-11 14:33:18 +01001608 "--remote_timeout=60",
Philipp Wollermann639c0452019-01-03 11:23:54 +01001609 "--remote_max_connections=200",
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001610 '--remote_default_platform_properties=properties:{name:"cache-silo-key" value:"%s"}'
1611 % platform_cache_digest.hexdigest(),
Philipp Wollermann639c0452019-01-03 11:23:54 +01001612 ]
Jakob Buchgraber4f1d2712018-02-20 10:22:47 +01001613
Philipp Wollermannd96d8fa2019-01-11 14:37:47 +01001614 return flags
1615
Jakob Buchgraber4f1d2712018-02-20 10:22:47 +01001616
Jakob Buchgraberb4342cd2018-02-20 16:35:07 +01001617def remote_enabled(flags):
1618 # Detect if the project configuration enabled its own remote caching / execution.
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001619 remote_flags = ["--remote_executor", "--remote_cache", "--remote_http_cache"]
Jakob Buchgraberb4342cd2018-02-20 16:35:07 +01001620 for flag in flags:
1621 for remote_flag in remote_flags:
1622 if flag.startswith(remote_flag):
1623 return True
1624 return False
1625
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001626
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001627def concurrent_jobs(platform):
1628 return "75" if platform.startswith("rbe_") else str(multiprocessing.cpu_count())
Jakob Buchgraber51a83662018-02-22 19:49:24 +01001629
1630
Philipp Wollermann3e28d3b2018-02-23 23:19:37 +01001631def concurrent_test_jobs(platform):
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001632 if platform.startswith("rbe_"):
1633 return "75"
1634 elif platform == "windows":
Jakob Buchgrabere3ccda32018-06-22 23:29:48 +02001635 return "8"
Philipp Wollermann85877cb2021-07-02 19:20:33 +02001636 elif platform.startswith("macos") and THIS_IS_TESTING:
1637 return "4"
1638 elif platform.startswith("macos"):
Philipp Wollermann111adfb2018-11-22 10:26:03 +01001639 return "8"
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001640 return "12"
Philipp Wollermann3e28d3b2018-02-23 23:19:37 +01001641
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001642
Yun Peng58977d62018-11-16 12:19:20 +01001643def common_startup_flags(platform):
Philipp Wollermannd5ab3d92020-02-05 16:55:13 +01001644 if platform == "windows":
1645 if os.path.exists("D:/b"):
1646 # This machine has a local SSD mounted as drive D.
1647 return ["--output_user_root=D:/b"]
1648 else:
1649 # This machine uses its PD-SSD as the build directory.
1650 return ["--output_user_root=C:/b"]
1651 return []
Yun Peng58977d62018-11-16 12:19:20 +01001652
1653
1654def common_build_flags(bep_file, platform):
Yun Peng088cc932018-11-16 12:11:46 +01001655 flags = [
Yun Pengf51e7842018-11-16 11:35:43 +01001656 "--show_progress_rate_limit=5",
1657 "--curses=yes",
1658 "--color=yes",
Philipp Wollermannd99414c2019-05-28 17:26:09 +02001659 "--terminal_columns=143",
Philipp Wollermann4c8391e2019-05-28 18:03:35 +02001660 "--show_timestamps",
Yun Pengf51e7842018-11-16 11:35:43 +01001661 "--verbose_failures",
Yun Pengf51e7842018-11-16 11:35:43 +01001662 "--jobs=" + concurrent_jobs(platform),
Yun Pengf51e7842018-11-16 11:35:43 +01001663 "--announce_rc",
Philipp Wollermannb97f9102019-04-16 18:05:56 +02001664 "--experimental_repository_cache_hardlinks",
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001665 # Some projects set --disk_cache in their project-specific bazelrc, which we never want on
1666 # CI, so let's just disable it explicitly.
1667 "--disk_cache=",
Yun Peng088cc932018-11-16 12:11:46 +01001668 ]
Philipp Wollermann639c0452019-01-03 11:23:54 +01001669
Philipp Wollermannb97f9102019-04-16 18:05:56 +02001670 if platform == "windows":
1671 pass
1672 elif platform == "macos":
1673 flags += [
1674 "--sandbox_writable_path=/var/tmp/_bazel_buildkite/cache/repos/v1",
1675 "--test_env=REPOSITORY_CACHE=/var/tmp/_bazel_buildkite/cache/repos/v1",
1676 ]
1677 else:
Philipp Wollermann639c0452019-01-03 11:23:54 +01001678 flags += ["--sandbox_tmpfs_path=/tmp"]
1679
Yun Peng088cc932018-11-16 12:11:46 +01001680 if bep_file:
Philipp Wollermann639c0452019-01-03 11:23:54 +01001681 flags += [
1682 "--experimental_build_event_json_file_path_conversion=false",
1683 "--build_event_json_file=" + bep_file,
1684 ]
1685
Yun Peng088cc932018-11-16 12:11:46 +01001686 return flags
Philipp Wollermann94bd9e32018-04-30 15:32:28 +02001687
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001688
Yun Pengb7247ff2018-11-15 13:52:39 +01001689def rbe_flags(original_flags, accept_cached):
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001690 # Enable remote execution via RBE.
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001691 flags = [
1692 "--remote_executor=remotebuildexecution.googleapis.com",
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001693 "--remote_instance_name=projects/bazel-untrusted/instances/default_instance",
Philipp Wollermann2df93482021-06-16 04:39:49 +02001694 "--remote_timeout=3600",
Philipp Wollermann57dadb82020-02-17 14:32:24 +01001695 "--incompatible_strict_action_env",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001696 "--google_default_credentials",
Philipp Wollermann57dadb82020-02-17 14:32:24 +01001697 "--toolchain_resolution_debug",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001698 ]
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001699
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001700 # Enable BES / Build Results reporting.
1701 flags += [
1702 "--bes_backend=buildeventservice.googleapis.com",
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001703 "--bes_timeout=360s",
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001704 "--project_id=bazel-untrusted",
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001705 ]
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001706
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001707 if not accept_cached:
1708 flags += ["--noremote_accept_cached"]
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001709
Nicolas Lopez36996222019-05-28 12:21:28 -04001710 # Adapted from https://github.com/bazelbuild/bazel-toolchains/blob/master/bazelrc/.bazelrc
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001711 flags += [
Nicolas Lopez36996222019-05-28 12:21:28 -04001712 # These should NOT longer need to be modified.
1713 # All that is needed is updating the @bazel_toolchains repo pin
1714 # in projects' WORKSPACE files.
Xindb02c012018-11-07 14:10:54 -05001715 #
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001716 # Toolchain related flags to append at the end of your .bazelrc file.
Nicolas Lopez36996222019-05-28 12:21:28 -04001717 "--host_javabase=@buildkite_config//java:jdk",
1718 "--javabase=@buildkite_config//java:jdk",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001719 "--host_java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8",
1720 "--java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8",
Nicolas Lopez36996222019-05-28 12:21:28 -04001721 "--crosstool_top=@buildkite_config//cc:toolchain",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001722 "--action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001723 ]
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001724
Yun Pengb7247ff2018-11-15 13:52:39 +01001725 # Platform flags:
1726 # The toolchain container used for execution is defined in the target indicated
1727 # by "extra_execution_platforms", "host_platform" and "platforms".
Xin03a88ab2019-03-11 19:18:50 -04001728 # If you are using your own toolchain container, you need to create a platform
1729 # target with "constraint_values" that allow for the toolchain specified with
1730 # "extra_toolchains" to be selected (given constraints defined in
1731 # "exec_compatible_with").
Yun Pengb7247ff2018-11-15 13:52:39 +01001732 # More about platforms: https://docs.bazel.build/versions/master/platforms.html
1733 # Don't add platform flags if they are specified already.
1734 platform_flags = {
Nicolas Lopez36996222019-05-28 12:21:28 -04001735 "--extra_toolchains": "@buildkite_config//config:cc-toolchain",
1736 "--extra_execution_platforms": "@buildkite_config//config:platform",
1737 "--host_platform": "@buildkite_config//config:platform",
1738 "--platforms": "@buildkite_config//config:platform",
Yun Pengb7247ff2018-11-15 13:52:39 +01001739 }
Yun Peng67ab5062018-11-15 13:58:15 +01001740 for platform_flag, value in list(platform_flags.items()):
Yun Pengb7247ff2018-11-15 13:52:39 +01001741 found = False
1742 for original_flag in original_flags:
1743 if original_flag.startswith(platform_flag):
1744 found = True
1745 break
1746 if not found:
1747 flags += [platform_flag + "=" + value]
1748
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001749 return flags
1750
1751
Philipp Wollermann87b45252020-01-22 12:43:42 +01001752def compute_flags(
1753 platform, flags, incompatible_flags, bep_file, bazel_binary, enable_remote_cache=False
1754):
Yun Peng58977d62018-11-16 12:19:20 +01001755 aggregated_flags = common_build_flags(bep_file, platform)
Yun Peng32dbec32018-11-02 12:47:41 +01001756 if not remote_enabled(flags):
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001757 if platform.startswith("rbe_"):
Florian Weikert24a4b482018-11-30 19:05:38 +01001758 aggregated_flags += rbe_flags(flags, accept_cached=enable_remote_cache)
1759 elif enable_remote_cache:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001760 aggregated_flags += remote_caching_flags(platform)
Yun Peng75786552018-11-13 15:23:30 +01001761 aggregated_flags += flags
Yun Peng4be92b32018-11-30 09:48:29 +01001762 if incompatible_flags:
1763 aggregated_flags += incompatible_flags
Yun Peng53598002018-12-03 10:42:02 +01001764
Philipp Wollermann87b45252020-01-22 12:43:42 +01001765 for i, flag in enumerate(aggregated_flags):
1766 if "$HOME" in flag:
Philipp Wollermannd5ab3d92020-02-05 16:55:13 +01001767 if platform == "windows":
1768 if os.path.exists("D:/"):
1769 home = "D:"
1770 else:
1771 home = "C:/b"
1772 elif platform == "macos":
1773 home = "/Users/buildkite"
1774 else:
1775 home = "/var/lib/buildkite-agent"
Philipp Wollermann87b45252020-01-22 12:43:42 +01001776 aggregated_flags[i] = flag.replace("$HOME", home)
1777 if "$OUTPUT_BASE" in flag:
1778 output_base = execute_command_and_get_output(
Philipp Wollermann0e394412020-01-26 15:52:32 +01001779 [bazel_binary] + common_startup_flags(platform) + ["info", "output_base"],
1780 print_output=False,
Philipp Wollermann87b45252020-01-22 12:43:42 +01001781 ).strip()
1782 aggregated_flags[i] = flag.replace("$OUTPUT_BASE", output_base)
1783
Florian Weikert24a4b482018-11-30 19:05:38 +01001784 return aggregated_flags
Yun Peng53598002018-12-03 10:42:02 +01001785
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001786
Yun Pengea0359e2019-01-17 15:37:47 +01001787def execute_bazel_clean(bazel_binary, platform):
1788 print_expanded_group(":bazel: Clean")
1789
1790 try:
Philipp Wollermannc05ac682019-01-19 12:37:28 +01001791 execute_command([bazel_binary] + common_startup_flags(platform) + ["clean", "--expunge"])
Yun Pengea0359e2019-01-17 15:37:47 +01001792 except subprocess.CalledProcessError as e:
1793 raise BuildkiteException("bazel clean failed with exit code {}".format(e.returncode))
1794
1795
Chi Wang6357efe2020-08-25 16:23:38 +08001796def kythe_startup_flags():
1797 return [f"--bazelrc={KYTHE_DIR}/extractors.bazelrc"]
1798
1799
1800def kythe_build_flags():
Philipp Wollermannf61a20b2021-05-05 22:04:20 +02001801 return [
1802 "--experimental_convenience_symlinks=normal",
Florian Weikert9d5e4c02021-05-27 15:10:20 +02001803 f"--override_repository=kythe_release={KYTHE_DIR}",
Philipp Wollermannf61a20b2021-05-05 22:04:20 +02001804 ]
Chi Wang6357efe2020-08-25 16:23:38 +08001805
1806
Florian Weikertc8642af2019-02-03 23:58:51 +01001807def execute_bazel_build(
1808 bazel_version, bazel_binary, platform, flags, targets, bep_file, incompatible_flags
1809):
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001810 print_collapsed_group(":bazel: Computing flags for build step")
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001811 aggregated_flags = compute_flags(
Yun Peng8975c6b2019-02-28 11:55:55 +01001812 platform,
1813 flags,
1814 # When using bazelisk --migrate to test incompatible flags,
1815 # incompatible flags set by "INCOMPATIBLE_FLAGS" env var will be ignored.
1816 [] if (use_bazelisk_migrate() or not incompatible_flags) else incompatible_flags,
1817 bep_file,
Philipp Wollermann87b45252020-01-22 12:43:42 +01001818 bazel_binary,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001819 enable_remote_cache=True,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001820 )
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001821
1822 print_expanded_group(":bazel: Build ({})".format(bazel_version))
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001823 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001824 execute_command(
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001825 [bazel_binary]
1826 + bazelisk_flags()
1827 + common_startup_flags(platform)
1828 + ["build"]
1829 + aggregated_flags
Philipp Wollermann2a160432019-09-19 15:57:28 +02001830 + ["--"]
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001831 + targets
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001832 )
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001833 except subprocess.CalledProcessError as e:
Yun Peng0a6a98a2019-03-06 13:07:54 +01001834 handle_bazel_failure(e, "build")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001835
1836
Chi Wang6357efe2020-08-25 16:23:38 +08001837def execute_bazel_build_with_kythe(
1838 bazel_version, bazel_binary, platform, flags, targets, bep_file, incompatible_flags
1839):
1840 print_collapsed_group(":bazel: Computing flags for build step")
1841 aggregated_flags = compute_flags(
1842 platform,
1843 flags,
1844 # When using bazelisk --migrate to test incompatible flags,
1845 # incompatible flags set by "INCOMPATIBLE_FLAGS" env var will be ignored.
1846 [] if (use_bazelisk_migrate() or not incompatible_flags) else incompatible_flags,
1847 bep_file,
1848 bazel_binary,
1849 enable_remote_cache=False,
1850 )
1851
1852 print_expanded_group(":bazel: Build ({})".format(bazel_version))
1853
1854 execute_command(
1855 [bazel_binary]
1856 + bazelisk_flags()
1857 + common_startup_flags(platform)
1858 + kythe_startup_flags()
1859 + ["build"]
1860 + kythe_build_flags()
1861 + aggregated_flags
1862 + ["--"]
1863 + targets
1864 )
1865
1866
Florian Weikert736d06e2019-05-08 13:16:42 +02001867def calculate_targets(task_config, platform, bazel_binary, build_only, test_only):
1868 build_targets = [] if test_only else task_config.get("build_targets", [])
1869 test_targets = [] if build_only else task_config.get("test_targets", [])
Chi Wang6357efe2020-08-25 16:23:38 +08001870 index_targets = [] if (build_only or test_only) else task_config.get("index_targets", [])
1871
Florian Weikertdb832a02020-11-19 19:14:48 +01001872 index_targets_query = (
1873 None if (build_only or test_only) else task_config.get("index_targets_query", None)
1874 )
Chi Wang6357efe2020-08-25 16:23:38 +08001875 if index_targets_query:
1876 output = execute_command_and_get_output(
1877 [bazel_binary]
1878 + common_startup_flags(platform)
Florian Weikertdb832a02020-11-19 19:14:48 +01001879 + ["--nomaster_bazelrc", "--bazelrc=/dev/null", "query", index_targets_query],
Chi Wang6357efe2020-08-25 16:23:38 +08001880 print_output=False,
1881 )
1882 index_targets += output.strip().split("\n")
Florian Weikert736d06e2019-05-08 13:16:42 +02001883
Philipp Wollermann2a160432019-09-19 15:57:28 +02001884 # Remove the "--" argument splitter from the list that some configs explicitly
1885 # include. We'll add it back again later where needed.
1886 build_targets = [x.strip() for x in build_targets if x.strip() != "--"]
1887 test_targets = [x.strip() for x in test_targets if x.strip() != "--"]
Chi Wang6357efe2020-08-25 16:23:38 +08001888 index_targets = [x.strip() for x in index_targets if x.strip() != "--"]
Philipp Wollermann2a160432019-09-19 15:57:28 +02001889
Florian Weikert736d06e2019-05-08 13:16:42 +02001890 shard_id = int(os.getenv("BUILDKITE_PARALLEL_JOB", "-1"))
1891 shard_count = int(os.getenv("BUILDKITE_PARALLEL_JOB_COUNT", "-1"))
1892 if shard_id > -1 and shard_count > -1:
1893 print_collapsed_group(
1894 ":female-detective: Calculating targets for shard {}/{}".format(
1895 shard_id + 1, shard_count
1896 )
1897 )
1898 expanded_test_targets = expand_test_target_patterns(bazel_binary, platform, test_targets)
Philipp Wollermann87b45252020-01-22 12:43:42 +01001899 test_targets = get_targets_for_shard(expanded_test_targets, shard_id, shard_count)
Florian Weikert736d06e2019-05-08 13:16:42 +02001900
Chi Wang6357efe2020-08-25 16:23:38 +08001901 return build_targets, test_targets, index_targets
Florian Weikert736d06e2019-05-08 13:16:42 +02001902
1903
1904def expand_test_target_patterns(bazel_binary, platform, test_targets):
Philipp Wollermann2a160432019-09-19 15:57:28 +02001905 included_targets, excluded_targets = partition_targets(test_targets)
Florian Weikert736d06e2019-05-08 13:16:42 +02001906 excluded_string = (
1907 " except tests(set({}))".format(" ".join("'{}'".format(t) for t in excluded_targets))
1908 if excluded_targets
1909 else ""
1910 )
1911
Philipp Wollermann2a160432019-09-19 15:57:28 +02001912 exclude_manual = ' except tests(attr("tags", "manual", set({})))'.format(
1913 " ".join("'{}'".format(t) for t in included_targets)
1914 )
1915
Florian Weikert736d06e2019-05-08 13:16:42 +02001916 eprint("Resolving test targets via bazel query")
1917 output = execute_command_and_get_output(
1918 [bazel_binary]
1919 + common_startup_flags(platform)
1920 + [
1921 "--nomaster_bazelrc",
1922 "--bazelrc=/dev/null",
1923 "query",
Philipp Wollermann2a160432019-09-19 15:57:28 +02001924 "tests(set({})){}{}".format(
1925 " ".join("'{}'".format(t) for t in included_targets),
1926 excluded_string,
1927 exclude_manual,
Florian Weikert736d06e2019-05-08 13:16:42 +02001928 ),
1929 ],
1930 print_output=False,
Philipp Wollermann54719fe2021-07-02 21:54:08 +02001931 ).strip()
1932 return output.split("\n") if output else []
Florian Weikert736d06e2019-05-08 13:16:42 +02001933
1934
Philipp Wollermann2a160432019-09-19 15:57:28 +02001935def partition_targets(targets):
Florian Weikert736d06e2019-05-08 13:16:42 +02001936 included_targets, excluded_targets = [], []
Philipp Wollermann2a160432019-09-19 15:57:28 +02001937 for target in targets:
1938 if target.startswith("-"):
Florian Weikert736d06e2019-05-08 13:16:42 +02001939 excluded_targets.append(target[1:])
1940 else:
1941 included_targets.append(target)
1942
1943 return included_targets, excluded_targets
1944
1945
Philipp Wollermann87b45252020-01-22 12:43:42 +01001946def get_targets_for_shard(test_targets, shard_id, shard_count):
Florian Weikert736d06e2019-05-08 13:16:42 +02001947 # TODO(fweikert): implement a more sophisticated algorithm
Philipp Wollermann87b45252020-01-22 12:43:42 +01001948 return sorted(test_targets)[shard_id::shard_count]
Florian Weikert736d06e2019-05-08 13:16:42 +02001949
1950
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001951def execute_bazel_test(
Florian Weikertc8642af2019-02-03 23:58:51 +01001952 bazel_version,
1953 bazel_binary,
1954 platform,
1955 flags,
1956 targets,
1957 bep_file,
1958 monitor_flaky_tests,
1959 incompatible_flags,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001960):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001961 aggregated_flags = [
1962 "--flaky_test_attempts=3",
1963 "--build_tests_only",
1964 "--local_test_jobs=" + concurrent_test_jobs(platform),
1965 ]
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001966 # Don't enable remote caching if the user enabled remote execution / caching themselves
Jakob Buchgraberc340f582018-06-22 13:48:33 +02001967 # or flaky test monitoring is enabled, as remote caching makes tests look less flaky than
1968 # they are.
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001969 print_collapsed_group(":bazel: Computing flags for test step")
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001970 aggregated_flags += compute_flags(
Yun Peng8975c6b2019-02-28 11:55:55 +01001971 platform,
1972 flags,
1973 # When using bazelisk --migrate to test incompatible flags,
1974 # incompatible flags set by "INCOMPATIBLE_FLAGS" env var will be ignored.
1975 [] if (use_bazelisk_migrate() or not incompatible_flags) else incompatible_flags,
1976 bep_file,
Philipp Wollermann87b45252020-01-22 12:43:42 +01001977 bazel_binary,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001978 enable_remote_cache=not monitor_flaky_tests,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001979 )
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001980
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001981 print_expanded_group(":bazel: Test ({})".format(bazel_version))
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001982 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001983 execute_command(
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001984 [bazel_binary]
1985 + bazelisk_flags()
1986 + common_startup_flags(platform)
1987 + ["test"]
1988 + aggregated_flags
Philipp Wollermann2a160432019-09-19 15:57:28 +02001989 + ["--"]
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001990 + targets
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001991 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001992 except subprocess.CalledProcessError as e:
Yun Peng0a6a98a2019-03-06 13:07:54 +01001993 handle_bazel_failure(e, "test")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001994
1995
Chi Wangd279d582021-09-29 10:59:06 +08001996def upload_test_logs_from_bep(bep_file, tmpdir, binary_platform, monitor_flaky_tests):
Chi Wang0bf22f12021-10-21 18:13:21 +08001997 bazelci_agent_binary = download_bazelci_agent(tmpdir, binary_platform, "0.1.3")
Chi Wangd279d582021-09-29 10:59:06 +08001998 execute_command(
1999 [bazelci_agent_binary, "artifact", "upload", "--delay=5", "--mode=buildkite", "--build_event_json_file={}".format(bep_file)]
2000 + (["--monitor_flaky_tests"] if monitor_flaky_tests else [])
2001 )
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002002
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02002003
joeleba76887952019-05-16 15:22:17 +02002004def upload_json_profile(json_profile_path, tmpdir):
2005 if not os.path.exists(json_profile_path):
2006 return
2007 print_collapsed_group(":gcloud: Uploading JSON Profile")
Philipp Wollermann92cf51e2019-05-16 15:31:11 +02002008 execute_command(["buildkite-agent", "artifact", "upload", json_profile_path], cwd=tmpdir)
joeleba76887952019-05-16 15:22:17 +02002009
Philipp Wollermannf436e742021-08-11 11:06:55 +02002010
Chi Wang54595a22021-06-11 17:49:58 +08002011def upload_corrupted_outputs(capture_corrupted_outputs_dir, tmpdir):
2012 if not os.path.exists(capture_corrupted_outputs_dir):
2013 return
2014 print_collapsed_group(":gcloud: Uploading corrupted outputs")
Philipp Wollermannf436e742021-08-11 11:06:55 +02002015 execute_command(
2016 ["buildkite-agent", "artifact", "upload", "{}/**/*".format(capture_corrupted_outputs_dir)],
2017 cwd=tmpdir,
2018 )
2019
Philipp Wollermann5b00a702019-07-18 11:21:38 +02002020
Philipp Wollermannaf35abf2019-05-22 17:52:01 +02002021def execute_command_and_get_output(args, shell=False, fail_if_nonzero=True, print_output=True):
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002022 eprint(" ".join(args))
Florian Weikertc8642af2019-02-03 23:58:51 +01002023 process = subprocess.run(
2024 args,
2025 shell=shell,
2026 check=fail_if_nonzero,
2027 env=os.environ,
2028 stdout=subprocess.PIPE,
Philipp Wollermannf13804b2019-02-05 21:08:30 +01002029 errors="replace",
Florian Weikertc8642af2019-02-03 23:58:51 +01002030 universal_newlines=True,
2031 )
Florian Weikert736d06e2019-05-08 13:16:42 +02002032 if print_output:
2033 eprint(process.stdout)
2034
Florian Weikertc8642af2019-02-03 23:58:51 +01002035 return process.stdout
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002036
2037
Yun Peng9337bb32020-02-28 13:31:29 +01002038def execute_command(args, shell=False, fail_if_nonzero=True, cwd=None, print_output=True):
2039 if print_output:
2040 eprint(" ".join(args))
Philipp Wollermann92cf51e2019-05-16 15:31:11 +02002041 return subprocess.run(
2042 args, shell=shell, check=fail_if_nonzero, env=os.environ, cwd=cwd
2043 ).returncode
Philipp Wollermannf13804b2019-02-05 21:08:30 +01002044
2045
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02002046def execute_command_background(args):
2047 eprint(" ".join(args))
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02002048 return subprocess.Popen(args, env=os.environ)
2049
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02002050
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02002051def terminate_background_process(process):
2052 if process:
2053 process.terminate()
2054 try:
2055 process.wait(timeout=10)
2056 except subprocess.TimeoutExpired:
2057 process.kill()
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02002058
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02002059
mai93b49bad72021-05-06 00:50:34 +02002060def create_step(label, commands, platform, shards=1, soft_fail=None):
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002061 if "docker-image" in PLATFORMS[platform]:
Florian Weikert736d06e2019-05-08 13:16:42 +02002062 step = create_docker_step(
Philipp Wollermannc05ac682019-01-19 12:37:28 +01002063 label, image=PLATFORMS[platform]["docker-image"], commands=commands
2064 )
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002065 else:
Philipp Wollermannf3750fa2019-05-21 17:11:59 +02002066 step = {
2067 "label": label,
2068 "command": commands,
2069 "agents": {"queue": PLATFORMS[platform]["queue"]},
2070 }
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002071
Florian Weikert736d06e2019-05-08 13:16:42 +02002072 if shards > 1:
2073 step["label"] += " (shard %n)"
2074 step["parallelism"] = shards
2075
mai93b49bad72021-05-06 00:50:34 +02002076 if soft_fail is not None:
2077 step["soft_fail"] = soft_fail
2078
Philipp Wollermann5b2f3fc2019-05-18 22:36:17 +02002079 # Enforce a global 8 hour job timeout.
2080 step["timeout_in_minutes"] = 8 * 60
2081
2082 # Automatically retry when an agent got lost (usually due to an infra flake).
Philipp Wollermannf22bba32019-07-18 11:22:50 +02002083 step["retry"] = {
2084 "automatic": [
2085 {"exit_status": -1, "limit": 3}, # Buildkite internal "agent lost" exit code
2086 {"exit_status": 137, "limit": 3}, # SIGKILL
2087 {"exit_status": 143, "limit": 3}, # SIGTERM
2088 ]
2089 }
Philipp Wollermann5b2f3fc2019-05-18 22:36:17 +02002090
Florian Weikert736d06e2019-05-08 13:16:42 +02002091 return step
2092
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002093
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002094def create_docker_step(label, image, commands=None, additional_env_vars=None):
Philipp Wollermann0e051dd2019-05-16 11:37:52 +02002095 env = ["ANDROID_HOME", "ANDROID_NDK_HOME", "BUILDKITE_ARTIFACT_UPLOAD_DESTINATION"]
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002096 if additional_env_vars:
2097 env += ["{}={}".format(k, v) for k, v in additional_env_vars.items()]
2098
Philipp Wollermannc05ac682019-01-19 12:37:28 +01002099 step = {
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002100 "label": label,
2101 "command": commands,
Philipp Wollermannb2fa2f62019-05-18 23:33:23 +02002102 "agents": {"queue": "default"},
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002103 "plugins": {
Philipp Wollermann9fa03542021-07-01 23:27:53 +02002104 "docker#v3.8.0": {
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002105 "always-pull": True,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002106 "environment": env,
Philipp Wollermannc05ac682019-01-19 12:37:28 +01002107 "image": image,
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002108 "network": "host",
2109 "privileged": True,
2110 "propagate-environment": True,
Philipp Wollermann7aa95492019-05-18 22:03:24 +02002111 "propagate-uid-gid": True,
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002112 "volumes": [
Philipp Wollermann7aa95492019-05-18 22:03:24 +02002113 "/etc/group:/etc/group:ro",
2114 "/etc/passwd:/etc/passwd:ro",
Philipp Wollermann3dc99b32021-10-12 00:34:30 +02002115 "/etc/shadow:/etc/shadow:ro",
Philipp Wollermann562ef1d2021-10-20 22:15:29 +02002116 "/opt/android-ndk-r15c:/opt/android-ndk-r15c:ro",
2117 "/opt/android-sdk-linux:/opt/android-sdk-linux:ro",
Philipp Wollermann7aa95492019-05-18 22:03:24 +02002118 "/var/lib/buildkite-agent:/var/lib/buildkite-agent",
Philipp Wollermann338db4a2019-05-18 11:21:04 +02002119 "/var/lib/gitmirrors:/var/lib/gitmirrors:ro",
Philipp Wollermanna65944a2020-02-03 12:45:22 +01002120 "/var/run/docker.sock:/var/run/docker.sock",
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002121 ],
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002122 }
2123 },
2124 }
Philipp Wollermannc05ac682019-01-19 12:37:28 +01002125 if not step["command"]:
2126 del step["command"]
2127 return step
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002128
2129
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002130def print_project_pipeline(
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002131 configs,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002132 project_name,
2133 http_config,
2134 file_config,
2135 git_repository,
2136 monitor_flaky_tests,
2137 use_but,
2138 incompatible_flags,
Florian Weikert60661912019-12-18 15:17:10 +01002139 notify,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002140):
Florian Weikert843d7a02019-02-03 17:24:50 +01002141 task_configs = configs.get("tasks", None)
2142 if not task_configs:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002143 raise BuildkiteException("{0} pipeline configuration is empty.".format(project_name))
2144
Jakob Buchgraberaa2af382018-02-21 19:56:54 +01002145 pipeline_steps = []
mai93f2e116c2020-10-19 09:33:14 +02002146 # If the repository is hosted on Git-on-borg, we show the link to the commit Gerrit review
2147 buildkite_repo = os.getenv("BUILDKITE_REPO")
2148 if is_git_on_borg_repo(buildkite_repo):
2149 show_gerrit_review_link(buildkite_repo, pipeline_steps)
2150
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02002151 task_configs = filter_tasks_that_should_be_skipped(task_configs, pipeline_steps)
Jakob Buchgraberff2bdad2018-02-25 13:06:30 +01002152
Philipp Wollermanndac65512019-02-05 22:14:10 +01002153 # In Bazel Downstream Project pipelines, git_repository and project_name must be specified.
2154 is_downstream_project = (use_but or incompatible_flags) and git_repository and project_name
2155
Florian Weikert85208912019-03-07 17:08:39 +01002156 buildifier_config = configs.get("buildifier")
Philipp Wollermanndac65512019-02-05 22:14:10 +01002157 # Skip Buildifier when we test downstream projects.
Florian Weikert85208912019-03-07 17:08:39 +01002158 if buildifier_config and not is_downstream_project:
2159 buildifier_env_vars = {}
2160 if isinstance(buildifier_config, str):
2161 # Simple format:
2162 # ---
2163 # buildifier: latest
Philipp Wollermann22538e72021-10-02 09:43:28 +02002164 buildifier_env_vars["BUILDIFIER_VERSION"] = buildifier_config
Florian Weikert85208912019-03-07 17:08:39 +01002165 else:
2166 # Advanced format:
2167 # ---
2168 # buildifier:
2169 # version: latest
2170 # warnings: all
Philipp Wollermann22538e72021-10-02 09:43:28 +02002171 if "version" in buildifier_config:
2172 buildifier_env_vars["BUILDIFIER_VERSION"] = buildifier_config["version"]
2173 if "warnings" in buildifier_config:
2174 buildifier_env_vars["BUILDIFIER_WARNINGS"] = buildifier_config["warnings"]
Florian Weikert85208912019-03-07 17:08:39 +01002175
2176 if not buildifier_env_vars:
2177 raise BuildkiteException(
2178 'Invalid buildifier configuration entry "{}"'.format(buildifier_config)
2179 )
2180
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002181 pipeline_steps.append(
2182 create_docker_step(
Florian Weikertde96a6f2019-03-07 14:57:50 +01002183 BUILDIFIER_STEP_NAME,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002184 image=BUILDIFIER_DOCKER_IMAGE,
Florian Weikert85208912019-03-07 17:08:39 +01002185 additional_env_vars=buildifier_env_vars,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01002186 )
2187 )
Philipp Wollermannc05ac682019-01-19 12:37:28 +01002188
Philipp Wollermanndac65512019-02-05 22:14:10 +01002189 # In Bazel Downstream Project pipelines, we should test the project at the last green commit.
Yun Peng376d2b32018-11-29 10:24:54 +01002190 git_commit = None
Philipp Wollermanndac65512019-02-05 22:14:10 +01002191 if is_downstream_project:
Florian Weikert35906542019-04-01 11:53:53 +02002192 last_green_commit_url = bazelci_last_green_commit_url(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002193 git_repository, DOWNSTREAM_PROJECTS[project_name]["pipeline_slug"]
2194 )
Florian Weikert35906542019-04-01 11:53:53 +02002195 git_commit = get_last_green_commit(last_green_commit_url)
Philipp Wollermanndac65512019-02-05 22:14:10 +01002196
Florian Weikert854fd852019-06-04 16:44:19 +02002197 config_hashes = set()
Florian Weikertdb832a02020-11-19 19:14:48 +01002198 skipped_due_to_bazel_version = []
Florian Weikert843d7a02019-02-03 17:24:50 +01002199 for task, task_config in task_configs.items():
Florian Weikertdb832a02020-11-19 19:14:48 +01002200 platform = get_platform_for_task(task, task_config)
2201 task_name = task_config.get("name")
mai93b49bad72021-05-06 00:50:34 +02002202 soft_fail = task_config.get("soft_fail")
Florian Weikertdb832a02020-11-19 19:14:48 +01002203
Florian Weikert854fd852019-06-04 16:44:19 +02002204 # We override the Bazel version in downstream pipelines. This means that two tasks that
2205 # only differ in the value of their explicit "bazel" field will be identical in the
2206 # downstream pipeline, thus leading to duplicate work.
2207 # Consequently, we filter those duplicate tasks here.
2208 if is_downstream_project:
Florian Weikertdb832a02020-11-19 19:14:48 +01002209 # Skip tasks that require a specific Bazel version
2210 bazel = task_config.get("bazel")
2211 if bazel and bazel != "latest":
2212 skipped_due_to_bazel_version.append(
2213 "{}: '{}'".format(
2214 create_label(platform, project_name, task_name=task_name), bazel
2215 )
2216 )
2217 continue
2218
Florian Weikert854fd852019-06-04 16:44:19 +02002219 h = hash_task_config(task, task_config)
2220 if h in config_hashes:
2221 continue
Florian Weikert854fd852019-06-04 16:44:19 +02002222 config_hashes.add(h)
2223
Florian Weikert736d06e2019-05-08 13:16:42 +02002224 shards = task_config.get("shards", "1")
2225 try:
2226 shards = int(shards)
2227 except ValueError:
2228 raise BuildkiteException("Task {} has invalid shard value '{}'".format(task, shards))
2229
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002230 step = runner_step(
Florian Weikertdb832a02020-11-19 19:14:48 +01002231 platform=platform,
Florian Weikert843d7a02019-02-03 17:24:50 +01002232 task=task,
Florian Weikertdb832a02020-11-19 19:14:48 +01002233 task_name=task_name,
Florian Weikert843d7a02019-02-03 17:24:50 +01002234 project_name=project_name,
2235 http_config=http_config,
2236 file_config=file_config,
2237 git_repository=git_repository,
2238 git_commit=git_commit,
2239 monitor_flaky_tests=monitor_flaky_tests,
2240 use_but=use_but,
2241 incompatible_flags=incompatible_flags,
Florian Weikert736d06e2019-05-08 13:16:42 +02002242 shards=shards,
mai93b49bad72021-05-06 00:50:34 +02002243 soft_fail=soft_fail,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002244 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002245 pipeline_steps.append(step)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002246
Florian Weikertdb832a02020-11-19 19:14:48 +01002247 if skipped_due_to_bazel_version:
Xùdōng Yáng045c9812021-08-18 01:42:35 +10002248 lines = ["\n- {}".format(s) for s in skipped_due_to_bazel_version]
Florian Weikertdb832a02020-11-19 19:14:48 +01002249 commands = [
Xùdōng Yáng2f2245a2021-08-17 00:21:58 +10002250 "buildkite-agent annotate --style=info '{}' --append --context 'ctx-skipped_due_to_bazel_version'".format(
Xùdōng Yáng045c9812021-08-18 01:42:35 +10002251 "".join(lines)
2252 ),
2253 "buildkite-agent meta-data set 'has-skipped-steps' 'true'",
Florian Weikertdb832a02020-11-19 19:14:48 +01002254 ]
2255 pipeline_steps.append(
2256 create_step(
2257 label=":pipeline: Print information about skipped tasks due to different Bazel versions",
2258 commands=commands,
2259 platform=DEFAULT_PLATFORM,
2260 )
2261 )
2262
Yun Peng996efad2018-11-27 17:19:44 +01002263 pipeline_slug = os.getenv("BUILDKITE_PIPELINE_SLUG")
2264 all_downstream_pipeline_slugs = []
2265 for _, config in DOWNSTREAM_PROJECTS.items():
2266 all_downstream_pipeline_slugs.append(config["pipeline_slug"])
Ivo List23ce48d2020-11-18 13:15:34 +01002267 # We update last green commit in the following cases:
2268 # 1. This job runs on master, stable or main branch (could be a custom build launched manually)
2269 # 2. We intend to run the same job in downstream with Bazel@HEAD (eg. google-bazel-presubmit)
2270 # 3. This job is not:
2271 # - a GitHub pull request
2272 # - uses a custom built Bazel binary (in Bazel Downstream Projects pipeline)
2273 # - testing incompatible flags
2274 # - running `bazelisk --migrate` in a non-downstream pipeline
Florian Weikertdb832a02020-11-19 19:14:48 +01002275 if (
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02002276 current_branch_is_main_branch()
Ivo List23ce48d2020-11-18 13:15:34 +01002277 and pipeline_slug in all_downstream_pipeline_slugs
2278 and not (is_pull_request() or use_but or incompatible_flags or use_bazelisk_migrate())
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002279 ):
Florian Weikertde96a6f2019-03-07 14:57:50 +01002280 # We need to call "Try Update Last Green Commit" even if there are failures,
2281 # since we don't want a failing Buildifier step to block the update of
2282 # the last green commit for this project.
2283 # try_update_last_green_commit() ensures that we don't update the commit
2284 # if any build or test steps fail.
2285 pipeline_steps.append({"wait": None, "continue_on_failure": True})
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002286 pipeline_steps.append(
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002287 create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002288 label="Try Update Last Green Commit",
2289 commands=[
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002290 fetch_bazelcipy_command(),
Philipp Wollermann57b32682019-05-18 22:09:27 +02002291 PLATFORMS[DEFAULT_PLATFORM]["python"]
2292 + " bazelci.py try_update_last_green_commit",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002293 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002294 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002295 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002296 )
Yun Peng43239b02018-11-23 13:57:34 +01002297
Florian Weikert778251c2019-04-25 15:14:44 +02002298 if "validate_config" in configs:
Florian Weikertf52f91a2019-05-08 15:19:30 +02002299 pipeline_steps += create_config_validation_steps()
Florian Weikert778251c2019-04-25 15:14:44 +02002300
Florian Weikert09813a02019-10-26 19:34:33 +02002301 if use_bazelisk_migrate() and not is_downstream_project:
2302 # Print results of bazelisk --migrate in project pipelines that explicitly set
2303 # the USE_BAZELISK_MIGRATE env var, but that are not being run as part of a
2304 # downstream pipeline.
2305 number = os.getenv("BUILDKITE_BUILD_NUMBER")
Florian Weikert60661912019-12-18 15:17:10 +01002306 pipeline_steps += get_steps_for_aggregating_migration_results(number, notify)
Florian Weikert09813a02019-10-26 19:34:33 +02002307
Florian Weikertd79dc502019-05-13 09:51:05 +02002308 print_pipeline_steps(pipeline_steps, handle_emergencies=not is_downstream_project)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002309
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002310
mai93f2e116c2020-10-19 09:33:14 +02002311def show_gerrit_review_link(git_repository, pipeline_steps):
2312 host = re.search(r"https://(.+?)\.googlesource", git_repository).group(1)
2313 if not host:
2314 raise BuildkiteException("Couldn't get host name from %s" % git_repository)
Florian Weikertdb832a02020-11-19 19:14:48 +01002315 text = "The transformed code used in this pipeline can be found under https://{}-review.googlesource.com/q/{}".format(
2316 host, os.getenv("BUILDKITE_COMMIT")
2317 )
mai93f2e116c2020-10-19 09:33:14 +02002318 commands = ["buildkite-agent annotate --style=info '{}'".format(text)]
2319 pipeline_steps.append(
2320 create_step(
2321 label=":pipeline: Print information about Gerrit Review Link",
2322 commands=commands,
2323 platform=DEFAULT_PLATFORM,
2324 )
2325 )
2326
2327
2328def is_git_on_borg_repo(git_repository):
2329 return git_repository and "googlesource.com" in git_repository
2330
2331
Florian Weikert854fd852019-06-04 16:44:19 +02002332def hash_task_config(task_name, task_config):
2333 # Two task configs c1 and c2 have the same hash iff they lead to two functionally identical jobs
2334 # in the downstream pipeline. This function discards the "bazel" field (since it's being
Philipp Wollermannce986af2019-07-18 14:46:05 +02002335 # overridden) and the "name" field (since it has no effect on the actual work).
Florian Weikert854fd852019-06-04 16:44:19 +02002336 # Moreover, it adds an explicit "platform" field if that's missing.
2337 cpy = task_config.copy()
2338 cpy.pop("bazel", None)
2339 cpy.pop("name", None)
2340 if "platform" not in cpy:
2341 cpy["platform"] = task_name
2342
2343 m = hashlib.md5()
2344 for key in sorted(cpy):
Florian Weikert8186c392019-06-05 12:53:39 +02002345 value = "%s:%s;" % (key, cpy[key])
2346 m.update(value.encode("utf-8"))
Florian Weikert854fd852019-06-04 16:44:19 +02002347
2348 return m.digest()
2349
2350
Florian Weikert843d7a02019-02-03 17:24:50 +01002351def get_platform_for_task(task, task_config):
2352 # Most pipeline configurations have exactly one task per platform, which makes it
2353 # convenient to use the platform name as task ID. Consequently, we use the
2354 # task ID as platform if there is no explicit "platform" field.
2355 return task_config.get("platform", task)
2356
2357
Florian Weikertf52f91a2019-05-08 15:19:30 +02002358def create_config_validation_steps():
2359 output = execute_command_and_get_output(
2360 ["git", "diff-tree", "--no-commit-id", "--name-only", "-r", os.getenv("BUILDKITE_COMMIT")]
2361 )
2362 config_files = [
Philipp Wollermann67225ec2021-08-11 11:12:51 +02002363 path
2364 for path in output.split("\n")
2365 if path.startswith(".bazelci/") and os.path.splitext(path)[1] in CONFIG_FILE_EXTENSIONS
Florian Weikertf52f91a2019-05-08 15:19:30 +02002366 ]
Florian Weikertf52f91a2019-05-08 15:19:30 +02002367 return [
2368 create_step(
2369 label=":cop: Validate {}".format(f),
2370 commands=[
2371 fetch_bazelcipy_command(),
2372 "{} bazelci.py project_pipeline --file_config={}".format(
Philipp Wollermann57b32682019-05-18 22:09:27 +02002373 PLATFORMS[DEFAULT_PLATFORM]["python"], f
Florian Weikertf52f91a2019-05-08 15:19:30 +02002374 ),
2375 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002376 platform=DEFAULT_PLATFORM,
Florian Weikertf52f91a2019-05-08 15:19:30 +02002377 )
2378 for f in config_files
2379 ]
2380
2381
Florian Weikertd79dc502019-05-13 09:51:05 +02002382def print_pipeline_steps(pipeline_steps, handle_emergencies=True):
2383 if handle_emergencies:
2384 emergency_step = create_emergency_announcement_step_if_necessary()
2385 if emergency_step:
2386 pipeline_steps.insert(0, emergency_step)
Florian Weikert13215a82019-05-10 12:42:21 +02002387
2388 print(yaml.dump({"steps": pipeline_steps}))
2389
2390
2391def create_emergency_announcement_step_if_necessary():
2392 style = "error"
2393 message, issue_url, last_good_bazel = None, None, None
2394 try:
2395 emergency_settings = load_remote_yaml_file(EMERGENCY_FILE_URL)
2396 message = emergency_settings.get("message")
2397 issue_url = emergency_settings.get("issue_url")
2398 last_good_bazel = emergency_settings.get("last_good_bazel")
2399 except urllib.error.HTTPError as ex:
2400 message = str(ex)
2401 style = "warning"
2402
2403 if not any([message, issue_url, last_good_bazel]):
2404 return
2405
2406 text = '<span class="h1">:rotating_light: Emergency :rotating_light:</span>\n'
2407 if message:
2408 text += "- {}\n".format(message)
2409 if issue_url:
2410 text += '- Please check this <a href="{}">issue</a> for more details.\n'.format(issue_url)
2411 if last_good_bazel:
2412 text += (
2413 "- Default Bazel version is *{}*, "
2414 "unless the pipeline configuration specifies an explicit version."
2415 ).format(last_good_bazel)
2416
2417 return create_step(
2418 label=":rotating_light: Emergency :rotating_light:",
Philipp Wollermann7590b962019-05-16 11:35:03 +02002419 commands=[
2420 'buildkite-agent annotate --append --style={} --context "omg" "{}"'.format(style, text)
2421 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002422 platform=DEFAULT_PLATFORM,
Florian Weikert13215a82019-05-10 12:42:21 +02002423 )
2424
2425
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002426def runner_step(
2427 platform,
Florian Weikert843d7a02019-02-03 17:24:50 +01002428 task,
2429 task_name=None,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002430 project_name=None,
2431 http_config=None,
2432 file_config=None,
2433 git_repository=None,
2434 git_commit=None,
2435 monitor_flaky_tests=False,
2436 use_but=False,
2437 incompatible_flags=None,
Florian Weikert736d06e2019-05-08 13:16:42 +02002438 shards=1,
mai93b49bad72021-05-06 00:50:34 +02002439 soft_fail=None,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002440):
Philipp Wollermann57b32682019-05-18 22:09:27 +02002441 command = PLATFORMS[platform]["python"] + " bazelci.py runner --task=" + task
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002442 if http_config:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002443 command += " --http_config=" + http_config
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002444 if file_config:
2445 command += " --file_config=" + file_config
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002446 if git_repository:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002447 command += " --git_repository=" + git_repository
Yun Peng376d2b32018-11-29 10:24:54 +01002448 if git_commit:
2449 command += " --git_commit=" + git_commit
Jakob Buchgraberc340f582018-06-22 13:48:33 +02002450 if monitor_flaky_tests:
2451 command += " --monitor_flaky_tests"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002452 if use_but:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002453 command += " --use_but"
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002454 for flag in incompatible_flags or []:
Yun Peng4be92b32018-11-30 09:48:29 +01002455 command += " --incompatible_flag=" + flag
Florian Weikert843d7a02019-02-03 17:24:50 +01002456 label = create_label(platform, project_name, task_name=task_name)
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002457 return create_step(
Florian Weikert9d5e4c02021-05-27 15:10:20 +02002458 label=label,
2459 commands=[fetch_bazelcipy_command(), command],
2460 platform=platform,
2461 shards=shards,
2462 soft_fail=soft_fail,
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002463 )
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002464
2465
2466def fetch_bazelcipy_command():
Philipp Wollermanne67eec42019-05-24 15:18:20 +02002467 return "curl -sS {0} -o bazelci.py".format(SCRIPT_URL)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002468
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002469
Yun Peng002eab92018-12-17 18:28:14 +01002470def fetch_incompatible_flag_verbose_failures_command():
Philipp Wollermannfe145a52019-01-11 13:16:48 +01002471 return "curl -sS {0} -o incompatible_flag_verbose_failures.py".format(
Philipp Wollermanne67eec42019-05-24 15:18:20 +02002472 INCOMPATIBLE_FLAG_VERBOSE_FAILURES_URL
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002473 )
Yun Peng002eab92018-12-17 18:28:14 +01002474
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002475
Yun Peng8975c6b2019-02-28 11:55:55 +01002476def fetch_aggregate_incompatible_flags_test_result_command():
2477 return "curl -sS {0} -o aggregate_incompatible_flags_test_result.py".format(
Philipp Wollermanne67eec42019-05-24 15:18:20 +02002478 AGGREGATE_INCOMPATIBLE_TEST_RESULT_URL
Yun Peng8975c6b2019-02-28 11:55:55 +01002479 )
2480
2481
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002482def upload_project_pipeline_step(
2483 project_name, git_repository, http_config, file_config, incompatible_flags
2484):
2485 pipeline_command = (
2486 '{0} bazelci.py project_pipeline --project_name="{1}" ' + "--git_repository={2}"
Philipp Wollermann57b32682019-05-18 22:09:27 +02002487 ).format(PLATFORMS[DEFAULT_PLATFORM]["python"], project_name, git_repository)
Philipp Wollermann639c0452019-01-03 11:23:54 +01002488 if incompatible_flags is None:
Yun Peng4be92b32018-11-30 09:48:29 +01002489 pipeline_command += " --use_but"
Yun Peng95908792018-11-30 15:03:55 +01002490 else:
2491 for flag in incompatible_flags:
2492 pipeline_command += " --incompatible_flag=" + flag
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002493 if http_config:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002494 pipeline_command += " --http_config=" + http_config
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002495 if file_config:
2496 pipeline_command += " --file_config=" + file_config
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002497 pipeline_command += " | buildkite-agent pipeline upload"
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002498
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002499 return create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002500 label="Setup {0}".format(project_name),
2501 commands=[fetch_bazelcipy_command(), pipeline_command],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002502 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002503 )
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002504
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002505
Florian Weikert843d7a02019-02-03 17:24:50 +01002506def create_label(platform, project_name, build_only=False, test_only=False, task_name=None):
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002507 if build_only and test_only:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002508 raise BuildkiteException("build_only and test_only cannot be true at the same time")
Florian Weikert843d7a02019-02-03 17:24:50 +01002509 platform_display_name = PLATFORMS[platform]["emoji-name"]
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002510
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002511 if build_only:
2512 label = "Build "
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002513 elif test_only:
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002514 label = "Test "
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002515 else:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002516 label = ""
2517
Florian Weikert843d7a02019-02-03 17:24:50 +01002518 platform_label = (
2519 "{0} on {1}".format(task_name, platform_display_name)
2520 if task_name
2521 else platform_display_name
2522 )
2523
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002524 if project_name:
Florian Weikert843d7a02019-02-03 17:24:50 +01002525 label += "{0} ({1})".format(project_name, platform_label)
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002526 else:
Florian Weikert843d7a02019-02-03 17:24:50 +01002527 label += platform_label
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002528
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002529 return label
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002530
2531
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002532def bazel_build_step(
Florian Weikert843d7a02019-02-03 17:24:50 +01002533 task,
2534 platform,
2535 project_name,
2536 http_config=None,
2537 file_config=None,
2538 build_only=False,
2539 test_only=False,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002540):
Philipp Wollermann57b32682019-05-18 22:09:27 +02002541 pipeline_command = PLATFORMS[platform]["python"] + " bazelci.py runner"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002542 if build_only:
Philipp Wollermannc52e26a2019-05-18 22:10:47 +02002543 pipeline_command += " --build_only --save_but"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002544 if test_only:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002545 pipeline_command += " --test_only"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002546 if http_config:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002547 pipeline_command += " --http_config=" + http_config
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002548 if file_config:
2549 pipeline_command += " --file_config=" + file_config
Florian Weikert843d7a02019-02-03 17:24:50 +01002550 pipeline_command += " --task=" + task
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002551
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002552 return create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002553 label=create_label(platform, project_name, build_only, test_only),
2554 commands=[fetch_bazelcipy_command(), pipeline_command],
2555 platform=platform,
2556 )
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002557
2558
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02002559def filter_tasks_that_should_be_skipped(task_configs, pipeline_steps):
2560 skip_tasks = get_skip_tasks()
2561 if not skip_tasks:
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02002562 return task_configs
2563
2564 actually_skipped = []
2565 skip_tasks = set(skip_tasks)
2566 for task in list(task_configs.keys()):
2567 if task in skip_tasks:
2568 actually_skipped.append(task)
2569 del task_configs[task]
2570 skip_tasks.remove(task)
2571
2572 if not task_configs:
2573 raise BuildkiteException(
2574 "Nothing to do since all tasks in the configuration should be skipped."
2575 )
2576
2577 annotations = []
2578 if actually_skipped:
2579 annotations.append(
2580 ("info", "Skipping the following task(s): {}".format(", ".join(actually_skipped)))
2581 )
2582
2583 if skip_tasks:
2584 annotations.append(
2585 (
2586 "warning",
2587 (
2588 "The following tasks should have been skipped, "
2589 "but were not part of the configuration: {}"
2590 ).format(", ".join(skip_tasks)),
2591 )
2592 )
2593
2594 if annotations:
2595 print_skip_task_annotations(annotations, pipeline_steps)
2596
2597 return task_configs
2598
2599
2600def get_skip_tasks():
2601 value = os.getenv(SKIP_TASKS_ENV_VAR, "")
2602 return [v for v in value.split(",") if v]
2603
2604
2605def print_skip_task_annotations(annotations, pipeline_steps):
2606 commands = [
2607 "buildkite-agent annotate --style={} '{}' --context 'ctx-{}'".format(s, t, hash(t))
2608 for s, t in annotations
2609 ]
2610 pipeline_steps.append(
Philipp Wollermann7a185322019-05-18 22:15:48 +02002611 create_step(
2612 label=":pipeline: Print information about skipped tasks",
2613 commands=commands,
2614 platform=DEFAULT_PLATFORM,
2615 )
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02002616 )
2617
2618
Florian Weikert843d7a02019-02-03 17:24:50 +01002619def print_bazel_publish_binaries_pipeline(task_configs, http_config, file_config):
2620 if not task_configs:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002621 raise BuildkiteException("Bazel publish binaries pipeline configuration is empty.")
2622
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02002623 pipeline_steps = []
2624 task_configs = filter_tasks_that_should_be_skipped(task_configs, pipeline_steps)
2625
Florian Weikert843d7a02019-02-03 17:24:50 +01002626 platforms = [get_platform_for_task(t, tc) for t, tc in task_configs.items()]
Philipp Wollermann783d1672019-06-06 13:35:30 +02002627
2628 # These are the platforms that the bazel_publish_binaries.yml config is actually building.
2629 configured_platforms = set(filter(should_publish_binaries_for_platform, platforms))
Philipp Wollermanna2ea5d82018-08-27 14:12:10 +02002630
Philipp Wollermann783d1672019-06-06 13:35:30 +02002631 # These are the platforms that we want to build and publish according to this script.
2632 expected_platforms = set(filter(should_publish_binaries_for_platform, PLATFORMS))
Florian Weikert843d7a02019-02-03 17:24:50 +01002633
Philipp Wollermann30f314d2021-06-11 10:51:39 +02002634 # We can skip this check if we're not on the main branch, because then we're probably
2635 # building a one-off custom debugging binary anyway.
2636 if current_branch_is_main_branch() and not expected_platforms.issubset(configured_platforms):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002637 raise BuildkiteException(
2638 "Bazel publish binaries pipeline needs to build Bazel for every commit on all publish_binary-enabled platforms."
2639 )
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01002640
Yun Pengd352b6d2018-10-17 13:28:39 +02002641 # Build Bazel
Florian Weikert843d7a02019-02-03 17:24:50 +01002642 for task, task_config in task_configs.items():
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002643 pipeline_steps.append(
Florian Weikert843d7a02019-02-03 17:24:50 +01002644 bazel_build_step(
2645 task,
2646 get_platform_for_task(task, task_config),
2647 "Bazel",
2648 http_config,
2649 file_config,
2650 build_only=True,
2651 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002652 )
Jakob Buchgraber4631a032018-03-22 17:12:46 +01002653
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002654 pipeline_steps.append("wait")
Jakob Buchgraber9d6ca8a2018-03-22 17:30:09 +01002655
Yun Pengc2dd6522018-10-17 12:58:35 +02002656 # If all builds succeed, publish the Bazel binaries to GCS.
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002657 pipeline_steps.append(
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002658 create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002659 label="Publish Bazel Binaries",
Philipp Wollermann57b32682019-05-18 22:09:27 +02002660 commands=[
2661 fetch_bazelcipy_command(),
2662 PLATFORMS[DEFAULT_PLATFORM]["python"] + " bazelci.py publish_binaries",
2663 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002664 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002665 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002666 )
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01002667
Florian Weikert13215a82019-05-10 12:42:21 +02002668 print_pipeline_steps(pipeline_steps)
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01002669
2670
Florian Weikert843d7a02019-02-03 17:24:50 +01002671def should_publish_binaries_for_platform(platform):
2672 if platform not in PLATFORMS:
2673 raise BuildkiteException("Unknown platform '{}'".format(platform))
2674
2675 return PLATFORMS[platform]["publish_binary"]
2676
2677
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01002678def print_disabled_projects_info_box_step():
2679 info_text = ["Downstream testing is disabled for the following projects :sadpanda:"]
2680 for project, config in DOWNSTREAM_PROJECTS.items():
2681 disabled_reason = config.get("disabled_reason", None)
2682 if disabled_reason:
2683 info_text.append("* **%s**: %s" % (project, disabled_reason))
2684
2685 if len(info_text) == 1:
2686 return None
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002687 return create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002688 label=":sadpanda:",
2689 commands=[
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002690 'buildkite-agent annotate --append --style=info "\n' + "\n".join(info_text) + '\n"'
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01002691 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002692 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002693 )
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01002694
Yun Peng6528e652019-01-02 14:41:07 +01002695
2696def print_incompatible_flags_info_box_step(incompatible_flags_map):
2697 info_text = ["Build and test with the following incompatible flags:"]
2698
2699 for flag in incompatible_flags_map:
2700 info_text.append("* **%s**: %s" % (flag, incompatible_flags_map[flag]))
2701
2702 if len(info_text) == 1:
2703 return None
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002704 return create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002705 label="Incompatible flags info",
2706 commands=[
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002707 'buildkite-agent annotate --append --style=info "\n' + "\n".join(info_text) + '\n"'
Yun Peng6528e652019-01-02 14:41:07 +01002708 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002709 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002710 )
Yun Peng6528e652019-01-02 14:41:07 +01002711
2712
Yun Peng7d302f62019-01-10 16:56:15 +01002713def fetch_incompatible_flags():
Yun Peng6528e652019-01-02 14:41:07 +01002714 """
2715 Return a list of incompatible flags to be tested in downstream with the current release Bazel
2716 """
Yun Peng7d302f62019-01-10 16:56:15 +01002717 incompatible_flags = {}
2718
2719 # If INCOMPATIBLE_FLAGS environment variable is set, we get incompatible flags from it.
2720 if "INCOMPATIBLE_FLAGS" in os.environ:
2721 for flag in os.environ["INCOMPATIBLE_FLAGS"].split():
2722 # We are not able to get the github link for this flag from INCOMPATIBLE_FLAGS,
2723 # so just assign the url to empty string.
2724 incompatible_flags[flag] = ""
2725 return incompatible_flags
2726
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002727 output = subprocess.check_output(
2728 [
2729 "curl",
Florian Weikert78467862021-09-23 13:39:00 +02002730 "https://api.github.com/search/issues?per_page=100&q=repo:bazelbuild/bazel+label:incompatible-change+state:open"
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002731 ]
2732 ).decode("utf-8")
Yun Peng6528e652019-01-02 14:41:07 +01002733 issue_info = json.loads(output)
2734
Yun Peng6528e652019-01-02 14:41:07 +01002735 for issue in issue_info["items"]:
Yun Peng6528e652019-01-02 14:41:07 +01002736 # Every incompatible flags issue should start with "<incompatible flag name (without --)>:"
2737 name = "--" + issue["title"].split(":")[0]
2738 url = issue["html_url"]
2739 if name.startswith("--incompatible_"):
2740 incompatible_flags[name] = url
2741 else:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002742 eprint(
Philipp Wollermann639c0452019-01-03 11:23:54 +01002743 f"{name} is not recognized as an incompatible flag, please modify the issue title "
2744 f'of {url} to "<incompatible flag name (without --)>:..."'
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002745 )
Yun Peng6528e652019-01-02 14:41:07 +01002746
2747 return incompatible_flags
2748
2749
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002750def print_bazel_downstream_pipeline(
Florian Weikert60661912019-12-18 15:17:10 +01002751 task_configs, http_config, file_config, test_incompatible_flags, test_disabled_projects, notify
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002752):
Florian Weikert843d7a02019-02-03 17:24:50 +01002753 if not task_configs:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002754 raise BuildkiteException("Bazel downstream pipeline configuration is empty.")
2755
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02002756 pipeline_steps = []
2757 task_configs = filter_tasks_that_should_be_skipped(task_configs, pipeline_steps)
2758
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002759 pipeline_steps = []
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002760
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01002761 info_box_step = print_disabled_projects_info_box_step()
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01002762 if info_box_step is not None:
2763 pipeline_steps.append(info_box_step)
2764
Yun Peng5599ca22019-01-16 12:32:41 +01002765 if not test_incompatible_flags:
Florian Weikert843d7a02019-02-03 17:24:50 +01002766 for task, task_config in task_configs.items():
Yun Peng5599ca22019-01-16 12:32:41 +01002767 pipeline_steps.append(
Florian Weikert843d7a02019-02-03 17:24:50 +01002768 bazel_build_step(
2769 task,
2770 get_platform_for_task(task, task_config),
2771 "Bazel",
2772 http_config,
2773 file_config,
2774 build_only=True,
2775 )
Yun Peng5599ca22019-01-16 12:32:41 +01002776 )
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002777
Yun Peng5599ca22019-01-16 12:32:41 +01002778 pipeline_steps.append("wait")
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002779
Yun Pengb9998d12018-12-03 10:18:28 +01002780 incompatible_flags = None
Yun Peng7a539ef2018-11-30 15:07:24 +01002781 if test_incompatible_flags:
Yun Peng7d302f62019-01-10 16:56:15 +01002782 incompatible_flags_map = fetch_incompatible_flags()
Yun Peng3c1d7d12020-06-30 14:58:34 +02002783 if not incompatible_flags_map:
Florian Weikert9d5e4c02021-05-27 15:10:20 +02002784 step = create_step(
2785 label="No Incompatible flags info",
2786 commands=[
Florian Weikert42738ac2021-05-27 15:54:14 +02002787 '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 +02002788 ],
2789 platform=DEFAULT_PLATFORM,
Florian Weikertdb832a02020-11-19 19:14:48 +01002790 )
Florian Weikert9d5e4c02021-05-27 15:10:20 +02002791 pipeline_steps.append(step)
2792 print_pipeline_steps(pipeline_steps)
2793 return
2794
Yun Peng6528e652019-01-02 14:41:07 +01002795 info_box_step = print_incompatible_flags_info_box_step(incompatible_flags_map)
2796 if info_box_step is not None:
2797 pipeline_steps.append(info_box_step)
2798 incompatible_flags = list(incompatible_flags_map.keys())
Yun Peng7a539ef2018-11-30 15:07:24 +01002799
Xùdōng Yáng045c9812021-08-18 01:42:35 +10002800 pipeline_steps.append(create_step(
2801 label="Print skipped tasks annotation",
2802 commands=['buildkite-agent annotate --style=info "The following tasks were skipped since they require specific Bazel versions:\n" --context "ctx-skipped_due_to_bazel_version"'],
2803 platform=DEFAULT_PLATFORM))
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002804 for project, config in DOWNSTREAM_PROJECTS.items():
Yun Peng996efad2018-11-27 17:19:44 +01002805 disabled_reason = config.get("disabled_reason", None)
Yun Pengfb759fa2018-12-13 11:35:39 +01002806 # If test_disabled_projects is true, we add configs for disabled projects.
Florian Weikert7b3f17e2019-03-14 13:52:42 +01002807 # If test_disabled_projects is false, we add configs for not disabled projects.
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002808 if (test_disabled_projects and disabled_reason) or (
2809 not test_disabled_projects and not disabled_reason
2810 ):
Yun Peng996efad2018-11-27 17:19:44 +01002811 pipeline_steps.append(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002812 upload_project_pipeline_step(
2813 project_name=project,
2814 git_repository=config["git_repository"],
2815 http_config=config.get("http_config", None),
2816 file_config=config.get("file_config", None),
2817 incompatible_flags=incompatible_flags,
2818 )
2819 )
Xùdōng Yáng045c9812021-08-18 01:42:35 +10002820 pipeline_steps.append(create_step(
2821 label="Remove skipped tasks annotation if unneeded",
2822 commands=['buildkite-agent meta-data exists "has-skipped-steps" || buildkite-agent annotation remove --context "ctx-skipped_due_to_bazel_version"'],
2823 platform=DEFAULT_PLATFORM))
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002824
Yun Peng002eab92018-12-17 18:28:14 +01002825 if test_incompatible_flags:
Yun Peng002eab92018-12-17 18:28:14 +01002826 current_build_number = os.environ.get("BUILDKITE_BUILD_NUMBER", None)
2827 if not current_build_number:
2828 raise BuildkiteException("Not running inside Buildkite")
Yun Peng8975c6b2019-02-28 11:55:55 +01002829 if use_bazelisk_migrate():
Florian Weikert09813a02019-10-26 19:34:33 +02002830 pipeline_steps += get_steps_for_aggregating_migration_results(
Florian Weikert60661912019-12-18 15:17:10 +01002831 current_build_number, notify
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002832 )
Yun Peng8975c6b2019-02-28 11:55:55 +01002833 else:
2834 pipeline_steps.append({"wait": "~", "continue_on_failure": "true"})
2835 pipeline_steps.append(
2836 create_step(
2837 label="Test failing jobs with incompatible flag separately",
2838 commands=[
2839 fetch_bazelcipy_command(),
2840 fetch_incompatible_flag_verbose_failures_command(),
Philipp Wollermann57b32682019-05-18 22:09:27 +02002841 PLATFORMS[DEFAULT_PLATFORM]["python"]
Yun Peng8975c6b2019-02-28 11:55:55 +01002842 + " incompatible_flag_verbose_failures.py --build_number=%s | buildkite-agent pipeline upload"
2843 % current_build_number,
2844 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002845 platform=DEFAULT_PLATFORM,
Yun Peng8975c6b2019-02-28 11:55:55 +01002846 )
2847 )
Yun Peng002eab92018-12-17 18:28:14 +01002848
Florian Weikert2896edb2019-04-04 16:12:47 +02002849 if (
2850 not test_disabled_projects
2851 and not test_incompatible_flags
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02002852 and current_branch_is_main_branch()
Florian Weikert2896edb2019-04-04 16:12:47 +02002853 ):
Florian Weikert35906542019-04-01 11:53:53 +02002854 # Only update the last green downstream commit in the regular Bazel@HEAD + Downstream pipeline.
2855 pipeline_steps.append("wait")
2856 pipeline_steps.append(
2857 create_step(
2858 label="Try Update Last Green Downstream Commit",
2859 commands=[
2860 fetch_bazelcipy_command(),
Philipp Wollermann57b32682019-05-18 22:09:27 +02002861 PLATFORMS[DEFAULT_PLATFORM]["python"]
2862 + " bazelci.py try_update_last_green_downstream_commit",
Florian Weikert35906542019-04-01 11:53:53 +02002863 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002864 platform=DEFAULT_PLATFORM,
Florian Weikert35906542019-04-01 11:53:53 +02002865 )
2866 )
2867
Florian Weikert13215a82019-05-10 12:42:21 +02002868 print_pipeline_steps(pipeline_steps)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002869
2870
Florian Weikert60661912019-12-18 15:17:10 +01002871def get_steps_for_aggregating_migration_results(current_build_number, notify):
Florian Weikert09813a02019-10-26 19:34:33 +02002872 parts = [
2873 PLATFORMS[DEFAULT_PLATFORM]["python"],
2874 "aggregate_incompatible_flags_test_result.py",
2875 "--build_number=%s" % current_build_number,
Florian Weikert09813a02019-10-26 19:34:33 +02002876 ]
Florian Weikert60661912019-12-18 15:17:10 +01002877 if notify:
2878 parts.append("--notify")
Florian Weikert09813a02019-10-26 19:34:33 +02002879 return [
2880 {"wait": "~", "continue_on_failure": "true"},
2881 create_step(
2882 label="Aggregate incompatible flags test result",
2883 commands=[
2884 fetch_bazelcipy_command(),
2885 fetch_aggregate_incompatible_flags_test_result_command(),
2886 " ".join(parts),
2887 ],
2888 platform=DEFAULT_PLATFORM,
2889 ),
2890 ]
2891
2892
Yun Pengc2dd6522018-10-17 12:58:35 +02002893def bazelci_builds_download_url(platform, git_commit):
Philipp Wollermanne67eec42019-05-24 15:18:20 +02002894 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
2895 return "https://storage.googleapis.com/{}/artifacts/{}/{}/bazel".format(
2896 bucket_name, platform, git_commit
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002897 )
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002898
2899
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04002900def bazelci_builds_nojdk_download_url(platform, git_commit):
2901 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
2902 return "https://storage.googleapis.com/{}/artifacts/{}/{}/bazel_nojdk".format(
2903 bucket_name, platform, git_commit
2904 )
2905
2906
Yun Peng20d45602018-10-18 13:27:05 +02002907def bazelci_builds_gs_url(platform, git_commit):
Philipp Wollermanne67eec42019-05-24 15:18:20 +02002908 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
2909 return "gs://{}/artifacts/{}/{}/bazel".format(bucket_name, platform, git_commit)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002910
2911
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04002912def bazelci_builds_nojdk_gs_url(platform, git_commit):
2913 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
2914 return "gs://{}/artifacts/{}/{}/bazel_nojdk".format(bucket_name, platform, git_commit)
2915
2916
mai93f04f9482020-10-20 17:22:30 +02002917def bazelci_latest_build_metadata_url():
Philipp Wollermanne67eec42019-05-24 15:18:20 +02002918 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
2919 return "gs://{}/metadata/latest.json".format(bucket_name)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002920
2921
mai93f04f9482020-10-20 17:22:30 +02002922def bazelci_builds_metadata_url(git_commit):
2923 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
2924 return "gs://{}/metadata/{}.json".format(bucket_name, git_commit)
2925
2926
Yun Peng996efad2018-11-27 17:19:44 +01002927def bazelci_last_green_commit_url(git_repository, pipeline_slug):
Philipp Wollermanne67eec42019-05-24 15:18:20 +02002928 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-untrusted-builds"
2929 return "gs://{}/last_green_commit/{}/{}".format(
2930 bucket_name, git_repository[len("https://") :], pipeline_slug
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002931 )
Yun Pengafe67d42018-11-23 17:06:43 +01002932
2933
Florian Weikert35906542019-04-01 11:53:53 +02002934def bazelci_last_green_downstream_commit_url():
Philipp Wollermanne67eec42019-05-24 15:18:20 +02002935 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-untrusted-builds"
2936 return "gs://{}/last_green_commit/downstream_pipeline".format(bucket_name)
Florian Weikert35906542019-04-01 11:53:53 +02002937
2938
2939def get_last_green_commit(last_green_commit_url):
Yun Peng61a448f2018-11-23 17:11:46 +01002940 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002941 return (
2942 subprocess.check_output(
2943 [gsutil_command(), "cat", last_green_commit_url], env=os.environ
2944 )
2945 .decode("utf-8")
2946 .strip()
2947 )
Yun Peng61a448f2018-11-23 17:11:46 +01002948 except subprocess.CalledProcessError:
2949 return None
Yun Peng43239b02018-11-23 13:57:34 +01002950
2951
Yun Peng358cd882018-11-29 10:25:18 +01002952def try_update_last_green_commit():
Florian Weikertde96a6f2019-03-07 14:57:50 +01002953 org_slug = os.getenv("BUILDKITE_ORGANIZATION_SLUG")
Yun Peng358cd882018-11-29 10:25:18 +01002954 pipeline_slug = os.getenv("BUILDKITE_PIPELINE_SLUG")
Florian Weikertde96a6f2019-03-07 14:57:50 +01002955 build_number = os.getenv("BUILDKITE_BUILD_NUMBER")
2956 current_job_id = os.getenv("BUILDKITE_JOB_ID")
2957
2958 client = BuildkiteClient(org=org_slug, pipeline=pipeline_slug)
2959 build_info = client.get_build_info(build_number)
2960
mai9302a609c2021-05-20 10:36:46 +02002961 # 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 +02002962 def has_failed(job):
Florian Weikertbd40a272019-03-08 10:20:18 +01002963 state = job.get("state")
2964 # Ignore steps that don't have a state (like "wait").
Florian Weikertde96a6f2019-03-07 14:57:50 +01002965 return (
Florian Weikert35906542019-04-01 11:53:53 +02002966 state is not None
2967 and state != "passed"
mai9302a609c2021-05-20 10:36:46 +02002968 and not job.get("soft_failed")
Florian Weikertde96a6f2019-03-07 14:57:50 +01002969 and job["id"] != current_job_id
2970 and job["name"] != BUILDIFIER_STEP_NAME
2971 )
2972
Philipp Wollermannce986af2019-07-18 14:46:05 +02002973 failing_jobs = [j["name"] for j in build_info["jobs"] if has_failed(j)]
Florian Weikertde96a6f2019-03-07 14:57:50 +01002974 if failing_jobs:
2975 raise BuildkiteException(
2976 "Cannot update last green commit due to {} failing step(s): {}".format(
2977 len(failing_jobs), ", ".join(failing_jobs)
2978 )
2979 )
2980
Yun Peng358cd882018-11-29 10:25:18 +01002981 git_repository = os.getenv("BUILDKITE_REPO")
Florian Weikert35906542019-04-01 11:53:53 +02002982 last_green_commit_url = bazelci_last_green_commit_url(git_repository, pipeline_slug)
2983 update_last_green_commit_if_newer(last_green_commit_url)
2984
2985
2986def update_last_green_commit_if_newer(last_green_commit_url):
2987 last_green_commit = get_last_green_commit(last_green_commit_url)
Yun Peng358cd882018-11-29 10:25:18 +01002988 current_commit = subprocess.check_output(["git", "rev-parse", "HEAD"]).decode("utf-8").strip()
2989 if last_green_commit:
Jakob Buchgraber7c7ceee2019-10-28 10:28:58 +01002990 success = False
2991 try:
2992 execute_command(["git", "fetch", "-v", "origin", last_green_commit])
2993 success = True
2994 except subprocess.CalledProcessError:
2995 # If there was an error fetching the commit it typically means
2996 # that the commit does not exist anymore - due to a force push. In
2997 # order to recover from that assume that the current commit is the
2998 # newest commit.
2999 result = [current_commit]
3000 finally:
3001 if success:
3002 result = (
3003 subprocess.check_output(
3004 ["git", "rev-list", "%s..%s" % (last_green_commit, current_commit)]
3005 )
3006 .decode("utf-8")
3007 .strip()
3008 )
Philipp Wollermannce986af2019-07-18 14:46:05 +02003009 else:
3010 result = None
Yun Peng358cd882018-11-29 10:25:18 +01003011
Philipp Wollermann639c0452019-01-03 11:23:54 +01003012 # If current_commit is newer that last_green_commit, `git rev-list A..B` will output a bunch of
3013 # commits, otherwise the output should be empty.
Yun Peng358cd882018-11-29 10:25:18 +01003014 if not last_green_commit or result:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003015 execute_command(
Philipp Wollermann76a7eac2020-02-17 18:29:52 +01003016 [
3017 "echo %s | %s -h 'Cache-Control: no-store' cp - %s"
3018 % (current_commit, gsutil_command(), last_green_commit_url)
3019 ],
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003020 shell=True,
3021 )
Yun Peng358cd882018-11-29 10:25:18 +01003022 else:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003023 eprint(
3024 "Updating abandoned: last green commit (%s) is not older than current commit (%s)."
3025 % (last_green_commit, current_commit)
3026 )
3027
Yun Peng358cd882018-11-29 10:25:18 +01003028
Florian Weikert35906542019-04-01 11:53:53 +02003029def try_update_last_green_downstream_commit():
3030 last_green_commit_url = bazelci_last_green_downstream_commit_url()
3031 update_last_green_commit_if_newer(last_green_commit_url)
3032
3033
Jakob Buchgraber76381e02018-02-19 16:19:56 +01003034def latest_generation_and_build_number():
Philipp Wollermannce986af2019-07-18 14:46:05 +02003035 generation = None
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003036 output = None
Philipp Wollermannce986af2019-07-18 14:46:05 +02003037 for attempt in range(5):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003038 output = subprocess.check_output(
mai93f04f9482020-10-20 17:22:30 +02003039 [gsutil_command(), "stat", bazelci_latest_build_metadata_url()], env=os.environ
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003040 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003041 match = re.search("Generation:[ ]*([0-9]+)", output.decode("utf-8"))
3042 if not match:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003043 raise BuildkiteException("Couldn't parse generation. gsutil output format changed?")
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003044 generation = match.group(1)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003045
Philipp Wollermannff39ef52018-02-21 14:18:52 +01003046 match = re.search(r"Hash \(md5\):[ ]*([^\s]+)", output.decode("utf-8"))
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003047 if not match:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003048 raise BuildkiteException("Couldn't parse md5 hash. gsutil output format changed?")
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003049 expected_md5hash = base64.b64decode(match.group(1))
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003050
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003051 output = subprocess.check_output(
mai93f04f9482020-10-20 17:22:30 +02003052 [gsutil_command(), "cat", bazelci_latest_build_metadata_url()], env=os.environ
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003053 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003054 hasher = hashlib.md5()
3055 hasher.update(output)
3056 actual_md5hash = hasher.digest()
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003057
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003058 if expected_md5hash == actual_md5hash:
3059 break
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003060 info = json.loads(output.decode("utf-8"))
Philipp Wollermannce986af2019-07-18 14:46:05 +02003061 return generation, info["build_number"]
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003062
Jakob Buchgraber699aece2018-02-19 12:49:30 +01003063
Jakob Buchgraber88083fd2018-02-18 17:23:35 +01003064def sha256_hexdigest(filename):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003065 sha256 = hashlib.sha256()
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003066 with open(filename, "rb") as f:
3067 for block in iter(lambda: f.read(65536), b""):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003068 sha256.update(block)
3069 return sha256.hexdigest()
Jakob Buchgraber699aece2018-02-19 12:49:30 +01003070
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003071
Philipp Wollermann02955272019-04-18 18:00:48 +02003072def upload_bazel_binaries():
3073 """
3074 Uploads all Bazel binaries to a deterministic URL based on the current Git commit.
3075
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003076 Returns maps of platform names to sha256 hashes of the corresponding bazel and bazel_nojdk binaries.
Philipp Wollermann02955272019-04-18 18:00:48 +02003077 """
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003078 bazel_hashes = {}
3079 bazel_nojdk_hashes = {}
Philipp Wollermannbdd4bf92019-06-06 14:43:50 +02003080 for platform_name, platform in PLATFORMS.items():
Philipp Wollermann783d1672019-06-06 13:35:30 +02003081 if not should_publish_binaries_for_platform(platform_name):
3082 continue
Jakob Buchgraberb13a9a82018-03-27 18:37:09 +02003083 tmpdir = tempfile.mkdtemp()
3084 try:
Philipp Wollermann783d1672019-06-06 13:35:30 +02003085 bazel_binary_path = download_bazel_binary(tmpdir, platform_name)
3086 # One platform that we build on can generate binaries for multiple platforms, e.g.
Philipp Wollermannf4aabb72019-06-25 15:59:00 +02003087 # the centos7 platform generates binaries for the "centos7" platform, but also
Philipp Wollermann783d1672019-06-06 13:35:30 +02003088 # for the generic "linux" platform.
3089 for target_platform_name in platform["publish_binary"]:
3090 execute_command(
3091 [
3092 gsutil_command(),
3093 "cp",
3094 bazel_binary_path,
3095 bazelci_builds_gs_url(target_platform_name, os.environ["BUILDKITE_COMMIT"]),
3096 ]
3097 )
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003098 bazel_hashes[target_platform_name] = sha256_hexdigest(bazel_binary_path)
3099
3100 # Also publish bazel_nojdk binaries.
3101 bazel_nojdk_binary_path = download_bazel_nojdk_binary(tmpdir, platform_name)
3102 for target_platform_name in platform["publish_binary"]:
3103 execute_command(
3104 [
3105 gsutil_command(),
3106 "cp",
3107 bazel_nojdk_binary_path,
Florian Weikertdb832a02020-11-19 19:14:48 +01003108 bazelci_builds_nojdk_gs_url(
3109 target_platform_name, os.environ["BUILDKITE_COMMIT"]
3110 ),
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003111 ]
3112 )
3113 bazel_nojdk_hashes[target_platform_name] = sha256_hexdigest(bazel_nojdk_binary_path)
Philipp Wollermann30f314d2021-06-11 10:51:39 +02003114 except subprocess.CalledProcessError as e:
3115 # If we're not on the main branch, we're probably building a custom one-off binary and
3116 # ignore failures for individual platforms (it's possible that we didn't build binaries
3117 # for all platforms).
3118 if not current_branch_is_main_branch():
3119 eprint(
3120 "Ignoring failure to download and publish Bazel binary for platform {}: {}".format(
3121 platform_name, e
3122 )
3123 )
3124 else:
3125 raise e
Jakob Buchgraberb13a9a82018-03-27 18:37:09 +02003126 finally:
3127 shutil.rmtree(tmpdir)
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003128 return bazel_hashes, bazel_nojdk_hashes
Philipp Wollermann02955272019-04-18 18:00:48 +02003129
3130
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003131def try_publish_binaries(bazel_hashes, bazel_nojdk_hashes, build_number, expected_generation):
Philipp Wollermann02955272019-04-18 18:00:48 +02003132 """
3133 Uploads the info.json file that contains information about the latest Bazel commit that was
3134 successfully built on CI.
3135 """
3136 now = datetime.datetime.now()
3137 git_commit = os.environ["BUILDKITE_COMMIT"]
3138 info = {
3139 "build_number": build_number,
3140 "build_time": now.strftime("%d-%m-%Y %H:%M"),
3141 "git_commit": git_commit,
3142 "platforms": {},
3143 }
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003144 for platform, sha256 in bazel_hashes.items():
Philipp Wollermann02955272019-04-18 18:00:48 +02003145 info["platforms"][platform] = {
3146 "url": bazelci_builds_download_url(platform, git_commit),
Philipp Wollermann783d1672019-06-06 13:35:30 +02003147 "sha256": sha256,
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003148 "nojdk_url": bazelci_builds_nojdk_download_url(platform, git_commit),
3149 "nojdk_sha256": bazel_nojdk_hashes[platform],
Philipp Wollermann02955272019-04-18 18:00:48 +02003150 }
Jakob Buchgraberb13a9a82018-03-27 18:37:09 +02003151 tmpdir = tempfile.mkdtemp()
3152 try:
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003153 info_file = os.path.join(tmpdir, "info.json")
3154 with open(info_file, mode="w", encoding="utf-8") as fp:
Jakob Buchgraber609a20e2018-02-25 17:06:51 +01003155 json.dump(info, fp, indent=2, sort_keys=True)
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003156
3157 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003158 execute_command(
3159 [
3160 gsutil_command(),
3161 "-h",
3162 "x-goog-if-generation-match:" + expected_generation,
3163 "-h",
3164 "Content-Type:application/json",
3165 "cp",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003166 info_file,
mai93f04f9482020-10-20 17:22:30 +02003167 bazelci_latest_build_metadata_url(),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003168 ]
3169 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003170 except subprocess.CalledProcessError:
3171 raise BinaryUploadRaceException()
mai93f04f9482020-10-20 17:22:30 +02003172
3173 execute_command(
3174 [
3175 gsutil_command(),
3176 "cp",
3177 bazelci_latest_build_metadata_url(),
3178 bazelci_builds_metadata_url(git_commit),
3179 ]
3180 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003181 finally:
Philipp Wollermann3e1a7712018-02-19 17:34:24 +01003182 shutil.rmtree(tmpdir)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003183
3184
Jakob Buchgraber76381e02018-02-19 16:19:56 +01003185def publish_binaries():
Philipp Wollermanndb024862018-02-19 17:16:56 +01003186 """
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003187 Publish Bazel binaries to GCS.
Philipp Wollermanndb024862018-02-19 17:16:56 +01003188 """
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003189 current_build_number = os.environ.get("BUILDKITE_BUILD_NUMBER", None)
3190 if not current_build_number:
3191 raise BuildkiteException("Not running inside Buildkite")
3192 current_build_number = int(current_build_number)
3193
Philipp Wollermann02955272019-04-18 18:00:48 +02003194 # Upload the Bazel binaries for this commit.
Rupert Shuttleworth7f3a91e2020-08-22 07:31:47 -04003195 bazel_hashes, bazel_nojdk_hashes = upload_bazel_binaries()
Philipp Wollermann02955272019-04-18 18:00:48 +02003196
3197 # 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 +02003198 # not the latest build. Only do this if we're building binaries from the main branch to avoid
3199 # accidentally publishing a custom debug build as the "latest" Bazel binary.
3200 if current_branch_is_main_branch():
3201 for _ in range(5):
3202 latest_generation, latest_build_number = latest_generation_and_build_number()
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003203
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02003204 if current_build_number <= latest_build_number:
3205 eprint(
3206 (
3207 "Current build '{0}' is not newer than latest published '{1}'. "
3208 + "Skipping publishing of binaries."
3209 ).format(current_build_number, latest_build_number)
3210 )
3211 break
3212
3213 try:
3214 try_publish_binaries(
3215 bazel_hashes, bazel_nojdk_hashes, current_build_number, latest_generation
3216 )
3217 except BinaryUploadRaceException:
3218 # Retry.
3219 continue
3220
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003221 eprint(
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02003222 "Successfully updated '{0}' to binaries from build {1}.".format(
3223 bazelci_latest_build_metadata_url(), current_build_number
3224 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003225 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003226 break
Philipp Wollermann1b5ecdc2021-06-10 21:52:55 +02003227 else:
3228 raise BuildkiteException("Could not publish binaries, ran out of attempts.")
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003229
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02003230
Philipp Wollermann639c0452019-01-03 11:23:54 +01003231# This is so that multiline python strings are represented as YAML
3232# block strings.
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01003233def str_presenter(dumper, data):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003234 if len(data.splitlines()) > 1: # check for multiline string
3235 return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|")
3236 return dumper.represent_scalar("tag:yaml.org,2002:str", data)
3237
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01003238
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003239def main(argv=None):
3240 if argv is None:
Yun Peng20d45602018-10-18 13:27:05 +02003241 argv = sys.argv[1:]
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003242
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01003243 yaml.add_representer(str, str_presenter)
3244
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003245 parser = argparse.ArgumentParser(description="Bazel Continuous Integration Script")
Florian Weikert944209b2019-05-10 12:41:48 +02003246 parser.add_argument("--script", type=str)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003247
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003248 subparsers = parser.add_subparsers(dest="subparsers_name")
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003249
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003250 bazel_publish_binaries_pipeline = subparsers.add_parser("bazel_publish_binaries_pipeline")
3251 bazel_publish_binaries_pipeline.add_argument("--file_config", type=str)
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01003252 bazel_publish_binaries_pipeline.add_argument("--http_config", type=str)
3253 bazel_publish_binaries_pipeline.add_argument("--git_repository", type=str)
3254
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003255 bazel_downstream_pipeline = subparsers.add_parser("bazel_downstream_pipeline")
3256 bazel_downstream_pipeline.add_argument("--file_config", type=str)
3257 bazel_downstream_pipeline.add_argument("--http_config", type=str)
3258 bazel_downstream_pipeline.add_argument("--git_repository", type=str)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003259 bazel_downstream_pipeline.add_argument(
3260 "--test_incompatible_flags", type=bool, nargs="?", const=True
3261 )
3262 bazel_downstream_pipeline.add_argument(
3263 "--test_disabled_projects", type=bool, nargs="?", const=True
3264 )
Florian Weikert60661912019-12-18 15:17:10 +01003265 bazel_downstream_pipeline.add_argument("--notify", type=bool, nargs="?", const=True)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003266
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003267 project_pipeline = subparsers.add_parser("project_pipeline")
3268 project_pipeline.add_argument("--project_name", type=str)
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003269 project_pipeline.add_argument("--file_config", type=str)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003270 project_pipeline.add_argument("--http_config", type=str)
3271 project_pipeline.add_argument("--git_repository", type=str)
Jakob Buchgraber66ba4fe2018-06-22 15:04:14 +02003272 project_pipeline.add_argument("--monitor_flaky_tests", type=bool, nargs="?", const=True)
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02003273 project_pipeline.add_argument("--use_but", type=bool, nargs="?", const=True)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003274 project_pipeline.add_argument("--incompatible_flag", type=str, action="append")
Florian Weikert60661912019-12-18 15:17:10 +01003275 project_pipeline.add_argument("--notify", type=bool, nargs="?", const=True)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003276
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003277 runner = subparsers.add_parser("runner")
Florian Weikert843d7a02019-02-03 17:24:50 +01003278 runner.add_argument("--task", action="store", type=str, default="")
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003279 runner.add_argument("--file_config", type=str)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003280 runner.add_argument("--http_config", type=str)
3281 runner.add_argument("--git_repository", type=str)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003282 runner.add_argument(
3283 "--git_commit", type=str, help="Reset the git repository to this commit after cloning it"
3284 )
3285 runner.add_argument(
Yun Peng5012a862021-09-16 16:35:43 +02003286 "--repo_location",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003287 type=str,
3288 help="Use an existing repository instead of cloning from github",
3289 )
3290 runner.add_argument(
Dan Halperinefda1192019-01-16 00:34:09 -08003291 "--use_bazel_at_commit", type=str, help="Use Bazel binary built at a specific commit"
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003292 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003293 runner.add_argument("--use_but", type=bool, nargs="?", const=True)
3294 runner.add_argument("--save_but", type=bool, nargs="?", const=True)
Yun Peng4d1d6542019-01-17 18:30:33 +01003295 runner.add_argument("--needs_clean", type=bool, nargs="?", const=True)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01003296 runner.add_argument("--build_only", type=bool, nargs="?", const=True)
3297 runner.add_argument("--test_only", type=bool, nargs="?", const=True)
Jakob Buchgraber66ba4fe2018-06-22 15:04:14 +02003298 runner.add_argument("--monitor_flaky_tests", type=bool, nargs="?", const=True)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003299 runner.add_argument("--incompatible_flag", type=str, action="append")
Jakob Buchgraberc340f582018-06-22 13:48:33 +02003300
Philipp Wollermannce986af2019-07-18 14:46:05 +02003301 subparsers.add_parser("publish_binaries")
3302 subparsers.add_parser("try_update_last_green_commit")
3303 subparsers.add_parser("try_update_last_green_downstream_commit")
Yun Peng358cd882018-11-29 10:25:18 +01003304
Yun Peng20d45602018-10-18 13:27:05 +02003305 args = parser.parse_args(argv)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01003306
Florian Weikert944209b2019-05-10 12:41:48 +02003307 if args.script:
3308 global SCRIPT_URL
3309 SCRIPT_URL = args.script
3310
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003311 try:
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01003312 if args.subparsers_name == "bazel_publish_binaries_pipeline":
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003313 configs = fetch_configs(args.http_config, args.file_config)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003314 print_bazel_publish_binaries_pipeline(
Florian Weikert843d7a02019-02-03 17:24:50 +01003315 task_configs=configs.get("tasks", None),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003316 http_config=args.http_config,
3317 file_config=args.file_config,
3318 )
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003319 elif args.subparsers_name == "bazel_downstream_pipeline":
3320 configs = fetch_configs(args.http_config, args.file_config)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003321 print_bazel_downstream_pipeline(
Florian Weikert843d7a02019-02-03 17:24:50 +01003322 task_configs=configs.get("tasks", None),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003323 http_config=args.http_config,
3324 file_config=args.file_config,
3325 test_incompatible_flags=args.test_incompatible_flags,
3326 test_disabled_projects=args.test_disabled_projects,
Florian Weikert60661912019-12-18 15:17:10 +01003327 notify=args.notify,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003328 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003329 elif args.subparsers_name == "project_pipeline":
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003330 configs = fetch_configs(args.http_config, args.file_config)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003331 print_project_pipeline(
Florian Weikertf20ae6f2019-01-16 14:32:09 +01003332 configs=configs,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003333 project_name=args.project_name,
3334 http_config=args.http_config,
3335 file_config=args.file_config,
3336 git_repository=args.git_repository,
3337 monitor_flaky_tests=args.monitor_flaky_tests,
3338 use_but=args.use_but,
3339 incompatible_flags=args.incompatible_flag,
Florian Weikert60661912019-12-18 15:17:10 +01003340 notify=args.notify,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003341 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003342 elif args.subparsers_name == "runner":
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01003343 configs = fetch_configs(args.http_config, args.file_config)
Florian Weikert843d7a02019-02-03 17:24:50 +01003344 tasks = configs.get("tasks", {})
3345 task_config = tasks.get(args.task)
3346 if not task_config:
3347 raise BuildkiteException(
3348 "No such task '{}' in configuration. Available: {}".format(
3349 args.task, ", ".join(tasks)
3350 )
3351 )
3352
3353 platform = get_platform_for_task(args.task, task_config)
3354
Yun Pengdb76f842021-08-30 18:39:38 +02003355 # The value of `BUILDKITE_MESSAGE` defaults to the commit message, which can be too large
3356 # on Windows, therefore we truncate the value to 1000 characters.
3357 # See https://github.com/bazelbuild/continuous-integration/issues/1218
3358 if "BUILDKITE_MESSAGE" in os.environ:
3359 os.environ["BUILDKITE_MESSAGE"] = os.environ["BUILDKITE_MESSAGE"][:1000]
3360
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003361 execute_commands(
Florian Weikertc8642af2019-02-03 23:58:51 +01003362 task_config=task_config,
Florian Weikert843d7a02019-02-03 17:24:50 +01003363 platform=platform,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003364 git_repository=args.git_repository,
3365 git_commit=args.git_commit,
Yun Peng5012a862021-09-16 16:35:43 +02003366 repo_location=args.repo_location,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003367 use_bazel_at_commit=args.use_bazel_at_commit,
3368 use_but=args.use_but,
3369 save_but=args.save_but,
Yun Peng4d1d6542019-01-17 18:30:33 +01003370 needs_clean=args.needs_clean,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003371 build_only=args.build_only,
3372 test_only=args.test_only,
3373 monitor_flaky_tests=args.monitor_flaky_tests,
3374 incompatible_flags=args.incompatible_flag,
Florian Weikertc8642af2019-02-03 23:58:51 +01003375 bazel_version=task_config.get("bazel") or configs.get("bazel"),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01003376 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003377 elif args.subparsers_name == "publish_binaries":
3378 publish_binaries()
Yun Peng358cd882018-11-29 10:25:18 +01003379 elif args.subparsers_name == "try_update_last_green_commit":
Florian Weikert35906542019-04-01 11:53:53 +02003380 # Update the last green commit of a project pipeline
Yun Peng358cd882018-11-29 10:25:18 +01003381 try_update_last_green_commit()
Florian Weikert35906542019-04-01 11:53:53 +02003382 elif args.subparsers_name == "try_update_last_green_downstream_commit":
3383 # Update the last green commit of the downstream pipeline
3384 try_update_last_green_downstream_commit()
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003385 else:
3386 parser.print_help()
3387 return 2
3388 except BuildkiteException as e:
3389 eprint(str(e))
3390 return 1
3391 return 0
3392
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01003393
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01003394if __name__ == "__main__":
3395 sys.exit(main())