blob: deeb46f66d13f7acb87a21f442fa19b1e9c01bf1 [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
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +010021import hashlib
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010022import json
Jakob Buchgraber6db0f262018-02-17 15:45:54 +010023import multiprocessing
Philipp Wollermann0a04cf32018-02-21 17:07:22 +010024import os
Philipp Wollermanndcaddd92018-02-21 14:13:43 +010025import os.path
Jakob Buchgraber257693b2018-02-20 00:03:56 +010026import random
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010027import re
Philipp Wollermanndcaddd92018-02-21 14:13:43 +010028from shutil import copyfile
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010029import shutil
Philipp Wollermanndcaddd92018-02-21 14:13:43 +010030import stat
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010031import subprocess
32import sys
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010033import tempfile
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +020034import threading
Philipp Wollermanne1318eb2018-08-13 15:08:01 +020035import time
Philipp Wollermannce986af2019-07-18 14:46:05 +020036import urllib.error
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010037import urllib.request
Philipp Wollermanne1318eb2018-08-13 15:08:01 +020038import uuid
Jakob Buchgraber25bb50f2018-02-22 18:06:21 +010039import yaml
Philipp Wollermannc030f2e2018-02-21 17:02:19 +010040from urllib.request import url2pathname
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010041from urllib.parse import urlparse
Philipp Wollermanndcaddd92018-02-21 14:13:43 +010042
43# Initialize the random number generator.
44random.seed()
45
Philipp Wollermanne67eec42019-05-24 15:18:20 +020046BUILDKITE_ORG = os.environ["BUILDKITE_ORGANIZATION_SLUG"]
47THIS_IS_PRODUCTION = BUILDKITE_ORG == "bazel-untrusted"
48THIS_IS_TESTING = BUILDKITE_ORG == "bazel-testing"
49THIS_IS_TRUSTED = BUILDKITE_ORG == "bazel-trusted"
50THIS_IS_SPARTA = True
51
52CLOUD_PROJECT = "bazel-public" if THIS_IS_TRUSTED else "bazel-untrusted"
53
54GITHUB_BRANCH = {"bazel": "master", "bazel-trusted": "master", "bazel-testing": "testing"}[
55 BUILDKITE_ORG
56]
57
58SCRIPT_URL = "https://raw.githubusercontent.com/bazelbuild/continuous-integration/{}/buildkite/bazelci.py?{}".format(
59 GITHUB_BRANCH, int(time.time())
Philipp Wollermannc05ac682019-01-19 12:37:28 +010060)
Jakob Buchgraber95e3d572018-02-21 18:48:49 +010061
Philipp Wollermanne67eec42019-05-24 15:18:20 +020062INCOMPATIBLE_FLAG_VERBOSE_FAILURES_URL = "https://raw.githubusercontent.com/bazelbuild/continuous-integration/{}/buildkite/incompatible_flag_verbose_failures.py?{}".format(
63 GITHUB_BRANCH, int(time.time())
64)
65
66AGGREGATE_INCOMPATIBLE_TEST_RESULT_URL = "https://raw.githubusercontent.com/bazelbuild/continuous-integration/{}/buildkite/aggregate_incompatible_flags_test_result.py?{}".format(
67 GITHUB_BRANCH, int(time.time())
68)
69
70EMERGENCY_FILE_URL = "https://raw.githubusercontent.com/bazelbuild/continuous-integration/{}/buildkite/emergency.yml?{}".format(
71 GITHUB_BRANCH, int(time.time())
72)
73
74FLAKY_TESTS_BUCKET = {
75 "bazel-testing": "gs://bazel-testing-buildkite-stats/flaky-tests-bep/",
76 "bazel-trusted": "gs://bazel-buildkite-stats/flaky-tests-bep/",
77 "bazel": "gs://bazel-buildkite-stats/flaky-tests-bep/",
78}[BUILDKITE_ORG]
79
80DOWNSTREAM_PROJECTS_PRODUCTION = {
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +010081 "Android Studio Plugin": {
82 "git_repository": "https://github.com/bazelbuild/intellij.git",
83 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/android-studio.yml",
84 "pipeline_slug": "android-studio-plugin",
85 },
Yun Peng996efad2018-11-27 17:19:44 +010086 "Android Testing": {
87 "git_repository": "https://github.com/googlesamples/android-testing.git",
Jingwenbde72602018-12-13 10:57:43 -050088 "http_config": "https://raw.githubusercontent.com/googlesamples/android-testing/master/bazelci/buildkite-pipeline.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +010089 "pipeline_slug": "android-testing",
Yun Peng996efad2018-11-27 17:19:44 +010090 },
Yun Peng8910fa32019-01-03 08:58:16 +010091 "Bazel": {
92 "git_repository": "https://github.com/bazelbuild/bazel.git",
93 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel/master/.bazelci/postsubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +010094 "pipeline_slug": "bazel-bazel",
Yun Peng8910fa32019-01-03 08:58:16 +010095 },
Tobias Werthd848eca2019-05-14 15:08:35 +020096 "Bazel Bench": {
97 "git_repository": "https://github.com/bazelbuild/bazel-bench.git",
joeleba92ffec82019-05-22 14:50:15 +020098 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-bench/master/.bazelci/postsubmit.yml",
Tobias Werthd848eca2019-05-14 15:08:35 +020099 "pipeline_slug": "bazel-bench",
100 },
Philipp Wollermannfefcbf42019-05-28 14:28:40 +0200101 "Bazel Codelabs": {
102 "git_repository": "https://github.com/bazelbuild/codelabs.git",
103 "http_config": "https://raw.githubusercontent.com/bazelbuild/codelabs/master/.bazelci/presubmit.yml",
104 "pipeline_slug": "bazel-codelabs",
Philipp Wollermannfefcbf42019-05-28 14:28:40 +0200105 },
Jinfce9b302019-08-08 15:18:26 -0400106 "Bazel Examples": {
107 "git_repository": "https://github.com/bazelbuild/examples.git",
108 "http_config": "https://raw.githubusercontent.com/bazelbuild/examples/master/.bazelci/presubmit.yml",
109 "pipeline_slug": "bazel-bazel-examples",
110 },
Florian Weikert4b3ec672019-08-14 19:05:12 +0200111 "Bazel Federation": {
112 "git_repository": "https://github.com/bazelbuild/bazel-federation.git",
113 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-federation/master/.bazelci/presubmit.yml",
114 "pipeline_slug": "bazel-federation",
115 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100116 "Bazel Remote Cache": {
117 "git_repository": "https://github.com/buchgr/bazel-remote.git",
118 "http_config": "https://raw.githubusercontent.com/buchgr/bazel-remote/master/.bazelci/presubmit.yml",
119 "pipeline_slug": "bazel-remote-cache",
Yun Peng996efad2018-11-27 17:19:44 +0100120 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200121 "Bazel integration testing": {
122 "git_repository": "https://github.com/bazelbuild/bazel-integration-testing.git",
123 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-integration-testing/master/.bazelci/presubmit.yml",
124 "pipeline_slug": "bazel-integration-testing",
125 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100126 "Bazel skylib": {
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200127 "git_repository": "https://github.com/bazelbuild/bazel-skylib.git",
Yun Peng996efad2018-11-27 17:19:44 +0100128 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-skylib/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100129 "pipeline_slug": "bazel-skylib",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200130 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100131 "Bazel toolchains": {
132 "git_repository": "https://github.com/bazelbuild/bazel-toolchains.git",
133 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-toolchains/master/.bazelci/presubmit.yml",
134 "pipeline_slug": "bazel-toolchains",
135 },
136 "Bazel watcher": {
137 "git_repository": "https://github.com/bazelbuild/bazel-watcher.git",
138 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-watcher/master/.bazelci/presubmit.yml",
139 "pipeline_slug": "bazel-watcher",
140 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200141 "Bazelisk": {
142 "git_repository": "https://github.com/bazelbuild/bazelisk.git",
143 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazelisk/master/.bazelci/config.yml",
144 "pipeline_slug": "bazelisk",
145 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100146 "Buildfarm": {
147 "git_repository": "https://github.com/bazelbuild/bazel-buildfarm.git",
148 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-buildfarm/master/.bazelci/presubmit.yml",
149 "pipeline_slug": "buildfarm-male-farmer",
150 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100151 "Buildtools": {
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200152 "git_repository": "https://github.com/bazelbuild/buildtools.git",
Yun Peng996efad2018-11-27 17:19:44 +0100153 "http_config": "https://raw.githubusercontent.com/bazelbuild/buildtools/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100154 "pipeline_slug": "buildtools",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200155 },
Yun Peng39a42582018-11-09 10:59:47 +0100156 "CLion Plugin": {
157 "git_repository": "https://github.com/bazelbuild/intellij.git",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100158 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/clion.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100159 "pipeline_slug": "clion-plugin",
Yun Peng39a42582018-11-09 10:59:47 +0100160 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200161 "Cartographer": {
162 "git_repository": "https://github.com/googlecartographer/cartographer.git",
163 "http_config": "https://raw.githubusercontent.com/googlecartographer/cartographer/master/.bazelci/presubmit.yml",
164 "pipeline_slug": "cartographer",
165 },
Philipp Wollermannee850782019-02-05 22:56:04 +0100166 "Cloud Robotics Core": {
Stefan Sauerb4dd3f92019-02-05 22:44:28 +0100167 "git_repository": "https://github.com/googlecloudrobotics/core.git",
168 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/cloud-robotics-postsubmit.yml",
169 "pipeline_slug": "cloud-robotics-core",
170 },
Keith Smiley3b0ba602019-05-15 04:42:19 -0700171 "Envoy": {
172 "git_repository": "https://github.com/envoyproxy/envoy.git",
173 "http_config": "https://raw.githubusercontent.com/envoyproxy/envoy/master/.bazelci/presubmit.yml",
174 "pipeline_slug": "envoy",
175 },
Florian Weikert1fe28b72019-07-02 12:47:55 +0200176 "FlatBuffers": {
177 "git_repository": "https://github.com/google/flatbuffers.git",
178 "http_config": "https://raw.githubusercontent.com/google/flatbuffers/master/.bazelci/presubmit.yml",
179 "pipeline_slug": "flatbuffers",
180 },
Philipp Wollermannf3750fa2019-05-21 17:11:59 +0200181 "Flogger": {
182 "git_repository": "https://github.com/google/flogger.git",
183 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/flogger.yml",
184 "pipeline_slug": "flogger",
185 },
Marcel Hlopkoc8840772018-10-23 12:51:46 +0200186 "Gerrit": {
187 "git_repository": "https://gerrit.googlesource.com/gerrit.git",
Yun Peng996efad2018-11-27 17:19:44 +0100188 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/gerrit-postsubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100189 "pipeline_slug": "gerrit",
Marcel Hlopkoc8840772018-10-23 12:51:46 +0200190 },
Yun Pengd6622022018-11-05 13:10:26 +0100191 "Google Logging": {
192 "git_repository": "https://github.com/google/glog.git",
Yun Peng996efad2018-11-27 17:19:44 +0100193 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/glog-postsubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100194 "pipeline_slug": "google-logging",
Yun Pengd6622022018-11-05 13:10:26 +0100195 },
Yun Peng9586db52018-11-02 10:48:40 +0100196 "IntelliJ Plugin": {
197 "git_repository": "https://github.com/bazelbuild/intellij.git",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100198 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/intellij.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100199 "pipeline_slug": "intellij-plugin",
Yun Peng9586db52018-11-02 10:48:40 +0100200 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100201 "IntelliJ Plugin Aspect": {
202 "git_repository": "https://github.com/bazelbuild/intellij.git",
203 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/aspect.yml",
204 "pipeline_slug": "intellij-plugin-aspect",
205 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200206 "Kythe": {
207 "git_repository": "https://github.com/kythe/kythe.git",
208 "http_config": "https://raw.githubusercontent.com/kythe/kythe/master/.bazelci/presubmit.yml",
209 "pipeline_slug": "kythe",
210 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100211 "Protobuf": {
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200212 "git_repository": "https://github.com/google/protobuf.git",
Yun Peng996efad2018-11-27 17:19:44 +0100213 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/protobuf-postsubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100214 "pipeline_slug": "protobuf",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200215 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200216 "Skydoc": {
217 "git_repository": "https://github.com/bazelbuild/skydoc.git",
218 "http_config": "https://raw.githubusercontent.com/bazelbuild/skydoc/master/.bazelci/presubmit.yml",
219 "pipeline_slug": "skydoc",
220 },
221 "Subpar": {
222 "git_repository": "https://github.com/google/subpar.git",
223 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/subpar-postsubmit.yml",
224 "pipeline_slug": "subpar",
225 },
226 "TensorFlow": {
227 "git_repository": "https://github.com/tensorflow/tensorflow.git",
228 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/tensorflow-postsubmit.yml",
229 "pipeline_slug": "tensorflow",
Marcel Hlopko8ca24812019-09-26 11:01:43 +0200230 "disabled_reason": "https://github.com/tensorflow/tensorflow/issues/32835"
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200231 },
232 "Tulsi": {
233 "git_repository": "https://github.com/bazelbuild/tulsi.git",
234 "http_config": "https://raw.githubusercontent.com/bazelbuild/tulsi/master/.bazelci/presubmit.yml",
235 "pipeline_slug": "tulsi-bazel-darwin",
236 },
237 "re2": {
238 "git_repository": "https://github.com/google/re2.git",
239 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/re2-postsubmit.yml",
240 "pipeline_slug": "re2",
241 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100242 "rules_android": {
243 "git_repository": "https://github.com/bazelbuild/rules_android.git",
244 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_android/master/.bazelci/postsubmit.yml",
245 "pipeline_slug": "rules-android",
246 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200247 "rules_appengine": {
248 "git_repository": "https://github.com/bazelbuild/rules_appengine.git",
Yun Peng996efad2018-11-27 17:19:44 +0100249 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_appengine/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100250 "pipeline_slug": "rules-appengine-appengine",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200251 },
Yun Peng809f27b2018-11-13 10:15:39 +0100252 "rules_apple": {
253 "git_repository": "https://github.com/bazelbuild/rules_apple.git",
Yun Peng996efad2018-11-27 17:19:44 +0100254 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_apple/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100255 "pipeline_slug": "rules-apple-darwin",
Yun Peng809f27b2018-11-13 10:15:39 +0100256 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100257 "rules_cc": {
258 "git_repository": "https://github.com/bazelbuild/rules_cc.git",
259 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_cc/master/.bazelci/presubmit.yml",
260 "pipeline_slug": "rules-cc",
261 },
Marcel Hlopko340dfd22018-10-19 11:33:01 +0200262 "rules_closure": {
263 "git_repository": "https://github.com/bazelbuild/rules_closure.git",
Yun Peng996efad2018-11-27 17:19:44 +0100264 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_closure/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100265 "pipeline_slug": "rules-closure-closure-compiler",
Marcel Hlopko340dfd22018-10-19 11:33:01 +0200266 },
Yun Peng51ce6692019-01-09 14:31:46 +0100267 "rules_d": {
268 "git_repository": "https://github.com/bazelbuild/rules_d.git",
269 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_d/master/.bazelci/presubmit.yml",
270 "pipeline_slug": "rules-d",
271 },
Yun Peng996efad2018-11-27 17:19:44 +0100272 "rules_docker": {
273 "git_repository": "https://github.com/bazelbuild/rules_docker.git",
274 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_docker/master/.bazelci/presubmit.yml",
Jakob Buchgrabera6a8ea82018-12-07 13:51:02 +0100275 "pipeline_slug": "rules-docker-docker",
Yun Peng996efad2018-11-27 17:19:44 +0100276 },
277 "rules_foreign_cc": {
278 "git_repository": "https://github.com/bazelbuild/rules_foreign_cc.git",
279 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_foreign_cc/master/.bazelci/config.yaml",
280 "pipeline_slug": "rules-foreign-cc",
Yun Peng996efad2018-11-27 17:19:44 +0100281 },
Xindb02c012018-11-07 14:10:54 -0500282 "rules_go": {
283 "git_repository": "https://github.com/bazelbuild/rules_go.git",
Yun Peng996efad2018-11-27 17:19:44 +0100284 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_go/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100285 "pipeline_slug": "rules-go-golang",
Yun Pengb7247ff2018-11-15 13:52:39 +0100286 },
Yun Peng7deea572018-11-05 10:47:45 +0100287 "rules_groovy": {
Yun Peng996efad2018-11-27 17:19:44 +0100288 "git_repository": "https://github.com/bazelbuild/rules_groovy.git",
289 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_groovy/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100290 "pipeline_slug": "rules-groovy",
Yun Peng996efad2018-11-27 17:19:44 +0100291 },
292 "rules_gwt": {
293 "git_repository": "https://github.com/bazelbuild/rules_gwt.git",
294 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_gwt/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100295 "pipeline_slug": "rules-gwt",
Philipp Wollermann2a160432019-09-19 15:57:28 +0200296 },
Florian Weikertff6444e2019-09-16 16:08:57 +0200297 "rules_haskell": {
298 "git_repository": "https://github.com/tweag/rules_haskell.git",
299 "http_config": "https://raw.githubusercontent.com/tweag/rules_haskell/master/.bazelci/presubmit.yml",
300 "pipeline_slug": "rules-haskell-haskell",
Yun Pengc01ca572019-10-17 16:46:52 +0200301 "disabled_reason": "https://github.com/tweag/rules_haskell/issues/1127",
Philipp Wollermann2a160432019-09-19 15:57:28 +0200302 },
Yun Peng996efad2018-11-27 17:19:44 +0100303 "rules_jsonnet": {
304 "git_repository": "https://github.com/bazelbuild/rules_jsonnet.git",
305 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_jsonnet/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100306 "pipeline_slug": "rules-jsonnet",
Yun Peng996efad2018-11-27 17:19:44 +0100307 },
Philipp Wollermann1dc76992019-05-28 16:42:51 +0200308 "rules_jvm_external": {
309 "git_repository": "https://github.com/bazelbuild/rules_jvm_external.git",
310 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_jvm_external/master/.bazelci/presubmit.yml",
311 "pipeline_slug": "rules-jvm-external",
312 },
313 "rules_jvm_external - examples": {
314 "git_repository": "https://github.com/bazelbuild/rules_jvm_external.git",
315 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_jvm_external/master/.bazelci/examples.yml",
316 "pipeline_slug": "rules-jvm-external-examples",
317 },
Yun Peng996efad2018-11-27 17:19:44 +0100318 "rules_k8s": {
319 "git_repository": "https://github.com/bazelbuild/rules_k8s.git",
320 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_k8s/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100321 "pipeline_slug": "rules-k8s-k8s",
Yun Peng996efad2018-11-27 17:19:44 +0100322 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100323 "rules_kotlin": {
324 "git_repository": "https://github.com/bazelbuild/rules_kotlin.git",
325 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_kotlin/master/.bazelci/presubmit.yml",
326 "pipeline_slug": "rules-kotlin-kotlin",
327 },
Yun Penga5650e12018-11-14 10:16:06 +0100328 "rules_nodejs": {
329 "git_repository": "https://github.com/bazelbuild/rules_nodejs.git",
Yun Peng996efad2018-11-27 17:19:44 +0100330 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_nodejs/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100331 "pipeline_slug": "rules-nodejs-nodejs",
Yun Penga5650e12018-11-14 10:16:06 +0100332 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200333 "rules_perl": {
334 "git_repository": "https://github.com/bazelbuild/rules_perl.git",
Yun Peng996efad2018-11-27 17:19:44 +0100335 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_perl/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100336 "pipeline_slug": "rules-perl",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200337 },
Yannic6110b3c2019-08-12 15:09:37 +0000338 "rules_proto": {
339 "git_repository": "https://github.com/bazelbuild/rules_proto.git",
340 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_proto/master/.bazelci/presubmit.yml",
341 "pipeline_slug": "rules-proto",
342 },
Yun Peng3d5a8a62018-11-19 11:42:01 +0100343 "rules_python": {
344 "git_repository": "https://github.com/bazelbuild/rules_python.git",
Yun Peng996efad2018-11-27 17:19:44 +0100345 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_python/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100346 "pipeline_slug": "rules-python-python",
Yun Peng3d5a8a62018-11-19 11:42:01 +0100347 },
Xindb02c012018-11-07 14:10:54 -0500348 "rules_rust": {
349 "git_repository": "https://github.com/bazelbuild/rules_rust.git",
Yun Peng996efad2018-11-27 17:19:44 +0100350 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_rust/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100351 "pipeline_slug": "rules-rust-rustlang",
Xindb02c012018-11-07 14:10:54 -0500352 },
Yun Pengca62fff2018-10-31 11:22:03 +0100353 "rules_sass": {
354 "git_repository": "https://github.com/bazelbuild/rules_sass.git",
Yun Peng996efad2018-11-27 17:19:44 +0100355 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_sass/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100356 "pipeline_slug": "rules-sass",
Yun Pengca62fff2018-10-31 11:22:03 +0100357 },
Xindb02c012018-11-07 14:10:54 -0500358 "rules_scala": {
359 "git_repository": "https://github.com/bazelbuild/rules_scala.git",
Yun Peng996efad2018-11-27 17:19:44 +0100360 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_scala/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100361 "pipeline_slug": "rules-scala-scala",
Xindb02c012018-11-07 14:10:54 -0500362 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100363 "rules_swift": {
364 "git_repository": "https://github.com/bazelbuild/rules_swift.git",
365 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_swift/master/.bazelci/presubmit.yml",
366 "pipeline_slug": "rules-swift-swift",
367 },
Yun Peng996efad2018-11-27 17:19:44 +0100368 "rules_typescript": {
369 "git_repository": "https://github.com/bazelbuild/rules_typescript.git",
370 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_typescript/master/.bazelci/presubmit.yml",
Jakob Buchgrabera6a8ea82018-12-07 13:51:02 +0100371 "pipeline_slug": "rules-typescript-typescript",
Yun Peng996efad2018-11-27 17:19:44 +0100372 },
373 "rules_webtesting": {
374 "git_repository": "https://github.com/bazelbuild/rules_webtesting.git",
Yun Pengc2fab332019-01-04 10:53:49 +0100375 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_webtesting/master/.bazelci/presubmit.yml",
Yun Peng996efad2018-11-27 17:19:44 +0100376 "pipeline_slug": "rules-webtesting-saucelabs",
Yun Peng996efad2018-11-27 17:19:44 +0100377 },
Philipp Wollermann389acd82019-05-21 17:41:48 +0200378 "upb": {
379 "git_repository": "https://github.com/protocolbuffers/upb.git",
380 "http_config": "https://raw.githubusercontent.com/protocolbuffers/upb/master/.bazelci/presubmit.yml",
381 "pipeline_slug": "upb",
Marcel Hlopko0bc60892019-05-24 14:37:29 +0200382 "disabled_reason": "https://github.com/protocolbuffers/upb/issues/172",
Philipp Wollermann389acd82019-05-21 17:41:48 +0200383 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200384}
385
Philipp Wollermanne67eec42019-05-24 15:18:20 +0200386DOWNSTREAM_PROJECTS_TESTING = {
Philipp Wollermannbed211d2019-06-07 11:38:59 +0200387 "Bazel": DOWNSTREAM_PROJECTS_PRODUCTION["Bazel"],
388 "Bazelisk": DOWNSTREAM_PROJECTS_PRODUCTION["Bazelisk"],
Florian Weikert8fda2a72019-05-31 15:21:54 +0200389 "Federation": {
390 "git_repository": "https://github.com/fweikert/bazel-federation.git",
391 "http_config": "https://raw.githubusercontent.com/fweikert/bazel-federation/master/.bazelci/presubmit.yml",
392 "pipeline_slug": "bazel-federation",
393 },
Philipp Wollermannbed211d2019-06-07 11:38:59 +0200394 "rules_docker": DOWNSTREAM_PROJECTS_PRODUCTION["rules_docker"],
395 "rules_go": DOWNSTREAM_PROJECTS_PRODUCTION["rules_go"],
396 "rules_groovy": DOWNSTREAM_PROJECTS_PRODUCTION["rules_groovy"],
397 "rules_kotlin": DOWNSTREAM_PROJECTS_PRODUCTION["rules_kotlin"],
398 "rules_nodejs": DOWNSTREAM_PROJECTS_PRODUCTION["rules_nodejs"],
399 "rules_rust": DOWNSTREAM_PROJECTS_PRODUCTION["rules_rust"],
400 "rules_scala": DOWNSTREAM_PROJECTS_PRODUCTION["rules_scala"],
Philipp Wollermanne67eec42019-05-24 15:18:20 +0200401}
402
403DOWNSTREAM_PROJECTS = {
404 "bazel-testing": DOWNSTREAM_PROJECTS_TESTING,
405 "bazel-trusted": {},
406 "bazel": DOWNSTREAM_PROJECTS_PRODUCTION,
407}[BUILDKITE_ORG]
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100408
Philipp Wollermann81a88412019-07-12 10:34:33 +0200409DOCKER_REGISTRY_PREFIX = {
410 "bazel-testing": "bazel-public/testing",
411 "bazel-trusted": "bazel-public",
412 "bazel": "bazel-public",
413}[BUILDKITE_ORG]
414
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200415# A map containing all supported platform names as keys, with the values being
416# the platform name in a human readable format, and a the buildkite-agent's
417# working directory.
418PLATFORMS = {
Philipp Wollermanneffcd6e2019-06-21 18:30:34 +0200419 "centos7": {
420 "name": "CentOS 7, Java 8",
421 "emoji-name": ":centos: 7 (Java 8)",
422 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermannf4aabb72019-06-25 15:59:00 +0200423 "publish_binary": ["ubuntu1404", "centos7", "linux"],
Philipp Wollermann81a88412019-07-12 10:34:33 +0200424 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/centos7:java8",
Philipp Wollermanneffcd6e2019-06-21 18:30:34 +0200425 "python": "python3.6",
426 },
Philipp Wollermann67fc3712019-06-12 15:39:21 +0200427 "debian10": {
428 "name": "Debian Buster, OpenJDK 11",
429 "emoji-name": ":debian: Buster (OpenJDK 11)",
430 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
431 "publish_binary": [],
432 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/debian10:java11",
433 "python": "python3.7",
434 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200435 "ubuntu1604": {
Philipp Wollermanndb877332019-04-23 17:58:01 +0200436 "name": "Ubuntu 16.04, OpenJDK 8",
437 "emoji-name": ":ubuntu: 16.04 (OpenJDK 8)",
Philipp Wollermannd551bf62019-05-18 22:04:35 +0200438 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermannf4aabb72019-06-25 15:59:00 +0200439 "publish_binary": ["ubuntu1604"],
Philipp Wollermann81a88412019-07-12 10:34:33 +0200440 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu1604:java8",
Philipp Wollermann57b32682019-05-18 22:09:27 +0200441 "python": "python3.6",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200442 },
443 "ubuntu1804": {
Philipp Wollermannf5a2feb2019-04-25 11:13:46 +0200444 "name": "Ubuntu 18.04, OpenJDK 11",
445 "emoji-name": ":ubuntu: 18.04 (OpenJDK 11)",
Philipp Wollermannd551bf62019-05-18 22:04:35 +0200446 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann783d1672019-06-06 13:35:30 +0200447 "publish_binary": ["ubuntu1804"],
Philipp Wollermann81a88412019-07-12 10:34:33 +0200448 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu1804:java11",
Philipp Wollermann57b32682019-05-18 22:09:27 +0200449 "python": "python3.6",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200450 },
451 "ubuntu1804_nojava": {
452 "name": "Ubuntu 18.04, no JDK",
453 "emoji-name": ":ubuntu: 18.04 (no JDK)",
Philipp Wollermannd551bf62019-05-18 22:04:35 +0200454 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann783d1672019-06-06 13:35:30 +0200455 "publish_binary": [],
Philipp Wollermann81a88412019-07-12 10:34:33 +0200456 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu1804:nojava",
Philipp Wollermann57b32682019-05-18 22:09:27 +0200457 "python": "python3.6",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200458 },
Philipp Wollermann438ec242018-09-05 14:39:24 +0200459 "macos": {
Philipp Wollermanndb877332019-04-23 17:58:01 +0200460 "name": "macOS, OpenJDK 8",
461 "emoji-name": ":darwin: (OpenJDK 8)",
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200462 "downstream-root": "/Users/buildkite/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann783d1672019-06-06 13:35:30 +0200463 "publish_binary": ["macos"],
Philipp Wollermann7a185322019-05-18 22:15:48 +0200464 "queue": "macos",
Philipp Wollermann57b32682019-05-18 22:09:27 +0200465 "python": "python3.7",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200466 },
467 "windows": {
Philipp Wollermanndb877332019-04-23 17:58:01 +0200468 "name": "Windows, OpenJDK 8",
469 "emoji-name": ":windows: (OpenJDK 8)",
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200470 "downstream-root": "d:/b/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann783d1672019-06-06 13:35:30 +0200471 "publish_binary": ["windows"],
Philipp Wollermann7a185322019-05-18 22:15:48 +0200472 "queue": "windows",
Philipp Wollermann57b32682019-05-18 22:09:27 +0200473 "python": "python.exe",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200474 },
475 "rbe_ubuntu1604": {
Philipp Wollermanndb877332019-04-23 17:58:01 +0200476 "name": "RBE (Ubuntu 16.04, OpenJDK 8)",
Jakob Buchgraber1f37fbd2019-07-17 17:08:28 +0200477 "emoji-name": "RBE (:ubuntu: 16.04, OpenJDK 8)",
Philipp Wollermannd551bf62019-05-18 22:04:35 +0200478 "downstream-root": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Philipp Wollermann783d1672019-06-06 13:35:30 +0200479 "publish_binary": [],
Philipp Wollermann81a88412019-07-12 10:34:33 +0200480 "docker-image": f"gcr.io/{DOCKER_REGISTRY_PREFIX}/ubuntu1604:java8",
Philipp Wollermann57b32682019-05-18 22:09:27 +0200481 "python": "python3.6",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100482 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200483}
484
Philipp Wollermannfce92bf2019-05-22 15:14:32 +0200485BUILDIFIER_DOCKER_IMAGE = "gcr.io/bazel-public/buildifier"
Florian Weikertf20ae6f2019-01-16 14:32:09 +0100486
Philipp Wollermann1403d2c2019-01-10 13:15:51 +0100487# The platform used for various steps (e.g. stuff that formerly ran on the "pipeline" workers).
488DEFAULT_PLATFORM = "ubuntu1804"
489
Philipp Wollermannf4aabb72019-06-25 15:59:00 +0200490# In order to test that "the one Linux binary" that we build for our official releases actually
491# works on all Linux distributions that we test on, we use the Linux binary built on our official
492# release platform for all Linux downstream tests.
493LINUX_BINARY_PLATFORM = "centos7"
494
Philipp Wollermann0ecf9922019-05-13 13:24:52 +0200495DEFAULT_XCODE_VERSION = "10.2.1"
Philipp Wollermann380f1e62019-04-12 16:45:27 +0200496XCODE_VERSION_REGEX = re.compile(r"^\d+\.\d+(\.\d+)?$")
497
Philipp Wollermann1403d2c2019-01-10 13:15:51 +0100498ENCRYPTED_SAUCELABS_TOKEN = """
Philipp Wollermanna4722b42019-01-10 16:50:13 +0100499CiQAry63sOlZtTNtuOT5DAOLkum0rGof+DOweppZY1aOWbat8zwSTQAL7Hu+rgHSOr6P4S1cu4YG
500/I1BHsWaOANqUgFt6ip9/CUGGJ1qggsPGXPrmhSbSPqNAIAkpxYzabQ3mfSIObxeBmhKg2dlILA/
501EDql
Philipp Wollermann1403d2c2019-01-10 13:15:51 +0100502""".strip()
503
Florian Weikertc8642af2019-02-03 23:58:51 +0100504BUILD_LABEL_PATTERN = re.compile(r"^Build label: (\S+)$", re.MULTILINE)
505
Florian Weikert29cb7ec2019-03-07 14:52:18 +0100506BUILDIFIER_VERSION_ENV_VAR = "BUILDIFIER_VERSION"
507
Florian Weikert85208912019-03-07 17:08:39 +0100508BUILDIFIER_WARNINGS_ENV_VAR = "BUILDIFIER_WARNINGS"
509
Florian Weikertde96a6f2019-03-07 14:57:50 +0100510BUILDIFIER_STEP_NAME = "Buildifier"
511
Florian Weikert5f5d3cb2019-04-15 15:36:27 +0200512SKIP_TASKS_ENV_VAR = "CI_SKIP_TASKS"
513
Philipp Wollermannce986af2019-07-18 14:46:05 +0200514CONFIG_FILE_EXTENSIONS = {".yml", ".yaml"}
Florian Weikert778251c2019-04-25 15:14:44 +0200515
Florian Weikert13215a82019-05-10 12:42:21 +0200516
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100517class BuildkiteException(Exception):
518 """
519 Raised whenever something goes wrong and we should exit with an error.
520 """
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100521
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100522 pass
523
524
525class BinaryUploadRaceException(Exception):
526 """
527 Raised when try_publish_binaries wasn't able to publish a set of binaries,
528 because the generation of the current file didn't match the expected value.
529 """
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100530
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100531 pass
532
533
Florian Weikerta0e74592019-03-07 11:56:12 +0100534class BuildkiteClient(object):
535
536 _ENCRYPTED_BUILDKITE_API_TOKEN = """
537CiQA4DEB9ldzC+E39KomywtqXfaQ86hhulgeDsicds2BuvbCYzsSUAAqwcvXZPh9IMWlwWh94J2F
538exosKKaWB0tSRJiPKnv2NPDfEqGul0ZwVjtWeASpugwxxKeLhFhPMcgHMPfndH6j2GEIY6nkKRbP
539uwoRMCwe
540""".strip()
541
Philipp Wollermanne67eec42019-05-24 15:18:20 +0200542 _ENCRYPTED_BUILDKITE_API_TESTING_TOKEN = """
543CiQAMTBkWjL1C+F5oon3+cC1vmum5+c1y5+96WQY44p0Lxd0PeASUQAy7iU0c6E3W5EOSFYfD5fA
544MWy/SHaMno1NQSUa4xDOl5yc2kizrtxPPVkX4x9pLNuGUY/xwAn2n1DdiUdWZNWlY1bX2C4ex65e
545P9w8kNhEbw==
546""".strip()
547
Florian Weikertde96a6f2019-03-07 14:57:50 +0100548 _BUILD_STATUS_URL_TEMPLATE = (
549 "https://api.buildkite.com/v2/organizations/{}/pipelines/{}/builds/{}"
550 )
Florian Weikerta0e74592019-03-07 11:56:12 +0100551
552 def __init__(self, org, pipeline):
553 self._org = org
554 self._pipeline = pipeline
555 self._token = self._get_buildkite_token()
556
557 def _get_buildkite_token(self):
558 return (
559 subprocess.check_output(
560 [
561 gcloud_command(),
562 "kms",
563 "decrypt",
564 "--project",
565 "bazel-untrusted",
566 "--location",
567 "global",
568 "--keyring",
569 "buildkite",
570 "--key",
Philipp Wollermanne67eec42019-05-24 15:18:20 +0200571 "buildkite-testing-api-token"
572 if THIS_IS_TESTING
573 else "buildkite-untrusted-api-token",
Florian Weikerta0e74592019-03-07 11:56:12 +0100574 "--ciphertext-file",
575 "-",
576 "--plaintext-file",
577 "-",
578 ],
Philipp Wollermanne67eec42019-05-24 15:18:20 +0200579 input=base64.b64decode(
580 self._ENCRYPTED_BUILDKITE_API_TESTING_TOKEN
581 if THIS_IS_TESTING
582 else self._ENCRYPTED_BUILDKITE_API_TOKEN
583 ),
Florian Weikerta0e74592019-03-07 11:56:12 +0100584 env=os.environ,
585 )
586 .decode("utf-8")
587 .strip()
588 )
589
590 def _open_url(self, url):
Florian Weikertde96a6f2019-03-07 14:57:50 +0100591 return (
592 urllib.request.urlopen("{}?access_token={}".format(url, self._token))
593 .read()
594 .decode("utf-8")
595 )
Florian Weikerta0e74592019-03-07 11:56:12 +0100596
597 def get_build_info(self, build_number):
598 url = self._BUILD_STATUS_URL_TEMPLATE.format(self._org, self._pipeline, build_number)
599 output = self._open_url(url)
600 return json.loads(output)
601
602 def get_build_log(self, job):
603 return self._open_url(job["raw_log_url"])
604
605
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100606def eprint(*args, **kwargs):
607 """
608 Print to stderr and flush (just in case).
609 """
610 print(*args, flush=True, file=sys.stderr, **kwargs)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100611
612
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100613def is_windows():
Jakob Buchgraber09048fa2018-02-27 11:39:39 +0100614 return os.name == "nt"
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100615
Jakob Buchgrabere6de16b2018-02-28 12:42:12 +0100616
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100617def gsutil_command():
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200618 return "gsutil.cmd" if is_windows() else "gsutil"
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100619
Jakob Buchgrabere6de16b2018-02-28 12:42:12 +0100620
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100621def gcloud_command():
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200622 return "gcloud.cmd" if is_windows() else "gcloud"
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100623
Jakob Buchgrabere6de16b2018-02-28 12:42:12 +0100624
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100625def downstream_projects_root(platform):
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200626 downstream_root = os.path.expandvars(PLATFORMS[platform]["downstream-root"])
627 if not os.path.exists(downstream_root):
628 os.makedirs(downstream_root)
629 return downstream_root
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100630
631
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +0100632def fetch_configs(http_url, file_config):
Philipp Wollermanndb024862018-02-19 17:16:56 +0100633 """
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +0100634 If specified fetches the build configuration from file_config or http_url, else tries to
Jakob Buchgraber25bb50f2018-02-22 18:06:21 +0100635 read it from .bazelci/presubmit.yml.
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100636 Returns the json configuration as a python data structure.
Philipp Wollermanndb024862018-02-19 17:16:56 +0100637 """
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +0100638 if file_config is not None and http_url is not None:
639 raise BuildkiteException("file_config and http_url cannot be set at the same time")
640
Florian Weikertc8b3ed22019-05-31 16:14:12 +0200641 return load_config(http_url, file_config)
642
643
644def load_config(http_url, file_config, allow_imports=True):
Florian Weikertc8b3ed22019-05-31 16:14:12 +0200645 if http_url:
646 config = load_remote_yaml_file(http_url)
647 else:
648 file_config = file_config or ".bazelci/presubmit.yml"
649 with open(file_config, "r") as fd:
650 config = yaml.safe_load(fd)
651
Florian Weikert843d7a02019-02-03 17:24:50 +0100652 # Legacy mode means that there is exactly one task per platform (e.g. ubuntu1604_nojdk),
653 # which means that we can get away with using the platform name as task ID.
654 # No other updates are needed since get_platform_for_task() falls back to using the
655 # task ID as platform if there is no explicit "platforms" field.
656 if "platforms" in config:
657 config["tasks"] = config.pop("platforms")
658
Florian Weikertc8b3ed22019-05-31 16:14:12 +0200659 if "tasks" not in config:
660 config["tasks"] = {}
661
662 imports = config.pop("imports", None)
663 if imports:
664 if not allow_imports:
665 raise BuildkiteException("Nested imports are not allowed")
666
667 for i in imports:
668 imported_tasks = load_imported_tasks(i, http_url, file_config)
669 config["tasks"].update(imported_tasks)
670
Florian Weikert843d7a02019-02-03 17:24:50 +0100671 return config
672
673
Florian Weikert13215a82019-05-10 12:42:21 +0200674def load_remote_yaml_file(http_url):
675 with urllib.request.urlopen(http_url) as resp:
676 reader = codecs.getreader("utf-8")
Philipp Wollermannd00107e2019-05-18 23:50:59 +0200677 return yaml.safe_load(reader(resp))
Florian Weikert13215a82019-05-10 12:42:21 +0200678
679
Florian Weikertc8b3ed22019-05-31 16:14:12 +0200680def load_imported_tasks(import_name, http_url, file_config):
681 if "/" in import_name:
682 raise BuildkiteException("Invalid import '%s'" % import_name)
683
684 old_path = http_url or file_config
685 new_path = "%s%s" % (old_path[: old_path.rfind("/") + 1], import_name)
686 if http_url:
687 http_url = new_path
688 else:
689 file_config = new_path
690
691 imported_config = load_config(http_url=http_url, file_config=file_config, allow_imports=False)
692
693 namespace = import_name.partition(".")[0]
694 tasks = {}
695 for task_name, task_config in imported_config["tasks"].items():
Florian Weikert61f29b82019-08-12 16:56:56 +0200696 fix_imported_task_platform(task_name, task_config)
697 fix_imported_task_name(namespace, task_config)
698 fix_imported_task_working_directory(namespace, task_config)
Florian Weikertc8b3ed22019-05-31 16:14:12 +0200699 tasks["%s_%s" % (namespace, task_name)] = task_config
700
701 return tasks
702
703
Florian Weikert61f29b82019-08-12 16:56:56 +0200704def fix_imported_task_platform(task_name, task_config):
705 if "platform" not in task_config:
706 task_config["platform"] = task_name
707
708
709def fix_imported_task_name(namespace, task_config):
710 old_name = task_config.get("name")
711 task_config["name"] = "%s (%s)" % (namespace, old_name) if old_name else namespace
712
713
714def fix_imported_task_working_directory(namespace, task_config):
715 old_dir = task_config.get("working_directory")
716 task_config["working_directory"] = os.path.join(namespace, old_dir) if old_dir else namespace
717
718
Jakob Buchgraber3120f7a2018-02-18 13:28:02 +0100719def print_collapsed_group(name):
Jakob Buchgraber5c9b13d2018-02-21 22:28:14 +0100720 eprint("\n\n--- {0}\n\n".format(name))
Jakob Buchgraber3120f7a2018-02-18 13:28:02 +0100721
Jakob Buchgraber9c83de72018-02-18 15:32:44 +0100722
Jakob Buchgraber3120f7a2018-02-18 13:28:02 +0100723def print_expanded_group(name):
Jakob Buchgraber5c9b13d2018-02-21 22:28:14 +0100724 eprint("\n\n+++ {0}\n\n".format(name))
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100725
Jakob Buchgraber9c83de72018-02-18 15:32:44 +0100726
Yun Peng8975c6b2019-02-28 11:55:55 +0100727def use_bazelisk_migrate():
728 """
729 If USE_BAZELISK_MIGRATE is set, we use `bazelisk --migrate` to test incompatible flags.
730 """
Florian Weikertde96a6f2019-03-07 14:57:50 +0100731 return bool(os.environ.get("USE_BAZELISK_MIGRATE"))
Yun Peng8975c6b2019-02-28 11:55:55 +0100732
733
734def bazelisk_flags():
735 return ["--migrate"] if use_bazelisk_migrate() else []
736
737
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100738def execute_commands(
Florian Weikertc8642af2019-02-03 23:58:51 +0100739 task_config,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100740 platform,
741 git_repository,
742 git_commit,
743 git_repo_location,
744 use_bazel_at_commit,
745 use_but,
746 save_but,
Yun Peng4d1d6542019-01-17 18:30:33 +0100747 needs_clean,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100748 build_only,
749 test_only,
750 monitor_flaky_tests,
751 incompatible_flags,
Florian Weikertc8642af2019-02-03 23:58:51 +0100752 bazel_version=None,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100753):
Yun Pengf50f7b72019-02-28 19:09:52 +0100754 # If we want to test incompatible flags, we ignore bazel_version and always use
755 # the latest Bazel version through Bazelisk.
756 if incompatible_flags:
757 bazel_version = None
Florian Weikert13215a82019-05-10 12:42:21 +0200758 if not bazel_version:
759 # The last good version of Bazel can be specified in an emergency file.
760 # However, we only use last_good_bazel for pipelines that do not
761 # explicitly specify a version of Bazel.
762 try:
763 emergency_settings = load_remote_yaml_file(EMERGENCY_FILE_URL)
764 bazel_version = emergency_settings.get("last_good_bazel")
765 except urllib.error.HTTPError:
766 # Ignore this error. The Setup step will have already complained about
767 # it by showing an error message.
768 pass
Yun Pengf50f7b72019-02-28 19:09:52 +0100769
Jakob Buchgraberfb95a2f2018-02-22 11:46:25 +0100770 if build_only and test_only:
771 raise BuildkiteException("build_only and test_only cannot be true at the same time")
Philipp Wollermanne1318eb2018-08-13 15:08:01 +0200772
Yun Peng20d45602018-10-18 13:27:05 +0200773 if use_bazel_at_commit and use_but:
774 raise BuildkiteException("use_bazel_at_commit cannot be set when use_but is true")
775
Philipp Wollermanne1318eb2018-08-13 15:08:01 +0200776 tmpdir = tempfile.mkdtemp()
777 sc_process = None
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100778 try:
Philipp Wollermann380f1e62019-04-12 16:45:27 +0200779 if platform == "macos":
Florian Weikertee84c5c2019-05-28 11:21:51 +0200780 activate_xcode(task_config)
Philipp Wollermann380f1e62019-04-12 16:45:27 +0200781
Florian Weikert4ee0bed2019-02-21 18:03:00 +0100782 # If the CI worker runs Bazelisk, we need to forward all required env variables to the test.
783 # Otherwise any integration test that invokes Bazel (=Bazelisk in this case) will fail.
Marcel Hlopko198328b2019-02-25 09:19:55 +0100784 test_env_vars = ["LocalAppData"] if platform == "windows" else ["HOME"]
Yun Peng376d2b32018-11-29 10:24:54 +0100785 if git_repo_location:
786 os.chdir(git_repo_location)
787 elif git_repository:
788 clone_git_repository(git_repository, platform, git_commit)
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200789
Philipp Wollermannf4aabb72019-06-25 15:59:00 +0200790 # We use one binary for all Linux platforms (because we also just release one binary for all
791 # Linux versions and we have to ensure that it works on all of them).
792 binary_platform = platform if platform in ["macos", "windows"] else LINUX_BINARY_PLATFORM
793
Yun Peng20d45602018-10-18 13:27:05 +0200794 if use_bazel_at_commit:
795 print_collapsed_group(":gcloud: Downloading Bazel built at " + use_bazel_at_commit)
Philipp Wollermannf4aabb72019-06-25 15:59:00 +0200796 bazel_binary = download_bazel_binary_at_commit(
797 tmpdir, binary_platform, use_bazel_at_commit
798 )
Yun Pengf0a66e22019-10-14 12:45:42 +0200799 os.environ["USE_BAZEL_VERSION"] = bazel_binary
Philipp Wollermann639c0452019-01-03 11:23:54 +0100800 elif use_but:
Jakob Buchgraber92755d72018-02-22 15:33:37 +0100801 print_collapsed_group(":gcloud: Downloading Bazel Under Test")
Philipp Wollermannf4aabb72019-06-25 15:59:00 +0200802 bazel_binary = download_bazel_binary(tmpdir, binary_platform)
Yun Pengf0a66e22019-10-14 12:45:42 +0200803 os.environ["USE_BAZEL_VERSION"] = bazel_binary
Philipp Wollermann639c0452019-01-03 11:23:54 +0100804 else:
805 bazel_binary = "bazel"
Florian Weikertc8642af2019-02-03 23:58:51 +0100806 if bazel_version:
Florian Weikertc8642af2019-02-03 23:58:51 +0100807 os.environ["USE_BAZEL_VERSION"] = bazel_version
Yun Pengf0a66e22019-10-14 12:45:42 +0200808 if "USE_BAZEL_VERSION" in os.environ:
809 # This will only work if the bazel binary in $PATH is actually a bazelisk binary
810 # (https://github.com/bazelbuild/bazelisk).
811 test_env_vars.append("USE_BAZEL_VERSION")
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200812
Philipp Wollermann5c7ea412019-05-24 15:26:57 +0200813 for key, value in task_config.get("environment", {}).items():
Philipp Wollermann4ad4aac2019-05-24 15:23:09 +0200814 # We have to explicitly convert the value to a string, because sometimes YAML tries to
815 # be smart and converts strings like "true" and "false" to booleans.
816 os.environ[key] = str(value)
Philipp Wollermann213ac9d2019-02-06 11:50:05 +0100817
Florian Weikerta8c020b2019-08-12 16:56:38 +0200818 cmd_exec_func = execute_batch_commands if platform == "windows" else execute_shell_commands
819 cmd_exec_func(task_config.get("setup", None))
820
Philipp Wollermanna5aee2c2019-02-11 16:55:19 +0100821 # Allow the config to override the current working directory.
822 required_prefix = os.getcwd()
823 requested_working_dir = os.path.abspath(task_config.get("working_directory", ""))
824 if os.path.commonpath([required_prefix, requested_working_dir]) != required_prefix:
825 raise BuildkiteException("working_directory refers to a path outside the workspace")
826 os.chdir(requested_working_dir)
827
Florian Weikerte72d68a2019-03-08 18:56:33 +0100828 if platform == "windows":
829 execute_batch_commands(task_config.get("batch_commands", None))
830 else:
831 execute_shell_commands(task_config.get("shell_commands", None))
832
Florian Weikertc8642af2019-02-03 23:58:51 +0100833 bazel_version = print_bazel_version_info(bazel_binary, platform)
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200834
Yun Penga5a1ee02018-12-05 15:00:58 +0100835 print_environment_variables_info()
836
Yun Pengd0217ed2018-11-30 14:51:11 +0100837 if incompatible_flags:
838 print_expanded_group("Build and test with the following incompatible flags:")
839 for flag in incompatible_flags:
840 eprint(flag + "\n")
841
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100842 execute_bazel_run(
Florian Weikertc8642af2019-02-03 23:58:51 +0100843 bazel_binary, platform, task_config.get("run_targets", None), incompatible_flags
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100844 )
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200845
Florian Weikertee84c5c2019-05-28 11:21:51 +0200846 if task_config.get("sauce"):
847 sc_process = start_sauce_connect_proxy(platform, tmpdir)
Philipp Wollermanne1318eb2018-08-13 15:08:01 +0200848
Yun Peng4d1d6542019-01-17 18:30:33 +0100849 if needs_clean:
Yun Pengea0359e2019-01-17 15:37:47 +0100850 execute_bazel_clean(bazel_binary, platform)
851
Florian Weikert736d06e2019-05-08 13:16:42 +0200852 build_targets, test_targets = calculate_targets(
853 task_config, platform, bazel_binary, build_only, test_only
854 )
Florian Weikert736d06e2019-05-08 13:16:42 +0200855
joeleba76887952019-05-16 15:22:17 +0200856 include_json_profile = task_config.get("include_json_profile", [])
857
Florian Weikert736d06e2019-05-08 13:16:42 +0200858 if build_targets:
joeleba76887952019-05-16 15:22:17 +0200859 json_profile_flags = []
Philipp Wollermann92cf51e2019-05-16 15:31:11 +0200860 include_json_profile_build = "build" in include_json_profile
Philipp Wollermannce986af2019-07-18 14:46:05 +0200861 json_profile_out_build = None
joeleba76887952019-05-16 15:22:17 +0200862 if include_json_profile_build:
joeleba05dbc8a2019-05-16 19:27:46 +0200863 json_profile_out_build = os.path.join(tmpdir, "build.profile.gz")
Philipp Wollermann92cf51e2019-05-16 15:31:11 +0200864 json_profile_flags = get_json_profile_flags(json_profile_out_build)
joeleba76887952019-05-16 15:22:17 +0200865
Florian Weikerte2affab2019-06-04 13:44:34 +0200866 build_flags = task_config.get("build_flags") or []
joeleba76887952019-05-16 15:22:17 +0200867 try:
868 execute_bazel_build(
869 bazel_version,
870 bazel_binary,
871 platform,
Florian Weikerte2affab2019-06-04 13:44:34 +0200872 build_flags + json_profile_flags,
joeleba76887952019-05-16 15:22:17 +0200873 build_targets,
874 None,
875 incompatible_flags,
876 )
877 if save_but:
878 upload_bazel_binary(platform)
879 finally:
880 if include_json_profile_build:
Philipp Wollermann92cf51e2019-05-16 15:31:11 +0200881 upload_json_profile(json_profile_out_build, tmpdir)
Philipp Wollermann639c0452019-01-03 11:23:54 +0100882
Florian Weikert736d06e2019-05-08 13:16:42 +0200883 if test_targets:
joeleba76887952019-05-16 15:22:17 +0200884 json_profile_flags = []
Philipp Wollermann92cf51e2019-05-16 15:31:11 +0200885 include_json_profile_test = "test" in include_json_profile
Philipp Wollermannce986af2019-07-18 14:46:05 +0200886 json_profile_out_test = None
joeleba76887952019-05-16 15:22:17 +0200887 if include_json_profile_test:
joeleba05dbc8a2019-05-16 19:27:46 +0200888 json_profile_out_test = os.path.join(tmpdir, "test.profile.gz")
Philipp Wollermann92cf51e2019-05-16 15:31:11 +0200889 json_profile_flags = get_json_profile_flags(json_profile_out_test)
joeleba76887952019-05-16 15:22:17 +0200890
Florian Weikerte2affab2019-06-04 13:44:34 +0200891 test_flags = task_config.get("test_flags") or []
892 test_flags += json_profile_flags
Florian Weikert4ee0bed2019-02-21 18:03:00 +0100893 if test_env_vars:
894 test_flags += ["--test_env={}".format(v) for v in test_env_vars]
895
Florian Weikert4901c662019-02-26 13:20:11 +0100896 if not is_windows():
897 # On platforms that support sandboxing (Linux, MacOS) we have
898 # to allow access to Bazelisk's cache directory.
899 # However, the flag requires the directory to exist,
900 # so we create it here in order to not crash when a test
901 # does not invoke Bazelisk.
902 bazelisk_cache_dir = get_bazelisk_cache_directory(platform)
903 os.makedirs(bazelisk_cache_dir, mode=0o755, exist_ok=True)
904 test_flags.append("--sandbox_writable_path={}".format(bazelisk_cache_dir))
Florian Weikert5b890332019-02-25 14:57:43 +0100905
Philipp Wollermannce986af2019-07-18 14:46:05 +0200906 test_bep_file = os.path.join(tmpdir, "test_bep.json")
907 stop_request = threading.Event()
908 upload_thread = threading.Thread(
909 target=upload_test_logs_from_bep, args=(test_bep_file, tmpdir, stop_request)
910 )
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100911 try:
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +0200912 upload_thread.start()
913 try:
914 execute_bazel_test(
915 bazel_version,
916 bazel_binary,
917 platform,
918 test_flags,
919 test_targets,
920 test_bep_file,
921 monitor_flaky_tests,
922 incompatible_flags,
923 )
924 if monitor_flaky_tests:
925 upload_bep_logs_for_flaky_tests(test_bep_file)
926 finally:
927 if include_json_profile_test:
928 upload_json_profile(json_profile_out_test, tmpdir)
Philipp Wollermann639c0452019-01-03 11:23:54 +0100929 finally:
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +0200930 stop_request.set()
931 upload_thread.join()
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100932 finally:
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +0200933 terminate_background_process(sc_process)
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100934 if tmpdir:
935 shutil.rmtree(tmpdir)
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100936
Philipp Wollermann3c8b8512019-07-16 15:28:03 +0200937
Florian Weikertee84c5c2019-05-28 11:21:51 +0200938def activate_xcode(task_config):
939 # Get the Xcode version from the config.
940 xcode_version = task_config.get("xcode_version", DEFAULT_XCODE_VERSION)
941 print_collapsed_group("Activating Xcode {}...".format(xcode_version))
942
943 # Ensure it's a valid version number.
944 if not isinstance(xcode_version, str):
945 raise BuildkiteException(
946 "Version number '{}' is not a string. Did you forget to put it in quotes?".format(
947 xcode_version
948 )
949 )
950 if not XCODE_VERSION_REGEX.match(xcode_version):
951 raise BuildkiteException(
952 "Invalid Xcode version format '{}', must match the format X.Y[.Z].".format(
953 xcode_version
954 )
955 )
956
957 # Check that the selected Xcode version is actually installed on the host.
958 xcode_path = "/Applications/Xcode{}.app".format(xcode_version)
959 if not os.path.exists(xcode_path):
960 raise BuildkiteException("Xcode not found at '{}'.".format(xcode_path))
961
962 # Now activate the specified Xcode version and let it install its required components.
963 # The CI machines have a sudoers config that allows the 'buildkite' user to run exactly
964 # these two commands, so don't change them without also modifying the file there.
965 execute_command(["/usr/bin/sudo", "/usr/bin/xcode-select", "--switch", xcode_path])
966 execute_command(["/usr/bin/sudo", "/usr/bin/xcodebuild", "-runFirstLaunch"])
967
968
Florian Weikert4901c662019-02-26 13:20:11 +0100969def get_bazelisk_cache_directory(platform):
970 # The path relies on the behavior of Go's os.UserCacheDir()
971 # and of the Go version of Bazelisk.
Philipp Wollermannce986af2019-07-18 14:46:05 +0200972 cache_dir = "Library/Caches" if platform == "macos" else ".cache"
973 return os.path.join(os.environ.get("HOME"), cache_dir, "bazelisk")
Florian Weikert4901c662019-02-26 13:20:11 +0100974
Florian Weikert5b890332019-02-25 14:57:43 +0100975
Jakob Buchgraber5d6c7142018-02-21 20:16:51 +0100976def tests_with_status(bep_file, status):
Jakob Buchgraberc874cdf2019-07-16 16:27:41 +0200977 return set(label for label, _ in test_logs_for_status(bep_file, status=[status]))
Jakob Buchgraber257693b2018-02-20 00:03:56 +0100978
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100979
Florian Weikertee84c5c2019-05-28 11:21:51 +0200980def start_sauce_connect_proxy(platform, tmpdir):
981 print_collapsed_group(":saucelabs: Starting Sauce Connect Proxy")
982 os.environ["SAUCE_USERNAME"] = "bazel_rules_webtesting"
983 os.environ["SAUCE_ACCESS_KEY"] = saucelabs_token()
984 os.environ["TUNNEL_IDENTIFIER"] = str(uuid.uuid4())
985 os.environ["BUILD_TAG"] = str(uuid.uuid4())
986 readyfile = os.path.join(tmpdir, "sc_is_ready")
987 if platform == "windows":
Philipp Wollermann8a8c25a2019-08-23 12:56:36 +0200988 cmd = ["sauce-connect.exe", "-i", os.environ["TUNNEL_IDENTIFIER"], "-f", readyfile]
Florian Weikertee84c5c2019-05-28 11:21:51 +0200989 else:
990 cmd = ["sc", "-i", os.environ["TUNNEL_IDENTIFIER"], "-f", readyfile]
991 sc_process = execute_command_background(cmd)
992 wait_start = time.time()
993 while not os.path.exists(readyfile):
Philipp Wollermann8a8c25a2019-08-23 12:56:36 +0200994 if time.time() - wait_start > 60:
Florian Weikertee84c5c2019-05-28 11:21:51 +0200995 raise BuildkiteException(
Philipp Wollermann8a8c25a2019-08-23 12:56:36 +0200996 "Sauce Connect Proxy is still not ready after 60 seconds, aborting!"
Florian Weikertee84c5c2019-05-28 11:21:51 +0200997 )
998 time.sleep(1)
999 print("Sauce Connect Proxy is ready, continuing...")
1000 return sc_process
1001
1002
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001003def saucelabs_token():
1004 return (
1005 subprocess.check_output(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001006 [
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001007 gcloud_command(),
1008 "kms",
1009 "decrypt",
Philipp Wollermanna4722b42019-01-10 16:50:13 +01001010 "--project",
1011 "bazel-untrusted",
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001012 "--location",
1013 "global",
1014 "--keyring",
1015 "buildkite",
1016 "--key",
1017 "saucelabs-access-key",
1018 "--ciphertext-file",
1019 "-",
1020 "--plaintext-file",
1021 "-",
1022 ],
1023 input=base64.b64decode(ENCRYPTED_SAUCELABS_TOKEN),
1024 env=os.environ,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001025 )
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001026 .decode("utf-8")
1027 .strip()
1028 )
Yun Pengb6b18862019-01-07 14:31:55 +01001029
1030
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001031def is_pull_request():
Jakob Buchgraber67761d32018-02-21 19:00:21 +01001032 third_party_repo = os.getenv("BUILDKITE_PULL_REQUEST_REPO", "")
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001033 return len(third_party_repo) > 0
1034
1035
Jakob Buchgraber02e07222018-02-19 15:05:56 +01001036def has_flaky_tests(bep_file):
Jakob Buchgraberc874cdf2019-07-16 16:27:41 +02001037 return len(test_logs_for_status(bep_file, status=["FLAKY"])) > 0
Jakob Buchgraber02e07222018-02-19 15:05:56 +01001038
1039
Yun Penge3cf12d2018-12-05 15:01:09 +01001040def print_bazel_version_info(bazel_binary, platform):
Jakob Buchgraber99c4bbb2018-02-22 11:59:31 +01001041 print_collapsed_group(":information_source: Bazel Info")
Philipp Wollermannf13804b2019-02-05 21:08:30 +01001042 version_output = execute_command_and_get_output(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001043 [bazel_binary]
1044 + common_startup_flags(platform)
1045 + ["--nomaster_bazelrc", "--bazelrc=/dev/null", "version"]
1046 )
1047 execute_command(
1048 [bazel_binary]
1049 + common_startup_flags(platform)
1050 + ["--nomaster_bazelrc", "--bazelrc=/dev/null", "info"]
1051 )
Jakob Buchgraber7e690a72018-02-18 13:22:15 +01001052
Florian Weikertc8642af2019-02-03 23:58:51 +01001053 match = BUILD_LABEL_PATTERN.search(version_output)
1054 return match.group(1) if match else "unreleased binary"
1055
Jakob Buchgraber7e690a72018-02-18 13:22:15 +01001056
Yun Penga5a1ee02018-12-05 15:00:58 +01001057def print_environment_variables_info():
1058 print_collapsed_group(":information_source: Environment Variables")
1059 for key, value in os.environ.items():
1060 eprint("%s=(%s)" % (key, value))
1061
1062
Jakob Buchgraber426399e2018-03-20 19:45:46 +01001063def upload_bazel_binary(platform):
Jakob Buchgraber7d1d3bb2018-02-21 22:38:22 +01001064 print_collapsed_group(":gcloud: Uploading Bazel Under Test")
Tobias Werth322aa742018-12-20 11:44:16 +01001065 binary_path = "bazel-bin/src/bazel"
Jakob Buchgraber426399e2018-03-20 19:45:46 +01001066 if platform == "windows":
Yun Peng97078002019-10-15 10:10:56 +02001067 binary_path = r"bazel-bin\src\bazel.exe"
Philipp Wollermann94bd9e32018-04-30 15:32:28 +02001068 execute_command(["buildkite-agent", "artifact", "upload", binary_path])
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001069
1070
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01001071def download_bazel_binary(dest_dir, platform):
Tobias Werth322aa742018-12-20 11:44:16 +01001072 binary_path = "bazel-bin/src/bazel"
Jakob Buchgraber426399e2018-03-20 19:45:46 +01001073 if platform == "windows":
Yun Peng97078002019-10-15 10:10:56 +02001074 binary_path = r"bazel-bin\src\bazel.exe"
Jakob Buchgraber426399e2018-03-20 19:45:46 +01001075
Philipp Wollermannc52e26a2019-05-18 22:10:47 +02001076 source_step = create_label(platform, "Bazel", build_only=True)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001077 execute_command(
1078 ["buildkite-agent", "artifact", "download", binary_path, dest_dir, "--step", source_step]
1079 )
Jakob Buchgraber00046232018-03-27 20:15:26 +02001080 bazel_binary_path = os.path.join(dest_dir, binary_path)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001081 st = os.stat(bazel_binary_path)
1082 os.chmod(bazel_binary_path, st.st_mode | stat.S_IEXEC)
1083 return bazel_binary_path
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001084
1085
Yun Peng20d45602018-10-18 13:27:05 +02001086def download_bazel_binary_at_commit(dest_dir, platform, bazel_git_commit):
Yun Peng20d45602018-10-18 13:27:05 +02001087 bazel_binary_path = os.path.join(dest_dir, "bazel.exe" if platform == "windows" else "bazel")
Yun Peng02312732019-01-17 18:17:05 +01001088 try:
1089 execute_command(
1090 [
1091 gsutil_command(),
1092 "cp",
1093 bazelci_builds_gs_url(platform, bazel_git_commit),
1094 bazel_binary_path,
1095 ]
1096 )
1097 except subprocess.CalledProcessError as e:
Philipp Wollermannc05ac682019-01-19 12:37:28 +01001098 raise BuildkiteException(
1099 "Failed to download Bazel binary at %s, error message:\n%s" % (bazel_git_commit, str(e))
1100 )
Yun Peng20d45602018-10-18 13:27:05 +02001101 st = os.stat(bazel_binary_path)
1102 os.chmod(bazel_binary_path, st.st_mode | stat.S_IEXEC)
1103 return bazel_binary_path
1104
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001105
joeleba7050d842019-05-23 17:03:31 +02001106def get_mirror_path(git_repository, platform):
1107 mirror_root = {
1108 "macos": "/usr/local/var/bazelbuild/",
1109 "windows": "c:\\buildkite\\bazelbuild\\",
1110 }.get(platform, "/var/lib/bazelbuild/")
1111
1112 return mirror_root + re.sub(r"[^0-9A-Za-z]", "-", git_repository)
1113
1114
Yun Peng376d2b32018-11-29 10:24:54 +01001115def clone_git_repository(git_repository, platform, git_commit=None):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001116 root = downstream_projects_root(platform)
Philipp Wollermannff39ef52018-02-21 14:18:52 +01001117 project_name = re.search(r"/([^/]+)\.git$", git_repository).group(1)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001118 clone_path = os.path.join(root, project_name)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001119 print_collapsed_group(
1120 "Fetching %s sources at %s" % (project_name, git_commit if git_commit else "HEAD")
1121 )
Philipp Wollermann438ec242018-09-05 14:39:24 +02001122
joeleba7050d842019-05-23 17:03:31 +02001123 mirror_path = get_mirror_path(git_repository, platform)
Philipp Wollermannea128282019-05-08 11:56:14 +02001124
Philipp Wollermann414703d2018-08-28 16:40:38 +02001125 if not os.path.exists(clone_path):
Philipp Wollermann62f4a032019-05-08 17:44:14 +02001126 if os.path.exists(mirror_path):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001127 execute_command(
Philipp Wollermann62f4a032019-05-08 17:44:14 +02001128 ["git", "clone", "-v", "--reference", mirror_path, git_repository, clone_path]
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001129 )
Philipp Wollermannd4cd0d82018-05-01 09:56:24 +02001130 else:
Philipp Wollermannea128282019-05-08 11:56:14 +02001131 execute_command(["git", "clone", "-v", git_repository, clone_path])
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001132
Philipp Wollermann414703d2018-08-28 16:40:38 +02001133 os.chdir(clone_path)
1134 execute_command(["git", "remote", "set-url", "origin", git_repository])
1135 execute_command(["git", "clean", "-fdqx"])
Florian Weikertd8f497c2019-06-19 15:44:20 +02001136 execute_command(["git", "submodule", "foreach", "--recursive", "git clean -fdqx"])
Philipp Wollermann414703d2018-08-28 16:40:38 +02001137 execute_command(["git", "fetch", "origin"])
Yun Peng376d2b32018-11-29 10:24:54 +01001138 if git_commit:
1139 # sync to a specific commit of this repository
1140 execute_command(["git", "reset", git_commit, "--hard"])
1141 else:
1142 # sync to the latest commit of HEAD. Unlikely git pull this also works after a force push.
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001143 remote_head = (
1144 subprocess.check_output(["git", "symbolic-ref", "refs/remotes/origin/HEAD"])
1145 .decode("utf-8")
1146 .rstrip()
1147 )
Yun Peng376d2b32018-11-29 10:24:54 +01001148 execute_command(["git", "reset", remote_head, "--hard"])
Philipp Wollermann414703d2018-08-28 16:40:38 +02001149 execute_command(["git", "submodule", "sync", "--recursive"])
1150 execute_command(["git", "submodule", "update", "--init", "--recursive", "--force"])
Florian Weikertd8f497c2019-06-19 15:44:20 +02001151 execute_command(["git", "submodule", "foreach", "--recursive", "git reset --hard"])
Philipp Wollermann414703d2018-08-28 16:40:38 +02001152 execute_command(["git", "clean", "-fdqx"])
Florian Weikertd8f497c2019-06-19 15:44:20 +02001153 execute_command(["git", "submodule", "foreach", "--recursive", "git clean -fdqx"])
Yun Peng20d45602018-10-18 13:27:05 +02001154 return clone_path
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001155
Philipp Wollermann438ec242018-09-05 14:39:24 +02001156
Yun Penga935a542018-05-18 15:08:53 +02001157def execute_batch_commands(commands):
1158 if not commands:
1159 return
1160 print_collapsed_group(":batch: Setup (Batch Commands)")
1161 batch_commands = "&".join(commands)
Jakob Buchgraber4a824412018-06-22 12:56:10 +02001162 return subprocess.run(batch_commands, shell=True, check=True, env=os.environ).returncode
Yun Penga935a542018-05-18 15:08:53 +02001163
Philipp Wollermann414703d2018-08-28 16:40:38 +02001164
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001165def execute_shell_commands(commands):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001166 if not commands:
1167 return
Jakob Buchgraber94d5c212018-02-22 09:57:08 +01001168 print_collapsed_group(":bash: Setup (Shell Commands)")
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001169 shell_command = "\n".join(commands)
Philipp Wollermann3e1a7712018-02-19 17:34:24 +01001170 execute_command([shell_command], shell=True)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001171
1172
Yun Peng0a6a98a2019-03-06 13:07:54 +01001173def handle_bazel_failure(exception, action):
1174 msg = "bazel {0} failed with exit code {1}".format(action, exception.returncode)
1175 if use_bazelisk_migrate():
1176 print_collapsed_group(msg)
1177 else:
1178 raise BuildkiteException(msg)
1179
1180
Yun Peng4be92b32018-11-30 09:48:29 +01001181def execute_bazel_run(bazel_binary, platform, targets, incompatible_flags):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001182 if not targets:
1183 return
1184 print_collapsed_group("Setup (Run Targets)")
Florian Weikert474d7972019-03-01 02:12:01 +01001185 # When using bazelisk --migrate to test incompatible flags,
1186 # incompatible flags set by "INCOMPATIBLE_FLAGS" env var will be ignored.
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001187 incompatible_flags_to_use = (
1188 [] if (use_bazelisk_migrate() or not incompatible_flags) else incompatible_flags
1189 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001190 for target in targets:
Yun Peng0a6a98a2019-03-06 13:07:54 +01001191 try:
1192 execute_command(
1193 [bazel_binary]
1194 + bazelisk_flags()
1195 + common_startup_flags(platform)
1196 + ["run"]
1197 + common_build_flags(None, platform)
1198 + incompatible_flags_to_use
1199 + [target]
1200 )
1201 except subprocess.CalledProcessError as e:
1202 handle_bazel_failure(e, "run")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001203
1204
Jakob Buchgraber4f1d2712018-02-20 10:22:47 +01001205def remote_caching_flags(platform):
Philipp Wollermanne67eec42019-05-24 15:18:20 +02001206 # Only enable caching for untrusted and testing builds.
Philipp Wollermannfce92bf2019-05-22 15:14:32 +02001207 if CLOUD_PROJECT not in ["bazel-untrusted"]:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001208 return []
Philipp Wollermann02955272019-04-18 18:00:48 +02001209
Philipp Wollermanne67eec42019-05-24 15:18:20 +02001210 platform_cache_key = [BUILDKITE_ORG.encode("utf-8")]
Jakob Buchgraber89df3982019-08-06 13:07:02 +02001211 # Whenever the remote cache was known to have been poisoned increase the number below
Yun Peng0eacd832019-10-15 14:34:06 +02001212 platform_cache_key += ["cache-poisoning-20191015".encode("utf-8")]
Philipp Wollermannfce92bf2019-05-22 15:14:32 +02001213
Philipp Wollermann380f1e62019-04-12 16:45:27 +02001214 if platform == "macos":
Philipp Wollermannfce92bf2019-05-22 15:14:32 +02001215 platform_cache_key += [
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001216 # macOS version:
1217 subprocess.check_output(["/usr/bin/sw_vers", "-productVersion"]),
1218 # Path to Xcode:
1219 subprocess.check_output(["/usr/bin/xcode-select", "-p"]),
1220 # Xcode version:
1221 subprocess.check_output(["/usr/bin/xcodebuild", "-version"]),
1222 ]
1223 # Use a local cache server for our macOS machines.
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001224 flags = ["--remote_cache=http://100.107.73.186"]
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001225 else:
Philipp Wollermannfce92bf2019-05-22 15:14:32 +02001226 platform_cache_key += [
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001227 # Platform name:
1228 platform.encode("utf-8")
1229 ]
Philipp Wollermanne74da4e2019-06-07 11:31:02 +02001230 # Use RBE for caching builds running on GCE.
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001231 flags = [
1232 "--google_default_credentials",
Philipp Wollermanne74da4e2019-06-07 11:31:02 +02001233 "--remote_cache=remotebuildexecution.googleapis.com",
1234 "--remote_instance_name=projects/{}/instances/default_instance".format(CLOUD_PROJECT),
1235 "--tls_enabled=true",
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001236 ]
Philipp Wollermann380f1e62019-04-12 16:45:27 +02001237
1238 platform_cache_digest = hashlib.sha256()
1239 for key in platform_cache_key:
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001240 eprint("Adding to platform cache key: {}".format(key))
Philipp Wollermann380f1e62019-04-12 16:45:27 +02001241 platform_cache_digest.update(key)
1242 platform_cache_digest.update(b":")
1243
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001244 flags += [
Philipp Wollermann94937722019-01-11 14:33:18 +01001245 "--remote_timeout=60",
Philipp Wollermann639c0452019-01-03 11:23:54 +01001246 "--remote_max_connections=200",
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001247 '--remote_default_platform_properties=properties:{name:"cache-silo-key" value:"%s"}'
1248 % platform_cache_digest.hexdigest(),
Philipp Wollermann639c0452019-01-03 11:23:54 +01001249 ]
Jakob Buchgraber4f1d2712018-02-20 10:22:47 +01001250
Philipp Wollermannd96d8fa2019-01-11 14:37:47 +01001251 return flags
1252
Jakob Buchgraber4f1d2712018-02-20 10:22:47 +01001253
Jakob Buchgraberb4342cd2018-02-20 16:35:07 +01001254def remote_enabled(flags):
1255 # Detect if the project configuration enabled its own remote caching / execution.
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001256 remote_flags = ["--remote_executor", "--remote_cache", "--remote_http_cache"]
Jakob Buchgraberb4342cd2018-02-20 16:35:07 +01001257 for flag in flags:
1258 for remote_flag in remote_flags:
1259 if flag.startswith(remote_flag):
1260 return True
1261 return False
1262
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001263
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001264def concurrent_jobs(platform):
1265 return "75" if platform.startswith("rbe_") else str(multiprocessing.cpu_count())
Jakob Buchgraber51a83662018-02-22 19:49:24 +01001266
1267
Philipp Wollermann3e28d3b2018-02-23 23:19:37 +01001268def concurrent_test_jobs(platform):
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001269 if platform.startswith("rbe_"):
1270 return "75"
1271 elif platform == "windows":
Jakob Buchgrabere3ccda32018-06-22 23:29:48 +02001272 return "8"
Philipp Wollermann111adfb2018-11-22 10:26:03 +01001273 elif platform == "macos":
1274 return "8"
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001275 return "12"
Philipp Wollermann3e28d3b2018-02-23 23:19:37 +01001276
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001277
Yun Peng58977d62018-11-16 12:19:20 +01001278def common_startup_flags(platform):
Philipp Wollermann639c0452019-01-03 11:23:54 +01001279 return ["--output_user_root=D:/b"] if platform == "windows" else []
Yun Peng58977d62018-11-16 12:19:20 +01001280
1281
1282def common_build_flags(bep_file, platform):
Yun Peng088cc932018-11-16 12:11:46 +01001283 flags = [
Yun Pengf51e7842018-11-16 11:35:43 +01001284 "--show_progress_rate_limit=5",
1285 "--curses=yes",
1286 "--color=yes",
Philipp Wollermannd99414c2019-05-28 17:26:09 +02001287 "--terminal_columns=143",
Philipp Wollermann4c8391e2019-05-28 18:03:35 +02001288 "--show_timestamps",
Yun Pengf51e7842018-11-16 11:35:43 +01001289 "--verbose_failures",
1290 "--keep_going",
1291 "--jobs=" + concurrent_jobs(platform),
Yun Pengf51e7842018-11-16 11:35:43 +01001292 "--announce_rc",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001293 "--experimental_multi_threaded_digest",
Philipp Wollermannb97f9102019-04-16 18:05:56 +02001294 "--experimental_repository_cache_hardlinks",
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001295 # Some projects set --disk_cache in their project-specific bazelrc, which we never want on
1296 # CI, so let's just disable it explicitly.
1297 "--disk_cache=",
Yun Peng088cc932018-11-16 12:11:46 +01001298 ]
Philipp Wollermann639c0452019-01-03 11:23:54 +01001299
Philipp Wollermannb97f9102019-04-16 18:05:56 +02001300 if platform == "windows":
1301 pass
1302 elif platform == "macos":
1303 flags += [
1304 "--sandbox_writable_path=/var/tmp/_bazel_buildkite/cache/repos/v1",
1305 "--test_env=REPOSITORY_CACHE=/var/tmp/_bazel_buildkite/cache/repos/v1",
1306 ]
1307 else:
Philipp Wollermann639c0452019-01-03 11:23:54 +01001308 flags += ["--sandbox_tmpfs_path=/tmp"]
1309
Yun Peng088cc932018-11-16 12:11:46 +01001310 if bep_file:
Philipp Wollermann639c0452019-01-03 11:23:54 +01001311 flags += [
1312 "--experimental_build_event_json_file_path_conversion=false",
1313 "--build_event_json_file=" + bep_file,
1314 ]
1315
Yun Peng088cc932018-11-16 12:11:46 +01001316 return flags
Philipp Wollermann94bd9e32018-04-30 15:32:28 +02001317
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001318
Yun Pengb7247ff2018-11-15 13:52:39 +01001319def rbe_flags(original_flags, accept_cached):
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001320 # Enable remote execution via RBE.
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001321 flags = [
1322 "--remote_executor=remotebuildexecution.googleapis.com",
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001323 "--remote_instance_name=projects/bazel-untrusted/instances/default_instance",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001324 "--remote_timeout=3600",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001325 "--experimental_strict_action_env",
1326 "--tls_enabled=true",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001327 "--google_default_credentials",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001328 ]
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001329
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001330 # Enable BES / Build Results reporting.
1331 flags += [
1332 "--bes_backend=buildeventservice.googleapis.com",
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001333 "--bes_timeout=360s",
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001334 "--project_id=bazel-untrusted",
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001335 ]
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001336
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001337 if not accept_cached:
1338 flags += ["--noremote_accept_cached"]
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001339
Nicolas Lopez36996222019-05-28 12:21:28 -04001340 # Adapted from https://github.com/bazelbuild/bazel-toolchains/blob/master/bazelrc/.bazelrc
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001341 flags += [
Nicolas Lopez36996222019-05-28 12:21:28 -04001342 # These should NOT longer need to be modified.
1343 # All that is needed is updating the @bazel_toolchains repo pin
1344 # in projects' WORKSPACE files.
Xindb02c012018-11-07 14:10:54 -05001345 #
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001346 # Toolchain related flags to append at the end of your .bazelrc file.
Nicolas Lopez36996222019-05-28 12:21:28 -04001347 "--host_javabase=@buildkite_config//java:jdk",
1348 "--javabase=@buildkite_config//java:jdk",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001349 "--host_java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8",
1350 "--java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8",
Nicolas Lopez36996222019-05-28 12:21:28 -04001351 "--crosstool_top=@buildkite_config//cc:toolchain",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001352 "--action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001353 ]
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001354
Yun Pengb7247ff2018-11-15 13:52:39 +01001355 # Platform flags:
1356 # The toolchain container used for execution is defined in the target indicated
1357 # by "extra_execution_platforms", "host_platform" and "platforms".
Xin03a88ab2019-03-11 19:18:50 -04001358 # If you are using your own toolchain container, you need to create a platform
1359 # target with "constraint_values" that allow for the toolchain specified with
1360 # "extra_toolchains" to be selected (given constraints defined in
1361 # "exec_compatible_with").
Yun Pengb7247ff2018-11-15 13:52:39 +01001362 # More about platforms: https://docs.bazel.build/versions/master/platforms.html
1363 # Don't add platform flags if they are specified already.
1364 platform_flags = {
Nicolas Lopez36996222019-05-28 12:21:28 -04001365 "--extra_toolchains": "@buildkite_config//config:cc-toolchain",
1366 "--extra_execution_platforms": "@buildkite_config//config:platform",
1367 "--host_platform": "@buildkite_config//config:platform",
1368 "--platforms": "@buildkite_config//config:platform",
Yun Pengb7247ff2018-11-15 13:52:39 +01001369 }
Yun Peng67ab5062018-11-15 13:58:15 +01001370 for platform_flag, value in list(platform_flags.items()):
Yun Pengb7247ff2018-11-15 13:52:39 +01001371 found = False
1372 for original_flag in original_flags:
1373 if original_flag.startswith(platform_flag):
1374 found = True
1375 break
1376 if not found:
1377 flags += [platform_flag + "=" + value]
1378
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001379 return flags
1380
1381
Florian Weikert24a4b482018-11-30 19:05:38 +01001382def compute_flags(platform, flags, incompatible_flags, bep_file, enable_remote_cache=False):
Yun Peng58977d62018-11-16 12:19:20 +01001383 aggregated_flags = common_build_flags(bep_file, platform)
Yun Peng32dbec32018-11-02 12:47:41 +01001384 if not remote_enabled(flags):
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001385 if platform.startswith("rbe_"):
Florian Weikert24a4b482018-11-30 19:05:38 +01001386 aggregated_flags += rbe_flags(flags, accept_cached=enable_remote_cache)
1387 elif enable_remote_cache:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001388 aggregated_flags += remote_caching_flags(platform)
Yun Peng75786552018-11-13 15:23:30 +01001389 aggregated_flags += flags
Yun Peng4be92b32018-11-30 09:48:29 +01001390 if incompatible_flags:
1391 aggregated_flags += incompatible_flags
Yun Peng53598002018-12-03 10:42:02 +01001392
Florian Weikert24a4b482018-11-30 19:05:38 +01001393 return aggregated_flags
Yun Peng53598002018-12-03 10:42:02 +01001394
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001395
Yun Pengea0359e2019-01-17 15:37:47 +01001396def execute_bazel_clean(bazel_binary, platform):
1397 print_expanded_group(":bazel: Clean")
1398
1399 try:
Philipp Wollermannc05ac682019-01-19 12:37:28 +01001400 execute_command([bazel_binary] + common_startup_flags(platform) + ["clean", "--expunge"])
Yun Pengea0359e2019-01-17 15:37:47 +01001401 except subprocess.CalledProcessError as e:
1402 raise BuildkiteException("bazel clean failed with exit code {}".format(e.returncode))
1403
1404
Florian Weikertc8642af2019-02-03 23:58:51 +01001405def execute_bazel_build(
1406 bazel_version, bazel_binary, platform, flags, targets, bep_file, incompatible_flags
1407):
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001408 print_collapsed_group(":bazel: Computing flags for build step")
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001409 aggregated_flags = compute_flags(
Yun Peng8975c6b2019-02-28 11:55:55 +01001410 platform,
1411 flags,
1412 # When using bazelisk --migrate to test incompatible flags,
1413 # incompatible flags set by "INCOMPATIBLE_FLAGS" env var will be ignored.
1414 [] if (use_bazelisk_migrate() or not incompatible_flags) else incompatible_flags,
1415 bep_file,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001416 enable_remote_cache=True,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001417 )
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001418
1419 print_expanded_group(":bazel: Build ({})".format(bazel_version))
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001420 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001421 execute_command(
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001422 [bazel_binary]
1423 + bazelisk_flags()
1424 + common_startup_flags(platform)
1425 + ["build"]
1426 + aggregated_flags
Philipp Wollermann2a160432019-09-19 15:57:28 +02001427 + ["--"]
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001428 + targets
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001429 )
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001430 except subprocess.CalledProcessError as e:
Yun Peng0a6a98a2019-03-06 13:07:54 +01001431 handle_bazel_failure(e, "build")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001432
1433
Florian Weikert736d06e2019-05-08 13:16:42 +02001434def calculate_targets(task_config, platform, bazel_binary, build_only, test_only):
1435 build_targets = [] if test_only else task_config.get("build_targets", [])
1436 test_targets = [] if build_only else task_config.get("test_targets", [])
1437
Philipp Wollermann2a160432019-09-19 15:57:28 +02001438 # Remove the "--" argument splitter from the list that some configs explicitly
1439 # include. We'll add it back again later where needed.
1440 build_targets = [x.strip() for x in build_targets if x.strip() != "--"]
1441 test_targets = [x.strip() for x in test_targets if x.strip() != "--"]
1442
Florian Weikert736d06e2019-05-08 13:16:42 +02001443 shard_id = int(os.getenv("BUILDKITE_PARALLEL_JOB", "-1"))
1444 shard_count = int(os.getenv("BUILDKITE_PARALLEL_JOB_COUNT", "-1"))
1445 if shard_id > -1 and shard_count > -1:
1446 print_collapsed_group(
1447 ":female-detective: Calculating targets for shard {}/{}".format(
1448 shard_id + 1, shard_count
1449 )
1450 )
1451 expanded_test_targets = expand_test_target_patterns(bazel_binary, platform, test_targets)
1452 build_targets, test_targets = get_targets_for_shard(
1453 build_targets, expanded_test_targets, shard_id, shard_count
1454 )
1455
1456 return build_targets, test_targets
1457
1458
1459def expand_test_target_patterns(bazel_binary, platform, test_targets):
Philipp Wollermann2a160432019-09-19 15:57:28 +02001460 included_targets, excluded_targets = partition_targets(test_targets)
Florian Weikert736d06e2019-05-08 13:16:42 +02001461 excluded_string = (
1462 " except tests(set({}))".format(" ".join("'{}'".format(t) for t in excluded_targets))
1463 if excluded_targets
1464 else ""
1465 )
1466
Philipp Wollermann2a160432019-09-19 15:57:28 +02001467 exclude_manual = ' except tests(attr("tags", "manual", set({})))'.format(
1468 " ".join("'{}'".format(t) for t in included_targets)
1469 )
1470
Florian Weikert736d06e2019-05-08 13:16:42 +02001471 eprint("Resolving test targets via bazel query")
1472 output = execute_command_and_get_output(
1473 [bazel_binary]
1474 + common_startup_flags(platform)
1475 + [
1476 "--nomaster_bazelrc",
1477 "--bazelrc=/dev/null",
1478 "query",
Philipp Wollermann2a160432019-09-19 15:57:28 +02001479 "tests(set({})){}{}".format(
1480 " ".join("'{}'".format(t) for t in included_targets),
1481 excluded_string,
1482 exclude_manual,
Florian Weikert736d06e2019-05-08 13:16:42 +02001483 ),
1484 ],
1485 print_output=False,
Florian Weikert736d06e2019-05-08 13:16:42 +02001486 )
Philipp Wollermann2a160432019-09-19 15:57:28 +02001487 return output.strip().split("\n")
Florian Weikert736d06e2019-05-08 13:16:42 +02001488
1489
Philipp Wollermann2a160432019-09-19 15:57:28 +02001490def partition_targets(targets):
Florian Weikert736d06e2019-05-08 13:16:42 +02001491 included_targets, excluded_targets = [], []
Philipp Wollermann2a160432019-09-19 15:57:28 +02001492 for target in targets:
1493 if target.startswith("-"):
Florian Weikert736d06e2019-05-08 13:16:42 +02001494 excluded_targets.append(target[1:])
1495 else:
1496 included_targets.append(target)
1497
1498 return included_targets, excluded_targets
1499
1500
1501def get_targets_for_shard(build_targets, test_targets, shard_id, shard_count):
1502 # TODO(fweikert): implement a more sophisticated algorithm
Philipp Wollermann2a160432019-09-19 15:57:28 +02001503 included_build_targets, excluded_build_targets = partition_targets(build_targets)
1504 build_targets_for_this_shard = sorted(included_build_targets)[shard_id::shard_count] + [
1505 "-" + x for x in excluded_build_targets
1506 ]
Florian Weikert736d06e2019-05-08 13:16:42 +02001507 test_targets_for_this_shard = sorted(test_targets)[shard_id::shard_count]
1508
1509 return build_targets_for_this_shard, test_targets_for_this_shard
1510
1511
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001512def execute_bazel_test(
Florian Weikertc8642af2019-02-03 23:58:51 +01001513 bazel_version,
1514 bazel_binary,
1515 platform,
1516 flags,
1517 targets,
1518 bep_file,
1519 monitor_flaky_tests,
1520 incompatible_flags,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001521):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001522 aggregated_flags = [
1523 "--flaky_test_attempts=3",
1524 "--build_tests_only",
1525 "--local_test_jobs=" + concurrent_test_jobs(platform),
1526 ]
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001527 # Don't enable remote caching if the user enabled remote execution / caching themselves
Jakob Buchgraberc340f582018-06-22 13:48:33 +02001528 # or flaky test monitoring is enabled, as remote caching makes tests look less flaky than
1529 # they are.
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001530 print_collapsed_group(":bazel: Computing flags for test step")
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001531 aggregated_flags += compute_flags(
Yun Peng8975c6b2019-02-28 11:55:55 +01001532 platform,
1533 flags,
1534 # When using bazelisk --migrate to test incompatible flags,
1535 # incompatible flags set by "INCOMPATIBLE_FLAGS" env var will be ignored.
1536 [] if (use_bazelisk_migrate() or not incompatible_flags) else incompatible_flags,
1537 bep_file,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001538 enable_remote_cache=not monitor_flaky_tests,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001539 )
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001540
Philipp Wollermannbda4b7d2019-05-16 20:04:17 +02001541 print_expanded_group(":bazel: Test ({})".format(bazel_version))
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001542 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001543 execute_command(
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001544 [bazel_binary]
1545 + bazelisk_flags()
1546 + common_startup_flags(platform)
1547 + ["test"]
1548 + aggregated_flags
Philipp Wollermann2a160432019-09-19 15:57:28 +02001549 + ["--"]
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001550 + targets
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001551 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001552 except subprocess.CalledProcessError as e:
Yun Peng0a6a98a2019-03-06 13:07:54 +01001553 handle_bazel_failure(e, "test")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001554
1555
joeleba76887952019-05-16 15:22:17 +02001556def get_json_profile_flags(out_file):
1557 return [
1558 "--experimental_generate_json_trace_profile",
1559 "--experimental_profile_cpu_usage",
1560 "--experimental_json_trace_compression",
Philipp Wollermann92cf51e2019-05-16 15:31:11 +02001561 "--profile={}".format(out_file),
joeleba76887952019-05-16 15:22:17 +02001562 ]
1563
1564
Florian Weikertee84c5c2019-05-28 11:21:51 +02001565def upload_bep_logs_for_flaky_tests(test_bep_file):
1566 if has_flaky_tests(test_bep_file):
1567 build_number = os.getenv("BUILDKITE_BUILD_NUMBER")
1568 pipeline_slug = os.getenv("BUILDKITE_PIPELINE_SLUG")
1569 execute_command(
1570 [
1571 gsutil_command(),
1572 "cp",
1573 test_bep_file,
1574 FLAKY_TESTS_BUCKET + pipeline_slug + "/" + build_number + ".json",
1575 ]
1576 )
1577
1578
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001579def upload_test_logs_from_bep(bep_file, tmpdir, stop_request):
1580 uploaded_targets = set()
1581 while True:
1582 done = stop_request.isSet()
1583 if os.path.exists(bep_file):
Jakob Buchgraberc874cdf2019-07-16 16:27:41 +02001584 all_test_logs = test_logs_for_status(bep_file, status=["FAILED", "TIMEOUT", "FLAKY"])
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02001585 test_logs_to_upload = [
1586 (target, files) for target, files in all_test_logs if target not in uploaded_targets
1587 ]
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001588
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001589 if test_logs_to_upload:
1590 files_to_upload = rename_test_logs_for_upload(test_logs_to_upload, tmpdir)
1591 cwd = os.getcwd()
1592 try:
1593 os.chdir(tmpdir)
1594 test_logs = [os.path.relpath(file, tmpdir) for file in files_to_upload]
1595 test_logs = sorted(test_logs)
1596 execute_command(["buildkite-agent", "artifact", "upload", ";".join(test_logs)])
1597 finally:
1598 uploaded_targets.update([target for target, _ in test_logs_to_upload])
1599 os.chdir(cwd)
1600 if done:
1601 break
1602 time.sleep(0.2)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001603
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02001604
joeleba76887952019-05-16 15:22:17 +02001605def upload_json_profile(json_profile_path, tmpdir):
1606 if not os.path.exists(json_profile_path):
1607 return
1608 print_collapsed_group(":gcloud: Uploading JSON Profile")
Philipp Wollermann92cf51e2019-05-16 15:31:11 +02001609 execute_command(["buildkite-agent", "artifact", "upload", json_profile_path], cwd=tmpdir)
joeleba76887952019-05-16 15:22:17 +02001610
Philipp Wollermann5b00a702019-07-18 11:21:38 +02001611
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001612def rename_test_logs_for_upload(test_logs, tmpdir):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001613 # Rename the test.log files to the target that created them
1614 # so that it's easy to associate test.log and target.
1615 new_paths = []
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001616 for label, files in test_logs:
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001617 attempt = 0
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001618 if len(files) > 1:
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001619 attempt = 1
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001620 for test_log in files:
Jakob Buchgraber070ef5f2018-02-20 17:57:14 +01001621 try:
1622 new_path = test_label_to_path(tmpdir, label, attempt)
Jakob Buchgraber070ef5f2018-02-20 17:57:14 +01001623 os.makedirs(os.path.dirname(new_path), exist_ok=True)
Jakob Buchgraber070ef5f2018-02-20 17:57:14 +01001624 copyfile(test_log, new_path)
Jakob Buchgraber070ef5f2018-02-20 17:57:14 +01001625 new_paths.append(new_path)
Philipp Wollermannc030f2e2018-02-21 17:02:19 +01001626 attempt += 1
Jakob Buchgraber070ef5f2018-02-20 17:57:14 +01001627 except IOError as err:
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001628 # Log error and ignore.
1629 eprint(err)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001630 return new_paths
Jakob Buchgraber699aece2018-02-19 12:49:30 +01001631
1632
Jakob Buchgraber02e07222018-02-19 15:05:56 +01001633def test_label_to_path(tmpdir, label, attempt):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001634 # remove leading //
1635 path = label[2:]
Philipp Wollermannc030f2e2018-02-21 17:02:19 +01001636 path = path.replace("/", os.sep)
1637 path = path.replace(":", os.sep)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001638 if attempt == 0:
1639 path = os.path.join(path, "test.log")
1640 else:
1641 path = os.path.join(path, "attempt_" + str(attempt) + ".log")
1642 return os.path.join(tmpdir, path)
Jakob Buchgraber699aece2018-02-19 12:49:30 +01001643
1644
Jakob Buchgraber02e07222018-02-19 15:05:56 +01001645def test_logs_for_status(bep_file, status):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001646 targets = []
Jakob Buchgraber94d5c212018-02-22 09:57:08 +01001647 with open(bep_file, encoding="utf-8") as f:
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001648 raw_data = f.read()
1649 decoder = json.JSONDecoder()
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001650
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001651 pos = 0
1652 while pos < len(raw_data):
Jakob Buchgraber0aabefc2019-07-16 16:18:36 +02001653 try:
Philipp Wollermann5b00a702019-07-18 11:21:38 +02001654 bep_obj, size = decoder.raw_decode(raw_data[pos:])
Jakob Buchgraber0aabefc2019-07-16 16:18:36 +02001655 except ValueError as e:
Philipp Wollermannce986af2019-07-18 14:46:05 +02001656 eprint("JSON decoding error: " + str(e))
Philipp Wollermann5b00a702019-07-18 11:21:38 +02001657 return targets
Jakob Buchgraber45e38632018-02-19 17:27:08 +01001658 if "testSummary" in bep_obj:
1659 test_target = bep_obj["id"]["testSummary"]["label"]
1660 test_status = bep_obj["testSummary"]["overallStatus"]
Jakob Buchgraberc874cdf2019-07-16 16:27:41 +02001661 if test_status in status:
Jakob Buchgraber45e38632018-02-19 17:27:08 +01001662 outputs = bep_obj["testSummary"]["failed"]
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001663 test_logs = []
1664 for output in outputs:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001665 test_logs.append(url2pathname(urlparse(output["uri"]).path))
Jakob Buchgraber45e38632018-02-19 17:27:08 +01001666 targets.append((test_target, test_logs))
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001667 pos += size + 1
1668 return targets
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001669
1670
Philipp Wollermannaf35abf2019-05-22 17:52:01 +02001671def execute_command_and_get_output(args, shell=False, fail_if_nonzero=True, print_output=True):
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001672 eprint(" ".join(args))
Florian Weikertc8642af2019-02-03 23:58:51 +01001673 process = subprocess.run(
1674 args,
1675 shell=shell,
1676 check=fail_if_nonzero,
1677 env=os.environ,
1678 stdout=subprocess.PIPE,
Philipp Wollermannf13804b2019-02-05 21:08:30 +01001679 errors="replace",
Florian Weikertc8642af2019-02-03 23:58:51 +01001680 universal_newlines=True,
1681 )
Florian Weikert736d06e2019-05-08 13:16:42 +02001682 if print_output:
1683 eprint(process.stdout)
1684
Florian Weikertc8642af2019-02-03 23:58:51 +01001685 return process.stdout
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001686
1687
joeleba76887952019-05-16 15:22:17 +02001688def execute_command(args, shell=False, fail_if_nonzero=True, cwd=None):
Philipp Wollermannf13804b2019-02-05 21:08:30 +01001689 eprint(" ".join(args))
Philipp Wollermann92cf51e2019-05-16 15:31:11 +02001690 return subprocess.run(
1691 args, shell=shell, check=fail_if_nonzero, env=os.environ, cwd=cwd
1692 ).returncode
Philipp Wollermannf13804b2019-02-05 21:08:30 +01001693
1694
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001695def execute_command_background(args):
1696 eprint(" ".join(args))
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001697 return subprocess.Popen(args, env=os.environ)
1698
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02001699
Jakob Buchgraber2b63a7f2019-07-16 15:27:34 +02001700def terminate_background_process(process):
1701 if process:
1702 process.terminate()
1703 try:
1704 process.wait(timeout=10)
1705 except subprocess.TimeoutExpired:
1706 process.kill()
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001707
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02001708
Philipp Wollermann7a185322019-05-18 22:15:48 +02001709def create_step(label, commands, platform, shards=1):
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01001710 if "docker-image" in PLATFORMS[platform]:
Florian Weikert736d06e2019-05-08 13:16:42 +02001711 step = create_docker_step(
Philipp Wollermannc05ac682019-01-19 12:37:28 +01001712 label, image=PLATFORMS[platform]["docker-image"], commands=commands
1713 )
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01001714 else:
Philipp Wollermannf3750fa2019-05-21 17:11:59 +02001715 step = {
1716 "label": label,
1717 "command": commands,
1718 "agents": {"queue": PLATFORMS[platform]["queue"]},
1719 }
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01001720
Florian Weikert736d06e2019-05-08 13:16:42 +02001721 if shards > 1:
1722 step["label"] += " (shard %n)"
1723 step["parallelism"] = shards
1724
Philipp Wollermann5b2f3fc2019-05-18 22:36:17 +02001725 # Enforce a global 8 hour job timeout.
1726 step["timeout_in_minutes"] = 8 * 60
1727
1728 # Automatically retry when an agent got lost (usually due to an infra flake).
Philipp Wollermannf22bba32019-07-18 11:22:50 +02001729 step["retry"] = {
1730 "automatic": [
1731 {"exit_status": -1, "limit": 3}, # Buildkite internal "agent lost" exit code
1732 {"exit_status": 137, "limit": 3}, # SIGKILL
1733 {"exit_status": 143, "limit": 3}, # SIGTERM
1734 ]
1735 }
Philipp Wollermann5b2f3fc2019-05-18 22:36:17 +02001736
Florian Weikert736d06e2019-05-08 13:16:42 +02001737 return step
1738
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01001739
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001740def create_docker_step(label, image, commands=None, additional_env_vars=None):
Philipp Wollermann0e051dd2019-05-16 11:37:52 +02001741 env = ["ANDROID_HOME", "ANDROID_NDK_HOME", "BUILDKITE_ARTIFACT_UPLOAD_DESTINATION"]
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001742 if additional_env_vars:
1743 env += ["{}={}".format(k, v) for k, v in additional_env_vars.items()]
1744
Philipp Wollermannc05ac682019-01-19 12:37:28 +01001745 step = {
Florian Weikertf20ae6f2019-01-16 14:32:09 +01001746 "label": label,
1747 "command": commands,
Philipp Wollermannb2fa2f62019-05-18 23:33:23 +02001748 "agents": {"queue": "default"},
Florian Weikertf20ae6f2019-01-16 14:32:09 +01001749 "plugins": {
Philipp Wollermannea128282019-05-08 11:56:14 +02001750 "docker#v3.2.0": {
Florian Weikertf20ae6f2019-01-16 14:32:09 +01001751 "always-pull": True,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001752 "environment": env,
Philipp Wollermannc05ac682019-01-19 12:37:28 +01001753 "image": image,
Florian Weikertf20ae6f2019-01-16 14:32:09 +01001754 "network": "host",
1755 "privileged": True,
1756 "propagate-environment": True,
Philipp Wollermann7aa95492019-05-18 22:03:24 +02001757 "propagate-uid-gid": True,
Florian Weikertf20ae6f2019-01-16 14:32:09 +01001758 "volumes": [
Philipp Wollermann7aa95492019-05-18 22:03:24 +02001759 "/etc/group:/etc/group:ro",
1760 "/etc/passwd:/etc/passwd:ro",
Philipp Wollermann338db4a2019-05-18 11:21:04 +02001761 "/opt:/opt:ro",
Philipp Wollermann7aa95492019-05-18 22:03:24 +02001762 "/var/lib/buildkite-agent:/var/lib/buildkite-agent",
Philipp Wollermann338db4a2019-05-18 11:21:04 +02001763 "/var/lib/gitmirrors:/var/lib/gitmirrors:ro",
1764 "/var/run/docker.sock:/var/run/docker.sock",
Florian Weikertf20ae6f2019-01-16 14:32:09 +01001765 ],
Florian Weikertf20ae6f2019-01-16 14:32:09 +01001766 }
1767 },
1768 }
Philipp Wollermannc05ac682019-01-19 12:37:28 +01001769 if not step["command"]:
1770 del step["command"]
1771 return step
Florian Weikertf20ae6f2019-01-16 14:32:09 +01001772
1773
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001774def print_project_pipeline(
Florian Weikertf20ae6f2019-01-16 14:32:09 +01001775 configs,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001776 project_name,
1777 http_config,
1778 file_config,
1779 git_repository,
1780 monitor_flaky_tests,
1781 use_but,
1782 incompatible_flags,
1783):
Florian Weikert843d7a02019-02-03 17:24:50 +01001784 task_configs = configs.get("tasks", None)
1785 if not task_configs:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001786 raise BuildkiteException("{0} pipeline configuration is empty.".format(project_name))
1787
Jakob Buchgraberaa2af382018-02-21 19:56:54 +01001788 pipeline_steps = []
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02001789 task_configs = filter_tasks_that_should_be_skipped(task_configs, pipeline_steps)
Jakob Buchgraberff2bdad2018-02-25 13:06:30 +01001790
Philipp Wollermanndac65512019-02-05 22:14:10 +01001791 # In Bazel Downstream Project pipelines, git_repository and project_name must be specified.
1792 is_downstream_project = (use_but or incompatible_flags) and git_repository and project_name
1793
Florian Weikert85208912019-03-07 17:08:39 +01001794 buildifier_config = configs.get("buildifier")
Philipp Wollermanndac65512019-02-05 22:14:10 +01001795 # Skip Buildifier when we test downstream projects.
Florian Weikert85208912019-03-07 17:08:39 +01001796 if buildifier_config and not is_downstream_project:
1797 buildifier_env_vars = {}
1798 if isinstance(buildifier_config, str):
1799 # Simple format:
1800 # ---
1801 # buildifier: latest
1802 buildifier_env_vars[BUILDIFIER_VERSION_ENV_VAR] = buildifier_config
1803 else:
1804 # Advanced format:
1805 # ---
1806 # buildifier:
1807 # version: latest
1808 # warnings: all
1809
Philipp Wollermannce986af2019-07-18 14:46:05 +02001810 def set_env_var(config_key, env_var_name):
Florian Weikert85208912019-03-07 17:08:39 +01001811 if config_key in buildifier_config:
1812 buildifier_env_vars[env_var_name] = buildifier_config[config_key]
1813
Philipp Wollermannce986af2019-07-18 14:46:05 +02001814 set_env_var("version", BUILDIFIER_VERSION_ENV_VAR)
1815 set_env_var("warnings", BUILDIFIER_WARNINGS_ENV_VAR)
Florian Weikert85208912019-03-07 17:08:39 +01001816
1817 if not buildifier_env_vars:
1818 raise BuildkiteException(
1819 'Invalid buildifier configuration entry "{}"'.format(buildifier_config)
1820 )
1821
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001822 pipeline_steps.append(
1823 create_docker_step(
Florian Weikertde96a6f2019-03-07 14:57:50 +01001824 BUILDIFIER_STEP_NAME,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001825 image=BUILDIFIER_DOCKER_IMAGE,
Florian Weikert85208912019-03-07 17:08:39 +01001826 additional_env_vars=buildifier_env_vars,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001827 )
1828 )
Philipp Wollermannc05ac682019-01-19 12:37:28 +01001829
Philipp Wollermanndac65512019-02-05 22:14:10 +01001830 # In Bazel Downstream Project pipelines, we should test the project at the last green commit.
Yun Peng376d2b32018-11-29 10:24:54 +01001831 git_commit = None
Philipp Wollermanndac65512019-02-05 22:14:10 +01001832 if is_downstream_project:
Florian Weikert35906542019-04-01 11:53:53 +02001833 last_green_commit_url = bazelci_last_green_commit_url(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001834 git_repository, DOWNSTREAM_PROJECTS[project_name]["pipeline_slug"]
1835 )
Florian Weikert35906542019-04-01 11:53:53 +02001836 git_commit = get_last_green_commit(last_green_commit_url)
Philipp Wollermanndac65512019-02-05 22:14:10 +01001837
Florian Weikert854fd852019-06-04 16:44:19 +02001838 config_hashes = set()
Florian Weikert843d7a02019-02-03 17:24:50 +01001839 for task, task_config in task_configs.items():
Florian Weikert854fd852019-06-04 16:44:19 +02001840 # We override the Bazel version in downstream pipelines. This means that two tasks that
1841 # only differ in the value of their explicit "bazel" field will be identical in the
1842 # downstream pipeline, thus leading to duplicate work.
1843 # Consequently, we filter those duplicate tasks here.
1844 if is_downstream_project:
1845 h = hash_task_config(task, task_config)
1846 if h in config_hashes:
1847 continue
Florian Weikert854fd852019-06-04 16:44:19 +02001848 config_hashes.add(h)
1849
Florian Weikert736d06e2019-05-08 13:16:42 +02001850 shards = task_config.get("shards", "1")
1851 try:
1852 shards = int(shards)
1853 except ValueError:
1854 raise BuildkiteException("Task {} has invalid shard value '{}'".format(task, shards))
1855
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001856 step = runner_step(
Florian Weikert843d7a02019-02-03 17:24:50 +01001857 platform=get_platform_for_task(task, task_config),
1858 task=task,
1859 task_name=task_config.get("name"),
1860 project_name=project_name,
1861 http_config=http_config,
1862 file_config=file_config,
1863 git_repository=git_repository,
1864 git_commit=git_commit,
1865 monitor_flaky_tests=monitor_flaky_tests,
1866 use_but=use_but,
1867 incompatible_flags=incompatible_flags,
Florian Weikert736d06e2019-05-08 13:16:42 +02001868 shards=shards,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001869 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001870 pipeline_steps.append(step)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001871
Yun Peng996efad2018-11-27 17:19:44 +01001872 pipeline_slug = os.getenv("BUILDKITE_PIPELINE_SLUG")
1873 all_downstream_pipeline_slugs = []
1874 for _, config in DOWNSTREAM_PROJECTS.items():
1875 all_downstream_pipeline_slugs.append(config["pipeline_slug"])
1876 # We don't need to update last green commit in the following cases:
Philipp Wollermannfce92bf2019-05-22 15:14:32 +02001877 # 1. This job is a GitHub pull request
1878 # 2. This job uses a custom built Bazel binary (in Bazel Downstream Projects pipeline)
1879 # 3. This job doesn't run on master branch (could be a custom build launched manually)
Philipp Wollermanne67eec42019-05-24 15:18:20 +02001880 # 4. We don't intend to run the same job in downstream with Bazel@HEAD (eg. google-bazel-presubmit)
1881 # 5. We are testing incompatible flags
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001882 if not (
1883 is_pull_request()
1884 or use_but
1885 or os.getenv("BUILDKITE_BRANCH") != "master"
1886 or pipeline_slug not in all_downstream_pipeline_slugs
1887 or incompatible_flags
1888 ):
Florian Weikertde96a6f2019-03-07 14:57:50 +01001889 # We need to call "Try Update Last Green Commit" even if there are failures,
1890 # since we don't want a failing Buildifier step to block the update of
1891 # the last green commit for this project.
1892 # try_update_last_green_commit() ensures that we don't update the commit
1893 # if any build or test steps fail.
1894 pipeline_steps.append({"wait": None, "continue_on_failure": True})
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001895 pipeline_steps.append(
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01001896 create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001897 label="Try Update Last Green Commit",
1898 commands=[
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001899 fetch_bazelcipy_command(),
Philipp Wollermann57b32682019-05-18 22:09:27 +02001900 PLATFORMS[DEFAULT_PLATFORM]["python"]
1901 + " bazelci.py try_update_last_green_commit",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001902 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02001903 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001904 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001905 )
Yun Peng43239b02018-11-23 13:57:34 +01001906
Florian Weikert778251c2019-04-25 15:14:44 +02001907 if "validate_config" in configs:
Florian Weikertf52f91a2019-05-08 15:19:30 +02001908 pipeline_steps += create_config_validation_steps()
Florian Weikert778251c2019-04-25 15:14:44 +02001909
Florian Weikert09813a02019-10-26 19:34:33 +02001910 if use_bazelisk_migrate() and not is_downstream_project:
1911 # Print results of bazelisk --migrate in project pipelines that explicitly set
1912 # the USE_BAZELISK_MIGRATE env var, but that are not being run as part of a
1913 # downstream pipeline.
1914 number = os.getenv("BUILDKITE_BUILD_NUMBER")
1915 pipeline_steps += get_steps_for_aggregating_migration_results(
1916 number, script_org, script_branch
1917 )
1918
Florian Weikertd79dc502019-05-13 09:51:05 +02001919 print_pipeline_steps(pipeline_steps, handle_emergencies=not is_downstream_project)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001920
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001921
Florian Weikert854fd852019-06-04 16:44:19 +02001922def hash_task_config(task_name, task_config):
1923 # Two task configs c1 and c2 have the same hash iff they lead to two functionally identical jobs
1924 # in the downstream pipeline. This function discards the "bazel" field (since it's being
Philipp Wollermannce986af2019-07-18 14:46:05 +02001925 # overridden) and the "name" field (since it has no effect on the actual work).
Florian Weikert854fd852019-06-04 16:44:19 +02001926 # Moreover, it adds an explicit "platform" field if that's missing.
1927 cpy = task_config.copy()
1928 cpy.pop("bazel", None)
1929 cpy.pop("name", None)
1930 if "platform" not in cpy:
1931 cpy["platform"] = task_name
1932
1933 m = hashlib.md5()
1934 for key in sorted(cpy):
Florian Weikert8186c392019-06-05 12:53:39 +02001935 value = "%s:%s;" % (key, cpy[key])
1936 m.update(value.encode("utf-8"))
Florian Weikert854fd852019-06-04 16:44:19 +02001937
1938 return m.digest()
1939
1940
Florian Weikert843d7a02019-02-03 17:24:50 +01001941def get_platform_for_task(task, task_config):
1942 # Most pipeline configurations have exactly one task per platform, which makes it
1943 # convenient to use the platform name as task ID. Consequently, we use the
1944 # task ID as platform if there is no explicit "platform" field.
1945 return task_config.get("platform", task)
1946
1947
Florian Weikertf52f91a2019-05-08 15:19:30 +02001948def create_config_validation_steps():
1949 output = execute_command_and_get_output(
1950 ["git", "diff-tree", "--no-commit-id", "--name-only", "-r", os.getenv("BUILDKITE_COMMIT")]
1951 )
1952 config_files = [
1953 l
1954 for l in output.split("\n")
1955 if l.startswith(".bazelci/") and os.path.splitext(l)[1] in CONFIG_FILE_EXTENSIONS
1956 ]
Florian Weikertf52f91a2019-05-08 15:19:30 +02001957 return [
1958 create_step(
1959 label=":cop: Validate {}".format(f),
1960 commands=[
1961 fetch_bazelcipy_command(),
1962 "{} bazelci.py project_pipeline --file_config={}".format(
Philipp Wollermann57b32682019-05-18 22:09:27 +02001963 PLATFORMS[DEFAULT_PLATFORM]["python"], f
Florian Weikertf52f91a2019-05-08 15:19:30 +02001964 ),
1965 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02001966 platform=DEFAULT_PLATFORM,
Florian Weikertf52f91a2019-05-08 15:19:30 +02001967 )
1968 for f in config_files
1969 ]
1970
1971
Florian Weikertd79dc502019-05-13 09:51:05 +02001972def print_pipeline_steps(pipeline_steps, handle_emergencies=True):
1973 if handle_emergencies:
1974 emergency_step = create_emergency_announcement_step_if_necessary()
1975 if emergency_step:
1976 pipeline_steps.insert(0, emergency_step)
Florian Weikert13215a82019-05-10 12:42:21 +02001977
1978 print(yaml.dump({"steps": pipeline_steps}))
1979
1980
1981def create_emergency_announcement_step_if_necessary():
1982 style = "error"
1983 message, issue_url, last_good_bazel = None, None, None
1984 try:
1985 emergency_settings = load_remote_yaml_file(EMERGENCY_FILE_URL)
1986 message = emergency_settings.get("message")
1987 issue_url = emergency_settings.get("issue_url")
1988 last_good_bazel = emergency_settings.get("last_good_bazel")
1989 except urllib.error.HTTPError as ex:
1990 message = str(ex)
1991 style = "warning"
1992
1993 if not any([message, issue_url, last_good_bazel]):
1994 return
1995
1996 text = '<span class="h1">:rotating_light: Emergency :rotating_light:</span>\n'
1997 if message:
1998 text += "- {}\n".format(message)
1999 if issue_url:
2000 text += '- Please check this <a href="{}">issue</a> for more details.\n'.format(issue_url)
2001 if last_good_bazel:
2002 text += (
2003 "- Default Bazel version is *{}*, "
2004 "unless the pipeline configuration specifies an explicit version."
2005 ).format(last_good_bazel)
2006
2007 return create_step(
2008 label=":rotating_light: Emergency :rotating_light:",
Philipp Wollermann7590b962019-05-16 11:35:03 +02002009 commands=[
2010 'buildkite-agent annotate --append --style={} --context "omg" "{}"'.format(style, text)
2011 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002012 platform=DEFAULT_PLATFORM,
Florian Weikert13215a82019-05-10 12:42:21 +02002013 )
2014
2015
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002016def runner_step(
2017 platform,
Florian Weikert843d7a02019-02-03 17:24:50 +01002018 task,
2019 task_name=None,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002020 project_name=None,
2021 http_config=None,
2022 file_config=None,
2023 git_repository=None,
2024 git_commit=None,
2025 monitor_flaky_tests=False,
2026 use_but=False,
2027 incompatible_flags=None,
Florian Weikert736d06e2019-05-08 13:16:42 +02002028 shards=1,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002029):
Philipp Wollermann57b32682019-05-18 22:09:27 +02002030 command = PLATFORMS[platform]["python"] + " bazelci.py runner --task=" + task
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002031 if http_config:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002032 command += " --http_config=" + http_config
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002033 if file_config:
2034 command += " --file_config=" + file_config
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002035 if git_repository:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002036 command += " --git_repository=" + git_repository
Yun Peng376d2b32018-11-29 10:24:54 +01002037 if git_commit:
2038 command += " --git_commit=" + git_commit
Jakob Buchgraberc340f582018-06-22 13:48:33 +02002039 if monitor_flaky_tests:
2040 command += " --monitor_flaky_tests"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002041 if use_but:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002042 command += " --use_but"
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002043 for flag in incompatible_flags or []:
Yun Peng4be92b32018-11-30 09:48:29 +01002044 command += " --incompatible_flag=" + flag
Florian Weikert843d7a02019-02-03 17:24:50 +01002045 label = create_label(platform, project_name, task_name=task_name)
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002046 return create_step(
Florian Weikert736d06e2019-05-08 13:16:42 +02002047 label=label, commands=[fetch_bazelcipy_command(), command], platform=platform, shards=shards
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002048 )
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002049
2050
2051def fetch_bazelcipy_command():
Philipp Wollermanne67eec42019-05-24 15:18:20 +02002052 return "curl -sS {0} -o bazelci.py".format(SCRIPT_URL)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002053
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002054
Yun Peng002eab92018-12-17 18:28:14 +01002055def fetch_incompatible_flag_verbose_failures_command():
Philipp Wollermannfe145a52019-01-11 13:16:48 +01002056 return "curl -sS {0} -o incompatible_flag_verbose_failures.py".format(
Philipp Wollermanne67eec42019-05-24 15:18:20 +02002057 INCOMPATIBLE_FLAG_VERBOSE_FAILURES_URL
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002058 )
Yun Peng002eab92018-12-17 18:28:14 +01002059
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002060
Yun Peng8975c6b2019-02-28 11:55:55 +01002061def fetch_aggregate_incompatible_flags_test_result_command():
2062 return "curl -sS {0} -o aggregate_incompatible_flags_test_result.py".format(
Philipp Wollermanne67eec42019-05-24 15:18:20 +02002063 AGGREGATE_INCOMPATIBLE_TEST_RESULT_URL
Yun Peng8975c6b2019-02-28 11:55:55 +01002064 )
2065
2066
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002067def upload_project_pipeline_step(
2068 project_name, git_repository, http_config, file_config, incompatible_flags
2069):
2070 pipeline_command = (
2071 '{0} bazelci.py project_pipeline --project_name="{1}" ' + "--git_repository={2}"
Philipp Wollermann57b32682019-05-18 22:09:27 +02002072 ).format(PLATFORMS[DEFAULT_PLATFORM]["python"], project_name, git_repository)
Philipp Wollermann639c0452019-01-03 11:23:54 +01002073 if incompatible_flags is None:
Yun Peng4be92b32018-11-30 09:48:29 +01002074 pipeline_command += " --use_but"
Yun Peng95908792018-11-30 15:03:55 +01002075 else:
2076 for flag in incompatible_flags:
2077 pipeline_command += " --incompatible_flag=" + flag
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002078 if http_config:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002079 pipeline_command += " --http_config=" + http_config
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002080 if file_config:
2081 pipeline_command += " --file_config=" + file_config
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002082 pipeline_command += " | buildkite-agent pipeline upload"
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002083
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002084 return create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002085 label="Setup {0}".format(project_name),
2086 commands=[fetch_bazelcipy_command(), pipeline_command],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002087 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002088 )
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002089
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002090
Florian Weikert843d7a02019-02-03 17:24:50 +01002091def create_label(platform, project_name, build_only=False, test_only=False, task_name=None):
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002092 if build_only and test_only:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002093 raise BuildkiteException("build_only and test_only cannot be true at the same time")
Florian Weikert843d7a02019-02-03 17:24:50 +01002094 platform_display_name = PLATFORMS[platform]["emoji-name"]
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002095
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002096 if build_only:
2097 label = "Build "
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002098 elif test_only:
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002099 label = "Test "
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002100 else:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002101 label = ""
2102
Florian Weikert843d7a02019-02-03 17:24:50 +01002103 platform_label = (
2104 "{0} on {1}".format(task_name, platform_display_name)
2105 if task_name
2106 else platform_display_name
2107 )
2108
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002109 if project_name:
Florian Weikert843d7a02019-02-03 17:24:50 +01002110 label += "{0} ({1})".format(project_name, platform_label)
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002111 else:
Florian Weikert843d7a02019-02-03 17:24:50 +01002112 label += platform_label
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002113
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002114 return label
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002115
2116
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002117def bazel_build_step(
Florian Weikert843d7a02019-02-03 17:24:50 +01002118 task,
2119 platform,
2120 project_name,
2121 http_config=None,
2122 file_config=None,
2123 build_only=False,
2124 test_only=False,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002125):
Philipp Wollermann57b32682019-05-18 22:09:27 +02002126 pipeline_command = PLATFORMS[platform]["python"] + " bazelci.py runner"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002127 if build_only:
Philipp Wollermannc52e26a2019-05-18 22:10:47 +02002128 pipeline_command += " --build_only --save_but"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002129 if test_only:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002130 pipeline_command += " --test_only"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002131 if http_config:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002132 pipeline_command += " --http_config=" + http_config
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002133 if file_config:
2134 pipeline_command += " --file_config=" + file_config
Florian Weikert843d7a02019-02-03 17:24:50 +01002135 pipeline_command += " --task=" + task
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002136
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002137 return create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002138 label=create_label(platform, project_name, build_only, test_only),
2139 commands=[fetch_bazelcipy_command(), pipeline_command],
2140 platform=platform,
2141 )
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002142
2143
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02002144def filter_tasks_that_should_be_skipped(task_configs, pipeline_steps):
2145 skip_tasks = get_skip_tasks()
2146 if not skip_tasks:
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02002147 return task_configs
2148
2149 actually_skipped = []
2150 skip_tasks = set(skip_tasks)
2151 for task in list(task_configs.keys()):
2152 if task in skip_tasks:
2153 actually_skipped.append(task)
2154 del task_configs[task]
2155 skip_tasks.remove(task)
2156
2157 if not task_configs:
2158 raise BuildkiteException(
2159 "Nothing to do since all tasks in the configuration should be skipped."
2160 )
2161
2162 annotations = []
2163 if actually_skipped:
2164 annotations.append(
2165 ("info", "Skipping the following task(s): {}".format(", ".join(actually_skipped)))
2166 )
2167
2168 if skip_tasks:
2169 annotations.append(
2170 (
2171 "warning",
2172 (
2173 "The following tasks should have been skipped, "
2174 "but were not part of the configuration: {}"
2175 ).format(", ".join(skip_tasks)),
2176 )
2177 )
2178
2179 if annotations:
2180 print_skip_task_annotations(annotations, pipeline_steps)
2181
2182 return task_configs
2183
2184
2185def get_skip_tasks():
2186 value = os.getenv(SKIP_TASKS_ENV_VAR, "")
2187 return [v for v in value.split(",") if v]
2188
2189
2190def print_skip_task_annotations(annotations, pipeline_steps):
2191 commands = [
2192 "buildkite-agent annotate --style={} '{}' --context 'ctx-{}'".format(s, t, hash(t))
2193 for s, t in annotations
2194 ]
2195 pipeline_steps.append(
Philipp Wollermann7a185322019-05-18 22:15:48 +02002196 create_step(
2197 label=":pipeline: Print information about skipped tasks",
2198 commands=commands,
2199 platform=DEFAULT_PLATFORM,
2200 )
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02002201 )
2202
2203
Florian Weikert843d7a02019-02-03 17:24:50 +01002204def print_bazel_publish_binaries_pipeline(task_configs, http_config, file_config):
2205 if not task_configs:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002206 raise BuildkiteException("Bazel publish binaries pipeline configuration is empty.")
2207
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02002208 pipeline_steps = []
2209 task_configs = filter_tasks_that_should_be_skipped(task_configs, pipeline_steps)
2210
Florian Weikert843d7a02019-02-03 17:24:50 +01002211 platforms = [get_platform_for_task(t, tc) for t, tc in task_configs.items()]
Philipp Wollermann783d1672019-06-06 13:35:30 +02002212
2213 # These are the platforms that the bazel_publish_binaries.yml config is actually building.
2214 configured_platforms = set(filter(should_publish_binaries_for_platform, platforms))
Philipp Wollermanna2ea5d82018-08-27 14:12:10 +02002215
Philipp Wollermann783d1672019-06-06 13:35:30 +02002216 # These are the platforms that we want to build and publish according to this script.
2217 expected_platforms = set(filter(should_publish_binaries_for_platform, PLATFORMS))
Florian Weikert843d7a02019-02-03 17:24:50 +01002218
Philipp Wollermannf64bf942019-06-06 14:34:41 +02002219 if not expected_platforms.issubset(configured_platforms):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002220 raise BuildkiteException(
2221 "Bazel publish binaries pipeline needs to build Bazel for every commit on all publish_binary-enabled platforms."
2222 )
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01002223
Yun Pengd352b6d2018-10-17 13:28:39 +02002224 # Build Bazel
Florian Weikert843d7a02019-02-03 17:24:50 +01002225 for task, task_config in task_configs.items():
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002226 pipeline_steps.append(
Florian Weikert843d7a02019-02-03 17:24:50 +01002227 bazel_build_step(
2228 task,
2229 get_platform_for_task(task, task_config),
2230 "Bazel",
2231 http_config,
2232 file_config,
2233 build_only=True,
2234 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002235 )
Jakob Buchgraber4631a032018-03-22 17:12:46 +01002236
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002237 pipeline_steps.append("wait")
Jakob Buchgraber9d6ca8a2018-03-22 17:30:09 +01002238
Yun Pengc2dd6522018-10-17 12:58:35 +02002239 # If all builds succeed, publish the Bazel binaries to GCS.
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002240 pipeline_steps.append(
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002241 create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002242 label="Publish Bazel Binaries",
Philipp Wollermann57b32682019-05-18 22:09:27 +02002243 commands=[
2244 fetch_bazelcipy_command(),
2245 PLATFORMS[DEFAULT_PLATFORM]["python"] + " bazelci.py publish_binaries",
2246 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002247 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002248 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002249 )
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01002250
Florian Weikert13215a82019-05-10 12:42:21 +02002251 print_pipeline_steps(pipeline_steps)
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01002252
2253
Florian Weikert843d7a02019-02-03 17:24:50 +01002254def should_publish_binaries_for_platform(platform):
2255 if platform not in PLATFORMS:
2256 raise BuildkiteException("Unknown platform '{}'".format(platform))
2257
2258 return PLATFORMS[platform]["publish_binary"]
2259
2260
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01002261def print_disabled_projects_info_box_step():
2262 info_text = ["Downstream testing is disabled for the following projects :sadpanda:"]
2263 for project, config in DOWNSTREAM_PROJECTS.items():
2264 disabled_reason = config.get("disabled_reason", None)
2265 if disabled_reason:
2266 info_text.append("* **%s**: %s" % (project, disabled_reason))
2267
2268 if len(info_text) == 1:
2269 return None
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002270 return create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002271 label=":sadpanda:",
2272 commands=[
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002273 'buildkite-agent annotate --append --style=info "\n' + "\n".join(info_text) + '\n"'
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01002274 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002275 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002276 )
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01002277
Yun Peng6528e652019-01-02 14:41:07 +01002278
2279def print_incompatible_flags_info_box_step(incompatible_flags_map):
2280 info_text = ["Build and test with the following incompatible flags:"]
2281
2282 for flag in incompatible_flags_map:
2283 info_text.append("* **%s**: %s" % (flag, incompatible_flags_map[flag]))
2284
2285 if len(info_text) == 1:
2286 return None
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01002287 return create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002288 label="Incompatible flags info",
2289 commands=[
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002290 'buildkite-agent annotate --append --style=info "\n' + "\n".join(info_text) + '\n"'
Yun Peng6528e652019-01-02 14:41:07 +01002291 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002292 platform=DEFAULT_PLATFORM,
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002293 )
Yun Peng6528e652019-01-02 14:41:07 +01002294
2295
Yun Peng7d302f62019-01-10 16:56:15 +01002296def fetch_incompatible_flags():
Yun Peng6528e652019-01-02 14:41:07 +01002297 """
2298 Return a list of incompatible flags to be tested in downstream with the current release Bazel
2299 """
Yun Peng7d302f62019-01-10 16:56:15 +01002300 incompatible_flags = {}
2301
2302 # If INCOMPATIBLE_FLAGS environment variable is set, we get incompatible flags from it.
2303 if "INCOMPATIBLE_FLAGS" in os.environ:
2304 for flag in os.environ["INCOMPATIBLE_FLAGS"].split():
2305 # We are not able to get the github link for this flag from INCOMPATIBLE_FLAGS,
2306 # so just assign the url to empty string.
2307 incompatible_flags[flag] = ""
2308 return incompatible_flags
2309
Yun Peng6528e652019-01-02 14:41:07 +01002310 # Get bazel major version on CI, eg. 0.21 from "Build label: 0.21.0\n..."
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002311 output = subprocess.check_output(
2312 ["bazel", "--nomaster_bazelrc", "--bazelrc=/dev/null", "version"]
2313 ).decode("utf-8")
Yun Peng6528e652019-01-02 14:41:07 +01002314 bazel_major_version = output.split()[2].rsplit(".", 1)[0]
2315
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002316 output = subprocess.check_output(
2317 [
2318 "curl",
Philipp Wollermann6f4058f2019-08-21 13:58:50 +02002319 "https://api.github.com/search/issues?per_page=100&q=repo:bazelbuild/bazel+label:migration-%s"
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002320 % bazel_major_version,
2321 ]
2322 ).decode("utf-8")
Yun Peng6528e652019-01-02 14:41:07 +01002323 issue_info = json.loads(output)
2324
Yun Peng6528e652019-01-02 14:41:07 +01002325 for issue in issue_info["items"]:
Yun Peng6528e652019-01-02 14:41:07 +01002326 # Every incompatible flags issue should start with "<incompatible flag name (without --)>:"
2327 name = "--" + issue["title"].split(":")[0]
2328 url = issue["html_url"]
2329 if name.startswith("--incompatible_"):
2330 incompatible_flags[name] = url
2331 else:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002332 eprint(
Philipp Wollermann639c0452019-01-03 11:23:54 +01002333 f"{name} is not recognized as an incompatible flag, please modify the issue title "
2334 f'of {url} to "<incompatible flag name (without --)>:..."'
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002335 )
Yun Peng6528e652019-01-02 14:41:07 +01002336
2337 return incompatible_flags
2338
2339
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002340def print_bazel_downstream_pipeline(
Florian Weikert843d7a02019-02-03 17:24:50 +01002341 task_configs, http_config, file_config, test_incompatible_flags, test_disabled_projects
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002342):
Florian Weikert843d7a02019-02-03 17:24:50 +01002343 if not task_configs:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002344 raise BuildkiteException("Bazel downstream pipeline configuration is empty.")
2345
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02002346 pipeline_steps = []
2347 task_configs = filter_tasks_that_should_be_skipped(task_configs, pipeline_steps)
2348
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002349 pipeline_steps = []
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002350
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01002351 info_box_step = print_disabled_projects_info_box_step()
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01002352 if info_box_step is not None:
2353 pipeline_steps.append(info_box_step)
2354
Yun Peng5599ca22019-01-16 12:32:41 +01002355 if not test_incompatible_flags:
Florian Weikert843d7a02019-02-03 17:24:50 +01002356 for task, task_config in task_configs.items():
Yun Peng5599ca22019-01-16 12:32:41 +01002357 pipeline_steps.append(
Florian Weikert843d7a02019-02-03 17:24:50 +01002358 bazel_build_step(
2359 task,
2360 get_platform_for_task(task, task_config),
2361 "Bazel",
2362 http_config,
2363 file_config,
2364 build_only=True,
2365 )
Yun Peng5599ca22019-01-16 12:32:41 +01002366 )
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002367
Yun Peng5599ca22019-01-16 12:32:41 +01002368 pipeline_steps.append("wait")
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002369
Yun Pengb9998d12018-12-03 10:18:28 +01002370 incompatible_flags = None
Yun Peng7a539ef2018-11-30 15:07:24 +01002371 if test_incompatible_flags:
Yun Peng7d302f62019-01-10 16:56:15 +01002372 incompatible_flags_map = fetch_incompatible_flags()
Yun Peng6528e652019-01-02 14:41:07 +01002373 info_box_step = print_incompatible_flags_info_box_step(incompatible_flags_map)
2374 if info_box_step is not None:
2375 pipeline_steps.append(info_box_step)
2376 incompatible_flags = list(incompatible_flags_map.keys())
Yun Peng7a539ef2018-11-30 15:07:24 +01002377
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002378 for project, config in DOWNSTREAM_PROJECTS.items():
Yun Peng996efad2018-11-27 17:19:44 +01002379 disabled_reason = config.get("disabled_reason", None)
Yun Pengfb759fa2018-12-13 11:35:39 +01002380 # If test_disabled_projects is true, we add configs for disabled projects.
Florian Weikert7b3f17e2019-03-14 13:52:42 +01002381 # If test_disabled_projects is false, we add configs for not disabled projects.
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002382 if (test_disabled_projects and disabled_reason) or (
2383 not test_disabled_projects and not disabled_reason
2384 ):
Yun Peng996efad2018-11-27 17:19:44 +01002385 pipeline_steps.append(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002386 upload_project_pipeline_step(
2387 project_name=project,
2388 git_repository=config["git_repository"],
2389 http_config=config.get("http_config", None),
2390 file_config=config.get("file_config", None),
2391 incompatible_flags=incompatible_flags,
2392 )
2393 )
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002394
Yun Peng002eab92018-12-17 18:28:14 +01002395 if test_incompatible_flags:
Yun Peng002eab92018-12-17 18:28:14 +01002396 current_build_number = os.environ.get("BUILDKITE_BUILD_NUMBER", None)
2397 if not current_build_number:
2398 raise BuildkiteException("Not running inside Buildkite")
Yun Peng8975c6b2019-02-28 11:55:55 +01002399 if use_bazelisk_migrate():
Florian Weikert09813a02019-10-26 19:34:33 +02002400 pipeline_steps += get_steps_for_aggregating_migration_results(
2401 current_build_number
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002402 )
Yun Peng8975c6b2019-02-28 11:55:55 +01002403 else:
2404 pipeline_steps.append({"wait": "~", "continue_on_failure": "true"})
2405 pipeline_steps.append(
2406 create_step(
2407 label="Test failing jobs with incompatible flag separately",
2408 commands=[
2409 fetch_bazelcipy_command(),
2410 fetch_incompatible_flag_verbose_failures_command(),
Philipp Wollermann57b32682019-05-18 22:09:27 +02002411 PLATFORMS[DEFAULT_PLATFORM]["python"]
Yun Peng8975c6b2019-02-28 11:55:55 +01002412 + " incompatible_flag_verbose_failures.py --build_number=%s | buildkite-agent pipeline upload"
2413 % current_build_number,
2414 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002415 platform=DEFAULT_PLATFORM,
Yun Peng8975c6b2019-02-28 11:55:55 +01002416 )
2417 )
Yun Peng002eab92018-12-17 18:28:14 +01002418
Florian Weikert2896edb2019-04-04 16:12:47 +02002419 if (
2420 not test_disabled_projects
2421 and not test_incompatible_flags
2422 and os.getenv("BUILDKITE_BRANCH") == "master"
2423 ):
Florian Weikert35906542019-04-01 11:53:53 +02002424 # Only update the last green downstream commit in the regular Bazel@HEAD + Downstream pipeline.
2425 pipeline_steps.append("wait")
2426 pipeline_steps.append(
2427 create_step(
2428 label="Try Update Last Green Downstream Commit",
2429 commands=[
2430 fetch_bazelcipy_command(),
Philipp Wollermann57b32682019-05-18 22:09:27 +02002431 PLATFORMS[DEFAULT_PLATFORM]["python"]
2432 + " bazelci.py try_update_last_green_downstream_commit",
Florian Weikert35906542019-04-01 11:53:53 +02002433 ],
Philipp Wollermann7a185322019-05-18 22:15:48 +02002434 platform=DEFAULT_PLATFORM,
Florian Weikert35906542019-04-01 11:53:53 +02002435 )
2436 )
2437
Florian Weikert13215a82019-05-10 12:42:21 +02002438 print_pipeline_steps(pipeline_steps)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002439
2440
Florian Weikert09813a02019-10-26 19:34:33 +02002441def get_steps_for_aggregating_migration_results(current_build_number):
2442 parts = [
2443 PLATFORMS[DEFAULT_PLATFORM]["python"],
2444 "aggregate_incompatible_flags_test_result.py",
2445 "--build_number=%s" % current_build_number,
2446 "--pipeline=%s" % os.getenv("BUILDKITE_PIPELINE_SLUG"),
2447 ]
2448 return [
2449 {"wait": "~", "continue_on_failure": "true"},
2450 create_step(
2451 label="Aggregate incompatible flags test result",
2452 commands=[
2453 fetch_bazelcipy_command(),
2454 fetch_aggregate_incompatible_flags_test_result_command(),
2455 " ".join(parts),
2456 ],
2457 platform=DEFAULT_PLATFORM,
2458 ),
2459 ]
2460
2461
Yun Pengc2dd6522018-10-17 12:58:35 +02002462def bazelci_builds_download_url(platform, git_commit):
Philipp Wollermanne67eec42019-05-24 15:18:20 +02002463 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
2464 return "https://storage.googleapis.com/{}/artifacts/{}/{}/bazel".format(
2465 bucket_name, platform, git_commit
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002466 )
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002467
2468
Yun Peng20d45602018-10-18 13:27:05 +02002469def bazelci_builds_gs_url(platform, git_commit):
Philipp Wollermanne67eec42019-05-24 15:18:20 +02002470 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
2471 return "gs://{}/artifacts/{}/{}/bazel".format(bucket_name, platform, git_commit)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002472
2473
Jakob Buchgraber76381e02018-02-19 16:19:56 +01002474def bazelci_builds_metadata_url():
Philipp Wollermanne67eec42019-05-24 15:18:20 +02002475 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-builds"
2476 return "gs://{}/metadata/latest.json".format(bucket_name)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002477
2478
Yun Peng996efad2018-11-27 17:19:44 +01002479def bazelci_last_green_commit_url(git_repository, pipeline_slug):
Philipp Wollermanne67eec42019-05-24 15:18:20 +02002480 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-untrusted-builds"
2481 return "gs://{}/last_green_commit/{}/{}".format(
2482 bucket_name, git_repository[len("https://") :], pipeline_slug
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002483 )
Yun Pengafe67d42018-11-23 17:06:43 +01002484
2485
Florian Weikert35906542019-04-01 11:53:53 +02002486def bazelci_last_green_downstream_commit_url():
Philipp Wollermanne67eec42019-05-24 15:18:20 +02002487 bucket_name = "bazel-testing-builds" if THIS_IS_TESTING else "bazel-untrusted-builds"
2488 return "gs://{}/last_green_commit/downstream_pipeline".format(bucket_name)
Florian Weikert35906542019-04-01 11:53:53 +02002489
2490
2491def get_last_green_commit(last_green_commit_url):
Yun Peng61a448f2018-11-23 17:11:46 +01002492 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002493 return (
2494 subprocess.check_output(
2495 [gsutil_command(), "cat", last_green_commit_url], env=os.environ
2496 )
2497 .decode("utf-8")
2498 .strip()
2499 )
Yun Peng61a448f2018-11-23 17:11:46 +01002500 except subprocess.CalledProcessError:
2501 return None
Yun Peng43239b02018-11-23 13:57:34 +01002502
2503
Yun Peng358cd882018-11-29 10:25:18 +01002504def try_update_last_green_commit():
Florian Weikertde96a6f2019-03-07 14:57:50 +01002505 org_slug = os.getenv("BUILDKITE_ORGANIZATION_SLUG")
Yun Peng358cd882018-11-29 10:25:18 +01002506 pipeline_slug = os.getenv("BUILDKITE_PIPELINE_SLUG")
Florian Weikertde96a6f2019-03-07 14:57:50 +01002507 build_number = os.getenv("BUILDKITE_BUILD_NUMBER")
2508 current_job_id = os.getenv("BUILDKITE_JOB_ID")
2509
2510 client = BuildkiteClient(org=org_slug, pipeline=pipeline_slug)
2511 build_info = client.get_build_info(build_number)
2512
2513 # Find any failing steps other than Buildifier and "try update last green".
Philipp Wollermannce986af2019-07-18 14:46:05 +02002514 def has_failed(job):
Florian Weikertbd40a272019-03-08 10:20:18 +01002515 state = job.get("state")
2516 # Ignore steps that don't have a state (like "wait").
Florian Weikertde96a6f2019-03-07 14:57:50 +01002517 return (
Florian Weikert35906542019-04-01 11:53:53 +02002518 state is not None
2519 and state != "passed"
Florian Weikertde96a6f2019-03-07 14:57:50 +01002520 and job["id"] != current_job_id
2521 and job["name"] != BUILDIFIER_STEP_NAME
2522 )
2523
Philipp Wollermannce986af2019-07-18 14:46:05 +02002524 failing_jobs = [j["name"] for j in build_info["jobs"] if has_failed(j)]
Florian Weikertde96a6f2019-03-07 14:57:50 +01002525 if failing_jobs:
2526 raise BuildkiteException(
2527 "Cannot update last green commit due to {} failing step(s): {}".format(
2528 len(failing_jobs), ", ".join(failing_jobs)
2529 )
2530 )
2531
Yun Peng358cd882018-11-29 10:25:18 +01002532 git_repository = os.getenv("BUILDKITE_REPO")
Florian Weikert35906542019-04-01 11:53:53 +02002533 last_green_commit_url = bazelci_last_green_commit_url(git_repository, pipeline_slug)
2534 update_last_green_commit_if_newer(last_green_commit_url)
2535
2536
2537def update_last_green_commit_if_newer(last_green_commit_url):
2538 last_green_commit = get_last_green_commit(last_green_commit_url)
Yun Peng358cd882018-11-29 10:25:18 +01002539 current_commit = subprocess.check_output(["git", "rev-parse", "HEAD"]).decode("utf-8").strip()
2540 if last_green_commit:
Yun Peng384058a2019-01-15 13:26:35 +01002541 execute_command(["git", "fetch", "-v", "origin", last_green_commit])
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002542 result = (
2543 subprocess.check_output(
2544 ["git", "rev-list", "%s..%s" % (last_green_commit, current_commit)]
2545 )
2546 .decode("utf-8")
2547 .strip()
2548 )
Philipp Wollermannce986af2019-07-18 14:46:05 +02002549 else:
2550 result = None
Yun Peng358cd882018-11-29 10:25:18 +01002551
Philipp Wollermann639c0452019-01-03 11:23:54 +01002552 # If current_commit is newer that last_green_commit, `git rev-list A..B` will output a bunch of
2553 # commits, otherwise the output should be empty.
Yun Peng358cd882018-11-29 10:25:18 +01002554 if not last_green_commit or result:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002555 execute_command(
Florian Weikert35906542019-04-01 11:53:53 +02002556 ["echo %s | %s cp - %s" % (current_commit, gsutil_command(), last_green_commit_url)],
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002557 shell=True,
2558 )
Yun Peng358cd882018-11-29 10:25:18 +01002559 else:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002560 eprint(
2561 "Updating abandoned: last green commit (%s) is not older than current commit (%s)."
2562 % (last_green_commit, current_commit)
2563 )
2564
Yun Peng358cd882018-11-29 10:25:18 +01002565
Florian Weikert35906542019-04-01 11:53:53 +02002566def try_update_last_green_downstream_commit():
2567 last_green_commit_url = bazelci_last_green_downstream_commit_url()
2568 update_last_green_commit_if_newer(last_green_commit_url)
2569
2570
Jakob Buchgraber76381e02018-02-19 16:19:56 +01002571def latest_generation_and_build_number():
Philipp Wollermannce986af2019-07-18 14:46:05 +02002572 generation = None
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002573 output = None
Philipp Wollermannce986af2019-07-18 14:46:05 +02002574 for attempt in range(5):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002575 output = subprocess.check_output(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002576 [gsutil_command(), "stat", bazelci_builds_metadata_url()], env=os.environ
2577 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002578 match = re.search("Generation:[ ]*([0-9]+)", output.decode("utf-8"))
2579 if not match:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002580 raise BuildkiteException("Couldn't parse generation. gsutil output format changed?")
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002581 generation = match.group(1)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002582
Philipp Wollermannff39ef52018-02-21 14:18:52 +01002583 match = re.search(r"Hash \(md5\):[ ]*([^\s]+)", output.decode("utf-8"))
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002584 if not match:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002585 raise BuildkiteException("Couldn't parse md5 hash. gsutil output format changed?")
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002586 expected_md5hash = base64.b64decode(match.group(1))
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002587
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002588 output = subprocess.check_output(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002589 [gsutil_command(), "cat", bazelci_builds_metadata_url()], env=os.environ
2590 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002591 hasher = hashlib.md5()
2592 hasher.update(output)
2593 actual_md5hash = hasher.digest()
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002594
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002595 if expected_md5hash == actual_md5hash:
2596 break
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002597 info = json.loads(output.decode("utf-8"))
Philipp Wollermannce986af2019-07-18 14:46:05 +02002598 return generation, info["build_number"]
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002599
Jakob Buchgraber699aece2018-02-19 12:49:30 +01002600
Jakob Buchgraber88083fd2018-02-18 17:23:35 +01002601def sha256_hexdigest(filename):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002602 sha256 = hashlib.sha256()
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002603 with open(filename, "rb") as f:
2604 for block in iter(lambda: f.read(65536), b""):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002605 sha256.update(block)
2606 return sha256.hexdigest()
Jakob Buchgraber699aece2018-02-19 12:49:30 +01002607
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002608
Philipp Wollermann02955272019-04-18 18:00:48 +02002609def upload_bazel_binaries():
2610 """
2611 Uploads all Bazel binaries to a deterministic URL based on the current Git commit.
2612
2613 Returns a map of platform names to sha256 hashes of the corresponding Bazel binary.
2614 """
2615 hashes = {}
Philipp Wollermannbdd4bf92019-06-06 14:43:50 +02002616 for platform_name, platform in PLATFORMS.items():
Philipp Wollermann783d1672019-06-06 13:35:30 +02002617 if not should_publish_binaries_for_platform(platform_name):
2618 continue
Jakob Buchgraberb13a9a82018-03-27 18:37:09 +02002619 tmpdir = tempfile.mkdtemp()
2620 try:
Philipp Wollermann783d1672019-06-06 13:35:30 +02002621 bazel_binary_path = download_bazel_binary(tmpdir, platform_name)
2622 # One platform that we build on can generate binaries for multiple platforms, e.g.
Philipp Wollermannf4aabb72019-06-25 15:59:00 +02002623 # the centos7 platform generates binaries for the "centos7" platform, but also
Philipp Wollermann783d1672019-06-06 13:35:30 +02002624 # for the generic "linux" platform.
2625 for target_platform_name in platform["publish_binary"]:
2626 execute_command(
2627 [
2628 gsutil_command(),
2629 "cp",
2630 bazel_binary_path,
2631 bazelci_builds_gs_url(target_platform_name, os.environ["BUILDKITE_COMMIT"]),
2632 ]
2633 )
2634 hashes[target_platform_name] = sha256_hexdigest(bazel_binary_path)
Jakob Buchgraberb13a9a82018-03-27 18:37:09 +02002635 finally:
2636 shutil.rmtree(tmpdir)
Philipp Wollermann02955272019-04-18 18:00:48 +02002637 return hashes
2638
2639
2640def try_publish_binaries(hashes, build_number, expected_generation):
2641 """
2642 Uploads the info.json file that contains information about the latest Bazel commit that was
2643 successfully built on CI.
2644 """
2645 now = datetime.datetime.now()
2646 git_commit = os.environ["BUILDKITE_COMMIT"]
2647 info = {
2648 "build_number": build_number,
2649 "build_time": now.strftime("%d-%m-%Y %H:%M"),
2650 "git_commit": git_commit,
2651 "platforms": {},
2652 }
Philipp Wollermann783d1672019-06-06 13:35:30 +02002653 for platform, sha256 in hashes.items():
Philipp Wollermann02955272019-04-18 18:00:48 +02002654 info["platforms"][platform] = {
2655 "url": bazelci_builds_download_url(platform, git_commit),
Philipp Wollermann783d1672019-06-06 13:35:30 +02002656 "sha256": sha256,
Philipp Wollermann02955272019-04-18 18:00:48 +02002657 }
Jakob Buchgraberb13a9a82018-03-27 18:37:09 +02002658 tmpdir = tempfile.mkdtemp()
2659 try:
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002660 info_file = os.path.join(tmpdir, "info.json")
2661 with open(info_file, mode="w", encoding="utf-8") as fp:
Jakob Buchgraber609a20e2018-02-25 17:06:51 +01002662 json.dump(info, fp, indent=2, sort_keys=True)
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002663
2664 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002665 execute_command(
2666 [
2667 gsutil_command(),
2668 "-h",
2669 "x-goog-if-generation-match:" + expected_generation,
2670 "-h",
2671 "Content-Type:application/json",
2672 "cp",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002673 info_file,
2674 bazelci_builds_metadata_url(),
2675 ]
2676 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002677 except subprocess.CalledProcessError:
2678 raise BinaryUploadRaceException()
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002679 finally:
Philipp Wollermann3e1a7712018-02-19 17:34:24 +01002680 shutil.rmtree(tmpdir)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002681
2682
Jakob Buchgraber76381e02018-02-19 16:19:56 +01002683def publish_binaries():
Philipp Wollermanndb024862018-02-19 17:16:56 +01002684 """
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002685 Publish Bazel binaries to GCS.
Philipp Wollermanndb024862018-02-19 17:16:56 +01002686 """
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002687 current_build_number = os.environ.get("BUILDKITE_BUILD_NUMBER", None)
2688 if not current_build_number:
2689 raise BuildkiteException("Not running inside Buildkite")
2690 current_build_number = int(current_build_number)
2691
Philipp Wollermann02955272019-04-18 18:00:48 +02002692 # Upload the Bazel binaries for this commit.
2693 hashes = upload_bazel_binaries()
2694
2695 # Try to update the info.json with data about our build. This will fail (expectedly) if we're
2696 # not the latest build.
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002697 for _ in range(5):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002698 latest_generation, latest_build_number = latest_generation_and_build_number()
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002699
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002700 if current_build_number <= latest_build_number:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002701 eprint(
2702 (
2703 "Current build '{0}' is not newer than latest published '{1}'. "
2704 + "Skipping publishing of binaries."
2705 ).format(current_build_number, latest_build_number)
2706 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002707 break
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002708
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002709 try:
Philipp Wollermann02955272019-04-18 18:00:48 +02002710 try_publish_binaries(hashes, current_build_number, latest_generation)
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002711 except BinaryUploadRaceException:
2712 # Retry.
2713 continue
2714
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002715 eprint(
2716 "Successfully updated '{0}' to binaries from build {1}.".format(
2717 bazelci_builds_metadata_url(), current_build_number
2718 )
2719 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002720 break
2721 else:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002722 raise BuildkiteException("Could not publish binaries, ran out of attempts.")
2723
Philipp Wollermann3c8b8512019-07-16 15:28:03 +02002724
Philipp Wollermann639c0452019-01-03 11:23:54 +01002725# This is so that multiline python strings are represented as YAML
2726# block strings.
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01002727def str_presenter(dumper, data):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002728 if len(data.splitlines()) > 1: # check for multiline string
2729 return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|")
2730 return dumper.represent_scalar("tag:yaml.org,2002:str", data)
2731
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002732
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002733def main(argv=None):
2734 if argv is None:
Yun Peng20d45602018-10-18 13:27:05 +02002735 argv = sys.argv[1:]
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002736
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01002737 yaml.add_representer(str, str_presenter)
2738
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002739 parser = argparse.ArgumentParser(description="Bazel Continuous Integration Script")
Florian Weikert944209b2019-05-10 12:41:48 +02002740 parser.add_argument("--script", type=str)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002741
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002742 subparsers = parser.add_subparsers(dest="subparsers_name")
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002743
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002744 bazel_publish_binaries_pipeline = subparsers.add_parser("bazel_publish_binaries_pipeline")
2745 bazel_publish_binaries_pipeline.add_argument("--file_config", type=str)
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01002746 bazel_publish_binaries_pipeline.add_argument("--http_config", type=str)
2747 bazel_publish_binaries_pipeline.add_argument("--git_repository", type=str)
2748
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002749 bazel_downstream_pipeline = subparsers.add_parser("bazel_downstream_pipeline")
2750 bazel_downstream_pipeline.add_argument("--file_config", type=str)
2751 bazel_downstream_pipeline.add_argument("--http_config", type=str)
2752 bazel_downstream_pipeline.add_argument("--git_repository", type=str)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002753 bazel_downstream_pipeline.add_argument(
2754 "--test_incompatible_flags", type=bool, nargs="?", const=True
2755 )
2756 bazel_downstream_pipeline.add_argument(
2757 "--test_disabled_projects", type=bool, nargs="?", const=True
2758 )
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002759
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002760 project_pipeline = subparsers.add_parser("project_pipeline")
2761 project_pipeline.add_argument("--project_name", type=str)
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002762 project_pipeline.add_argument("--file_config", type=str)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002763 project_pipeline.add_argument("--http_config", type=str)
2764 project_pipeline.add_argument("--git_repository", type=str)
Jakob Buchgraber66ba4fe2018-06-22 15:04:14 +02002765 project_pipeline.add_argument("--monitor_flaky_tests", type=bool, nargs="?", const=True)
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002766 project_pipeline.add_argument("--use_but", type=bool, nargs="?", const=True)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002767 project_pipeline.add_argument("--incompatible_flag", type=str, action="append")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002768
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002769 runner = subparsers.add_parser("runner")
Florian Weikert843d7a02019-02-03 17:24:50 +01002770 runner.add_argument("--task", action="store", type=str, default="")
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002771 runner.add_argument("--file_config", type=str)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002772 runner.add_argument("--http_config", type=str)
2773 runner.add_argument("--git_repository", type=str)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002774 runner.add_argument(
2775 "--git_commit", type=str, help="Reset the git repository to this commit after cloning it"
2776 )
2777 runner.add_argument(
2778 "--git_repo_location",
2779 type=str,
2780 help="Use an existing repository instead of cloning from github",
2781 )
2782 runner.add_argument(
Dan Halperinefda1192019-01-16 00:34:09 -08002783 "--use_bazel_at_commit", type=str, help="Use Bazel binary built at a specific commit"
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002784 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002785 runner.add_argument("--use_but", type=bool, nargs="?", const=True)
2786 runner.add_argument("--save_but", type=bool, nargs="?", const=True)
Yun Peng4d1d6542019-01-17 18:30:33 +01002787 runner.add_argument("--needs_clean", type=bool, nargs="?", const=True)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002788 runner.add_argument("--build_only", type=bool, nargs="?", const=True)
2789 runner.add_argument("--test_only", type=bool, nargs="?", const=True)
Jakob Buchgraber66ba4fe2018-06-22 15:04:14 +02002790 runner.add_argument("--monitor_flaky_tests", type=bool, nargs="?", const=True)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002791 runner.add_argument("--incompatible_flag", type=str, action="append")
Jakob Buchgraberc340f582018-06-22 13:48:33 +02002792
Philipp Wollermannce986af2019-07-18 14:46:05 +02002793 subparsers.add_parser("publish_binaries")
2794 subparsers.add_parser("try_update_last_green_commit")
2795 subparsers.add_parser("try_update_last_green_downstream_commit")
Yun Peng358cd882018-11-29 10:25:18 +01002796
Yun Peng20d45602018-10-18 13:27:05 +02002797 args = parser.parse_args(argv)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002798
Florian Weikert944209b2019-05-10 12:41:48 +02002799 if args.script:
2800 global SCRIPT_URL
2801 SCRIPT_URL = args.script
2802
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002803 try:
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01002804 if args.subparsers_name == "bazel_publish_binaries_pipeline":
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002805 configs = fetch_configs(args.http_config, args.file_config)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002806 print_bazel_publish_binaries_pipeline(
Florian Weikert843d7a02019-02-03 17:24:50 +01002807 task_configs=configs.get("tasks", None),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002808 http_config=args.http_config,
2809 file_config=args.file_config,
2810 )
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002811 elif args.subparsers_name == "bazel_downstream_pipeline":
2812 configs = fetch_configs(args.http_config, args.file_config)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002813 print_bazel_downstream_pipeline(
Florian Weikert843d7a02019-02-03 17:24:50 +01002814 task_configs=configs.get("tasks", None),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002815 http_config=args.http_config,
2816 file_config=args.file_config,
2817 test_incompatible_flags=args.test_incompatible_flags,
2818 test_disabled_projects=args.test_disabled_projects,
2819 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002820 elif args.subparsers_name == "project_pipeline":
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002821 configs = fetch_configs(args.http_config, args.file_config)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002822 print_project_pipeline(
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002823 configs=configs,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002824 project_name=args.project_name,
2825 http_config=args.http_config,
2826 file_config=args.file_config,
2827 git_repository=args.git_repository,
2828 monitor_flaky_tests=args.monitor_flaky_tests,
2829 use_but=args.use_but,
2830 incompatible_flags=args.incompatible_flag,
2831 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002832 elif args.subparsers_name == "runner":
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002833 configs = fetch_configs(args.http_config, args.file_config)
Florian Weikert843d7a02019-02-03 17:24:50 +01002834 tasks = configs.get("tasks", {})
2835 task_config = tasks.get(args.task)
2836 if not task_config:
2837 raise BuildkiteException(
2838 "No such task '{}' in configuration. Available: {}".format(
2839 args.task, ", ".join(tasks)
2840 )
2841 )
2842
2843 platform = get_platform_for_task(args.task, task_config)
2844
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002845 execute_commands(
Florian Weikertc8642af2019-02-03 23:58:51 +01002846 task_config=task_config,
Florian Weikert843d7a02019-02-03 17:24:50 +01002847 platform=platform,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002848 git_repository=args.git_repository,
2849 git_commit=args.git_commit,
2850 git_repo_location=args.git_repo_location,
2851 use_bazel_at_commit=args.use_bazel_at_commit,
2852 use_but=args.use_but,
2853 save_but=args.save_but,
Yun Peng4d1d6542019-01-17 18:30:33 +01002854 needs_clean=args.needs_clean,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002855 build_only=args.build_only,
2856 test_only=args.test_only,
2857 monitor_flaky_tests=args.monitor_flaky_tests,
2858 incompatible_flags=args.incompatible_flag,
Florian Weikertc8642af2019-02-03 23:58:51 +01002859 bazel_version=task_config.get("bazel") or configs.get("bazel"),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002860 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002861 elif args.subparsers_name == "publish_binaries":
2862 publish_binaries()
Yun Peng358cd882018-11-29 10:25:18 +01002863 elif args.subparsers_name == "try_update_last_green_commit":
Florian Weikert35906542019-04-01 11:53:53 +02002864 # Update the last green commit of a project pipeline
Yun Peng358cd882018-11-29 10:25:18 +01002865 try_update_last_green_commit()
Florian Weikert35906542019-04-01 11:53:53 +02002866 elif args.subparsers_name == "try_update_last_green_downstream_commit":
2867 # Update the last green commit of the downstream pipeline
2868 try_update_last_green_downstream_commit()
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002869 else:
2870 parser.print_help()
2871 return 2
2872 except BuildkiteException as e:
2873 eprint(str(e))
2874 return 1
2875 return 0
2876
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01002877
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002878if __name__ == "__main__":
2879 sys.exit(main())