blob: 0e2c2ffccb90f14f6bcc1abb1e38472baa002f05 [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
Philipp Wollermanne1318eb2018-08-13 15:08:01 +020034import time
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010035import urllib.request
Philipp Wollermanne1318eb2018-08-13 15:08:01 +020036import uuid
Jakob Buchgraber25bb50f2018-02-22 18:06:21 +010037import yaml
Philipp Wollermannc030f2e2018-02-21 17:02:19 +010038from urllib.request import url2pathname
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010039from urllib.parse import urlparse
Philipp Wollermanndcaddd92018-02-21 14:13:43 +010040
41# Initialize the random number generator.
42random.seed()
43
Philipp Wollermannc05ac682019-01-19 12:37:28 +010044CLOUD_PROJECT = (
45 "bazel-public"
Florian Weikert3259af92019-01-28 11:19:29 -050046 if os.environ.get("BUILDKITE_ORGANIZATION_SLUG") == "bazel-trusted"
Philipp Wollermannc05ac682019-01-19 12:37:28 +010047 else "bazel-untrusted"
48)
Jakob Buchgraber95e3d572018-02-21 18:48:49 +010049
Philipp Wollermann2409c6e2018-08-07 07:37:54 +020050DOWNSTREAM_PROJECTS = {
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +010051 "Android Studio Plugin": {
52 "git_repository": "https://github.com/bazelbuild/intellij.git",
53 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/android-studio.yml",
54 "pipeline_slug": "android-studio-plugin",
55 },
Yun Peng996efad2018-11-27 17:19:44 +010056 "Android Testing": {
57 "git_repository": "https://github.com/googlesamples/android-testing.git",
Jingwenbde72602018-12-13 10:57:43 -050058 "http_config": "https://raw.githubusercontent.com/googlesamples/android-testing/master/bazelci/buildkite-pipeline.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +010059 "pipeline_slug": "android-testing",
Yun Peng996efad2018-11-27 17:19:44 +010060 },
Yun Peng8910fa32019-01-03 08:58:16 +010061 "Bazel": {
62 "git_repository": "https://github.com/bazelbuild/bazel.git",
63 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel/master/.bazelci/postsubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +010064 "pipeline_slug": "bazel-bazel",
Yun Peng8910fa32019-01-03 08:58:16 +010065 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +010066 "Bazel integration testing": {
67 "git_repository": "https://github.com/bazelbuild/bazel-integration-testing.git",
68 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-integration-testing/master/.bazelci/presubmit.yml",
69 "pipeline_slug": "bazel-integration-testing",
Yun Peng996efad2018-11-27 17:19:44 +010070 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +010071 "Bazelisk": {
72 "git_repository": "https://github.com/philwo/bazelisk.git",
73 "http_config": "https://raw.githubusercontent.com/philwo/bazelisk/master/.bazelci/config.yml",
74 "pipeline_slug": "bazelisk",
Yun Peng9c7ead92019-01-15 13:59:47 +010075 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +010076 "Bazel Remote Cache": {
77 "git_repository": "https://github.com/buchgr/bazel-remote.git",
78 "http_config": "https://raw.githubusercontent.com/buchgr/bazel-remote/master/.bazelci/presubmit.yml",
79 "pipeline_slug": "bazel-remote-cache",
Laurent Le Brun16ac2782019-03-19 15:46:46 +010080 "disabled_reason": "https://github.com/buchgr/bazel-remote/issues/82",
Yun Peng996efad2018-11-27 17:19:44 +010081 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +010082 "Bazel skylib": {
Philipp Wollermann2409c6e2018-08-07 07:37:54 +020083 "git_repository": "https://github.com/bazelbuild/bazel-skylib.git",
Yun Peng996efad2018-11-27 17:19:44 +010084 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-skylib/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +010085 "pipeline_slug": "bazel-skylib",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +020086 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +010087 "Bazel toolchains": {
88 "git_repository": "https://github.com/bazelbuild/bazel-toolchains.git",
89 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-toolchains/master/.bazelci/presubmit.yml",
90 "pipeline_slug": "bazel-toolchains",
91 },
92 "Bazel watcher": {
93 "git_repository": "https://github.com/bazelbuild/bazel-watcher.git",
94 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-watcher/master/.bazelci/presubmit.yml",
95 "pipeline_slug": "bazel-watcher",
96 },
97 "Buildfarm": {
98 "git_repository": "https://github.com/bazelbuild/bazel-buildfarm.git",
99 "http_config": "https://raw.githubusercontent.com/bazelbuild/bazel-buildfarm/master/.bazelci/presubmit.yml",
100 "pipeline_slug": "buildfarm-male-farmer",
101 },
102 "BUILD file generator": {
103 "git_repository": "https://github.com/bazelbuild/BUILD_file_generator.git",
104 "http_config": "https://raw.githubusercontent.com/bazelbuild/BUILD_file_generator/master/.bazelci/presubmit.yml",
105 "pipeline_slug": "build-file-generator",
Yun Pengf7ecda22019-05-07 12:40:39 +0200106 "disabled_reason": "https://github.com/bazelbuild/BUILD_file_generator/issues/53",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100107 },
108 "Buildtools": {
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200109 "git_repository": "https://github.com/bazelbuild/buildtools.git",
Yun Peng996efad2018-11-27 17:19:44 +0100110 "http_config": "https://raw.githubusercontent.com/bazelbuild/buildtools/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100111 "pipeline_slug": "buildtools",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200112 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100113 "Cartographer": {
114 "git_repository": "https://github.com/googlecartographer/cartographer.git",
115 "http_config": "https://raw.githubusercontent.com/googlecartographer/cartographer/master/.bazelci/presubmit.yml",
116 "pipeline_slug": "cartographer",
117 },
Yun Peng39a42582018-11-09 10:59:47 +0100118 "CLion Plugin": {
119 "git_repository": "https://github.com/bazelbuild/intellij.git",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100120 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/clion.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100121 "pipeline_slug": "clion-plugin",
Yun Peng39a42582018-11-09 10:59:47 +0100122 },
Philipp Wollermannee850782019-02-05 22:56:04 +0100123 "Cloud Robotics Core": {
Stefan Sauerb4dd3f92019-02-05 22:44:28 +0100124 "git_repository": "https://github.com/googlecloudrobotics/core.git",
125 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/cloud-robotics-postsubmit.yml",
126 "pipeline_slug": "cloud-robotics-core",
127 },
Marcel Hlopkoc8840772018-10-23 12:51:46 +0200128 "Gerrit": {
129 "git_repository": "https://gerrit.googlesource.com/gerrit.git",
Yun Peng996efad2018-11-27 17:19:44 +0100130 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/gerrit-postsubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100131 "pipeline_slug": "gerrit",
Marcel Hlopkoc8840772018-10-23 12:51:46 +0200132 },
Jingwen3f155da2019-03-14 15:04:58 -0400133 "rules_jvm_external": {
Jingwene712ba52019-03-12 20:20:09 -0400134 "git_repository": "https://github.com/bazelbuild/rules_jvm_external.git",
135 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_jvm_external/master/.bazelci/presubmit.yml",
136 "pipeline_slug": "rules-jvm-external",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100137 },
Jinaa6c6f32019-05-07 06:22:58 -0700138 "rules_jvm_external - examples": {
139 "git_repository": "https://github.com/bazelbuild/rules_jvm_external.git",
140 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_jvm_external/master/.bazelci/examples.yml",
141 "pipeline_slug": "rules-jvm-external-examples",
142 },
Yun Pengd6622022018-11-05 13:10:26 +0100143 "Google Logging": {
144 "git_repository": "https://github.com/google/glog.git",
Yun Peng996efad2018-11-27 17:19:44 +0100145 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/glog-postsubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100146 "pipeline_slug": "google-logging",
Yun Pengd6622022018-11-05 13:10:26 +0100147 },
Yun Peng9586db52018-11-02 10:48:40 +0100148 "IntelliJ Plugin": {
149 "git_repository": "https://github.com/bazelbuild/intellij.git",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100150 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/intellij.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100151 "pipeline_slug": "intellij-plugin",
Yun Peng9586db52018-11-02 10:48:40 +0100152 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100153 "IntelliJ Plugin Aspect": {
154 "git_repository": "https://github.com/bazelbuild/intellij.git",
155 "http_config": "https://raw.githubusercontent.com/bazelbuild/intellij/master/.bazelci/aspect.yml",
156 "pipeline_slug": "intellij-plugin-aspect",
157 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100158 "Protobuf": {
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200159 "git_repository": "https://github.com/google/protobuf.git",
Yun Peng996efad2018-11-27 17:19:44 +0100160 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/protobuf-postsubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100161 "pipeline_slug": "protobuf",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200162 },
163 "re2": {
164 "git_repository": "https://github.com/google/re2.git",
Yun Peng996efad2018-11-27 17:19:44 +0100165 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/re2-postsubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100166 "pipeline_slug": "re2",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200167 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100168 "Remote execution": {
169 "git_repository": "https://github.com/bazelbuild/bazel.git",
170 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/bazel-remote-execution-postsubmit.yml",
171 "pipeline_slug": "remote-execution",
172 },
173 "rules_android": {
174 "git_repository": "https://github.com/bazelbuild/rules_android.git",
175 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_android/master/.bazelci/postsubmit.yml",
176 "pipeline_slug": "rules-android",
177 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200178 "rules_appengine": {
179 "git_repository": "https://github.com/bazelbuild/rules_appengine.git",
Yun Peng996efad2018-11-27 17:19:44 +0100180 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_appengine/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100181 "pipeline_slug": "rules-appengine-appengine",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200182 },
Yun Peng809f27b2018-11-13 10:15:39 +0100183 "rules_apple": {
184 "git_repository": "https://github.com/bazelbuild/rules_apple.git",
Yun Peng996efad2018-11-27 17:19:44 +0100185 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_apple/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100186 "pipeline_slug": "rules-apple-darwin",
Yun Peng809f27b2018-11-13 10:15:39 +0100187 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100188 "rules_cc": {
189 "git_repository": "https://github.com/bazelbuild/rules_cc.git",
190 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_cc/master/.bazelci/presubmit.yml",
191 "pipeline_slug": "rules-cc",
192 },
Marcel Hlopko340dfd22018-10-19 11:33:01 +0200193 "rules_closure": {
194 "git_repository": "https://github.com/bazelbuild/rules_closure.git",
Yun Peng996efad2018-11-27 17:19:44 +0100195 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_closure/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100196 "pipeline_slug": "rules-closure-closure-compiler",
Marcel Hlopko340dfd22018-10-19 11:33:01 +0200197 },
Yun Peng51ce6692019-01-09 14:31:46 +0100198 "rules_d": {
199 "git_repository": "https://github.com/bazelbuild/rules_d.git",
200 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_d/master/.bazelci/presubmit.yml",
201 "pipeline_slug": "rules-d",
202 },
Yun Peng996efad2018-11-27 17:19:44 +0100203 "rules_docker": {
204 "git_repository": "https://github.com/bazelbuild/rules_docker.git",
205 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_docker/master/.bazelci/presubmit.yml",
Jakob Buchgrabera6a8ea82018-12-07 13:51:02 +0100206 "pipeline_slug": "rules-docker-docker",
Yun Peng996efad2018-11-27 17:19:44 +0100207 },
208 "rules_foreign_cc": {
209 "git_repository": "https://github.com/bazelbuild/rules_foreign_cc.git",
210 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_foreign_cc/master/.bazelci/config.yaml",
211 "pipeline_slug": "rules-foreign-cc",
Yun Peng996efad2018-11-27 17:19:44 +0100212 },
Xindb02c012018-11-07 14:10:54 -0500213 "rules_go": {
214 "git_repository": "https://github.com/bazelbuild/rules_go.git",
Yun Peng996efad2018-11-27 17:19:44 +0100215 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_go/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100216 "pipeline_slug": "rules-go-golang",
Yun Pengb7247ff2018-11-15 13:52:39 +0100217 },
Yun Peng7deea572018-11-05 10:47:45 +0100218 "rules_groovy": {
Yun Peng996efad2018-11-27 17:19:44 +0100219 "git_repository": "https://github.com/bazelbuild/rules_groovy.git",
220 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_groovy/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100221 "pipeline_slug": "rules-groovy",
Yun Peng996efad2018-11-27 17:19:44 +0100222 },
223 "rules_gwt": {
224 "git_repository": "https://github.com/bazelbuild/rules_gwt.git",
225 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_gwt/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100226 "pipeline_slug": "rules-gwt",
Yun Pengf7ecda22019-05-07 12:40:39 +0200227 "disabled_reason": "https://github.com/bazelbuild/rules_gwt/issues/23",
Yun Peng996efad2018-11-27 17:19:44 +0100228 },
229 "rules_jsonnet": {
230 "git_repository": "https://github.com/bazelbuild/rules_jsonnet.git",
231 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_jsonnet/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100232 "pipeline_slug": "rules-jsonnet",
Yun Peng996efad2018-11-27 17:19:44 +0100233 },
Yun Peng996efad2018-11-27 17:19:44 +0100234 "rules_k8s": {
235 "git_repository": "https://github.com/bazelbuild/rules_k8s.git",
236 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_k8s/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100237 "pipeline_slug": "rules-k8s-k8s",
Yun Peng996efad2018-11-27 17:19:44 +0100238 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100239 "rules_kotlin": {
240 "git_repository": "https://github.com/bazelbuild/rules_kotlin.git",
241 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_kotlin/master/.bazelci/presubmit.yml",
242 "pipeline_slug": "rules-kotlin-kotlin",
243 },
Yun Penga5650e12018-11-14 10:16:06 +0100244 "rules_nodejs": {
245 "git_repository": "https://github.com/bazelbuild/rules_nodejs.git",
Yun Peng996efad2018-11-27 17:19:44 +0100246 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_nodejs/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100247 "pipeline_slug": "rules-nodejs-nodejs",
Yun Penga5650e12018-11-14 10:16:06 +0100248 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200249 "rules_perl": {
250 "git_repository": "https://github.com/bazelbuild/rules_perl.git",
Yun Peng996efad2018-11-27 17:19:44 +0100251 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_perl/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100252 "pipeline_slug": "rules-perl",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200253 },
Yun Peng3d5a8a62018-11-19 11:42:01 +0100254 "rules_python": {
255 "git_repository": "https://github.com/bazelbuild/rules_python.git",
Yun Peng996efad2018-11-27 17:19:44 +0100256 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_python/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100257 "pipeline_slug": "rules-python-python",
Yun Peng3d5a8a62018-11-19 11:42:01 +0100258 },
Xindb02c012018-11-07 14:10:54 -0500259 "rules_rust": {
260 "git_repository": "https://github.com/bazelbuild/rules_rust.git",
Yun Peng996efad2018-11-27 17:19:44 +0100261 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_rust/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100262 "pipeline_slug": "rules-rust-rustlang",
Xindb02c012018-11-07 14:10:54 -0500263 },
Yun Pengca62fff2018-10-31 11:22:03 +0100264 "rules_sass": {
265 "git_repository": "https://github.com/bazelbuild/rules_sass.git",
Yun Peng996efad2018-11-27 17:19:44 +0100266 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_sass/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100267 "pipeline_slug": "rules-sass",
Yun Pengca62fff2018-10-31 11:22:03 +0100268 },
Xindb02c012018-11-07 14:10:54 -0500269 "rules_scala": {
270 "git_repository": "https://github.com/bazelbuild/rules_scala.git",
Yun Peng996efad2018-11-27 17:19:44 +0100271 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_scala/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100272 "pipeline_slug": "rules-scala-scala",
Xindb02c012018-11-07 14:10:54 -0500273 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100274 "rules_swift": {
275 "git_repository": "https://github.com/bazelbuild/rules_swift.git",
276 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_swift/master/.bazelci/presubmit.yml",
277 "pipeline_slug": "rules-swift-swift",
278 },
Yun Peng996efad2018-11-27 17:19:44 +0100279 "rules_typescript": {
280 "git_repository": "https://github.com/bazelbuild/rules_typescript.git",
281 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_typescript/master/.bazelci/presubmit.yml",
Jakob Buchgrabera6a8ea82018-12-07 13:51:02 +0100282 "pipeline_slug": "rules-typescript-typescript",
Yun Peng996efad2018-11-27 17:19:44 +0100283 },
284 "rules_webtesting": {
285 "git_repository": "https://github.com/bazelbuild/rules_webtesting.git",
Yun Pengc2fab332019-01-04 10:53:49 +0100286 "http_config": "https://raw.githubusercontent.com/bazelbuild/rules_webtesting/master/.bazelci/presubmit.yml",
Yun Peng996efad2018-11-27 17:19:44 +0100287 "pipeline_slug": "rules-webtesting-saucelabs",
Yun Peng996efad2018-11-27 17:19:44 +0100288 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100289 "Skydoc": {
Yun Pengc3fb6192018-10-30 11:27:46 +0100290 "git_repository": "https://github.com/bazelbuild/skydoc.git",
Yun Peng996efad2018-11-27 17:19:44 +0100291 "http_config": "https://raw.githubusercontent.com/bazelbuild/skydoc/master/.bazelci/presubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100292 "pipeline_slug": "skydoc",
Yun Pengc3fb6192018-10-30 11:27:46 +0100293 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100294 "Subpar": {
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200295 "git_repository": "https://github.com/google/subpar.git",
Yun Peng996efad2018-11-27 17:19:44 +0100296 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/subpar-postsubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100297 "pipeline_slug": "subpar",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200298 },
Yun Peng996efad2018-11-27 17:19:44 +0100299 "TensorFlow": {
300 "git_repository": "https://github.com/tensorflow/tensorflow.git",
301 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/tensorflow-postsubmit.yml",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100302 "pipeline_slug": "tensorflow",
Yun Pengf7ecda22019-05-07 12:40:39 +0200303 "disabled_reason": "https://github.com/bazelbuild/continuous-integration/issues/602",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100304 },
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100305 "Tulsi": {
306 "git_repository": "https://github.com/bazelbuild/tulsi.git",
307 "http_config": "https://raw.githubusercontent.com/bazelbuild/tulsi/master/.bazelci/presubmit.yml",
308 "pipeline_slug": "tulsi-bazel-darwin",
Jakob Buchgraber83164042019-04-24 10:37:35 +0200309 "disabled_reason": "https://github.com/bazelbuild/tulsi/issues/86",
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100310 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200311}
312
Philipp Wollermann6dd7aa32019-02-05 22:42:15 +0100313
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200314# A map containing all supported platform names as keys, with the values being
315# the platform name in a human readable format, and a the buildkite-agent's
316# working directory.
317PLATFORMS = {
318 "ubuntu1404": {
Philipp Wollermanndb877332019-04-23 17:58:01 +0200319 "name": "Ubuntu 14.04, OpenJDK 8",
320 "emoji-name": ":ubuntu: 14.04 (OpenJDK 8)",
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200321 "downstream-root": "/workdir/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Yun Pengc2dd6522018-10-17 12:58:35 +0200322 "publish_binary": True,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100323 "java": "8",
Philipp Wollermannc419f352019-01-17 13:06:28 +0100324 "docker-image": f"gcr.io/{CLOUD_PROJECT}/ubuntu1404:java8",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200325 },
326 "ubuntu1604": {
Philipp Wollermanndb877332019-04-23 17:58:01 +0200327 "name": "Ubuntu 16.04, OpenJDK 8",
328 "emoji-name": ":ubuntu: 16.04 (OpenJDK 8)",
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200329 "downstream-root": "/workdir/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Yun Pengc2dd6522018-10-17 12:58:35 +0200330 "publish_binary": False,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100331 "java": "8",
Philipp Wollermannc419f352019-01-17 13:06:28 +0100332 "docker-image": f"gcr.io/{CLOUD_PROJECT}/ubuntu1604:java8",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200333 },
334 "ubuntu1804": {
Philipp Wollermannf5a2feb2019-04-25 11:13:46 +0200335 "name": "Ubuntu 18.04, OpenJDK 11",
336 "emoji-name": ":ubuntu: 18.04 (OpenJDK 11)",
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200337 "downstream-root": "/workdir/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Yun Pengc2dd6522018-10-17 12:58:35 +0200338 "publish_binary": False,
Philipp Wollermannf5a2feb2019-04-25 11:13:46 +0200339 "java": "11",
340 "docker-image": f"gcr.io/{CLOUD_PROJECT}/ubuntu1804:java11",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200341 },
342 "ubuntu1804_nojava": {
343 "name": "Ubuntu 18.04, no JDK",
344 "emoji-name": ":ubuntu: 18.04 (no JDK)",
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200345 "downstream-root": "/workdir/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Yun Pengc2dd6522018-10-17 12:58:35 +0200346 "publish_binary": False,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100347 "java": "no",
Philipp Wollermannc419f352019-01-17 13:06:28 +0100348 "docker-image": f"gcr.io/{CLOUD_PROJECT}/ubuntu1804:nojava",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200349 },
Philipp Wollermann438ec242018-09-05 14:39:24 +0200350 "macos": {
Philipp Wollermanndb877332019-04-23 17:58:01 +0200351 "name": "macOS, OpenJDK 8",
352 "emoji-name": ":darwin: (OpenJDK 8)",
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200353 "downstream-root": "/Users/buildkite/builds/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Yun Pengc2dd6522018-10-17 12:58:35 +0200354 "publish_binary": True,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100355 "java": "8",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200356 },
357 "windows": {
Philipp Wollermanndb877332019-04-23 17:58:01 +0200358 "name": "Windows, OpenJDK 8",
359 "emoji-name": ":windows: (OpenJDK 8)",
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200360 "downstream-root": "d:/b/${BUILDKITE_AGENT_NAME}/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Yun Pengc2dd6522018-10-17 12:58:35 +0200361 "publish_binary": True,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100362 "java": "8",
Philipp Wollermann438ec242018-09-05 14:39:24 +0200363 },
364 "rbe_ubuntu1604": {
Philipp Wollermanndb877332019-04-23 17:58:01 +0200365 "name": "RBE (Ubuntu 16.04, OpenJDK 8)",
366 "emoji-name": ":gcloud: (OpenJDK 8)",
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200367 "downstream-root": "/workdir/${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects",
Yun Pengc2dd6522018-10-17 12:58:35 +0200368 "publish_binary": False,
Philipp Wollermann438ec242018-09-05 14:39:24 +0200369 "host-platform": "ubuntu1604",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100370 "java": "8",
Philipp Wollermannc419f352019-01-17 13:06:28 +0100371 "docker-image": f"gcr.io/{CLOUD_PROJECT}/ubuntu1604:java8",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100372 },
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200373}
374
Philipp Wollermann7f0dc902019-01-19 13:19:03 +0100375BUILDIFIER_DOCKER_IMAGE = f"gcr.io/{CLOUD_PROJECT}/buildifier"
Florian Weikertf20ae6f2019-01-16 14:32:09 +0100376
Philipp Wollermann1403d2c2019-01-10 13:15:51 +0100377# The platform used for various steps (e.g. stuff that formerly ran on the "pipeline" workers).
378DEFAULT_PLATFORM = "ubuntu1804"
379
Philipp Wollermann380f1e62019-04-12 16:45:27 +0200380DEFAULT_XCODE_VERSION = "10.2"
381XCODE_VERSION_REGEX = re.compile(r"^\d+\.\d+(\.\d+)?$")
382
Philipp Wollermann1403d2c2019-01-10 13:15:51 +0100383ENCRYPTED_SAUCELABS_TOKEN = """
Philipp Wollermanna4722b42019-01-10 16:50:13 +0100384CiQAry63sOlZtTNtuOT5DAOLkum0rGof+DOweppZY1aOWbat8zwSTQAL7Hu+rgHSOr6P4S1cu4YG
385/I1BHsWaOANqUgFt6ip9/CUGGJ1qggsPGXPrmhSbSPqNAIAkpxYzabQ3mfSIObxeBmhKg2dlILA/
386EDql
Philipp Wollermann1403d2c2019-01-10 13:15:51 +0100387""".strip()
388
Florian Weikertc8642af2019-02-03 23:58:51 +0100389BUILD_LABEL_PATTERN = re.compile(r"^Build label: (\S+)$", re.MULTILINE)
390
Florian Weikert29cb7ec2019-03-07 14:52:18 +0100391BUILDIFIER_VERSION_ENV_VAR = "BUILDIFIER_VERSION"
392
Florian Weikert85208912019-03-07 17:08:39 +0100393BUILDIFIER_WARNINGS_ENV_VAR = "BUILDIFIER_WARNINGS"
394
Florian Weikertde96a6f2019-03-07 14:57:50 +0100395BUILDIFIER_STEP_NAME = "Buildifier"
396
Florian Weikert5f5d3cb2019-04-15 15:36:27 +0200397SKIP_TASKS_ENV_VAR = "CI_SKIP_TASKS"
398
Florian Weikert778251c2019-04-25 15:14:44 +0200399CONFIG_FILE_EXTENSIONS = set([".yml", ".yaml"])
400
Florian Weikert944209b2019-05-10 12:41:48 +0200401SCRIPT_URL = "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/bazelci.py"
402
Florian Weikertde96a6f2019-03-07 14:57:50 +0100403
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100404class BuildkiteException(Exception):
405 """
406 Raised whenever something goes wrong and we should exit with an error.
407 """
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100408
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100409 pass
410
411
412class BinaryUploadRaceException(Exception):
413 """
414 Raised when try_publish_binaries wasn't able to publish a set of binaries,
415 because the generation of the current file didn't match the expected value.
416 """
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100417
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100418 pass
419
420
Florian Weikerta0e74592019-03-07 11:56:12 +0100421class BuildkiteClient(object):
422
423 _ENCRYPTED_BUILDKITE_API_TOKEN = """
424CiQA4DEB9ldzC+E39KomywtqXfaQ86hhulgeDsicds2BuvbCYzsSUAAqwcvXZPh9IMWlwWh94J2F
425exosKKaWB0tSRJiPKnv2NPDfEqGul0ZwVjtWeASpugwxxKeLhFhPMcgHMPfndH6j2GEIY6nkKRbP
426uwoRMCwe
427""".strip()
428
Florian Weikertde96a6f2019-03-07 14:57:50 +0100429 _BUILD_STATUS_URL_TEMPLATE = (
430 "https://api.buildkite.com/v2/organizations/{}/pipelines/{}/builds/{}"
431 )
Florian Weikerta0e74592019-03-07 11:56:12 +0100432
433 def __init__(self, org, pipeline):
434 self._org = org
435 self._pipeline = pipeline
436 self._token = self._get_buildkite_token()
437
438 def _get_buildkite_token(self):
439 return (
440 subprocess.check_output(
441 [
442 gcloud_command(),
443 "kms",
444 "decrypt",
445 "--project",
446 "bazel-untrusted",
447 "--location",
448 "global",
449 "--keyring",
450 "buildkite",
451 "--key",
452 "buildkite-untrusted-api-token",
453 "--ciphertext-file",
454 "-",
455 "--plaintext-file",
456 "-",
457 ],
458 input=base64.b64decode(self._ENCRYPTED_BUILDKITE_API_TOKEN),
459 env=os.environ,
460 )
461 .decode("utf-8")
462 .strip()
463 )
464
465 def _open_url(self, url):
Florian Weikertde96a6f2019-03-07 14:57:50 +0100466 return (
467 urllib.request.urlopen("{}?access_token={}".format(url, self._token))
468 .read()
469 .decode("utf-8")
470 )
Florian Weikerta0e74592019-03-07 11:56:12 +0100471
472 def get_build_info(self, build_number):
473 url = self._BUILD_STATUS_URL_TEMPLATE.format(self._org, self._pipeline, build_number)
474 output = self._open_url(url)
475 return json.loads(output)
476
477 def get_build_log(self, job):
478 return self._open_url(job["raw_log_url"])
479
480
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100481def eprint(*args, **kwargs):
482 """
483 Print to stderr and flush (just in case).
484 """
485 print(*args, flush=True, file=sys.stderr, **kwargs)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100486
487
Philipp Wollermann5b7f38a2018-09-06 12:34:33 +0200488def rchop(string_, *endings):
489 for ending in endings:
490 if string_.endswith(ending):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100491 return string_[: -len(ending)]
Philipp Wollermann5b7f38a2018-09-06 12:34:33 +0200492 return string_
493
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100494
Jakob Buchgraber09048fa2018-02-27 11:39:39 +0100495def python_binary(platform=None):
496 if platform == "windows":
Philipp Wollermannbcedf9b2018-02-19 18:07:44 +0100497 return "python.exe"
Philipp Wollermann17c8f0d2018-08-01 15:40:09 +0200498 if platform == "macos":
499 return "python3.7"
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100500 return "python3.6"
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100501
Jakob Buchgrabere6de16b2018-02-28 12:42:12 +0100502
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100503def is_windows():
Jakob Buchgraber09048fa2018-02-27 11:39:39 +0100504 return os.name == "nt"
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100505
Jakob Buchgrabere6de16b2018-02-28 12:42:12 +0100506
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100507def gsutil_command():
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200508 return "gsutil.cmd" if is_windows() else "gsutil"
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100509
Jakob Buchgrabere6de16b2018-02-28 12:42:12 +0100510
Jakob Buchgraber9f153542018-02-27 10:56:04 +0100511def gcloud_command():
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200512 return "gcloud.cmd" if is_windows() else "gcloud"
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100513
Jakob Buchgrabere6de16b2018-02-28 12:42:12 +0100514
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100515def bazelcipy_url():
Philipp Wollermanndb024862018-02-19 17:16:56 +0100516 """
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100517 URL to the latest version of this script.
Philipp Wollermanndb024862018-02-19 17:16:56 +0100518 """
Florian Weikert944209b2019-05-10 12:41:48 +0200519 return "{}?{}".format(SCRIPT_URL, int(time.time()))
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100520
521
Yun Peng002eab92018-12-17 18:28:14 +0100522def incompatible_flag_verbose_failures_url():
523 """
524 URL to the latest version of this script.
525 """
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100526 return "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/incompatible_flag_verbose_failures.py?{}".format(
527 int(time.time())
528 )
Yun Peng002eab92018-12-17 18:28:14 +0100529
530
Yun Peng8975c6b2019-02-28 11:55:55 +0100531def aggregate_incompatible_flags_test_result_url():
532 """
533 URL to the latest version of this script.
534 """
535 return "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/aggregate_incompatible_flags_test_result.py?{}".format(
536 int(time.time())
537 )
538
539
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100540def downstream_projects_root(platform):
Philipp Wollermann51147bf2019-05-08 15:50:10 +0200541 downstream_root = os.path.expandvars(PLATFORMS[platform]["downstream-root"])
542 if not os.path.exists(downstream_root):
543 os.makedirs(downstream_root)
544 return downstream_root
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100545
546
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +0100547def fetch_configs(http_url, file_config):
Philipp Wollermanndb024862018-02-19 17:16:56 +0100548 """
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +0100549 If specified fetches the build configuration from file_config or http_url, else tries to
Jakob Buchgraber25bb50f2018-02-22 18:06:21 +0100550 read it from .bazelci/presubmit.yml.
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100551 Returns the json configuration as a python data structure.
Philipp Wollermanndb024862018-02-19 17:16:56 +0100552 """
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +0100553 if file_config is not None and http_url is not None:
554 raise BuildkiteException("file_config and http_url cannot be set at the same time")
555
Florian Weikert843d7a02019-02-03 17:24:50 +0100556 config = load_config(http_url, file_config)
557 # Legacy mode means that there is exactly one task per platform (e.g. ubuntu1604_nojdk),
558 # which means that we can get away with using the platform name as task ID.
559 # No other updates are needed since get_platform_for_task() falls back to using the
560 # task ID as platform if there is no explicit "platforms" field.
561 if "platforms" in config:
562 config["tasks"] = config.pop("platforms")
563
564 return config
565
566
567def load_config(http_url, file_config):
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +0100568 if file_config is not None:
569 with open(file_config, "r") as fd:
Jakob Buchgraber1a14b2e2018-02-22 20:27:49 +0100570 return yaml.load(fd)
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +0100571 if http_url is not None:
572 with urllib.request.urlopen(http_url) as resp:
573 reader = codecs.getreader("utf-8")
574 return yaml.load(reader(resp))
575 with open(".bazelci/presubmit.yml", "r") as fd:
576 return yaml.load(fd)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100577
Jakob Buchgraber9c83de72018-02-18 15:32:44 +0100578
Jakob Buchgraber3120f7a2018-02-18 13:28:02 +0100579def print_collapsed_group(name):
Jakob Buchgraber5c9b13d2018-02-21 22:28:14 +0100580 eprint("\n\n--- {0}\n\n".format(name))
Jakob Buchgraber3120f7a2018-02-18 13:28:02 +0100581
Jakob Buchgraber9c83de72018-02-18 15:32:44 +0100582
Jakob Buchgraber3120f7a2018-02-18 13:28:02 +0100583def print_expanded_group(name):
Jakob Buchgraber5c9b13d2018-02-21 22:28:14 +0100584 eprint("\n\n+++ {0}\n\n".format(name))
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100585
Jakob Buchgraber9c83de72018-02-18 15:32:44 +0100586
Yun Peng8975c6b2019-02-28 11:55:55 +0100587def use_bazelisk_migrate():
588 """
589 If USE_BAZELISK_MIGRATE is set, we use `bazelisk --migrate` to test incompatible flags.
590 """
Florian Weikertde96a6f2019-03-07 14:57:50 +0100591 return bool(os.environ.get("USE_BAZELISK_MIGRATE"))
Yun Peng8975c6b2019-02-28 11:55:55 +0100592
593
594def bazelisk_flags():
595 return ["--migrate"] if use_bazelisk_migrate() else []
596
597
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100598def execute_commands(
Florian Weikertc8642af2019-02-03 23:58:51 +0100599 task_config,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100600 platform,
601 git_repository,
602 git_commit,
603 git_repo_location,
604 use_bazel_at_commit,
605 use_but,
606 save_but,
Yun Peng4d1d6542019-01-17 18:30:33 +0100607 needs_clean,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100608 build_only,
609 test_only,
610 monitor_flaky_tests,
611 incompatible_flags,
Florian Weikertc8642af2019-02-03 23:58:51 +0100612 bazel_version=None,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100613):
Yun Pengf50f7b72019-02-28 19:09:52 +0100614 # If we want to test incompatible flags, we ignore bazel_version and always use
615 # the latest Bazel version through Bazelisk.
616 if incompatible_flags:
617 bazel_version = None
618
Jakob Buchgraberfb95a2f2018-02-22 11:46:25 +0100619 if build_only and test_only:
620 raise BuildkiteException("build_only and test_only cannot be true at the same time")
Philipp Wollermanne1318eb2018-08-13 15:08:01 +0200621
Yun Peng20d45602018-10-18 13:27:05 +0200622 if use_bazel_at_commit and use_but:
623 raise BuildkiteException("use_bazel_at_commit cannot be set when use_but is true")
624
Philipp Wollermanne1318eb2018-08-13 15:08:01 +0200625 tmpdir = tempfile.mkdtemp()
626 sc_process = None
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100627 try:
Philipp Wollermann380f1e62019-04-12 16:45:27 +0200628 # Activate the correct Xcode version on macOS machines.
629 if platform == "macos":
630 # Get the Xcode version from the config.
631 xcode_version = task_config.get("xcode_version", DEFAULT_XCODE_VERSION)
632 print_collapsed_group("Activating Xcode {}...".format(xcode_version))
633
634 # Ensure it's a valid version number.
635 if not isinstance(xcode_version, str):
636 raise BuildkiteException(
637 "Version number '{}' is not a string. Did you forget to put it in quotes?".format(
638 xcode_version
639 )
640 )
641 if not XCODE_VERSION_REGEX.match(xcode_version):
642 raise BuildkiteException(
643 "Invalid Xcode version format '{}', must match the format X.Y[.Z].".format(
644 xcode_version
645 )
646 )
647
648 # Check that the selected Xcode version is actually installed on the host.
Philipp Wollermann07986582019-04-12 18:08:50 +0200649 xcode_path = "/Applications/Xcode{}.app".format(xcode_version)
Philipp Wollermann380f1e62019-04-12 16:45:27 +0200650 if not os.path.exists(xcode_path):
651 raise BuildkiteException("Xcode not found at '{}'.".format(xcode_path))
652
653 # Now activate the specified Xcode version and let it install its required components.
654 # The CI machines have a sudoers config that allows the 'buildkite' user to run exactly
655 # these two commands, so don't change them without also modifying the file there.
656 execute_command(["/usr/bin/sudo", "/usr/bin/xcode-select", "--switch", xcode_path])
657 execute_command(["/usr/bin/sudo", "/usr/bin/xcodebuild", "-runFirstLaunch"])
658
Florian Weikert4ee0bed2019-02-21 18:03:00 +0100659 # If the CI worker runs Bazelisk, we need to forward all required env variables to the test.
660 # Otherwise any integration test that invokes Bazel (=Bazelisk in this case) will fail.
Marcel Hlopko198328b2019-02-25 09:19:55 +0100661 test_env_vars = ["LocalAppData"] if platform == "windows" else ["HOME"]
Yun Peng376d2b32018-11-29 10:24:54 +0100662 if git_repo_location:
663 os.chdir(git_repo_location)
664 elif git_repository:
665 clone_git_repository(git_repository, platform, git_commit)
Jakob Buchgraber2ab68f82018-02-21 19:43:08 +0100666 else:
667 git_repository = os.getenv("BUILDKITE_REPO")
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200668
Yun Peng20d45602018-10-18 13:27:05 +0200669 if use_bazel_at_commit:
670 print_collapsed_group(":gcloud: Downloading Bazel built at " + use_bazel_at_commit)
671 bazel_binary = download_bazel_binary_at_commit(tmpdir, platform, use_bazel_at_commit)
Philipp Wollermann639c0452019-01-03 11:23:54 +0100672 elif use_but:
Jakob Buchgraber92755d72018-02-22 15:33:37 +0100673 print_collapsed_group(":gcloud: Downloading Bazel Under Test")
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100674 bazel_binary = download_bazel_binary(tmpdir, platform)
Philipp Wollermann639c0452019-01-03 11:23:54 +0100675 else:
676 bazel_binary = "bazel"
Florian Weikertc8642af2019-02-03 23:58:51 +0100677 if bazel_version:
678 # This will only work if the bazel binary in $PATH is actually a bazelisk binary
679 # (https://github.com/philwo/bazelisk).
680 os.environ["USE_BAZEL_VERSION"] = bazel_version
Florian Weikert4ee0bed2019-02-21 18:03:00 +0100681 test_env_vars.append("USE_BAZEL_VERSION")
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200682
Philipp Wollermann213ac9d2019-02-06 11:50:05 +0100683 os.environ.update(task_config.get("environment", {}))
684
Philipp Wollermanna5aee2c2019-02-11 16:55:19 +0100685 # Allow the config to override the current working directory.
686 required_prefix = os.getcwd()
687 requested_working_dir = os.path.abspath(task_config.get("working_directory", ""))
688 if os.path.commonpath([required_prefix, requested_working_dir]) != required_prefix:
689 raise BuildkiteException("working_directory refers to a path outside the workspace")
690 os.chdir(requested_working_dir)
691
Florian Weikerte72d68a2019-03-08 18:56:33 +0100692 if platform == "windows":
693 execute_batch_commands(task_config.get("batch_commands", None))
694 else:
695 execute_shell_commands(task_config.get("shell_commands", None))
696
Florian Weikertc8642af2019-02-03 23:58:51 +0100697 bazel_version = print_bazel_version_info(bazel_binary, platform)
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200698
Yun Penga5a1ee02018-12-05 15:00:58 +0100699 print_environment_variables_info()
700
Yun Pengd0217ed2018-11-30 14:51:11 +0100701 if incompatible_flags:
702 print_expanded_group("Build and test with the following incompatible flags:")
703 for flag in incompatible_flags:
704 eprint(flag + "\n")
705
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100706 execute_bazel_run(
Florian Weikertc8642af2019-02-03 23:58:51 +0100707 bazel_binary, platform, task_config.get("run_targets", None), incompatible_flags
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100708 )
Philipp Wollermann2409c6e2018-08-07 07:37:54 +0200709
Florian Weikertc8642af2019-02-03 23:58:51 +0100710 if task_config.get("sauce", None):
Philipp Wollermanne1318eb2018-08-13 15:08:01 +0200711 print_collapsed_group(":saucelabs: Starting Sauce Connect Proxy")
712 os.environ["SAUCE_USERNAME"] = "bazel_rules_webtesting"
Philipp Wollermann1403d2c2019-01-10 13:15:51 +0100713 os.environ["SAUCE_ACCESS_KEY"] = saucelabs_token()
Philipp Wollermann733a3602018-08-14 12:44:03 +0200714 os.environ["TUNNEL_IDENTIFIER"] = str(uuid.uuid4())
Philipp Wollermanne1318eb2018-08-13 15:08:01 +0200715 os.environ["BUILD_TAG"] = str(uuid.uuid4())
716 readyfile = os.path.join(tmpdir, "sc_is_ready")
717 if platform == "windows":
Philipp Wollermann733a3602018-08-14 12:44:03 +0200718 cmd = ["sauce-connect.exe", "/i", os.environ["TUNNEL_IDENTIFIER"], "/f", readyfile]
Philipp Wollermanne1318eb2018-08-13 15:08:01 +0200719 else:
Philipp Wollermann733a3602018-08-14 12:44:03 +0200720 cmd = ["sc", "-i", os.environ["TUNNEL_IDENTIFIER"], "-f", readyfile]
Philipp Wollermanne1318eb2018-08-13 15:08:01 +0200721 sc_process = execute_command_background(cmd)
722 wait_start = time.time()
723 while not os.path.exists(readyfile):
724 if time.time() - wait_start > 30:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100725 raise BuildkiteException(
726 "Sauce Connect Proxy is still not ready after 30 seconds, aborting!"
727 )
Philipp Wollermanne1318eb2018-08-13 15:08:01 +0200728 time.sleep(1)
729 print("Sauce Connect Proxy is ready, continuing...")
730
Yun Peng4d1d6542019-01-17 18:30:33 +0100731 if needs_clean:
Yun Pengea0359e2019-01-17 15:37:47 +0100732 execute_bazel_clean(bazel_binary, platform)
733
Florian Weikert736d06e2019-05-08 13:16:42 +0200734 build_targets, test_targets = calculate_targets(
735 task_config, platform, bazel_binary, build_only, test_only
736 )
737 if not build_targets and not test_targets:
738 raise BuildkiteException("There are neither build nor test targets")
739
740 if build_targets:
Philipp Wollermann639c0452019-01-03 11:23:54 +0100741 execute_bazel_build(
Florian Weikertc8642af2019-02-03 23:58:51 +0100742 bazel_version,
Philipp Wollermann639c0452019-01-03 11:23:54 +0100743 bazel_binary,
744 platform,
Florian Weikertc8642af2019-02-03 23:58:51 +0100745 task_config.get("build_flags", []),
Florian Weikert736d06e2019-05-08 13:16:42 +0200746 build_targets,
Philipp Wollermann639c0452019-01-03 11:23:54 +0100747 None,
748 incompatible_flags,
749 )
750 if save_but:
751 upload_bazel_binary(platform)
752
Florian Weikert736d06e2019-05-08 13:16:42 +0200753 if test_targets:
Florian Weikert4ee0bed2019-02-21 18:03:00 +0100754 test_flags = task_config.get("test_flags", [])
755 if test_env_vars:
756 test_flags += ["--test_env={}".format(v) for v in test_env_vars]
757
Florian Weikert4901c662019-02-26 13:20:11 +0100758 if not is_windows():
759 # On platforms that support sandboxing (Linux, MacOS) we have
760 # to allow access to Bazelisk's cache directory.
761 # However, the flag requires the directory to exist,
762 # so we create it here in order to not crash when a test
763 # does not invoke Bazelisk.
764 bazelisk_cache_dir = get_bazelisk_cache_directory(platform)
765 os.makedirs(bazelisk_cache_dir, mode=0o755, exist_ok=True)
766 test_flags.append("--sandbox_writable_path={}".format(bazelisk_cache_dir))
Florian Weikert5b890332019-02-25 14:57:43 +0100767
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100768 test_bep_file = os.path.join(tmpdir, "test_bep.json")
769 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100770 execute_bazel_test(
Florian Weikertc8642af2019-02-03 23:58:51 +0100771 bazel_version,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100772 bazel_binary,
773 platform,
Florian Weikert4ee0bed2019-02-21 18:03:00 +0100774 test_flags,
Florian Weikert736d06e2019-05-08 13:16:42 +0200775 test_targets,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100776 test_bep_file,
777 monitor_flaky_tests,
778 incompatible_flags,
779 )
Jakob Buchgraber5d6c7142018-02-21 20:16:51 +0100780 if has_flaky_tests(test_bep_file):
Jakob Buchgraberc340f582018-06-22 13:48:33 +0200781 if monitor_flaky_tests:
Jakob Buchgraberfef7ef42018-03-16 17:56:11 +0100782 # Upload the BEP logs from Bazel builds for later analysis on flaky tests
783 build_id = os.getenv("BUILDKITE_BUILD_ID")
Jakob Buchgraberc340f582018-06-22 13:48:33 +0200784 pipeline_slug = os.getenv("BUILDKITE_PIPELINE_SLUG")
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100785 execute_command(
786 [
787 gsutil_command(),
788 "cp",
789 test_bep_file,
790 "gs://bazel-buildkite-stats/flaky-tests-bep/"
791 + pipeline_slug
792 + "/"
793 + build_id
794 + ".json",
795 ]
796 )
Philipp Wollermann639c0452019-01-03 11:23:54 +0100797 finally:
798 upload_test_logs(test_bep_file, tmpdir)
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100799 finally:
Philipp Wollermanne1318eb2018-08-13 15:08:01 +0200800 if sc_process:
801 sc_process.terminate()
802 try:
803 sc_process.wait(timeout=10)
804 except subprocess.TimeoutExpired:
805 sc_process.kill()
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100806 if tmpdir:
807 shutil.rmtree(tmpdir)
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100808
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100809
Florian Weikert4901c662019-02-26 13:20:11 +0100810def get_bazelisk_cache_directory(platform):
811 # The path relies on the behavior of Go's os.UserCacheDir()
812 # and of the Go version of Bazelisk.
Florian Weikert5b890332019-02-25 14:57:43 +0100813 dir = "Library/Caches" if platform == "macos" else ".cache"
Florian Weikert4901c662019-02-26 13:20:11 +0100814 return os.path.join(os.environ.get("HOME"), dir, "bazelisk")
815
Florian Weikert5b890332019-02-25 14:57:43 +0100816
Jakob Buchgraber5d6c7142018-02-21 20:16:51 +0100817def tests_with_status(bep_file, status):
818 return set(label for label, _ in test_logs_for_status(bep_file, status=status))
Jakob Buchgraber257693b2018-02-20 00:03:56 +0100819
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100820
Philipp Wollermann1403d2c2019-01-10 13:15:51 +0100821def saucelabs_token():
822 return (
823 subprocess.check_output(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100824 [
Philipp Wollermann1403d2c2019-01-10 13:15:51 +0100825 gcloud_command(),
826 "kms",
827 "decrypt",
Philipp Wollermanna4722b42019-01-10 16:50:13 +0100828 "--project",
829 "bazel-untrusted",
Philipp Wollermann1403d2c2019-01-10 13:15:51 +0100830 "--location",
831 "global",
832 "--keyring",
833 "buildkite",
834 "--key",
835 "saucelabs-access-key",
836 "--ciphertext-file",
837 "-",
838 "--plaintext-file",
839 "-",
840 ],
841 input=base64.b64decode(ENCRYPTED_SAUCELABS_TOKEN),
842 env=os.environ,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100843 )
Philipp Wollermann1403d2c2019-01-10 13:15:51 +0100844 .decode("utf-8")
845 .strip()
846 )
Yun Pengb6b18862019-01-07 14:31:55 +0100847
848
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100849def is_pull_request():
Jakob Buchgraber67761d32018-02-21 19:00:21 +0100850 third_party_repo = os.getenv("BUILDKITE_PULL_REQUEST_REPO", "")
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100851 return len(third_party_repo) > 0
852
853
Jakob Buchgraber02e07222018-02-19 15:05:56 +0100854def has_flaky_tests(bep_file):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100855 return len(test_logs_for_status(bep_file, status="FLAKY")) > 0
Jakob Buchgraber02e07222018-02-19 15:05:56 +0100856
857
Yun Penge3cf12d2018-12-05 15:01:09 +0100858def print_bazel_version_info(bazel_binary, platform):
Jakob Buchgraber99c4bbb2018-02-22 11:59:31 +0100859 print_collapsed_group(":information_source: Bazel Info")
Philipp Wollermannf13804b2019-02-05 21:08:30 +0100860 version_output = execute_command_and_get_output(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100861 [bazel_binary]
862 + common_startup_flags(platform)
863 + ["--nomaster_bazelrc", "--bazelrc=/dev/null", "version"]
864 )
865 execute_command(
866 [bazel_binary]
867 + common_startup_flags(platform)
868 + ["--nomaster_bazelrc", "--bazelrc=/dev/null", "info"]
869 )
Jakob Buchgraber7e690a72018-02-18 13:22:15 +0100870
Florian Weikertc8642af2019-02-03 23:58:51 +0100871 match = BUILD_LABEL_PATTERN.search(version_output)
872 return match.group(1) if match else "unreleased binary"
873
Jakob Buchgraber7e690a72018-02-18 13:22:15 +0100874
Yun Penga5a1ee02018-12-05 15:00:58 +0100875def print_environment_variables_info():
876 print_collapsed_group(":information_source: Environment Variables")
877 for key, value in os.environ.items():
878 eprint("%s=(%s)" % (key, value))
879
880
Jakob Buchgraber426399e2018-03-20 19:45:46 +0100881def upload_bazel_binary(platform):
Jakob Buchgraber7d1d3bb2018-02-21 22:38:22 +0100882 print_collapsed_group(":gcloud: Uploading Bazel Under Test")
Tobias Werth322aa742018-12-20 11:44:16 +0100883 binary_path = "bazel-bin/src/bazel"
Jakob Buchgraber426399e2018-03-20 19:45:46 +0100884 if platform == "windows":
Tobias Werth322aa742018-12-20 11:44:16 +0100885 binary_path = r"bazel-bin\src\bazel"
Philipp Wollermann94bd9e32018-04-30 15:32:28 +0200886 execute_command(["buildkite-agent", "artifact", "upload", binary_path])
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100887
888
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +0100889def download_bazel_binary(dest_dir, platform):
Philipp Wollermann962a89e2018-08-07 07:55:22 +0200890 host_platform = PLATFORMS[platform].get("host-platform", platform)
Tobias Werth322aa742018-12-20 11:44:16 +0100891 binary_path = "bazel-bin/src/bazel"
Jakob Buchgraber426399e2018-03-20 19:45:46 +0100892 if platform == "windows":
Tobias Werth322aa742018-12-20 11:44:16 +0100893 binary_path = r"bazel-bin\src\bazel"
Jakob Buchgraber426399e2018-03-20 19:45:46 +0100894
Philipp Wollermann962a89e2018-08-07 07:55:22 +0200895 source_step = create_label(host_platform, "Bazel", build_only=True)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100896 execute_command(
897 ["buildkite-agent", "artifact", "download", binary_path, dest_dir, "--step", source_step]
898 )
Jakob Buchgraber00046232018-03-27 20:15:26 +0200899 bazel_binary_path = os.path.join(dest_dir, binary_path)
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100900 st = os.stat(bazel_binary_path)
901 os.chmod(bazel_binary_path, st.st_mode | stat.S_IEXEC)
902 return bazel_binary_path
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100903
904
Yun Peng20d45602018-10-18 13:27:05 +0200905def download_bazel_binary_at_commit(dest_dir, platform, bazel_git_commit):
906 # We only build bazel binary on ubuntu14.04 for every bazel commit.
907 # It should be OK to use it on other ubuntu platforms.
908 if "ubuntu" in PLATFORMS[platform].get("host-platform", platform):
909 platform = "ubuntu1404"
910 bazel_binary_path = os.path.join(dest_dir, "bazel.exe" if platform == "windows" else "bazel")
Yun Peng02312732019-01-17 18:17:05 +0100911 try:
912 execute_command(
913 [
914 gsutil_command(),
915 "cp",
916 bazelci_builds_gs_url(platform, bazel_git_commit),
917 bazel_binary_path,
918 ]
919 )
920 except subprocess.CalledProcessError as e:
Philipp Wollermannc05ac682019-01-19 12:37:28 +0100921 raise BuildkiteException(
922 "Failed to download Bazel binary at %s, error message:\n%s" % (bazel_git_commit, str(e))
923 )
Yun Peng20d45602018-10-18 13:27:05 +0200924 st = os.stat(bazel_binary_path)
925 os.chmod(bazel_binary_path, st.st_mode | stat.S_IEXEC)
926 return bazel_binary_path
927
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100928
Yun Peng376d2b32018-11-29 10:24:54 +0100929def clone_git_repository(git_repository, platform, git_commit=None):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100930 root = downstream_projects_root(platform)
Philipp Wollermannff39ef52018-02-21 14:18:52 +0100931 project_name = re.search(r"/([^/]+)\.git$", git_repository).group(1)
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100932 clone_path = os.path.join(root, project_name)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100933 print_collapsed_group(
934 "Fetching %s sources at %s" % (project_name, git_commit if git_commit else "HEAD")
935 )
Philipp Wollermann438ec242018-09-05 14:39:24 +0200936
Philipp Wollermann62f4a032019-05-08 17:44:14 +0200937 mirror_root = {
938 "macos": "/usr/local/var/bazelbuild/",
939 "windows": "c:\\buildkite\\bazelbuild\\",
940 }.get(platform, "/var/lib/bazelbuild/")
941
942 mirror_path = mirror_root + re.sub(r"[^0-9A-Za-z]", "-", git_repository)
Philipp Wollermannea128282019-05-08 11:56:14 +0200943
Philipp Wollermann414703d2018-08-28 16:40:38 +0200944 if not os.path.exists(clone_path):
Philipp Wollermann62f4a032019-05-08 17:44:14 +0200945 if os.path.exists(mirror_path):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100946 execute_command(
Philipp Wollermann62f4a032019-05-08 17:44:14 +0200947 ["git", "clone", "-v", "--reference", mirror_path, git_repository, clone_path]
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100948 )
Philipp Wollermannd4cd0d82018-05-01 09:56:24 +0200949 else:
Philipp Wollermannea128282019-05-08 11:56:14 +0200950 execute_command(["git", "clone", "-v", git_repository, clone_path])
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100951
Philipp Wollermann414703d2018-08-28 16:40:38 +0200952 os.chdir(clone_path)
953 execute_command(["git", "remote", "set-url", "origin", git_repository])
954 execute_command(["git", "clean", "-fdqx"])
955 execute_command(["git", "submodule", "foreach", "--recursive", "git", "clean", "-fdqx"])
Philipp Wollermann414703d2018-08-28 16:40:38 +0200956 execute_command(["git", "fetch", "origin"])
Yun Peng376d2b32018-11-29 10:24:54 +0100957 if git_commit:
958 # sync to a specific commit of this repository
959 execute_command(["git", "reset", git_commit, "--hard"])
960 else:
961 # sync to the latest commit of HEAD. Unlikely git pull this also works after a force push.
Philipp Wollermanncd5694c2019-01-03 14:53:04 +0100962 remote_head = (
963 subprocess.check_output(["git", "symbolic-ref", "refs/remotes/origin/HEAD"])
964 .decode("utf-8")
965 .rstrip()
966 )
Yun Peng376d2b32018-11-29 10:24:54 +0100967 execute_command(["git", "reset", remote_head, "--hard"])
Philipp Wollermann414703d2018-08-28 16:40:38 +0200968 execute_command(["git", "submodule", "sync", "--recursive"])
969 execute_command(["git", "submodule", "update", "--init", "--recursive", "--force"])
970 execute_command(["git", "submodule", "foreach", "--recursive", "git", "reset", "--hard"])
971 execute_command(["git", "clean", "-fdqx"])
972 execute_command(["git", "submodule", "foreach", "--recursive", "git", "clean", "-fdqx"])
Yun Peng20d45602018-10-18 13:27:05 +0200973 return clone_path
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100974
Philipp Wollermann438ec242018-09-05 14:39:24 +0200975
Yun Penga935a542018-05-18 15:08:53 +0200976def execute_batch_commands(commands):
977 if not commands:
978 return
979 print_collapsed_group(":batch: Setup (Batch Commands)")
980 batch_commands = "&".join(commands)
Jakob Buchgraber4a824412018-06-22 12:56:10 +0200981 return subprocess.run(batch_commands, shell=True, check=True, env=os.environ).returncode
Yun Penga935a542018-05-18 15:08:53 +0200982
Philipp Wollermann414703d2018-08-28 16:40:38 +0200983
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100984def execute_shell_commands(commands):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100985 if not commands:
986 return
Jakob Buchgraber94d5c212018-02-22 09:57:08 +0100987 print_collapsed_group(":bash: Setup (Shell Commands)")
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100988 shell_command = "\n".join(commands)
Philipp Wollermann3e1a7712018-02-19 17:34:24 +0100989 execute_command([shell_command], shell=True)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100990
991
Yun Peng0a6a98a2019-03-06 13:07:54 +0100992def handle_bazel_failure(exception, action):
993 msg = "bazel {0} failed with exit code {1}".format(action, exception.returncode)
994 if use_bazelisk_migrate():
995 print_collapsed_group(msg)
996 else:
997 raise BuildkiteException(msg)
998
999
Yun Peng4be92b32018-11-30 09:48:29 +01001000def execute_bazel_run(bazel_binary, platform, targets, incompatible_flags):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001001 if not targets:
1002 return
1003 print_collapsed_group("Setup (Run Targets)")
Florian Weikert474d7972019-03-01 02:12:01 +01001004 # When using bazelisk --migrate to test incompatible flags,
1005 # incompatible flags set by "INCOMPATIBLE_FLAGS" env var will be ignored.
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001006 incompatible_flags_to_use = (
1007 [] if (use_bazelisk_migrate() or not incompatible_flags) else incompatible_flags
1008 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001009 for target in targets:
Yun Peng0a6a98a2019-03-06 13:07:54 +01001010 try:
1011 execute_command(
1012 [bazel_binary]
1013 + bazelisk_flags()
1014 + common_startup_flags(platform)
1015 + ["run"]
1016 + common_build_flags(None, platform)
1017 + incompatible_flags_to_use
1018 + [target]
1019 )
1020 except subprocess.CalledProcessError as e:
1021 handle_bazel_failure(e, "run")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001022
1023
Jakob Buchgraber4f1d2712018-02-20 10:22:47 +01001024def remote_caching_flags(platform):
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001025 # Only enable caching for untrusted builds.
1026 if CLOUD_PROJECT != "bazel-untrusted":
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001027 return []
Philipp Wollermann02955272019-04-18 18:00:48 +02001028
Philipp Wollermann380f1e62019-04-12 16:45:27 +02001029 if platform == "macos":
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001030 platform_cache_key = [
1031 # macOS version:
1032 subprocess.check_output(["/usr/bin/sw_vers", "-productVersion"]),
1033 # Path to Xcode:
1034 subprocess.check_output(["/usr/bin/xcode-select", "-p"]),
1035 # Xcode version:
1036 subprocess.check_output(["/usr/bin/xcodebuild", "-version"]),
1037 ]
1038 # Use a local cache server for our macOS machines.
1039 cache_url = "http://100.107.67.248"
1040 else:
1041 platform_cache_key = [
1042 # Platform name:
1043 platform.encode("utf-8")
1044 ]
1045 # Use GCS for caching builds running on GCE.
1046 cache_url = "https://storage.googleapis.com/bazel-untrusted-buildkite-cache"
Philipp Wollermann380f1e62019-04-12 16:45:27 +02001047
1048 platform_cache_digest = hashlib.sha256()
1049 for key in platform_cache_key:
1050 platform_cache_digest.update(key)
1051 platform_cache_digest.update(b":")
1052
Philipp Wollermannd96d8fa2019-01-11 14:37:47 +01001053 flags = [
Philipp Wollermann94937722019-01-11 14:33:18 +01001054 "--remote_timeout=60",
Philipp Wollermann639c0452019-01-03 11:23:54 +01001055 "--remote_max_connections=200",
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001056 "--remote_http_cache={}/{}".format(cache_url, platform_cache_digest.hexdigest()),
Philipp Wollermann639c0452019-01-03 11:23:54 +01001057 ]
Jakob Buchgraber4f1d2712018-02-20 10:22:47 +01001058
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001059 # Need to use the correct credentials when running on GCE.
1060 if platform != "macos":
Philipp Wollermann3845ad82019-01-17 14:01:05 +01001061 flags += ["--google_default_credentials"]
Philipp Wollermannd96d8fa2019-01-11 14:37:47 +01001062
1063 return flags
1064
Jakob Buchgraber4f1d2712018-02-20 10:22:47 +01001065
Jakob Buchgraberb4342cd2018-02-20 16:35:07 +01001066def remote_enabled(flags):
1067 # Detect if the project configuration enabled its own remote caching / execution.
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001068 remote_flags = ["--remote_executor", "--remote_cache", "--remote_http_cache"]
Jakob Buchgraberb4342cd2018-02-20 16:35:07 +01001069 for flag in flags:
1070 for remote_flag in remote_flags:
1071 if flag.startswith(remote_flag):
1072 return True
1073 return False
1074
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001075
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001076def concurrent_jobs(platform):
1077 return "75" if platform.startswith("rbe_") else str(multiprocessing.cpu_count())
Jakob Buchgraber51a83662018-02-22 19:49:24 +01001078
1079
Philipp Wollermann3e28d3b2018-02-23 23:19:37 +01001080def concurrent_test_jobs(platform):
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001081 if platform.startswith("rbe_"):
1082 return "75"
1083 elif platform == "windows":
Jakob Buchgrabere3ccda32018-06-22 23:29:48 +02001084 return "8"
Philipp Wollermann111adfb2018-11-22 10:26:03 +01001085 elif platform == "macos":
1086 return "8"
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001087 return "12"
Philipp Wollermann3e28d3b2018-02-23 23:19:37 +01001088
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001089
Yun Peng58977d62018-11-16 12:19:20 +01001090def common_startup_flags(platform):
Philipp Wollermann639c0452019-01-03 11:23:54 +01001091 return ["--output_user_root=D:/b"] if platform == "windows" else []
Yun Peng58977d62018-11-16 12:19:20 +01001092
1093
1094def common_build_flags(bep_file, platform):
Yun Peng088cc932018-11-16 12:11:46 +01001095 flags = [
Yun Pengf51e7842018-11-16 11:35:43 +01001096 "--show_progress_rate_limit=5",
1097 "--curses=yes",
1098 "--color=yes",
1099 "--verbose_failures",
1100 "--keep_going",
1101 "--jobs=" + concurrent_jobs(platform),
Yun Pengf51e7842018-11-16 11:35:43 +01001102 "--announce_rc",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001103 "--experimental_multi_threaded_digest",
Philipp Wollermannb97f9102019-04-16 18:05:56 +02001104 "--experimental_repository_cache_hardlinks",
Philipp Wollermannef89d2f2019-04-18 15:52:24 +02001105 # Some projects set --disk_cache in their project-specific bazelrc, which we never want on
1106 # CI, so let's just disable it explicitly.
1107 "--disk_cache=",
Yun Peng088cc932018-11-16 12:11:46 +01001108 ]
Philipp Wollermann639c0452019-01-03 11:23:54 +01001109
Philipp Wollermannb97f9102019-04-16 18:05:56 +02001110 if platform == "windows":
1111 pass
1112 elif platform == "macos":
1113 flags += [
1114 "--sandbox_writable_path=/var/tmp/_bazel_buildkite/cache/repos/v1",
1115 "--test_env=REPOSITORY_CACHE=/var/tmp/_bazel_buildkite/cache/repos/v1",
1116 ]
1117 else:
Philipp Wollermann639c0452019-01-03 11:23:54 +01001118 flags += ["--sandbox_tmpfs_path=/tmp"]
1119
Yun Peng088cc932018-11-16 12:11:46 +01001120 if bep_file:
Philipp Wollermann639c0452019-01-03 11:23:54 +01001121 flags += [
1122 "--experimental_build_event_json_file_path_conversion=false",
1123 "--build_event_json_file=" + bep_file,
1124 ]
1125
Yun Peng088cc932018-11-16 12:11:46 +01001126 return flags
Philipp Wollermann94bd9e32018-04-30 15:32:28 +02001127
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001128
Yun Pengb7247ff2018-11-15 13:52:39 +01001129def rbe_flags(original_flags, accept_cached):
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001130 # Enable remote execution via RBE.
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001131 flags = [
1132 "--remote_executor=remotebuildexecution.googleapis.com",
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001133 "--remote_instance_name=projects/bazel-untrusted/instances/default_instance",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001134 "--remote_timeout=3600",
1135 "--spawn_strategy=remote",
1136 "--strategy=Javac=remote",
1137 "--strategy=Closure=remote",
1138 "--genrule_strategy=remote",
1139 "--experimental_strict_action_env",
1140 "--tls_enabled=true",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001141 "--google_default_credentials",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001142 ]
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001143
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001144 # Enable BES / Build Results reporting.
1145 flags += [
1146 "--bes_backend=buildeventservice.googleapis.com",
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001147 "--bes_timeout=360s",
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001148 "--project_id=bazel-untrusted",
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001149 ]
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001150
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001151 if not accept_cached:
1152 flags += ["--noremote_accept_cached"]
Philipp Wollermannbcfd9da2018-08-09 15:31:18 +02001153
Xin03a88ab2019-03-11 19:18:50 -04001154 # Copied from https://github.com/bazelbuild/bazel-toolchains/blob/master/configs/ubuntu16_04_clang/1.0/toolchain.bazelrc
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001155 flags += [
Xindb02c012018-11-07 14:10:54 -05001156 # These should NOT be modified before @bazel_toolchains repo pin is
1157 # updated in projects' WORKSPACE files.
1158 #
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001159 # Toolchain related flags to append at the end of your .bazelrc file.
Xin03a88ab2019-03-11 19:18:50 -04001160 "--host_javabase=@bazel_toolchains//configs/ubuntu16_04_clang/latest:javabase",
1161 "--javabase=@bazel_toolchains//configs/ubuntu16_04_clang/latest:javabase",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001162 "--host_java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8",
1163 "--java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8",
Xin03a88ab2019-03-11 19:18:50 -04001164 "--crosstool_top=@bazel_toolchains//configs/ubuntu16_04_clang/latest:crosstool_top_default",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001165 "--action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1",
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001166 ]
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001167
Yun Pengb7247ff2018-11-15 13:52:39 +01001168 # Platform flags:
1169 # The toolchain container used for execution is defined in the target indicated
1170 # by "extra_execution_platforms", "host_platform" and "platforms".
Xin03a88ab2019-03-11 19:18:50 -04001171 # If you are using your own toolchain container, you need to create a platform
1172 # target with "constraint_values" that allow for the toolchain specified with
1173 # "extra_toolchains" to be selected (given constraints defined in
1174 # "exec_compatible_with").
Yun Pengb7247ff2018-11-15 13:52:39 +01001175 # More about platforms: https://docs.bazel.build/versions/master/platforms.html
1176 # Don't add platform flags if they are specified already.
1177 platform_flags = {
Xin03a88ab2019-03-11 19:18:50 -04001178 "--extra_toolchains": "@bazel_toolchains//configs/ubuntu16_04_clang/latest:toolchain_default",
1179 "--extra_execution_platforms": "@bazel_toolchains//configs/ubuntu16_04_clang/latest:platform",
1180 "--host_platform": "@bazel_toolchains//configs/ubuntu16_04_clang/latest:platform",
1181 "--platforms": "@bazel_toolchains//configs/ubuntu16_04_clang/latest:platform",
Yun Pengb7247ff2018-11-15 13:52:39 +01001182 }
Yun Peng67ab5062018-11-15 13:58:15 +01001183 for platform_flag, value in list(platform_flags.items()):
Yun Pengb7247ff2018-11-15 13:52:39 +01001184 found = False
1185 for original_flag in original_flags:
1186 if original_flag.startswith(platform_flag):
1187 found = True
1188 break
1189 if not found:
1190 flags += [platform_flag + "=" + value]
1191
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001192 return flags
1193
1194
Florian Weikert24a4b482018-11-30 19:05:38 +01001195def compute_flags(platform, flags, incompatible_flags, bep_file, enable_remote_cache=False):
Yun Peng58977d62018-11-16 12:19:20 +01001196 aggregated_flags = common_build_flags(bep_file, platform)
Yun Peng32dbec32018-11-02 12:47:41 +01001197 if not remote_enabled(flags):
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001198 if platform.startswith("rbe_"):
Florian Weikert24a4b482018-11-30 19:05:38 +01001199 aggregated_flags += rbe_flags(flags, accept_cached=enable_remote_cache)
1200 elif enable_remote_cache:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001201 aggregated_flags += remote_caching_flags(platform)
Yun Peng75786552018-11-13 15:23:30 +01001202 aggregated_flags += flags
Yun Peng4be92b32018-11-30 09:48:29 +01001203 if incompatible_flags:
1204 aggregated_flags += incompatible_flags
Yun Peng53598002018-12-03 10:42:02 +01001205
Florian Weikert24a4b482018-11-30 19:05:38 +01001206 return aggregated_flags
Yun Peng53598002018-12-03 10:42:02 +01001207
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001208
Yun Pengea0359e2019-01-17 15:37:47 +01001209def execute_bazel_clean(bazel_binary, platform):
1210 print_expanded_group(":bazel: Clean")
1211
1212 try:
Philipp Wollermannc05ac682019-01-19 12:37:28 +01001213 execute_command([bazel_binary] + common_startup_flags(platform) + ["clean", "--expunge"])
Yun Pengea0359e2019-01-17 15:37:47 +01001214 except subprocess.CalledProcessError as e:
1215 raise BuildkiteException("bazel clean failed with exit code {}".format(e.returncode))
1216
1217
Florian Weikertc8642af2019-02-03 23:58:51 +01001218def execute_bazel_build(
1219 bazel_version, bazel_binary, platform, flags, targets, bep_file, incompatible_flags
1220):
1221 print_expanded_group(":bazel: Build ({})".format(bazel_version))
Florian Weikert24a4b482018-11-30 19:05:38 +01001222
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001223 aggregated_flags = compute_flags(
Yun Peng8975c6b2019-02-28 11:55:55 +01001224 platform,
1225 flags,
1226 # When using bazelisk --migrate to test incompatible flags,
1227 # incompatible flags set by "INCOMPATIBLE_FLAGS" env var will be ignored.
1228 [] if (use_bazelisk_migrate() or not incompatible_flags) else incompatible_flags,
1229 bep_file,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001230 enable_remote_cache=True,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001231 )
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001232 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001233 execute_command(
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001234 [bazel_binary]
1235 + bazelisk_flags()
1236 + common_startup_flags(platform)
1237 + ["build"]
1238 + aggregated_flags
1239 + targets
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001240 )
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001241 except subprocess.CalledProcessError as e:
Yun Peng0a6a98a2019-03-06 13:07:54 +01001242 handle_bazel_failure(e, "build")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001243
1244
Florian Weikert736d06e2019-05-08 13:16:42 +02001245def calculate_targets(task_config, platform, bazel_binary, build_only, test_only):
1246 build_targets = [] if test_only else task_config.get("build_targets", [])
1247 test_targets = [] if build_only else task_config.get("test_targets", [])
1248
1249 shard_id = int(os.getenv("BUILDKITE_PARALLEL_JOB", "-1"))
1250 shard_count = int(os.getenv("BUILDKITE_PARALLEL_JOB_COUNT", "-1"))
1251 if shard_id > -1 and shard_count > -1:
1252 print_collapsed_group(
1253 ":female-detective: Calculating targets for shard {}/{}".format(
1254 shard_id + 1, shard_count
1255 )
1256 )
1257 expanded_test_targets = expand_test_target_patterns(bazel_binary, platform, test_targets)
1258 build_targets, test_targets = get_targets_for_shard(
1259 build_targets, expanded_test_targets, shard_id, shard_count
1260 )
1261
1262 return build_targets, test_targets
1263
1264
1265def expand_test_target_patterns(bazel_binary, platform, test_targets):
1266 included_targets, excluded_targets = partition_test_targets(test_targets)
1267 excluded_string = (
1268 " except tests(set({}))".format(" ".join("'{}'".format(t) for t in excluded_targets))
1269 if excluded_targets
1270 else ""
1271 )
1272
1273 eprint("Resolving test targets via bazel query")
1274 output = execute_command_and_get_output(
1275 [bazel_binary]
1276 + common_startup_flags(platform)
1277 + [
1278 "--nomaster_bazelrc",
1279 "--bazelrc=/dev/null",
1280 "query",
1281 "tests(set({})){}".format(
1282 " ".join("'{}'".format(t) for t in included_targets), excluded_string
1283 ),
1284 ],
1285 print_output=False,
1286 capture_stderr=False,
1287 )
1288 return output.split("\n")
1289
1290
1291def partition_test_targets(test_targets):
1292 included_targets, excluded_targets = [], []
1293 for target in test_targets:
1294 if target == "--":
1295 continue
1296 elif target.startswith("-"):
1297 excluded_targets.append(target[1:])
1298 else:
1299 included_targets.append(target)
1300
1301 return included_targets, excluded_targets
1302
1303
1304def get_targets_for_shard(build_targets, test_targets, shard_id, shard_count):
1305 # TODO(fweikert): implement a more sophisticated algorithm
1306 build_targets_for_this_shard = sorted(build_targets)[shard_id::shard_count]
1307 test_targets_for_this_shard = sorted(test_targets)[shard_id::shard_count]
1308
1309 return build_targets_for_this_shard, test_targets_for_this_shard
1310
1311
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001312def execute_bazel_test(
Florian Weikertc8642af2019-02-03 23:58:51 +01001313 bazel_version,
1314 bazel_binary,
1315 platform,
1316 flags,
1317 targets,
1318 bep_file,
1319 monitor_flaky_tests,
1320 incompatible_flags,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001321):
Florian Weikertc8642af2019-02-03 23:58:51 +01001322 print_expanded_group(":bazel: Test ({})".format(bazel_version))
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001323
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001324 aggregated_flags = [
1325 "--flaky_test_attempts=3",
1326 "--build_tests_only",
1327 "--local_test_jobs=" + concurrent_test_jobs(platform),
1328 ]
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001329 # Don't enable remote caching if the user enabled remote execution / caching themselves
Jakob Buchgraberc340f582018-06-22 13:48:33 +02001330 # or flaky test monitoring is enabled, as remote caching makes tests look less flaky than
1331 # they are.
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001332 aggregated_flags += compute_flags(
Yun Peng8975c6b2019-02-28 11:55:55 +01001333 platform,
1334 flags,
1335 # When using bazelisk --migrate to test incompatible flags,
1336 # incompatible flags set by "INCOMPATIBLE_FLAGS" env var will be ignored.
1337 [] if (use_bazelisk_migrate() or not incompatible_flags) else incompatible_flags,
1338 bep_file,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001339 enable_remote_cache=not monitor_flaky_tests,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001340 )
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001341
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001342 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001343 execute_command(
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001344 [bazel_binary]
1345 + bazelisk_flags()
1346 + common_startup_flags(platform)
1347 + ["test"]
1348 + aggregated_flags
1349 + targets
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001350 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001351 except subprocess.CalledProcessError as e:
Yun Peng0a6a98a2019-03-06 13:07:54 +01001352 handle_bazel_failure(e, "test")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001353
1354
Jakob Buchgraber02e07222018-02-19 15:05:56 +01001355def upload_test_logs(bep_file, tmpdir):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001356 if not os.path.exists(bep_file):
1357 return
1358 test_logs = test_logs_to_upload(bep_file, tmpdir)
1359 if test_logs:
1360 cwd = os.getcwd()
1361 try:
1362 os.chdir(tmpdir)
Jakob Buchgraber3f9e8b12018-02-23 16:19:05 +01001363 test_logs = [os.path.relpath(test_log, tmpdir) for test_log in test_logs]
Jakob Buchgraber92755d72018-02-22 15:33:37 +01001364 test_logs = sorted(test_logs)
Jakob Buchgraber2fc1bb72018-02-22 20:11:40 +01001365 print_collapsed_group(":gcloud: Uploading Test Logs")
Jakob Buchgraber92755d72018-02-22 15:33:37 +01001366 execute_command(["buildkite-agent", "artifact", "upload", ";".join(test_logs)])
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001367 finally:
1368 os.chdir(cwd)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001369
1370
Jakob Buchgraber02e07222018-02-19 15:05:56 +01001371def test_logs_to_upload(bep_file, tmpdir):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001372 failed = test_logs_for_status(bep_file, status="FAILED")
1373 timed_out = test_logs_for_status(bep_file, status="TIMEOUT")
1374 flaky = test_logs_for_status(bep_file, status="FLAKY")
1375 # Rename the test.log files to the target that created them
1376 # so that it's easy to associate test.log and target.
1377 new_paths = []
Philipp Wollermannff39ef52018-02-21 14:18:52 +01001378 for label, test_logs in failed + timed_out + flaky:
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001379 attempt = 0
1380 if len(test_logs) > 1:
1381 attempt = 1
1382 for test_log in test_logs:
Jakob Buchgraber070ef5f2018-02-20 17:57:14 +01001383 try:
1384 new_path = test_label_to_path(tmpdir, label, attempt)
Jakob Buchgraber070ef5f2018-02-20 17:57:14 +01001385 os.makedirs(os.path.dirname(new_path), exist_ok=True)
Jakob Buchgraber070ef5f2018-02-20 17:57:14 +01001386 copyfile(test_log, new_path)
Jakob Buchgraber070ef5f2018-02-20 17:57:14 +01001387 new_paths.append(new_path)
Philipp Wollermannc030f2e2018-02-21 17:02:19 +01001388 attempt += 1
Jakob Buchgraber070ef5f2018-02-20 17:57:14 +01001389 except IOError as err:
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001390 # Log error and ignore.
1391 eprint(err)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001392 return new_paths
Jakob Buchgraber699aece2018-02-19 12:49:30 +01001393
1394
Jakob Buchgraber02e07222018-02-19 15:05:56 +01001395def test_label_to_path(tmpdir, label, attempt):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001396 # remove leading //
1397 path = label[2:]
Philipp Wollermannc030f2e2018-02-21 17:02:19 +01001398 path = path.replace("/", os.sep)
1399 path = path.replace(":", os.sep)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001400 if attempt == 0:
1401 path = os.path.join(path, "test.log")
1402 else:
1403 path = os.path.join(path, "attempt_" + str(attempt) + ".log")
1404 return os.path.join(tmpdir, path)
Jakob Buchgraber699aece2018-02-19 12:49:30 +01001405
1406
Jakob Buchgraber02e07222018-02-19 15:05:56 +01001407def test_logs_for_status(bep_file, status):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001408 targets = []
1409 raw_data = ""
Jakob Buchgraber94d5c212018-02-22 09:57:08 +01001410 with open(bep_file, encoding="utf-8") as f:
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001411 raw_data = f.read()
1412 decoder = json.JSONDecoder()
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001413
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001414 pos = 0
1415 while pos < len(raw_data):
1416 bep_obj, size = decoder.raw_decode(raw_data[pos:])
Jakob Buchgraber45e38632018-02-19 17:27:08 +01001417 if "testSummary" in bep_obj:
1418 test_target = bep_obj["id"]["testSummary"]["label"]
1419 test_status = bep_obj["testSummary"]["overallStatus"]
1420 if test_status == status:
1421 outputs = bep_obj["testSummary"]["failed"]
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001422 test_logs = []
1423 for output in outputs:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001424 test_logs.append(url2pathname(urlparse(output["uri"]).path))
Jakob Buchgraber45e38632018-02-19 17:27:08 +01001425 targets.append((test_target, test_logs))
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001426 pos += size + 1
1427 return targets
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001428
1429
Florian Weikert736d06e2019-05-08 13:16:42 +02001430def execute_command_and_get_output(
1431 args, shell=False, fail_if_nonzero=True, print_output=True, capture_stderr=True
1432):
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001433 eprint(" ".join(args))
Florian Weikertc8642af2019-02-03 23:58:51 +01001434 process = subprocess.run(
1435 args,
1436 shell=shell,
1437 check=fail_if_nonzero,
1438 env=os.environ,
1439 stdout=subprocess.PIPE,
Florian Weikert736d06e2019-05-08 13:16:42 +02001440 stderr=subprocess.STDOUT if capture_stderr else None,
Philipp Wollermannf13804b2019-02-05 21:08:30 +01001441 errors="replace",
Florian Weikertc8642af2019-02-03 23:58:51 +01001442 universal_newlines=True,
1443 )
Florian Weikert736d06e2019-05-08 13:16:42 +02001444 if print_output:
1445 eprint(process.stdout)
1446
Florian Weikertc8642af2019-02-03 23:58:51 +01001447 return process.stdout
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001448
1449
Philipp Wollermannf13804b2019-02-05 21:08:30 +01001450def execute_command(args, shell=False, fail_if_nonzero=True):
1451 eprint(" ".join(args))
1452 return subprocess.run(args, shell=shell, check=fail_if_nonzero, env=os.environ).returncode
1453
1454
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001455def execute_command_background(args):
1456 eprint(" ".join(args))
Philipp Wollermanne1318eb2018-08-13 15:08:01 +02001457 return subprocess.Popen(args, env=os.environ)
1458
1459
Florian Weikert736d06e2019-05-08 13:16:42 +02001460def create_step(label, commands, platform=DEFAULT_PLATFORM, shards=1):
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01001461 host_platform = PLATFORMS[platform].get("host-platform", platform)
1462 if "docker-image" in PLATFORMS[platform]:
Florian Weikert736d06e2019-05-08 13:16:42 +02001463 step = create_docker_step(
Philipp Wollermannc05ac682019-01-19 12:37:28 +01001464 label, image=PLATFORMS[platform]["docker-image"], commands=commands
1465 )
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01001466 else:
Florian Weikert736d06e2019-05-08 13:16:42 +02001467 step = {
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01001468 "label": label,
1469 "command": commands,
1470 "agents": {
1471 "kind": "worker",
1472 "java": PLATFORMS[platform]["java"],
Philipp Wollermann9f9c1892019-01-14 16:43:59 +01001473 "os": rchop(host_platform, "_nojava", "_java8", "_java9", "_java10", "_java11"),
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01001474 },
1475 }
1476
Florian Weikert736d06e2019-05-08 13:16:42 +02001477 if shards > 1:
1478 step["label"] += " (shard %n)"
1479 step["parallelism"] = shards
1480
1481 return step
1482
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01001483
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001484def create_docker_step(label, image, commands=None, additional_env_vars=None):
Philipp Wollermann9c771e92019-04-16 16:21:15 +02001485 env = ["BUILDKITE_ARTIFACT_UPLOAD_DESTINATION"]
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001486 if additional_env_vars:
1487 env += ["{}={}".format(k, v) for k, v in additional_env_vars.items()]
1488
Philipp Wollermannc05ac682019-01-19 12:37:28 +01001489 step = {
Florian Weikertf20ae6f2019-01-16 14:32:09 +01001490 "label": label,
1491 "command": commands,
1492 "agents": {"kind": "docker", "os": "linux"},
1493 "plugins": {
Philipp Wollermannea128282019-05-08 11:56:14 +02001494 "docker#v3.2.0": {
Florian Weikertf20ae6f2019-01-16 14:32:09 +01001495 "always-pull": True,
1496 "debug": True,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001497 "environment": env,
Philipp Wollermannc05ac682019-01-19 12:37:28 +01001498 "image": image,
Florian Weikertf20ae6f2019-01-16 14:32:09 +01001499 "network": "host",
1500 "privileged": True,
1501 "propagate-environment": True,
1502 "volumes": [
1503 ".:/workdir",
Philipp Wollermannea128282019-05-08 11:56:14 +02001504 "{0}:{0}".format("/home/bazel/.cache/bazel/_bazel_bazel/cache"),
1505 "{0}:{0}".format("/var/lib/bazelbuild"),
Philipp Wollermann49cdcc22019-04-16 11:11:26 +02001506 "{0}:{0}".format("/var/run/docker.sock"),
Florian Weikertf20ae6f2019-01-16 14:32:09 +01001507 ],
1508 "workdir": "/workdir",
1509 }
1510 },
1511 }
Philipp Wollermannc05ac682019-01-19 12:37:28 +01001512 if not step["command"]:
1513 del step["command"]
1514 return step
Florian Weikertf20ae6f2019-01-16 14:32:09 +01001515
1516
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001517def print_project_pipeline(
Florian Weikertf20ae6f2019-01-16 14:32:09 +01001518 configs,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001519 project_name,
1520 http_config,
1521 file_config,
1522 git_repository,
1523 monitor_flaky_tests,
1524 use_but,
1525 incompatible_flags,
1526):
Florian Weikert843d7a02019-02-03 17:24:50 +01001527 task_configs = configs.get("tasks", None)
1528 if not task_configs:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001529 raise BuildkiteException("{0} pipeline configuration is empty.".format(project_name))
1530
Jakob Buchgraberaa2af382018-02-21 19:56:54 +01001531 pipeline_steps = []
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02001532 task_configs = filter_tasks_that_should_be_skipped(task_configs, pipeline_steps)
Jakob Buchgraberff2bdad2018-02-25 13:06:30 +01001533
Philipp Wollermanndac65512019-02-05 22:14:10 +01001534 # In Bazel Downstream Project pipelines, git_repository and project_name must be specified.
1535 is_downstream_project = (use_but or incompatible_flags) and git_repository and project_name
1536
Florian Weikert85208912019-03-07 17:08:39 +01001537 buildifier_config = configs.get("buildifier")
Philipp Wollermanndac65512019-02-05 22:14:10 +01001538 # Skip Buildifier when we test downstream projects.
Florian Weikert85208912019-03-07 17:08:39 +01001539 if buildifier_config and not is_downstream_project:
1540 buildifier_env_vars = {}
1541 if isinstance(buildifier_config, str):
1542 # Simple format:
1543 # ---
1544 # buildifier: latest
1545 buildifier_env_vars[BUILDIFIER_VERSION_ENV_VAR] = buildifier_config
1546 else:
1547 # Advanced format:
1548 # ---
1549 # buildifier:
1550 # version: latest
1551 # warnings: all
1552
1553 def SetEnvVar(config_key, env_var_name):
1554 if config_key in buildifier_config:
1555 buildifier_env_vars[env_var_name] = buildifier_config[config_key]
1556
1557 SetEnvVar("version", BUILDIFIER_VERSION_ENV_VAR)
1558 SetEnvVar("warnings", BUILDIFIER_WARNINGS_ENV_VAR)
1559
1560 if not buildifier_env_vars:
1561 raise BuildkiteException(
1562 'Invalid buildifier configuration entry "{}"'.format(buildifier_config)
1563 )
1564
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001565 pipeline_steps.append(
1566 create_docker_step(
Florian Weikertde96a6f2019-03-07 14:57:50 +01001567 BUILDIFIER_STEP_NAME,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001568 image=BUILDIFIER_DOCKER_IMAGE,
Florian Weikert85208912019-03-07 17:08:39 +01001569 additional_env_vars=buildifier_env_vars,
Florian Weikert29cb7ec2019-03-07 14:52:18 +01001570 )
1571 )
Philipp Wollermannc05ac682019-01-19 12:37:28 +01001572
Philipp Wollermanndac65512019-02-05 22:14:10 +01001573 # In Bazel Downstream Project pipelines, we should test the project at the last green commit.
Yun Peng376d2b32018-11-29 10:24:54 +01001574 git_commit = None
Philipp Wollermanndac65512019-02-05 22:14:10 +01001575 if is_downstream_project:
Florian Weikert35906542019-04-01 11:53:53 +02001576 last_green_commit_url = bazelci_last_green_commit_url(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001577 git_repository, DOWNSTREAM_PROJECTS[project_name]["pipeline_slug"]
1578 )
Florian Weikert35906542019-04-01 11:53:53 +02001579 git_commit = get_last_green_commit(last_green_commit_url)
Philipp Wollermanndac65512019-02-05 22:14:10 +01001580
Florian Weikert843d7a02019-02-03 17:24:50 +01001581 for task, task_config in task_configs.items():
Florian Weikert736d06e2019-05-08 13:16:42 +02001582 shards = task_config.get("shards", "1")
1583 try:
1584 shards = int(shards)
1585 except ValueError:
1586 raise BuildkiteException("Task {} has invalid shard value '{}'".format(task, shards))
1587
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001588 step = runner_step(
Florian Weikert843d7a02019-02-03 17:24:50 +01001589 platform=get_platform_for_task(task, task_config),
1590 task=task,
1591 task_name=task_config.get("name"),
1592 project_name=project_name,
1593 http_config=http_config,
1594 file_config=file_config,
1595 git_repository=git_repository,
1596 git_commit=git_commit,
1597 monitor_flaky_tests=monitor_flaky_tests,
1598 use_but=use_but,
1599 incompatible_flags=incompatible_flags,
Florian Weikert736d06e2019-05-08 13:16:42 +02001600 shards=shards,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001601 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001602 pipeline_steps.append(step)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001603
Yun Peng996efad2018-11-27 17:19:44 +01001604 pipeline_slug = os.getenv("BUILDKITE_PIPELINE_SLUG")
1605 all_downstream_pipeline_slugs = []
1606 for _, config in DOWNSTREAM_PROJECTS.items():
1607 all_downstream_pipeline_slugs.append(config["pipeline_slug"])
1608 # We don't need to update last green commit in the following cases:
1609 # 1. This job is a github pull request
1610 # 2. This job uses a custom built Bazel binary (In Bazel Downstream Projects pipeline)
1611 # 3. This job doesn't run on master branch (Could be a custom build launched manually)
1612 # 4. We don't intend to run the same job in downstream with Bazel@HEAD (eg. google-bazel-presubmit)
Yun Peng4be92b32018-11-30 09:48:29 +01001613 # 5. We are testing incompatible flags
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001614 if not (
1615 is_pull_request()
1616 or use_but
1617 or os.getenv("BUILDKITE_BRANCH") != "master"
1618 or pipeline_slug not in all_downstream_pipeline_slugs
1619 or incompatible_flags
1620 ):
Florian Weikertde96a6f2019-03-07 14:57:50 +01001621 # We need to call "Try Update Last Green Commit" even if there are failures,
1622 # since we don't want a failing Buildifier step to block the update of
1623 # the last green commit for this project.
1624 # try_update_last_green_commit() ensures that we don't update the commit
1625 # if any build or test steps fail.
1626 pipeline_steps.append({"wait": None, "continue_on_failure": True})
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001627 pipeline_steps.append(
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01001628 create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001629 label="Try Update Last Green Commit",
1630 commands=[
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001631 fetch_bazelcipy_command(),
1632 python_binary() + " bazelci.py try_update_last_green_commit",
1633 ],
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001634 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001635 )
Yun Peng43239b02018-11-23 13:57:34 +01001636
Florian Weikert778251c2019-04-25 15:14:44 +02001637 if "validate_config" in configs:
Florian Weikertf52f91a2019-05-08 15:19:30 +02001638 pipeline_steps += create_config_validation_steps()
Florian Weikert778251c2019-04-25 15:14:44 +02001639
Yun Peng43239b02018-11-23 13:57:34 +01001640 print(yaml.dump({"steps": pipeline_steps}))
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001641
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001642
Florian Weikert843d7a02019-02-03 17:24:50 +01001643def get_platform_for_task(task, task_config):
1644 # Most pipeline configurations have exactly one task per platform, which makes it
1645 # convenient to use the platform name as task ID. Consequently, we use the
1646 # task ID as platform if there is no explicit "platform" field.
1647 return task_config.get("platform", task)
1648
1649
Florian Weikertf52f91a2019-05-08 15:19:30 +02001650def create_config_validation_steps():
1651 output = execute_command_and_get_output(
1652 ["git", "diff-tree", "--no-commit-id", "--name-only", "-r", os.getenv("BUILDKITE_COMMIT")]
1653 )
1654 config_files = [
1655 l
1656 for l in output.split("\n")
1657 if l.startswith(".bazelci/") and os.path.splitext(l)[1] in CONFIG_FILE_EXTENSIONS
1658 ]
1659 platform = DEFAULT_PLATFORM
1660 return [
1661 create_step(
1662 label=":cop: Validate {}".format(f),
1663 commands=[
1664 fetch_bazelcipy_command(),
1665 "{} bazelci.py project_pipeline --file_config={}".format(
1666 python_binary(platform), f
1667 ),
1668 ],
1669 platform=platform,
1670 )
1671 for f in config_files
1672 ]
1673
1674
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001675def runner_step(
1676 platform,
Florian Weikert843d7a02019-02-03 17:24:50 +01001677 task,
1678 task_name=None,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001679 project_name=None,
1680 http_config=None,
1681 file_config=None,
1682 git_repository=None,
1683 git_commit=None,
1684 monitor_flaky_tests=False,
1685 use_but=False,
1686 incompatible_flags=None,
Florian Weikert736d06e2019-05-08 13:16:42 +02001687 shards=1,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001688):
Philipp Wollermann962a89e2018-08-07 07:55:22 +02001689 host_platform = PLATFORMS[platform].get("host-platform", platform)
Florian Weikert843d7a02019-02-03 17:24:50 +01001690 command = python_binary(host_platform) + " bazelci.py runner --task=" + task
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001691 if http_config:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01001692 command += " --http_config=" + http_config
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01001693 if file_config:
1694 command += " --file_config=" + file_config
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001695 if git_repository:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01001696 command += " --git_repository=" + git_repository
Yun Peng376d2b32018-11-29 10:24:54 +01001697 if git_commit:
1698 command += " --git_commit=" + git_commit
Jakob Buchgraberc340f582018-06-22 13:48:33 +02001699 if monitor_flaky_tests:
1700 command += " --monitor_flaky_tests"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001701 if use_but:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01001702 command += " --use_but"
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001703 for flag in incompatible_flags or []:
Yun Peng4be92b32018-11-30 09:48:29 +01001704 command += " --incompatible_flag=" + flag
Florian Weikert843d7a02019-02-03 17:24:50 +01001705 label = create_label(platform, project_name, task_name=task_name)
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01001706 return create_step(
Florian Weikert736d06e2019-05-08 13:16:42 +02001707 label=label, commands=[fetch_bazelcipy_command(), command], platform=platform, shards=shards
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01001708 )
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001709
1710
1711def fetch_bazelcipy_command():
Philipp Wollermannfe145a52019-01-11 13:16:48 +01001712 return "curl -sS {0} -o bazelci.py".format(bazelcipy_url())
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001713
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001714
Yun Peng002eab92018-12-17 18:28:14 +01001715def fetch_incompatible_flag_verbose_failures_command():
Philipp Wollermannfe145a52019-01-11 13:16:48 +01001716 return "curl -sS {0} -o incompatible_flag_verbose_failures.py".format(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001717 incompatible_flag_verbose_failures_url()
1718 )
Yun Peng002eab92018-12-17 18:28:14 +01001719
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001720
Yun Peng8975c6b2019-02-28 11:55:55 +01001721def fetch_aggregate_incompatible_flags_test_result_command():
1722 return "curl -sS {0} -o aggregate_incompatible_flags_test_result.py".format(
1723 aggregate_incompatible_flags_test_result_url()
1724 )
1725
1726
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001727def upload_project_pipeline_step(
1728 project_name, git_repository, http_config, file_config, incompatible_flags
1729):
1730 pipeline_command = (
1731 '{0} bazelci.py project_pipeline --project_name="{1}" ' + "--git_repository={2}"
1732 ).format(python_binary(), project_name, git_repository)
Philipp Wollermann639c0452019-01-03 11:23:54 +01001733 if incompatible_flags is None:
Yun Peng4be92b32018-11-30 09:48:29 +01001734 pipeline_command += " --use_but"
Yun Peng95908792018-11-30 15:03:55 +01001735 else:
1736 for flag in incompatible_flags:
1737 pipeline_command += " --incompatible_flag=" + flag
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001738 if http_config:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01001739 pipeline_command += " --http_config=" + http_config
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01001740 if file_config:
1741 pipeline_command += " --file_config=" + file_config
Philipp Wollermannf6be4662018-02-21 14:48:28 +01001742 pipeline_command += " | buildkite-agent pipeline upload"
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001743
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01001744 return create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001745 label="Setup {0}".format(project_name),
1746 commands=[fetch_bazelcipy_command(), pipeline_command],
1747 )
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001748
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001749
Florian Weikert843d7a02019-02-03 17:24:50 +01001750def create_label(platform, project_name, build_only=False, test_only=False, task_name=None):
Philipp Wollermannf6be4662018-02-21 14:48:28 +01001751 if build_only and test_only:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001752 raise BuildkiteException("build_only and test_only cannot be true at the same time")
Florian Weikert843d7a02019-02-03 17:24:50 +01001753 platform_display_name = PLATFORMS[platform]["emoji-name"]
Philipp Wollermannf6be4662018-02-21 14:48:28 +01001754
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001755 if build_only:
1756 label = "Build "
Philipp Wollermannf6be4662018-02-21 14:48:28 +01001757 elif test_only:
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001758 label = "Test "
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001759 else:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01001760 label = ""
1761
Florian Weikert843d7a02019-02-03 17:24:50 +01001762 platform_label = (
1763 "{0} on {1}".format(task_name, platform_display_name)
1764 if task_name
1765 else platform_display_name
1766 )
1767
Philipp Wollermannf6be4662018-02-21 14:48:28 +01001768 if project_name:
Florian Weikert843d7a02019-02-03 17:24:50 +01001769 label += "{0} ({1})".format(project_name, platform_label)
Philipp Wollermannf6be4662018-02-21 14:48:28 +01001770 else:
Florian Weikert843d7a02019-02-03 17:24:50 +01001771 label += platform_label
Philipp Wollermannf6be4662018-02-21 14:48:28 +01001772
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001773 return label
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001774
1775
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001776def bazel_build_step(
Florian Weikert843d7a02019-02-03 17:24:50 +01001777 task,
1778 platform,
1779 project_name,
1780 http_config=None,
1781 file_config=None,
1782 build_only=False,
1783 test_only=False,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001784):
Philipp Wollermann962a89e2018-08-07 07:55:22 +02001785 host_platform = PLATFORMS[platform].get("host-platform", platform)
1786 pipeline_command = python_binary(host_platform) + " bazelci.py runner"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001787 if build_only:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001788 pipeline_command += " --build_only"
1789 if "host-platform" not in PLATFORMS[platform]:
1790 pipeline_command += " --save_but"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001791 if test_only:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01001792 pipeline_command += " --test_only"
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001793 if http_config:
Philipp Wollermannf6be4662018-02-21 14:48:28 +01001794 pipeline_command += " --http_config=" + http_config
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01001795 if file_config:
1796 pipeline_command += " --file_config=" + file_config
Florian Weikert843d7a02019-02-03 17:24:50 +01001797 pipeline_command += " --task=" + task
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001798
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01001799 return create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001800 label=create_label(platform, project_name, build_only, test_only),
1801 commands=[fetch_bazelcipy_command(), pipeline_command],
1802 platform=platform,
1803 )
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01001804
1805
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02001806def filter_tasks_that_should_be_skipped(task_configs, pipeline_steps):
1807 skip_tasks = get_skip_tasks()
1808 if not skip_tasks:
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02001809 return task_configs
1810
1811 actually_skipped = []
1812 skip_tasks = set(skip_tasks)
1813 for task in list(task_configs.keys()):
1814 if task in skip_tasks:
1815 actually_skipped.append(task)
1816 del task_configs[task]
1817 skip_tasks.remove(task)
1818
1819 if not task_configs:
1820 raise BuildkiteException(
1821 "Nothing to do since all tasks in the configuration should be skipped."
1822 )
1823
1824 annotations = []
1825 if actually_skipped:
1826 annotations.append(
1827 ("info", "Skipping the following task(s): {}".format(", ".join(actually_skipped)))
1828 )
1829
1830 if skip_tasks:
1831 annotations.append(
1832 (
1833 "warning",
1834 (
1835 "The following tasks should have been skipped, "
1836 "but were not part of the configuration: {}"
1837 ).format(", ".join(skip_tasks)),
1838 )
1839 )
1840
1841 if annotations:
1842 print_skip_task_annotations(annotations, pipeline_steps)
1843
1844 return task_configs
1845
1846
1847def get_skip_tasks():
1848 value = os.getenv(SKIP_TASKS_ENV_VAR, "")
1849 return [v for v in value.split(",") if v]
1850
1851
1852def print_skip_task_annotations(annotations, pipeline_steps):
1853 commands = [
1854 "buildkite-agent annotate --style={} '{}' --context 'ctx-{}'".format(s, t, hash(t))
1855 for s, t in annotations
1856 ]
1857 pipeline_steps.append(
1858 create_step(label=":pipeline: Print information about skipped tasks", commands=commands)
1859 )
1860
1861
Florian Weikert843d7a02019-02-03 17:24:50 +01001862def print_bazel_publish_binaries_pipeline(task_configs, http_config, file_config):
1863 if not task_configs:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001864 raise BuildkiteException("Bazel publish binaries pipeline configuration is empty.")
1865
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02001866 pipeline_steps = []
1867 task_configs = filter_tasks_that_should_be_skipped(task_configs, pipeline_steps)
1868
Florian Weikert843d7a02019-02-03 17:24:50 +01001869 platforms = [get_platform_for_task(t, tc) for t, tc in task_configs.items()]
1870 configured_platforms = set(p for p in platforms if should_publish_binaries_for_platform(p))
Philipp Wollermanna2ea5d82018-08-27 14:12:10 +02001871
Florian Weikert843d7a02019-02-03 17:24:50 +01001872 if len(task_configs) != len(configured_platforms):
1873 raise BuildkiteException(
1874 "Configuration for Bazel publish binaries pipeline must contain exactly one task per platform."
1875 )
1876
1877 expected_platforms = set(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001878 name for name, platform in PLATFORMS.items() if platform["publish_binary"]
Florian Weikert843d7a02019-02-03 17:24:50 +01001879 )
1880
1881 if configured_platforms != expected_platforms:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001882 raise BuildkiteException(
1883 "Bazel publish binaries pipeline needs to build Bazel for every commit on all publish_binary-enabled platforms."
1884 )
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01001885
Yun Pengd352b6d2018-10-17 13:28:39 +02001886 # Build Bazel
Florian Weikert843d7a02019-02-03 17:24:50 +01001887 for task, task_config in task_configs.items():
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001888 pipeline_steps.append(
Florian Weikert843d7a02019-02-03 17:24:50 +01001889 bazel_build_step(
1890 task,
1891 get_platform_for_task(task, task_config),
1892 "Bazel",
1893 http_config,
1894 file_config,
1895 build_only=True,
1896 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001897 )
Jakob Buchgraber4631a032018-03-22 17:12:46 +01001898
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001899 pipeline_steps.append("wait")
Jakob Buchgraber9d6ca8a2018-03-22 17:30:09 +01001900
Yun Pengc2dd6522018-10-17 12:58:35 +02001901 # If all builds succeed, publish the Bazel binaries to GCS.
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001902 pipeline_steps.append(
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01001903 create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001904 label="Publish Bazel Binaries",
1905 commands=[fetch_bazelcipy_command(), python_binary() + " bazelci.py publish_binaries"],
1906 )
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001907 )
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01001908
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02001909 print(yaml.dump({"steps": pipeline_steps}))
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01001910
1911
Florian Weikert843d7a02019-02-03 17:24:50 +01001912def should_publish_binaries_for_platform(platform):
1913 if platform not in PLATFORMS:
1914 raise BuildkiteException("Unknown platform '{}'".format(platform))
1915
1916 return PLATFORMS[platform]["publish_binary"]
1917
1918
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01001919def print_disabled_projects_info_box_step():
1920 info_text = ["Downstream testing is disabled for the following projects :sadpanda:"]
1921 for project, config in DOWNSTREAM_PROJECTS.items():
1922 disabled_reason = config.get("disabled_reason", None)
1923 if disabled_reason:
1924 info_text.append("* **%s**: %s" % (project, disabled_reason))
1925
1926 if len(info_text) == 1:
1927 return None
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01001928 return create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001929 label=":sadpanda:",
1930 commands=[
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001931 'buildkite-agent annotate --append --style=info "\n' + "\n".join(info_text) + '\n"'
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01001932 ],
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001933 )
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01001934
Yun Peng6528e652019-01-02 14:41:07 +01001935
1936def print_incompatible_flags_info_box_step(incompatible_flags_map):
1937 info_text = ["Build and test with the following incompatible flags:"]
1938
1939 for flag in incompatible_flags_map:
1940 info_text.append("* **%s**: %s" % (flag, incompatible_flags_map[flag]))
1941
1942 if len(info_text) == 1:
1943 return None
Philipp Wollermannc43d3cf2019-01-10 13:24:15 +01001944 return create_step(
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001945 label="Incompatible flags info",
1946 commands=[
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001947 'buildkite-agent annotate --append --style=info "\n' + "\n".join(info_text) + '\n"'
Yun Peng6528e652019-01-02 14:41:07 +01001948 ],
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01001949 )
Yun Peng6528e652019-01-02 14:41:07 +01001950
1951
Yun Peng7d302f62019-01-10 16:56:15 +01001952def fetch_incompatible_flags():
Yun Peng6528e652019-01-02 14:41:07 +01001953 """
1954 Return a list of incompatible flags to be tested in downstream with the current release Bazel
1955 """
Yun Peng7d302f62019-01-10 16:56:15 +01001956 incompatible_flags = {}
1957
1958 # If INCOMPATIBLE_FLAGS environment variable is set, we get incompatible flags from it.
1959 if "INCOMPATIBLE_FLAGS" in os.environ:
1960 for flag in os.environ["INCOMPATIBLE_FLAGS"].split():
1961 # We are not able to get the github link for this flag from INCOMPATIBLE_FLAGS,
1962 # so just assign the url to empty string.
1963 incompatible_flags[flag] = ""
1964 return incompatible_flags
1965
Yun Peng6528e652019-01-02 14:41:07 +01001966 # Get bazel major version on CI, eg. 0.21 from "Build label: 0.21.0\n..."
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001967 output = subprocess.check_output(
1968 ["bazel", "--nomaster_bazelrc", "--bazelrc=/dev/null", "version"]
1969 ).decode("utf-8")
Yun Peng6528e652019-01-02 14:41:07 +01001970 bazel_major_version = output.split()[2].rsplit(".", 1)[0]
1971
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001972 output = subprocess.check_output(
1973 [
1974 "curl",
Yun Peng3e25e092019-03-11 11:33:43 +01001975 "https://api.github.com/search/issues?per_page=100&q=repo:bazelbuild/bazel+label:migration-%s+state:open"
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001976 % bazel_major_version,
1977 ]
1978 ).decode("utf-8")
Yun Peng6528e652019-01-02 14:41:07 +01001979 issue_info = json.loads(output)
1980
Yun Peng6528e652019-01-02 14:41:07 +01001981 for issue in issue_info["items"]:
Yun Peng6528e652019-01-02 14:41:07 +01001982 # Every incompatible flags issue should start with "<incompatible flag name (without --)>:"
1983 name = "--" + issue["title"].split(":")[0]
1984 url = issue["html_url"]
1985 if name.startswith("--incompatible_"):
1986 incompatible_flags[name] = url
1987 else:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001988 eprint(
Philipp Wollermann639c0452019-01-03 11:23:54 +01001989 f"{name} is not recognized as an incompatible flag, please modify the issue title "
1990 f'of {url} to "<incompatible flag name (without --)>:..."'
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001991 )
Yun Peng6528e652019-01-02 14:41:07 +01001992
1993 return incompatible_flags
1994
1995
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001996def print_bazel_downstream_pipeline(
Florian Weikert843d7a02019-02-03 17:24:50 +01001997 task_configs, http_config, file_config, test_incompatible_flags, test_disabled_projects
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01001998):
Florian Weikert843d7a02019-02-03 17:24:50 +01001999 if not task_configs:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002000 raise BuildkiteException("Bazel downstream pipeline configuration is empty.")
2001
Florian Weikert5f5d3cb2019-04-15 15:36:27 +02002002 pipeline_steps = []
2003 task_configs = filter_tasks_that_should_be_skipped(task_configs, pipeline_steps)
2004
Florian Weikert843d7a02019-02-03 17:24:50 +01002005 configured_platforms = set(get_platform_for_task(t, c) for t, c in task_configs.items())
2006 if configured_platforms != set(PLATFORMS):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002007 raise BuildkiteException(
2008 "Bazel downstream pipeline needs to build Bazel on all supported platforms (has=%s vs. want=%s)."
Florian Weikert843d7a02019-02-03 17:24:50 +01002009 % (sorted(configured_platforms), sorted(set(PLATFORMS)))
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002010 )
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002011
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002012 pipeline_steps = []
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002013
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01002014 info_box_step = print_disabled_projects_info_box_step()
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01002015 if info_box_step is not None:
2016 pipeline_steps.append(info_box_step)
2017
Yun Peng5599ca22019-01-16 12:32:41 +01002018 if not test_incompatible_flags:
Florian Weikert843d7a02019-02-03 17:24:50 +01002019 for task, task_config in task_configs.items():
Yun Peng5599ca22019-01-16 12:32:41 +01002020 pipeline_steps.append(
Florian Weikert843d7a02019-02-03 17:24:50 +01002021 bazel_build_step(
2022 task,
2023 get_platform_for_task(task, task_config),
2024 "Bazel",
2025 http_config,
2026 file_config,
2027 build_only=True,
2028 )
Yun Peng5599ca22019-01-16 12:32:41 +01002029 )
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002030
Yun Peng5599ca22019-01-16 12:32:41 +01002031 pipeline_steps.append("wait")
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002032
Yun Pengb9998d12018-12-03 10:18:28 +01002033 incompatible_flags = None
Yun Peng7a539ef2018-11-30 15:07:24 +01002034 if test_incompatible_flags:
Yun Peng7d302f62019-01-10 16:56:15 +01002035 incompatible_flags_map = fetch_incompatible_flags()
Yun Peng6528e652019-01-02 14:41:07 +01002036 info_box_step = print_incompatible_flags_info_box_step(incompatible_flags_map)
2037 if info_box_step is not None:
2038 pipeline_steps.append(info_box_step)
2039 incompatible_flags = list(incompatible_flags_map.keys())
Yun Peng7a539ef2018-11-30 15:07:24 +01002040
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002041 for project, config in DOWNSTREAM_PROJECTS.items():
Yun Peng996efad2018-11-27 17:19:44 +01002042 disabled_reason = config.get("disabled_reason", None)
Yun Pengfb759fa2018-12-13 11:35:39 +01002043 # If test_disabled_projects is true, we add configs for disabled projects.
Florian Weikert7b3f17e2019-03-14 13:52:42 +01002044 # If test_disabled_projects is false, we add configs for not disabled projects.
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002045 if (test_disabled_projects and disabled_reason) or (
2046 not test_disabled_projects and not disabled_reason
2047 ):
Yun Peng996efad2018-11-27 17:19:44 +01002048 pipeline_steps.append(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002049 upload_project_pipeline_step(
2050 project_name=project,
2051 git_repository=config["git_repository"],
2052 http_config=config.get("http_config", None),
2053 file_config=config.get("file_config", None),
2054 incompatible_flags=incompatible_flags,
2055 )
2056 )
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002057
Yun Peng002eab92018-12-17 18:28:14 +01002058 if test_incompatible_flags:
Yun Peng002eab92018-12-17 18:28:14 +01002059 current_build_number = os.environ.get("BUILDKITE_BUILD_NUMBER", None)
2060 if not current_build_number:
2061 raise BuildkiteException("Not running inside Buildkite")
Yun Peng8975c6b2019-02-28 11:55:55 +01002062 if use_bazelisk_migrate():
2063 pipeline_steps.append({"wait": "~", "continue_on_failure": "true"})
2064 pipeline_steps.append(
2065 create_step(
2066 label="Aggregate incompatible flags test result",
2067 commands=[
2068 fetch_bazelcipy_command(),
2069 fetch_aggregate_incompatible_flags_test_result_command(),
2070 python_binary()
Yun Penge1679032019-02-28 17:04:08 +01002071 + " aggregate_incompatible_flags_test_result.py --build_number=%s"
Yun Peng8975c6b2019-02-28 11:55:55 +01002072 % current_build_number,
2073 ],
2074 )
Philipp Wollermann1403d2c2019-01-10 13:15:51 +01002075 )
Yun Peng8975c6b2019-02-28 11:55:55 +01002076 else:
2077 pipeline_steps.append({"wait": "~", "continue_on_failure": "true"})
2078 pipeline_steps.append(
2079 create_step(
2080 label="Test failing jobs with incompatible flag separately",
2081 commands=[
2082 fetch_bazelcipy_command(),
2083 fetch_incompatible_flag_verbose_failures_command(),
2084 python_binary()
2085 + " incompatible_flag_verbose_failures.py --build_number=%s | buildkite-agent pipeline upload"
2086 % current_build_number,
2087 ],
2088 )
2089 )
Yun Peng002eab92018-12-17 18:28:14 +01002090
Florian Weikert2896edb2019-04-04 16:12:47 +02002091 if (
2092 not test_disabled_projects
2093 and not test_incompatible_flags
2094 and os.getenv("BUILDKITE_BRANCH") == "master"
2095 ):
Florian Weikert35906542019-04-01 11:53:53 +02002096 # Only update the last green downstream commit in the regular Bazel@HEAD + Downstream pipeline.
2097 pipeline_steps.append("wait")
2098 pipeline_steps.append(
2099 create_step(
2100 label="Try Update Last Green Downstream Commit",
2101 commands=[
2102 fetch_bazelcipy_command(),
2103 python_binary() + " bazelci.py try_update_last_green_downstream_commit",
2104 ],
2105 )
2106 )
2107
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002108 print(yaml.dump({"steps": pipeline_steps}))
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002109
2110
Yun Pengc2dd6522018-10-17 12:58:35 +02002111def bazelci_builds_download_url(platform, git_commit):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002112 return "https://storage.googleapis.com/bazel-builds/artifacts/{0}/{1}/bazel".format(
2113 platform, git_commit
2114 )
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002115
2116
Yun Peng20d45602018-10-18 13:27:05 +02002117def bazelci_builds_gs_url(platform, git_commit):
Yun Pengc2dd6522018-10-17 12:58:35 +02002118 return "gs://bazel-builds/artifacts/{0}/{1}/bazel".format(platform, git_commit)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002119
2120
Jakob Buchgraber76381e02018-02-19 16:19:56 +01002121def bazelci_builds_metadata_url():
Jakob Buchgrabercaa73c42018-02-27 11:48:40 +01002122 return "gs://bazel-builds/metadata/latest.json"
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002123
2124
Yun Peng996efad2018-11-27 17:19:44 +01002125def bazelci_last_green_commit_url(git_repository, pipeline_slug):
Philipp Wollermanne7d7ec62019-01-17 14:11:08 +01002126 return "gs://%s/last_green_commit/%s/%s" % (
2127 "bazel-builds" if CLOUD_PROJECT == "bazel-public" else "bazel-untrusted-builds",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002128 git_repository[len("https://") :],
2129 pipeline_slug,
2130 )
Yun Pengafe67d42018-11-23 17:06:43 +01002131
2132
Florian Weikert35906542019-04-01 11:53:53 +02002133def bazelci_last_green_downstream_commit_url():
2134 # Downstream pipeline runs in the unstrusted org
2135 return "gs://bazel-untrusted-builds/last_green_commit/downstream_pipeline"
2136
2137
2138def get_last_green_commit(last_green_commit_url):
Yun Peng61a448f2018-11-23 17:11:46 +01002139 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002140 return (
2141 subprocess.check_output(
2142 [gsutil_command(), "cat", last_green_commit_url], env=os.environ
2143 )
2144 .decode("utf-8")
2145 .strip()
2146 )
Yun Peng61a448f2018-11-23 17:11:46 +01002147 except subprocess.CalledProcessError:
2148 return None
Yun Peng43239b02018-11-23 13:57:34 +01002149
2150
Yun Peng358cd882018-11-29 10:25:18 +01002151def try_update_last_green_commit():
Florian Weikertde96a6f2019-03-07 14:57:50 +01002152 org_slug = os.getenv("BUILDKITE_ORGANIZATION_SLUG")
Yun Peng358cd882018-11-29 10:25:18 +01002153 pipeline_slug = os.getenv("BUILDKITE_PIPELINE_SLUG")
Florian Weikertde96a6f2019-03-07 14:57:50 +01002154 build_number = os.getenv("BUILDKITE_BUILD_NUMBER")
2155 current_job_id = os.getenv("BUILDKITE_JOB_ID")
2156
2157 client = BuildkiteClient(org=org_slug, pipeline=pipeline_slug)
2158 build_info = client.get_build_info(build_number)
2159
2160 # Find any failing steps other than Buildifier and "try update last green".
2161 def HasFailed(job):
Florian Weikertbd40a272019-03-08 10:20:18 +01002162 state = job.get("state")
2163 # Ignore steps that don't have a state (like "wait").
Florian Weikertde96a6f2019-03-07 14:57:50 +01002164 return (
Florian Weikert35906542019-04-01 11:53:53 +02002165 state is not None
2166 and state != "passed"
Florian Weikertde96a6f2019-03-07 14:57:50 +01002167 and job["id"] != current_job_id
2168 and job["name"] != BUILDIFIER_STEP_NAME
2169 )
2170
2171 failing_jobs = [j["name"] for j in build_info["jobs"] if HasFailed(j)]
2172 if failing_jobs:
2173 raise BuildkiteException(
2174 "Cannot update last green commit due to {} failing step(s): {}".format(
2175 len(failing_jobs), ", ".join(failing_jobs)
2176 )
2177 )
2178
Yun Peng358cd882018-11-29 10:25:18 +01002179 git_repository = os.getenv("BUILDKITE_REPO")
Florian Weikert35906542019-04-01 11:53:53 +02002180 last_green_commit_url = bazelci_last_green_commit_url(git_repository, pipeline_slug)
2181 update_last_green_commit_if_newer(last_green_commit_url)
2182
2183
2184def update_last_green_commit_if_newer(last_green_commit_url):
2185 last_green_commit = get_last_green_commit(last_green_commit_url)
Yun Peng358cd882018-11-29 10:25:18 +01002186 current_commit = subprocess.check_output(["git", "rev-parse", "HEAD"]).decode("utf-8").strip()
2187 if last_green_commit:
Yun Peng384058a2019-01-15 13:26:35 +01002188 execute_command(["git", "fetch", "-v", "origin", last_green_commit])
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002189 result = (
2190 subprocess.check_output(
2191 ["git", "rev-list", "%s..%s" % (last_green_commit, current_commit)]
2192 )
2193 .decode("utf-8")
2194 .strip()
2195 )
Yun Peng358cd882018-11-29 10:25:18 +01002196
Philipp Wollermann639c0452019-01-03 11:23:54 +01002197 # If current_commit is newer that last_green_commit, `git rev-list A..B` will output a bunch of
2198 # commits, otherwise the output should be empty.
Yun Peng358cd882018-11-29 10:25:18 +01002199 if not last_green_commit or result:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002200 execute_command(
Florian Weikert35906542019-04-01 11:53:53 +02002201 ["echo %s | %s cp - %s" % (current_commit, gsutil_command(), last_green_commit_url)],
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002202 shell=True,
2203 )
Yun Peng358cd882018-11-29 10:25:18 +01002204 else:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002205 eprint(
2206 "Updating abandoned: last green commit (%s) is not older than current commit (%s)."
2207 % (last_green_commit, current_commit)
2208 )
2209
Yun Peng358cd882018-11-29 10:25:18 +01002210
Florian Weikert35906542019-04-01 11:53:53 +02002211def try_update_last_green_downstream_commit():
2212 last_green_commit_url = bazelci_last_green_downstream_commit_url()
2213 update_last_green_commit_if_newer(last_green_commit_url)
2214
2215
Jakob Buchgraber76381e02018-02-19 16:19:56 +01002216def latest_generation_and_build_number():
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002217 output = None
2218 attempt = 0
2219 while attempt < 5:
2220 output = subprocess.check_output(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002221 [gsutil_command(), "stat", bazelci_builds_metadata_url()], env=os.environ
2222 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002223 match = re.search("Generation:[ ]*([0-9]+)", output.decode("utf-8"))
2224 if not match:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002225 raise BuildkiteException("Couldn't parse generation. gsutil output format changed?")
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002226 generation = match.group(1)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002227
Philipp Wollermannff39ef52018-02-21 14:18:52 +01002228 match = re.search(r"Hash \(md5\):[ ]*([^\s]+)", output.decode("utf-8"))
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002229 if not match:
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002230 raise BuildkiteException("Couldn't parse md5 hash. gsutil output format changed?")
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002231 expected_md5hash = base64.b64decode(match.group(1))
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002232
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002233 output = subprocess.check_output(
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002234 [gsutil_command(), "cat", bazelci_builds_metadata_url()], env=os.environ
2235 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002236 hasher = hashlib.md5()
2237 hasher.update(output)
2238 actual_md5hash = hasher.digest()
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002239
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002240 if expected_md5hash == actual_md5hash:
2241 break
Philipp Wollermannf6be4662018-02-21 14:48:28 +01002242 attempt += 1
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002243 info = json.loads(output.decode("utf-8"))
2244 return (generation, info["build_number"])
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002245
Jakob Buchgraber699aece2018-02-19 12:49:30 +01002246
Jakob Buchgraber88083fd2018-02-18 17:23:35 +01002247def sha256_hexdigest(filename):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002248 sha256 = hashlib.sha256()
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002249 with open(filename, "rb") as f:
2250 for block in iter(lambda: f.read(65536), b""):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002251 sha256.update(block)
2252 return sha256.hexdigest()
Jakob Buchgraber699aece2018-02-19 12:49:30 +01002253
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002254
Philipp Wollermann02955272019-04-18 18:00:48 +02002255def upload_bazel_binaries():
2256 """
2257 Uploads all Bazel binaries to a deterministic URL based on the current Git commit.
2258
2259 Returns a map of platform names to sha256 hashes of the corresponding Bazel binary.
2260 """
2261 hashes = {}
Yun Pengc2dd6522018-10-17 12:58:35 +02002262 for platform in (name for name in PLATFORMS if PLATFORMS[name]["publish_binary"]):
Jakob Buchgraberb13a9a82018-03-27 18:37:09 +02002263 tmpdir = tempfile.mkdtemp()
2264 try:
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002265 bazel_binary_path = download_bazel_binary(tmpdir, platform)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002266 execute_command(
2267 [
2268 gsutil_command(),
2269 "cp",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002270 bazel_binary_path,
Philipp Wollermann02955272019-04-18 18:00:48 +02002271 bazelci_builds_gs_url(platform, os.environ["BUILDKITE_COMMIT"]),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002272 ]
2273 )
Philipp Wollermann02955272019-04-18 18:00:48 +02002274 hashes[platform] = sha256_hexdigest(bazel_binary_path)
Jakob Buchgraberb13a9a82018-03-27 18:37:09 +02002275 finally:
2276 shutil.rmtree(tmpdir)
Philipp Wollermann02955272019-04-18 18:00:48 +02002277 return hashes
2278
2279
2280def try_publish_binaries(hashes, build_number, expected_generation):
2281 """
2282 Uploads the info.json file that contains information about the latest Bazel commit that was
2283 successfully built on CI.
2284 """
2285 now = datetime.datetime.now()
2286 git_commit = os.environ["BUILDKITE_COMMIT"]
2287 info = {
2288 "build_number": build_number,
2289 "build_time": now.strftime("%d-%m-%Y %H:%M"),
2290 "git_commit": git_commit,
2291 "platforms": {},
2292 }
2293 for platform in (name for name in PLATFORMS if PLATFORMS[name]["publish_binary"]):
2294 info["platforms"][platform] = {
2295 "url": bazelci_builds_download_url(platform, git_commit),
2296 "sha256": hashes[platform],
2297 }
Jakob Buchgraberb13a9a82018-03-27 18:37:09 +02002298 tmpdir = tempfile.mkdtemp()
2299 try:
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002300 info_file = os.path.join(tmpdir, "info.json")
2301 with open(info_file, mode="w", encoding="utf-8") as fp:
Jakob Buchgraber609a20e2018-02-25 17:06:51 +01002302 json.dump(info, fp, indent=2, sort_keys=True)
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002303
2304 try:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002305 execute_command(
2306 [
2307 gsutil_command(),
2308 "-h",
2309 "x-goog-if-generation-match:" + expected_generation,
2310 "-h",
2311 "Content-Type:application/json",
2312 "cp",
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002313 info_file,
2314 bazelci_builds_metadata_url(),
2315 ]
2316 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002317 except subprocess.CalledProcessError:
2318 raise BinaryUploadRaceException()
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002319 finally:
Philipp Wollermann3e1a7712018-02-19 17:34:24 +01002320 shutil.rmtree(tmpdir)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002321
2322
Jakob Buchgraber76381e02018-02-19 16:19:56 +01002323def publish_binaries():
Philipp Wollermanndb024862018-02-19 17:16:56 +01002324 """
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002325 Publish Bazel binaries to GCS.
Philipp Wollermanndb024862018-02-19 17:16:56 +01002326 """
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002327 current_build_number = os.environ.get("BUILDKITE_BUILD_NUMBER", None)
2328 if not current_build_number:
2329 raise BuildkiteException("Not running inside Buildkite")
2330 current_build_number = int(current_build_number)
2331
Philipp Wollermann02955272019-04-18 18:00:48 +02002332 # Upload the Bazel binaries for this commit.
2333 hashes = upload_bazel_binaries()
2334
2335 # Try to update the info.json with data about our build. This will fail (expectedly) if we're
2336 # not the latest build.
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002337 for _ in range(5):
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002338 latest_generation, latest_build_number = latest_generation_and_build_number()
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002339
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002340 if current_build_number <= latest_build_number:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002341 eprint(
2342 (
2343 "Current build '{0}' is not newer than latest published '{1}'. "
2344 + "Skipping publishing of binaries."
2345 ).format(current_build_number, latest_build_number)
2346 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002347 break
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002348
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002349 try:
Philipp Wollermann02955272019-04-18 18:00:48 +02002350 try_publish_binaries(hashes, current_build_number, latest_generation)
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002351 except BinaryUploadRaceException:
2352 # Retry.
2353 continue
2354
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002355 eprint(
2356 "Successfully updated '{0}' to binaries from build {1}.".format(
2357 bazelci_builds_metadata_url(), current_build_number
2358 )
2359 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002360 break
2361 else:
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002362 raise BuildkiteException("Could not publish binaries, ran out of attempts.")
2363
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002364
Philipp Wollermann639c0452019-01-03 11:23:54 +01002365# This is so that multiline python strings are represented as YAML
2366# block strings.
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01002367def str_presenter(dumper, data):
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002368 if len(data.splitlines()) > 1: # check for multiline string
2369 return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|")
2370 return dumper.represent_scalar("tag:yaml.org,2002:str", data)
2371
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002372
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002373def main(argv=None):
2374 if argv is None:
Yun Peng20d45602018-10-18 13:27:05 +02002375 argv = sys.argv[1:]
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002376
Jakob Buchgraber9952a3b2018-12-06 15:38:51 +01002377 yaml.add_representer(str, str_presenter)
2378
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002379 parser = argparse.ArgumentParser(description="Bazel Continuous Integration Script")
Florian Weikert944209b2019-05-10 12:41:48 +02002380 parser.add_argument("--script", type=str)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002381
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002382 subparsers = parser.add_subparsers(dest="subparsers_name")
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002383
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002384 bazel_publish_binaries_pipeline = subparsers.add_parser("bazel_publish_binaries_pipeline")
2385 bazel_publish_binaries_pipeline.add_argument("--file_config", type=str)
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01002386 bazel_publish_binaries_pipeline.add_argument("--http_config", type=str)
2387 bazel_publish_binaries_pipeline.add_argument("--git_repository", type=str)
2388
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002389 bazel_downstream_pipeline = subparsers.add_parser("bazel_downstream_pipeline")
2390 bazel_downstream_pipeline.add_argument("--file_config", type=str)
2391 bazel_downstream_pipeline.add_argument("--http_config", type=str)
2392 bazel_downstream_pipeline.add_argument("--git_repository", type=str)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002393 bazel_downstream_pipeline.add_argument(
2394 "--test_incompatible_flags", type=bool, nargs="?", const=True
2395 )
2396 bazel_downstream_pipeline.add_argument(
2397 "--test_disabled_projects", type=bool, nargs="?", const=True
2398 )
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002399
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002400 project_pipeline = subparsers.add_parser("project_pipeline")
2401 project_pipeline.add_argument("--project_name", type=str)
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002402 project_pipeline.add_argument("--file_config", type=str)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002403 project_pipeline.add_argument("--http_config", type=str)
2404 project_pipeline.add_argument("--git_repository", type=str)
Jakob Buchgraber66ba4fe2018-06-22 15:04:14 +02002405 project_pipeline.add_argument("--monitor_flaky_tests", type=bool, nargs="?", const=True)
Philipp Wollermann2409c6e2018-08-07 07:37:54 +02002406 project_pipeline.add_argument("--use_but", type=bool, nargs="?", const=True)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002407 project_pipeline.add_argument("--incompatible_flag", type=str, action="append")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002408
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002409 runner = subparsers.add_parser("runner")
Florian Weikert843d7a02019-02-03 17:24:50 +01002410 runner.add_argument("--task", action="store", type=str, default="")
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002411 runner.add_argument("--file_config", type=str)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002412 runner.add_argument("--http_config", type=str)
2413 runner.add_argument("--git_repository", type=str)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002414 runner.add_argument(
2415 "--git_commit", type=str, help="Reset the git repository to this commit after cloning it"
2416 )
2417 runner.add_argument(
2418 "--git_repo_location",
2419 type=str,
2420 help="Use an existing repository instead of cloning from github",
2421 )
2422 runner.add_argument(
Dan Halperinefda1192019-01-16 00:34:09 -08002423 "--use_bazel_at_commit", type=str, help="Use Bazel binary built at a specific commit"
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002424 )
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002425 runner.add_argument("--use_but", type=bool, nargs="?", const=True)
2426 runner.add_argument("--save_but", type=bool, nargs="?", const=True)
Yun Peng4d1d6542019-01-17 18:30:33 +01002427 runner.add_argument("--needs_clean", type=bool, nargs="?", const=True)
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002428 runner.add_argument("--build_only", type=bool, nargs="?", const=True)
2429 runner.add_argument("--test_only", type=bool, nargs="?", const=True)
Jakob Buchgraber66ba4fe2018-06-22 15:04:14 +02002430 runner.add_argument("--monitor_flaky_tests", type=bool, nargs="?", const=True)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002431 runner.add_argument("--incompatible_flag", type=str, action="append")
Jakob Buchgraberc340f582018-06-22 13:48:33 +02002432
Philipp Wollermann598b4a42018-02-19 17:03:36 +01002433 runner = subparsers.add_parser("publish_binaries")
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01002434
Yun Peng358cd882018-11-29 10:25:18 +01002435 runner = subparsers.add_parser("try_update_last_green_commit")
Florian Weikert35906542019-04-01 11:53:53 +02002436 runner = subparsers.add_parser("try_update_last_green_downstream_commit")
Yun Peng358cd882018-11-29 10:25:18 +01002437
Yun Peng20d45602018-10-18 13:27:05 +02002438 args = parser.parse_args(argv)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01002439
Florian Weikert944209b2019-05-10 12:41:48 +02002440 if args.script:
2441 global SCRIPT_URL
2442 SCRIPT_URL = args.script
2443
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002444 try:
Jakob Buchgraber08e8e402018-03-20 19:22:07 +01002445 if args.subparsers_name == "bazel_publish_binaries_pipeline":
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002446 configs = fetch_configs(args.http_config, args.file_config)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002447 print_bazel_publish_binaries_pipeline(
Florian Weikert843d7a02019-02-03 17:24:50 +01002448 task_configs=configs.get("tasks", None),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002449 http_config=args.http_config,
2450 file_config=args.file_config,
2451 )
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002452 elif args.subparsers_name == "bazel_downstream_pipeline":
2453 configs = fetch_configs(args.http_config, args.file_config)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002454 print_bazel_downstream_pipeline(
Florian Weikert843d7a02019-02-03 17:24:50 +01002455 task_configs=configs.get("tasks", None),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002456 http_config=args.http_config,
2457 file_config=args.file_config,
2458 test_incompatible_flags=args.test_incompatible_flags,
2459 test_disabled_projects=args.test_disabled_projects,
2460 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002461 elif args.subparsers_name == "project_pipeline":
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002462 configs = fetch_configs(args.http_config, args.file_config)
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002463 print_project_pipeline(
Florian Weikertf20ae6f2019-01-16 14:32:09 +01002464 configs=configs,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002465 project_name=args.project_name,
2466 http_config=args.http_config,
2467 file_config=args.file_config,
2468 git_repository=args.git_repository,
2469 monitor_flaky_tests=args.monitor_flaky_tests,
2470 use_but=args.use_but,
2471 incompatible_flags=args.incompatible_flag,
2472 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002473 elif args.subparsers_name == "runner":
Jakob Buchgraberc57d4ad2018-03-22 12:33:17 +01002474 configs = fetch_configs(args.http_config, args.file_config)
Florian Weikert843d7a02019-02-03 17:24:50 +01002475 tasks = configs.get("tasks", {})
2476 task_config = tasks.get(args.task)
2477 if not task_config:
2478 raise BuildkiteException(
2479 "No such task '{}' in configuration. Available: {}".format(
2480 args.task, ", ".join(tasks)
2481 )
2482 )
2483
2484 platform = get_platform_for_task(args.task, task_config)
2485
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002486 execute_commands(
Florian Weikertc8642af2019-02-03 23:58:51 +01002487 task_config=task_config,
Florian Weikert843d7a02019-02-03 17:24:50 +01002488 platform=platform,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002489 git_repository=args.git_repository,
2490 git_commit=args.git_commit,
2491 git_repo_location=args.git_repo_location,
2492 use_bazel_at_commit=args.use_bazel_at_commit,
2493 use_but=args.use_but,
2494 save_but=args.save_but,
Yun Peng4d1d6542019-01-17 18:30:33 +01002495 needs_clean=args.needs_clean,
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002496 build_only=args.build_only,
2497 test_only=args.test_only,
2498 monitor_flaky_tests=args.monitor_flaky_tests,
2499 incompatible_flags=args.incompatible_flag,
Florian Weikertc8642af2019-02-03 23:58:51 +01002500 bazel_version=task_config.get("bazel") or configs.get("bazel"),
Philipp Wollermanncd5694c2019-01-03 14:53:04 +01002501 )
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002502 elif args.subparsers_name == "publish_binaries":
2503 publish_binaries()
Yun Peng358cd882018-11-29 10:25:18 +01002504 elif args.subparsers_name == "try_update_last_green_commit":
Florian Weikert35906542019-04-01 11:53:53 +02002505 # Update the last green commit of a project pipeline
Yun Peng358cd882018-11-29 10:25:18 +01002506 try_update_last_green_commit()
Florian Weikert35906542019-04-01 11:53:53 +02002507 elif args.subparsers_name == "try_update_last_green_downstream_commit":
2508 # Update the last green commit of the downstream pipeline
2509 try_update_last_green_downstream_commit()
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002510 else:
2511 parser.print_help()
2512 return 2
2513 except BuildkiteException as e:
2514 eprint(str(e))
2515 return 1
2516 return 0
2517
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01002518
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01002519if __name__ == "__main__":
2520 sys.exit(main())