blob: f1747b7ae7f52da19d0393eaad786bb2cc4869e8 [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 Buchgraberd20ffeb2018-02-18 03:16:43 +010020import hashlib
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010021import json
Jakob Buchgraber6db0f262018-02-17 15:45:54 +010022import multiprocessing
Philipp Wollermann0a04cf32018-02-21 17:07:22 +010023import os
Philipp Wollermanndcaddd92018-02-21 14:13:43 +010024import os.path
Jakob Buchgraber257693b2018-02-20 00:03:56 +010025import random
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010026import re
Philipp Wollermanndcaddd92018-02-21 14:13:43 +010027from shutil import copyfile
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010028import shutil
Philipp Wollermanndcaddd92018-02-21 14:13:43 +010029import stat
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010030import subprocess
31import sys
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010032import tempfile
33import urllib.request
Jakob Buchgraber540d47b2018-02-21 19:11:23 +010034from github3 import login
Philipp Wollermannc030f2e2018-02-21 17:02:19 +010035from urllib.request import url2pathname
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010036from urllib.parse import urlparse
Philipp Wollermanndcaddd92018-02-21 14:13:43 +010037
38# Initialize the random number generator.
39random.seed()
40
Jakob Buchgraber95e3d572018-02-21 18:48:49 +010041
Philipp Wollermanndcaddd92018-02-21 14:13:43 +010042class BuildkiteException(Exception):
43 """
44 Raised whenever something goes wrong and we should exit with an error.
45 """
46 pass
47
48
49class BinaryUploadRaceException(Exception):
50 """
51 Raised when try_publish_binaries wasn't able to publish a set of binaries,
52 because the generation of the current file didn't match the expected value.
53 """
54 pass
55
56
57class BazelTestFailedException(Exception):
58 """
59 Raised when a Bazel test fails.
60 """
61 pass
62
63
Jakob Buchgraberc8b6bbe2018-02-22 09:54:47 +010064class BazelBuildFailedException(Exception):
Jakob Buchgraber95e3d572018-02-21 18:48:49 +010065 """
66 Raised when a Bazel build fails.
67 """
68 pass
69
Jakob Buchgraberd26a7d92018-02-21 18:53:54 +010070
Philipp Wollermanndcaddd92018-02-21 14:13:43 +010071def eprint(*args, **kwargs):
72 """
73 Print to stderr and flush (just in case).
74 """
75 print(*args, flush=True, file=sys.stderr, **kwargs)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +010076
77
78def downstream_projects():
Philipp Wollermann598b4a42018-02-19 17:03:36 +010079 return {
Jakob Buchgraberf462ff92018-02-20 17:34:09 +010080 "Bazel Remote Execution": {
81 "git_repository": "https://github.com/bazelbuild/bazel.git",
82 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/bazel-remote-execution-postsubmit.json"
83 },
Philipp Wollermann598b4a42018-02-19 17:03:36 +010084 "BUILD_file_generator": {
85 "git_repository": "https://github.com/bazelbuild/BUILD_file_generator.git",
86 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/BUILD_file_generator-postsubmit.json"
87 },
88 "bazel-toolchains": {
89 "git_repository": "https://github.com/bazelbuild/bazel-toolchains.git",
90 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/bazel-toolchains-postsubmit.json"
91 },
92 "buildtools": {
93 "git_repository": "https://github.com/bazelbuild/buildtools.git",
94 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/buildtools-postsubmit.json"
95 },
96 "CLion Plugin": {
97 "git_repository": "https://github.com/bazelbuild/intellij.git",
98 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/clion-postsubmit.json"
99 },
100 "Eclipse Plugin": {
101 "git_repository": "https://github.com/bazelbuild/eclipse.git",
102 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/eclipse-postsubmit.json"
103 },
104 "Gerrit": {
105 "git_repository": "https://gerrit.googlesource.com/gerrit.git",
106 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/gerrit-postsubmit.json"
107 },
108 "Google Logging": {
109 "git_repository": "https://github.com/google/glog.git",
110 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/glog-postsubmit.json"
111 },
112 "IntelliJ Plugin": {
113 "git_repository": "https://github.com/bazelbuild/intellij.git",
114 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/intellij-postsubmit.json"
115 },
116 "migration-tooling": {
117 "git_repository": "https://github.com/bazelbuild/migration-tooling.git",
118 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/migration-tooling-postsubmit.json"
119 },
120 "protobuf": {
121 "git_repository": "https://github.com/google/protobuf.git",
122 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/protobuf-postsubmit.json"
123 },
124 "re2": {
125 "git_repository": "https://github.com/google/re2.git",
126 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/re2-postsubmit.json"
127 },
128 "rules_appengine": {
129 "git_repository": "https://github.com/bazelbuild/rules_appengine.git",
130 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_appengine-postsubmit.json"
131 },
132 "rules_closure": {
133 "git_repository": "https://github.com/bazelbuild/rules_closure.git",
134 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_closure-postsubmit.json"
135 },
136 "rules_d": {
137 "git_repository": "https://github.com/bazelbuild/rules_d.git",
138 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_d-postsubmit.json"
139 },
140 "rules_go": {
141 "git_repository": "https://github.com/bazelbuild/rules_go.git",
142 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_go-postsubmit.json"
143 },
144 "rules_groovy": {
145 "git_repository": "https://github.com/bazelbuild/rules_groovy.git",
146 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_groovy-postsubmit.json"
147 },
148 "rules_gwt": {
149 "git_repository": "https://github.com/bazelbuild/rules_gwt.git",
150 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_gwt-postsubmit.json"
151 },
152 "rules_jsonnet": {
153 "git_repository": "https://github.com/bazelbuild/rules_jsonnet.git",
154 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_jsonnet-postsubmit.json"
155 },
156 "rules_k8s": {
157 "git_repository": "https://github.com/bazelbuild/rules_k8s.git",
158 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_k8s-postsubmit.json"
159 },
160 "rules_nodejs": {
161 "git_repository": "https://github.com/bazelbuild/rules_nodejs.git",
162 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_nodejs-postsubmit.json"
163 },
164 "rules_perl": {
165 "git_repository": "https://github.com/bazelbuild/rules_perl.git",
166 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_perl-postsubmit.json"
167 },
168 "rules_python": {
169 "git_repository": "https://github.com/bazelbuild/rules_python.git",
170 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_python-postsubmit.json"
171 },
172 "rules_rust": {
173 "git_repository": "https://github.com/bazelbuild/rules_rust.git",
174 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_rust-postsubmit.json"
175 },
176 "rules_sass": {
177 "git_repository": "https://github.com/bazelbuild/rules_sass.git",
178 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_sass-postsubmit.json"
179 },
180 "rules_scala": {
181 "git_repository": "https://github.com/bazelbuild/rules_scala.git",
182 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_scala-postsubmit.json"
183 },
184 "rules_typescript": {
185 "git_repository": "https://github.com/bazelbuild/rules_typescript.git",
186 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_typescript-postsubmit.json"
187 },
188 # Enable once is resolved: https://github.com/bazelbuild/continuous-integration/issues/191
189 # "rules_webtesting": {
190 # "git_repository": "https://github.com/bazelbuild/rules_webtesting.git",
191 # "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_webtesting-postsubmit.json"
192 # },
193 "skydoc": {
194 "git_repository": "https://github.com/bazelbuild/skydoc.git",
195 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/skydoc-postsubmit.json"
196 },
197 "subpar": {
198 "git_repository": "https://github.com/google/subpar.git",
199 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/subpar-postsubmit.json"
200 },
201 "TensorFlow": {
202 "git_repository": "https://github.com/tensorflow/tensorflow.git",
203 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/tensorflow-postsubmit.json"
204 },
205 "TensorFlow Serving": {
206 "git_repository": "https://github.com/tensorflow/serving.git",
207 "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/tensorflow-serving-postsubmit.json"
208 }
209 }
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100210
211
Philipp Wollermannbcedf9b2018-02-19 18:07:44 +0100212def python_binary(platform=None):
213 if platform == "windows":
214 return "python.exe"
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100215 return "python3.6"
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100216
217
218def bazelcipy_url():
Philipp Wollermanndb024862018-02-19 17:16:56 +0100219 """
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100220 URL to the latest version of this script.
Philipp Wollermanndb024862018-02-19 17:16:56 +0100221 """
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100222 return "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/bazelci.py"
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100223
224
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100225def platforms_info():
Philipp Wollermanndb024862018-02-19 17:16:56 +0100226 """
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100227 Returns a map containing all supported platform names as keys, with the
228 values being the platform name in a human readable format, and a the
229 buildkite-agent's working directory.
Philipp Wollermanndb024862018-02-19 17:16:56 +0100230 """
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100231 return {
232 "ubuntu1404": {
233 "name": "Ubuntu 14.04",
Jakob Buchgraber7d1d3bb2018-02-21 22:38:22 +0100234 "emoji-name": ":ubuntu: 14.04",
Philipp Wollermann1c036362018-02-19 17:16:31 +0100235 "agent-directory": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}"
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100236 },
237 "ubuntu1604": {
238 "name": "Ubuntu 16.04",
Jakob Buchgraber7d1d3bb2018-02-21 22:38:22 +0100239 "emoji-name": ":ubuntu: 16.04",
Philipp Wollermann1c036362018-02-19 17:16:31 +0100240 "agent-directory": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}"
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100241 },
242 "macos": {
243 "name": "macOS",
Jakob Buchgraber7d1d3bb2018-02-21 22:38:22 +0100244 "emoji-name": ":darwin:",
Philipp Wollermann1c036362018-02-19 17:16:31 +0100245 "agent-directory": "/usr/local/var/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}"
246 },
247 "windows": {
Jakob Buchgraber3a2c77d2018-02-21 22:39:53 +0100248 "name": "Windows",
Jakob Buchgraber4973b6f2018-02-21 22:40:57 +0100249 "emoji-name": ":windows:",
Philipp Wollermann1c036362018-02-19 17:16:31 +0100250 "agent-directory": "d:/build/${BUILDKITE_AGENT_NAME}",
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100251 }
252 }
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100253
Jakob Buchgraber6db0f262018-02-17 15:45:54 +0100254
Jakob Buchgraber257693b2018-02-20 00:03:56 +0100255def flaky_test_meme_url():
Jakob Buchgraberf9107462018-02-20 00:18:39 +0100256 urls = ["https://storage.googleapis.com/bazel-buildkite-memes/flaky_tests_1.jpg",
Jakob Buchgraberad6692e2018-02-20 11:12:00 +0100257 "https://storage.googleapis.com/bazel-buildkite-memes/flaky_tests_2.jpg"]
Jakob Buchgraber257693b2018-02-20 00:03:56 +0100258 return random.choice(urls)
259
260
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100261def downstream_projects_root(platform):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100262 downstream_projects_dir = os.path.expandvars(
263 "${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects")
264 path = os.path.join(agent_directory(platform), downstream_projects_dir)
265 if not os.path.exists(path):
266 os.makedirs(path)
267 return path
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100268
269
270def agent_directory(platform):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100271 return os.path.expandvars(platforms_info()[platform]["agent-directory"])
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100272
273
274def supported_platforms():
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100275 return set(platforms_info().keys())
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100276
277
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100278def fetch_configs(http_url):
Philipp Wollermanndb024862018-02-19 17:16:56 +0100279 """
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100280 If specified fetches the build configuration from http_url, else tries to
281 read it from .bazelci/config.json.
282 Returns the json configuration as a python data structure.
Philipp Wollermanndb024862018-02-19 17:16:56 +0100283 """
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100284 if http_url is None:
285 with open(".bazelci/config.json", "r") as fd:
286 return json.load(fd)
287 with urllib.request.urlopen(http_url) as resp:
288 reader = codecs.getreader("utf-8")
289 return json.load(reader(resp))
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100290
Jakob Buchgraber9c83de72018-02-18 15:32:44 +0100291
Jakob Buchgraber3120f7a2018-02-18 13:28:02 +0100292def print_collapsed_group(name):
Jakob Buchgraber5c9b13d2018-02-21 22:28:14 +0100293 eprint("\n\n--- {0}\n\n".format(name))
Jakob Buchgraber3120f7a2018-02-18 13:28:02 +0100294
Jakob Buchgraber9c83de72018-02-18 15:32:44 +0100295
Jakob Buchgraber3120f7a2018-02-18 13:28:02 +0100296def print_expanded_group(name):
Jakob Buchgraber5c9b13d2018-02-21 22:28:14 +0100297 eprint("\n\n+++ {0}\n\n".format(name))
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100298
Jakob Buchgraber9c83de72018-02-18 15:32:44 +0100299
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100300def execute_commands(config, platform, git_repository, use_but, save_but,
301 build_only, test_only):
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100302 fail_pipeline = False
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100303 tmpdir = None
304 bazel_binary = "bazel"
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100305 commit = os.getenv("BUILDKITE_COMMIT")
Jakob Buchgraberfb95a2f2018-02-22 11:46:25 +0100306 build_only = build_only or "test_targets" not in config
307 test_only = test_only or "build_targets" not in config
308 if build_only and test_only:
309 raise BuildkiteException("build_only and test_only cannot be true at the same time")
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100310 try:
311 if git_repository:
312 clone_git_repository(git_repository, platform)
Jakob Buchgraber2ab68f82018-02-21 19:43:08 +0100313 else:
314 git_repository = os.getenv("BUILDKITE_REPO")
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100315 if is_pull_request():
Jakob Buchgraber0109fa72018-02-21 22:13:10 +0100316 update_pull_request_verification_status(git_repository, commit, state="success")
Philipp Wollermannff39ef52018-02-21 14:18:52 +0100317 cleanup()
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100318 tmpdir = tempfile.mkdtemp()
319 if use_but:
320 print_collapsed_group("Downloading Bazel under test")
321 bazel_binary = download_bazel_binary(tmpdir, platform)
322 print_bazel_version_info(bazel_binary)
323 execute_shell_commands(config.get("shell_commands", None))
324 execute_bazel_run(bazel_binary, config.get("run_targets", None))
325 if not test_only:
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100326 build_bep_file = os.path.join(tmpdir, "build_bep.json")
327 if is_pull_request():
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100328 update_pull_request_build_status(
329 platform, git_repository, commit, "pending", None)
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100330 try:
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100331 execute_bazel_build(bazel_binary, platform, config.get("build_flags", []),
332 config.get("build_targets", None), build_bep_file)
333 if is_pull_request():
334 invocation_id = bes_invocation_id(build_bep_file)
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100335 update_pull_request_build_status(
336 platform, git_repository, commit, "success", invocation_id)
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100337 if save_but:
338 upload_bazel_binary()
339 except BazelBuildFailedException:
Jakob Buchgraberd26a7d92018-02-21 18:53:54 +0100340 if is_pull_request():
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100341 invocation_id = bes_invocation_id(build_bep_file)
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100342 update_pull_request_build_status(
343 platform, git_repository, commit, "failure", invocation_id)
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100344 fail_pipeline = True
Jakob Buchgraber9f403732018-02-22 10:18:29 +0100345 if (not fail_pipeline) and (not build_only):
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100346 test_bep_file = os.path.join(tmpdir, "test_bep.json")
347 try:
348 if is_pull_request():
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100349 update_pull_request_test_status(
350 platform, git_repository, commit, "pending", None)
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100351 execute_bazel_test(bazel_binary, platform, config.get("test_flags", []),
352 config.get("test_targets", None), test_bep_file)
Jakob Buchgraber5d6c7142018-02-21 20:16:51 +0100353 if has_flaky_tests(test_bep_file):
354 show_image(flaky_test_meme_url(), "Flaky Tests")
355 # We also treat flaky tests as test failures
356 raise BazelTestFailedException
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100357 if is_pull_request():
358 invocation_id = bes_invocation_id(test_bep_file)
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100359 update_pull_request_test_status(
360 platform, git_repository, commit, "success", invocation_id)
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100361 except BazelTestFailedException:
362 if is_pull_request():
363 invocation_id = bes_invocation_id(test_bep_file)
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100364 failed_tests = tests_with_status(
365 test_bep_file, status="FAILED")
366 timed_out_tests = tests_with_status(
367 test_bep_file, status="TIMEOUT")
368 flaky_tests = tests_with_status(
369 test_bep_file, status="FLAKY")
Jakob Buchgraberde682f52018-02-21 21:53:53 +0100370
371 update_pull_request_test_status(platform, git_repository, commit, "failure", invocation_id,
Jakob Buchgraber5d6c7142018-02-21 20:16:51 +0100372 len(failed_tests), len(timed_out_tests), len(flaky_tests))
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100373 fail_pipeline = True
374
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100375 upload_test_logs(test_bep_file, tmpdir)
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100376 finally:
377 if tmpdir:
378 shutil.rmtree(tmpdir)
Philipp Wollermannff39ef52018-02-21 14:18:52 +0100379 cleanup()
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100380
381 if fail_pipeline:
382 raise BuildkiteException("At least one test failed or was flaky.")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100383
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100384
Jakob Buchgraber5d6c7142018-02-21 20:16:51 +0100385def tests_with_status(bep_file, status):
386 return set(label for label, _ in test_logs_for_status(bep_file, status=status))
Jakob Buchgraber257693b2018-02-20 00:03:56 +0100387
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100388
Jakob Buchgraber27670f82018-02-21 22:09:56 +0100389__github_token__ = None
Jakob Buchgraber8498ea62018-02-21 22:02:35 +0100390
391
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100392def fetch_github_token():
Jakob Buchgraber27670f82018-02-21 22:09:56 +0100393 global __github_token__
394 if __github_token__:
395 return __github_token__
Jakob Buchgraberaa2af382018-02-21 19:56:54 +0100396 try:
397 execute_command(
398 ["gsutil", "cp", "gs://bazel-encrypted-secrets/github-token.enc", "github-token.enc"])
Jakob Buchgraber27670f82018-02-21 22:09:56 +0100399 __github_token__ = subprocess.check_output(["gcloud", "kms", "decrypt", "--location", "global", "--keyring", "buildkite",
Jakob Buchgraber0109fa72018-02-21 22:13:10 +0100400 "--key", "github-token", "--ciphertext-file", "github-token.enc",
401 "--plaintext-file", "-"]).decode("utf-8").strip()
Jakob Buchgraber27670f82018-02-21 22:09:56 +0100402 return __github_token__
Jakob Buchgraberaa2af382018-02-21 19:56:54 +0100403 finally:
Jakob Buchgraberc1055ad2018-02-21 20:04:23 +0100404 os.remove("github-token.enc")
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100405
406
407def owner_repository_from_url(git_repository):
Jakob Buchgraber18a46c72018-02-21 19:18:51 +0100408 m = re.search(r"/([^/]+)/([^/]+)\.git$", git_repository)
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100409 owner = m.group(1)
410 repository = m.group(2)
411 return (owner, repository)
412
413
Jakob Buchgraber564bcae2018-02-21 22:19:10 +0100414def results_view_url(invocation_id):
Jakob Buchgraberaa2af382018-02-21 19:56:54 +0100415 results_url = None
416 if invocation_id:
417 results_url = "https://source.cloud.google.com/results/invocations/" + invocation_id
Jakob Buchgraber84e523c2018-02-21 22:25:00 +0100418 return results_url
Jakob Buchgraber564bcae2018-02-21 22:19:10 +0100419
420
421def update_pull_request_status(git_repository, commit, state, details_url, description, context):
422 gh = login(token=fetch_github_token())
423 owner, repo = owner_repository_from_url(git_repository)
424 repo = gh.repository(owner=owner, repository=repo)
425 repo.create_status(sha=commit, state=state, target_url=details_url, description=description,
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100426 context=context)
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100427
428
Jakob Buchgraber0109fa72018-02-21 22:13:10 +0100429def update_pull_request_verification_status(git_repository, commit, state):
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100430 description = ""
431 if state == "pending":
Jakob Buchgraber0109fa72018-02-21 22:13:10 +0100432 description = "A project member must verify this pull request."
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100433 elif state == "success":
Jakob Buchgraberde682f52018-02-21 21:53:53 +0100434 description = "Verified"
Jakob Buchgraber564bcae2018-02-21 22:19:10 +0100435 build_url = os.getenv("BUILDKITE_BUILD_URL")
436 update_pull_request_status(git_repository, commit, state, build_url, description,
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100437 "Untrusted Code Verification")
438
439
440def update_pull_request_build_status(platform, git_repository, commit, state, invocation_id):
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100441 description = ""
442 if state == "pending":
Jakob Buchgraberde682f52018-02-21 21:53:53 +0100443 description = "Building ..."
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100444 elif state == "failure":
Jakob Buchgraberde682f52018-02-21 21:53:53 +0100445 description = "Failure"
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100446 elif state == "success":
Jakob Buchgraberde682f52018-02-21 21:53:53 +0100447 description = "Success"
Jakob Buchgraber564bcae2018-02-21 22:19:10 +0100448 update_pull_request_status(git_repository, commit, state, results_view_url(invocation_id), description,
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100449 "bazel build ({0})".format(platforms_info()[platform]["name"]))
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100450
451
Jakob Buchgraberde682f52018-02-21 21:53:53 +0100452def update_pull_request_test_status(platform, git_repository, commit, state, invocation_id, num_failed=0,
453 num_timed_out=0, num_flaky=0):
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100454 description = ""
Jakob Buchgraberaa2af382018-02-21 19:56:54 +0100455 if state == "pending":
Jakob Buchgraberde682f52018-02-21 21:53:53 +0100456 description = "Testing ..."
Jakob Buchgraberaa2af382018-02-21 19:56:54 +0100457 elif state == "failure":
Jakob Buchgraber7e9a4d22018-02-21 22:51:44 +0100458 if num_failed > 0:
Jakob Buchgraberde682f52018-02-21 21:53:53 +0100459 description = description + "{0} tests failed, ".format(num_failed)
460 if num_timed_out > 0:
461 description = description + "{0} tests timed out, ".format(num_timed_out)
462 if num_flaky > 0:
463 description = description + "{0} tests are flaky, ".format(num_flaky)
464 if len(description) > 0:
465 description = description[:-2]
466 else:
467 description = "Some tests didn't pass"
Jakob Buchgraberc1055ad2018-02-21 20:04:23 +0100468 elif state == "success":
Jakob Buchgraberde682f52018-02-21 21:53:53 +0100469 description = "All tests passed"
Jakob Buchgraber564bcae2018-02-21 22:19:10 +0100470 update_pull_request_status(git_repository, commit, state, results_view_url(invocation_id), description,
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100471 "bazel test ({0})".format(platforms_info()[platform]["name"]))
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100472
473
474def is_pull_request():
Jakob Buchgraber67761d32018-02-21 19:00:21 +0100475 third_party_repo = os.getenv("BUILDKITE_PULL_REQUEST_REPO", "")
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100476 return len(third_party_repo) > 0
477
478
479def bes_invocation_id(bep_file):
480 targets = []
481 raw_data = ""
482 with open(bep_file) as f:
483 raw_data = f.read()
484 decoder = json.JSONDecoder()
485
486 pos = 0
487 while pos < len(raw_data):
488 bep_obj, size = decoder.raw_decode(raw_data[pos:])
489 if "started" in bep_obj:
490 return bep_obj["started"]["uuid"]
491 pos += size + 1
492 return None
493
494
Jakob Buchgraber257693b2018-02-20 00:03:56 +0100495def show_image(url, alt):
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100496 eprint("\033]1338;url='\"{0}\"';alt='\"{1}\"'\a\n".format(url, alt))
Jakob Buchgraber257693b2018-02-20 00:03:56 +0100497
498
Jakob Buchgraber02e07222018-02-19 15:05:56 +0100499def has_flaky_tests(bep_file):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100500 return len(test_logs_for_status(bep_file, status="FLAKY")) > 0
Jakob Buchgraber02e07222018-02-19 15:05:56 +0100501
502
Jakob Buchgraber7e690a72018-02-18 13:22:15 +0100503def print_bazel_version_info(bazel_binary):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100504 print_collapsed_group("Bazel Info")
Philipp Wollermann3e1a7712018-02-19 17:34:24 +0100505 execute_command([bazel_binary, "version"])
506 execute_command([bazel_binary, "info"])
Jakob Buchgraber7e690a72018-02-18 13:22:15 +0100507
508
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100509def upload_bazel_binary():
Jakob Buchgraber7d1d3bb2018-02-21 22:38:22 +0100510 print_collapsed_group(":gcloud: Uploading Bazel Under Test")
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100511 execute_command(["buildkite-agent", "artifact",
512 "upload", "bazel-bin/src/bazel"])
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100513
514
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +0100515def download_bazel_binary(dest_dir, platform):
Philipp Wollermannf6be4662018-02-21 14:48:28 +0100516 source_step = create_label(platform, "Bazel", build_only=True)
Philipp Wollermann3e1a7712018-02-19 17:34:24 +0100517 execute_command(["buildkite-agent", "artifact", "download",
518 "bazel-bin/src/bazel", dest_dir, "--step", source_step])
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100519 bazel_binary_path = os.path.join(dest_dir, "bazel-bin/src/bazel")
520 st = os.stat(bazel_binary_path)
521 os.chmod(bazel_binary_path, st.st_mode | stat.S_IEXEC)
522 return bazel_binary_path
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100523
524
525def clone_git_repository(git_repository, platform):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100526 root = downstream_projects_root(platform)
Philipp Wollermannff39ef52018-02-21 14:18:52 +0100527 project_name = re.search(r"/([^/]+)\.git$", git_repository).group(1)
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100528 clone_path = os.path.join(root, project_name)
529 print_collapsed_group("Fetching " + project_name + " sources")
530 if os.path.exists(clone_path):
531 os.chdir(clone_path)
Philipp Wollermann3e1a7712018-02-19 17:34:24 +0100532 execute_command(["git", "remote", "set-url", "origin", git_repository])
533 execute_command(["git", "clean", "-fdqx"])
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100534 execute_command(["git", "submodule", "foreach",
535 "--recursive", "git", "clean", "-fdqx"])
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100536 # sync to the latest commit of HEAD. Unlikely git pull this also works after
537 # a force push.
Philipp Wollermann3e1a7712018-02-19 17:34:24 +0100538 execute_command(["git", "fetch", "origin"])
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100539 remote_head = subprocess.check_output(
540 ["git", "symbolic-ref", "refs/remotes/origin/HEAD"])
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100541 remote_head = remote_head.decode("utf-8")
542 remote_head = remote_head.rstrip()
Philipp Wollermann3e1a7712018-02-19 17:34:24 +0100543 execute_command(["git", "reset", remote_head, "--hard"])
544 execute_command(["git", "submodule", "sync", "--recursive"])
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100545 execute_command(["git", "submodule", "update",
546 "--init", "--recursive", "--force"])
547 execute_command(["git", "submodule", "foreach",
548 "--recursive", "git", "reset", "--hard"])
Philipp Wollermann3e1a7712018-02-19 17:34:24 +0100549 execute_command(["git", "clean", "-fdqx"])
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100550 execute_command(["git", "submodule", "foreach",
551 "--recursive", "git", "clean", "-fdqx"])
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100552 else:
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100553 execute_command(
554 ["git", "clone", "--recurse-submodules", git_repository, clone_path])
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100555 os.chdir(clone_path)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100556
557
Philipp Wollermannff39ef52018-02-21 14:18:52 +0100558def cleanup():
Jakob Buchgraberc03052a2018-02-22 10:59:58 +0100559 print_collapsed_group(":wastebasket: Cleanup")
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100560 if os.path.exists("WORKSPACE"):
Jakob Buchgraber9d578fd2018-02-22 11:32:15 +0100561 execute_command(["bazel", "clean", "--expunge"])
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100562
Jakob Buchgraberfd1eaca2018-02-17 17:27:14 +0100563
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100564def execute_shell_commands(commands):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100565 if not commands:
566 return
Jakob Buchgraber94d5c212018-02-22 09:57:08 +0100567 print_collapsed_group(":bash: Setup (Shell Commands)")
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100568 shell_command = "\n".join(commands)
Philipp Wollermann3e1a7712018-02-19 17:34:24 +0100569 execute_command([shell_command], shell=True)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100570
571
572def execute_bazel_run(bazel_binary, targets):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100573 if not targets:
574 return
575 print_collapsed_group("Setup (Run Targets)")
576 for target in targets:
Philipp Wollermann3e1a7712018-02-19 17:34:24 +0100577 execute_command([bazel_binary, "run", "--curses=yes",
Jakob Buchgraber99659532018-02-19 17:38:50 +0100578 "--color=yes", "--verbose_failures", target])
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100579
580
Jakob Buchgraber4f1d2712018-02-20 10:22:47 +0100581def remote_caching_flags(platform):
Jakob Buchgraber27c53292018-02-22 10:48:53 +0100582 if is_pull_request():
583 common_flags = ["--bes_backend=buildeventservice.googleapis.com", "--bes_best_effort=false",
584 "--bes_timeout=10s", "--tls_enabled", "--project_id=bazel-public",
585 "--remote_instance_name=projects/bazel-public",
586 "--experimental_remote_spawn_cache",
587 "--remote_timeout=10", "--remote_cache=remotebuildexecution.googleapis.com",
588 "--experimental_remote_platform_override=properties:{name:\"platform\" value:\"" + platform + "\"}"]
589 else:
590 common_flags = ["--remote_timeout=10", "--experimental_remote_spawn_cache",
591 "--experimental_remote_platform_override=properties:{name:\"platform\" value:\"" + platform + "\"}",
592 "--remote_http_cache=https://storage.googleapis.com/bazel-buildkite-cache"]
Jakob Buchgraberc38a7192018-02-20 12:56:52 +0100593 if platform in ["ubuntu1404", "ubuntu1604"]:
594 return common_flags + ["--google_default_credentials"]
595 elif platform == "macos":
596 return common_flags + ["--google_credentials=/Users/ci/GoogleDrive/bazel-public-e29b1f995cb1.json"]
Jakob Buchgraber4f1d2712018-02-20 10:22:47 +0100597 return []
598
599
Jakob Buchgraberb4342cd2018-02-20 16:35:07 +0100600def remote_enabled(flags):
601 # Detect if the project configuration enabled its own remote caching / execution.
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100602 remote_flags = ["--remote_executor",
603 "--remote_cache", "--remote_http_cache"]
Jakob Buchgraberb4342cd2018-02-20 16:35:07 +0100604 for flag in flags:
605 for remote_flag in remote_flags:
606 if flag.startswith(remote_flag):
607 return True
608 return False
609
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100610
611def execute_bazel_build(bazel_binary, platform, flags, targets, bep_file):
Jakob Buchgraber7d1d3bb2018-02-21 22:38:22 +0100612 print_expanded_group(":bazel: Build")
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100613 num_jobs = str(multiprocessing.cpu_count())
Jakob Buchgraberad6692e2018-02-20 11:12:00 +0100614 common_flags = ["--show_progress_rate_limit=5", "--curses=yes", "--color=yes", "--keep_going",
Jakob Buchgraberd26a7d92018-02-21 18:53:54 +0100615 "--jobs=" + num_jobs, "--build_event_json_file=" + bep_file,
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100616 "--experimental_build_event_json_file_path_conversion=false"]
Jakob Buchgraberb4342cd2018-02-20 16:35:07 +0100617 caching_flags = []
618 if not remote_enabled(flags):
619 caching_flags = remote_caching_flags(platform)
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100620 try:
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100621 execute_command([bazel_binary, "build"] +
622 common_flags + caching_flags + flags + targets)
Jakob Buchgraber95e3d572018-02-21 18:48:49 +0100623 except subprocess.CalledProcessError as e:
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100624 raise BazelBuildFailedException(
625 "bazel build failed with exit code {}".format(e.returncode))
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100626
627
Jakob Buchgraberd2204292018-02-20 10:25:40 +0100628def execute_bazel_test(bazel_binary, platform, flags, targets, bep_file):
Jakob Buchgraber7d1d3bb2018-02-21 22:38:22 +0100629 print_expanded_group(":bazel: Test")
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100630 num_jobs = str(multiprocessing.cpu_count())
Jakob Buchgraber77175c72018-02-20 15:32:07 +0100631 common_flags = ["--show_progress_rate_limit=5", "--curses=yes", "--color=yes", "--keep_going",
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100632 "--flaky_test_attempts=3", "--build_tests_only",
633 "--jobs=" + num_jobs, "--local_test_jobs=" + num_jobs,
Jakob Buchgraber77595f12018-02-21 11:44:18 +0100634 "--build_event_json_file=" + bep_file,
635 "--experimental_build_event_json_file_path_conversion=false"]
Jakob Buchgraberb4342cd2018-02-20 16:35:07 +0100636 caching_flags = []
637 if not remote_enabled(flags):
638 caching_flags = remote_caching_flags(platform)
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100639 try:
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100640 execute_command([bazel_binary, "test"] +
641 common_flags + caching_flags + flags + targets)
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100642 except subprocess.CalledProcessError as e:
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100643 raise BazelTestFailedException(
644 "bazel test failed with exit code {}".format(e.returncode))
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100645
646
Jakob Buchgraber02e07222018-02-19 15:05:56 +0100647def upload_test_logs(bep_file, tmpdir):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100648 if not os.path.exists(bep_file):
649 return
650 test_logs = test_logs_to_upload(bep_file, tmpdir)
651 if test_logs:
652 cwd = os.getcwd()
653 try:
654 os.chdir(tmpdir)
Jakob Buchgraber7d1d3bb2018-02-21 22:38:22 +0100655 print_collapsed_group(":gcloud: Uploading Test Logs")
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100656 execute_command(
657 ["buildkite-agent", "artifact", "upload", "*/**/*.log"])
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100658 finally:
659 os.chdir(cwd)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100660
661
Jakob Buchgraber02e07222018-02-19 15:05:56 +0100662def test_logs_to_upload(bep_file, tmpdir):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100663 failed = test_logs_for_status(bep_file, status="FAILED")
664 timed_out = test_logs_for_status(bep_file, status="TIMEOUT")
665 flaky = test_logs_for_status(bep_file, status="FLAKY")
666 # Rename the test.log files to the target that created them
667 # so that it's easy to associate test.log and target.
668 new_paths = []
Philipp Wollermannff39ef52018-02-21 14:18:52 +0100669 for label, test_logs in failed + timed_out + flaky:
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100670 attempt = 0
671 if len(test_logs) > 1:
672 attempt = 1
673 for test_log in test_logs:
Jakob Buchgraber070ef5f2018-02-20 17:57:14 +0100674 try:
675 new_path = test_label_to_path(tmpdir, label, attempt)
Jakob Buchgraber070ef5f2018-02-20 17:57:14 +0100676 os.makedirs(os.path.dirname(new_path), exist_ok=True)
Jakob Buchgraber070ef5f2018-02-20 17:57:14 +0100677 copyfile(test_log, new_path)
Jakob Buchgraber070ef5f2018-02-20 17:57:14 +0100678 new_paths.append(new_path)
Philipp Wollermannc030f2e2018-02-21 17:02:19 +0100679 attempt += 1
Jakob Buchgraber070ef5f2018-02-20 17:57:14 +0100680 except IOError as err:
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100681 # Log error and ignore.
682 eprint(err)
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100683 return new_paths
Jakob Buchgraber699aece2018-02-19 12:49:30 +0100684
685
Jakob Buchgraber02e07222018-02-19 15:05:56 +0100686def test_label_to_path(tmpdir, label, attempt):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100687 # remove leading //
688 path = label[2:]
Philipp Wollermannc030f2e2018-02-21 17:02:19 +0100689 path = path.replace("/", os.sep)
690 path = path.replace(":", os.sep)
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100691 if attempt == 0:
692 path = os.path.join(path, "test.log")
693 else:
694 path = os.path.join(path, "attempt_" + str(attempt) + ".log")
695 return os.path.join(tmpdir, path)
Jakob Buchgraber699aece2018-02-19 12:49:30 +0100696
697
Jakob Buchgraber02e07222018-02-19 15:05:56 +0100698def test_logs_for_status(bep_file, status):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100699 targets = []
700 raw_data = ""
Jakob Buchgraber94d5c212018-02-22 09:57:08 +0100701 with open(bep_file, encoding="utf-8") as f:
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100702 raw_data = f.read()
703 decoder = json.JSONDecoder()
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100704
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100705 pos = 0
706 while pos < len(raw_data):
707 bep_obj, size = decoder.raw_decode(raw_data[pos:])
Jakob Buchgraber45e38632018-02-19 17:27:08 +0100708 if "testSummary" in bep_obj:
709 test_target = bep_obj["id"]["testSummary"]["label"]
710 test_status = bep_obj["testSummary"]["overallStatus"]
711 if test_status == status:
712 outputs = bep_obj["testSummary"]["failed"]
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100713 test_logs = []
714 for output in outputs:
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100715 test_logs.append(url2pathname(
716 urlparse(output["uri"]).path))
Jakob Buchgraber45e38632018-02-19 17:27:08 +0100717 targets.append((test_target, test_logs))
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100718 pos += size + 1
719 return targets
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100720
721
Philipp Wollermann3e1a7712018-02-19 17:34:24 +0100722def execute_command(args, shell=False, fail_if_nonzero=True):
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100723 eprint(" ".join(args))
724 return subprocess.run(args, shell=shell, check=fail_if_nonzero).returncode
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100725
726
Jakob Buchgraber22890f12018-02-21 20:33:25 +0100727def untrusted_code_verification_step():
Jakob Buchgraber1abb4202018-02-21 20:30:28 +0100728 return """
729 - block: \"Untrusted Code Verification\"
730 prompt: \"Did you review this pull request for malicious code?\""""
731
Jakob Buchgraber16b29a62018-02-21 20:46:40 +0100732
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100733def print_project_pipeline(platform_configs, project_name, http_config,
734 git_repository, use_but):
Jakob Buchgraberaa2af382018-02-21 19:56:54 +0100735 pipeline_steps = []
Jakob Buchgraber1abb4202018-02-21 20:30:28 +0100736 if is_pull_request():
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100737 trusted_git_repository = git_repository
738 if not trusted_git_repository:
739 trusted_git_repository = os.getenv("BUILDKITE_REPO")
Jakob Buchgraberc16e4222018-02-21 21:18:24 +0100740 commit = os.getenv("BUILDKITE_COMMIT")
Jakob Buchgraber0109fa72018-02-21 22:13:10 +0100741 update_pull_request_verification_status(trusted_git_repository, commit, state="pending")
Jakob Buchgraberf4656952018-02-21 20:34:35 +0100742 pipeline_steps.append(untrusted_code_verification_step())
Philipp Wollermannff39ef52018-02-21 14:18:52 +0100743 for platform, _ in platform_configs.items():
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100744 step = runner_step(platform, project_name,
745 http_config, git_repository, use_but)
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100746 pipeline_steps.append(step)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100747
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100748 print_pipeline(pipeline_steps)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100749
750
Jakob Buchgraberaa2af382018-02-21 19:56:54 +0100751def runner_step(platform, project_name=None, http_config=None,
Philipp Wollermannf6be4662018-02-21 14:48:28 +0100752 git_repository=None, use_but=False):
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100753 command = python_binary(platform) + \
754 " bazelci.py runner --platform=" + platform
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100755 if http_config:
Philipp Wollermannf6be4662018-02-21 14:48:28 +0100756 command += " --http_config=" + http_config
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100757 if git_repository:
Philipp Wollermannf6be4662018-02-21 14:48:28 +0100758 command += " --git_repository=" + git_repository
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100759 if use_but:
Philipp Wollermannf6be4662018-02-21 14:48:28 +0100760 command += " --use_but"
761 label = create_label(platform, project_name)
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100762 return """
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100763 - label: \"{0}\"
764 command: \"{1}\\n{2}\"
765 agents:
766 - \"os={3}\"""".format(label, fetch_bazelcipy_command(), command, platform)
767
768
769def print_pipeline(steps):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100770 print("steps:")
771 for step in steps:
772 print(step)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100773
774
775def wait_step():
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100776 return """
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100777 - wait"""
778
779
780def http_config_flag(http_config):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100781 if http_config is not None:
782 return "--http_config=" + http_config
783 return ""
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100784
785
786def fetch_bazelcipy_command():
Jakob Buchgraber9cd9d752018-02-21 19:22:03 +0100787 return "curl -s {0} -o bazelci.py".format(bazelcipy_url())
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100788
789
790def upload_project_pipeline_step(project_name, git_repository, http_config):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100791 pipeline_command = ("{0} bazelci.py project_pipeline --project_name=\\\"{1}\\\" " +
792 "--use_but --git_repository={2}").format(python_binary(), project_name,
793 git_repository)
794 if http_config:
Philipp Wollermannf6be4662018-02-21 14:48:28 +0100795 pipeline_command += " --http_config=" + http_config
796 pipeline_command += " | buildkite-agent pipeline upload"
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100797
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100798 return """
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100799 - label: \"Setup {0}\"
800 command: \"{1}\\n{2}\"
801 agents:
802 - \"pipeline=true\"""".format(project_name, fetch_bazelcipy_command(),
803 pipeline_command)
804
805
Philipp Wollermannf6be4662018-02-21 14:48:28 +0100806def create_label(platform, project_name, build_only=False, test_only=False):
807 if build_only and test_only:
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100808 raise BuildkiteException(
809 "build_only and test_only cannot be true at the same time")
Jakob Buchgraber7d1d3bb2018-02-21 22:38:22 +0100810 platform_name = platforms_info()[platform]["emoji-name"]
Philipp Wollermannf6be4662018-02-21 14:48:28 +0100811
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100812 if build_only:
813 label = "Build "
Philipp Wollermannf6be4662018-02-21 14:48:28 +0100814 elif test_only:
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100815 label = "Test "
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100816 else:
Philipp Wollermannf6be4662018-02-21 14:48:28 +0100817 label = ""
818
819 if project_name:
820 label += "{0} ({1})".format(project_name, platform_name)
821 else:
822 label += platform_name
823
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100824 return label
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100825
826
Philipp Wollermannf6be4662018-02-21 14:48:28 +0100827def bazel_build_step(platform, project_name, http_config=None, build_only=False, test_only=False):
Philipp Wollermannbcedf9b2018-02-19 18:07:44 +0100828 pipeline_command = python_binary(platform) + " bazelci.py runner"
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100829 if build_only:
Philipp Wollermannf6be4662018-02-21 14:48:28 +0100830 pipeline_command += " --build_only --save_but"
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100831 if test_only:
Philipp Wollermannf6be4662018-02-21 14:48:28 +0100832 pipeline_command += " --test_only"
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100833 if http_config:
Philipp Wollermannf6be4662018-02-21 14:48:28 +0100834 pipeline_command += " --http_config=" + http_config
835 label = create_label(platform, project_name, build_only, test_only)
836 pipeline_command += " --platform=" + platform
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100837
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100838 return """
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100839 - label: \"{0}\"
840 command: \"{1}\\n{2}\"
841 agents:
842 - \"os={3}\"""".format(label, fetch_bazelcipy_command(),
843 pipeline_command, platform)
844
845
Jakob Buchgraber76381e02018-02-19 16:19:56 +0100846def publish_bazel_binaries_step():
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100847 command = python_binary() + " bazelci.py publish_binaries"
848 return """
Jakob Buchgraber76381e02018-02-19 16:19:56 +0100849 - label: \"Publish Bazel Binaries\"
850 command: \"{0}\\n{1}\"
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +0100851 agents:
Jakob Buchgraber76381e02018-02-19 16:19:56 +0100852 - \"pipeline=true\"""".format(fetch_bazelcipy_command(), command)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +0100853
854
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100855def print_bazel_postsubmit_pipeline(configs, http_config):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100856 if not configs:
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100857 raise BuildkiteException(
858 "Bazel postsubmit pipeline configuration is empty.")
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100859 if set(configs.keys()) != set(supported_platforms()):
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100860 raise BuildkiteException(
861 "Bazel postsubmit pipeline needs to build Bazel on all supported platforms.")
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100862
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100863 pipeline_steps = []
864 for platform, config in configs.items():
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100865 pipeline_steps.append(bazel_build_step(
866 platform, "Bazel", http_config, build_only=True))
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100867 pipeline_steps.append(wait_step())
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +0100868
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100869 # todo move this to the end with a wait step.
870 pipeline_steps.append(publish_bazel_binaries_step())
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +0100871
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100872 for platform, config in configs.items():
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100873 pipeline_steps.append(bazel_build_step(
874 platform, "Bazel", http_config, test_only=True))
Philipp Wollermannf6be4662018-02-21 14:48:28 +0100875
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100876 for project, config in downstream_projects().items():
877 git_repository = config["git_repository"]
878 http_config = config.get("http_config", None)
879 pipeline_steps.append(upload_project_pipeline_step(project,
880 git_repository, http_config))
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100881
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100882 print_pipeline(pipeline_steps)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +0100883
884
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +0100885def bazelci_builds_download_url(platform, build_number):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100886 return "https://storage.googleapis.com/bazel-builds/artifacts/{0}/{1}/bazel".format(platform, build_number)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +0100887
888
889def bazelci_builds_upload_url(platform, build_number):
Jakob Buchgraber2a2304f2018-02-19 21:29:44 +0100890 return "gs://bazel-builds/artifacts/{0}/{1}/bazel".format(platform, build_number)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +0100891
892
Jakob Buchgraber76381e02018-02-19 16:19:56 +0100893def bazelci_builds_metadata_url():
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100894 return "gs://bazel-builds/metadata/latest_fully_tested.json"
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +0100895
896
Jakob Buchgraber76381e02018-02-19 16:19:56 +0100897def latest_generation_and_build_number():
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100898 output = None
899 attempt = 0
900 while attempt < 5:
901 output = subprocess.check_output(
902 ["gsutil", "stat", bazelci_builds_metadata_url()])
903 match = re.search("Generation:[ ]*([0-9]+)", output.decode("utf-8"))
904 if not match:
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100905 raise BuildkiteException(
906 "Couldn't parse generation. gsutil output format changed?")
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100907 generation = match.group(1)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +0100908
Philipp Wollermannff39ef52018-02-21 14:18:52 +0100909 match = re.search(r"Hash \(md5\):[ ]*([^\s]+)", output.decode("utf-8"))
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100910 if not match:
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100911 raise BuildkiteException(
912 "Couldn't parse md5 hash. gsutil output format changed?")
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100913 expected_md5hash = base64.b64decode(match.group(1))
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +0100914
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100915 output = subprocess.check_output(
916 ["gsutil", "cat", bazelci_builds_metadata_url()])
917 hasher = hashlib.md5()
918 hasher.update(output)
919 actual_md5hash = hasher.digest()
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +0100920
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100921 if expected_md5hash == actual_md5hash:
922 break
Philipp Wollermannf6be4662018-02-21 14:48:28 +0100923 attempt += 1
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100924 info = json.loads(output.decode("utf-8"))
925 return (generation, info["build_number"])
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +0100926
Jakob Buchgraber699aece2018-02-19 12:49:30 +0100927
Jakob Buchgraber88083fd2018-02-18 17:23:35 +0100928def sha256_hexdigest(filename):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100929 sha256 = hashlib.sha256()
930 with open(filename, 'rb') as f:
931 for block in iter(lambda: f.read(65536), b''):
932 sha256.update(block)
933 return sha256.hexdigest()
Jakob Buchgraber699aece2018-02-19 12:49:30 +0100934
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +0100935
Jakob Buchgraber76381e02018-02-19 16:19:56 +0100936def try_publish_binaries(build_number, expected_generation):
Philipp Wollermann3e1a7712018-02-19 17:34:24 +0100937 tmpdir = tempfile.mkdtemp()
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100938 try:
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100939 info = {
940 "build_number": build_number,
941 "git_commit": os.environ["BUILDKITE_COMMIT"],
942 "platforms": {}
943 }
944 for platform in supported_platforms():
945 bazel_binary_path = download_bazel_binary(tmpdir, platform)
Philipp Wollermann3e1a7712018-02-19 17:34:24 +0100946 execute_command(["gsutil", "cp", "-a", "public-read", bazel_binary_path,
947 bazelci_builds_upload_url(platform, build_number)])
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100948 info["platforms"][platform] = {
949 "url": bazelci_builds_download_url(platform, build_number),
950 "sha256": sha256_hexdigest(bazel_binary_path),
951 }
Jakob Buchgraber76381e02018-02-19 16:19:56 +0100952
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100953 info_file = os.path.join(tmpdir, "info.json")
954 with open(info_file, mode="w", encoding="utf-8") as fp:
955 json.dump(info, fp)
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100956
957 try:
958 execute_command([
959 "gsutil",
960 "-h", "x-goog-if-generation-match:" + expected_generation,
961 "-h", "Content-Type:application/json",
962 "cp", "-a", "public-read",
963 info_file, bazelci_builds_metadata_url()])
964 except subprocess.CalledProcessError:
965 raise BinaryUploadRaceException()
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100966 finally:
Philipp Wollermann3e1a7712018-02-19 17:34:24 +0100967 shutil.rmtree(tmpdir)
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +0100968
969
Jakob Buchgraber76381e02018-02-19 16:19:56 +0100970def publish_binaries():
Philipp Wollermanndb024862018-02-19 17:16:56 +0100971 """
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100972 Publish Bazel binaries to GCS.
Philipp Wollermanndb024862018-02-19 17:16:56 +0100973 """
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100974 current_build_number = os.environ.get("BUILDKITE_BUILD_NUMBER", None)
975 if not current_build_number:
976 raise BuildkiteException("Not running inside Buildkite")
977 current_build_number = int(current_build_number)
978
979 for _ in range(5):
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100980 latest_generation, latest_build_number = latest_generation_and_build_number()
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +0100981
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100982 if current_build_number <= latest_build_number:
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100983 eprint(("Current build '{0}' is not newer than latest published '{1}'. " +
984 "Skipping publishing of binaries.").format(current_build_number,
985 latest_build_number))
Philipp Wollermann598b4a42018-02-19 17:03:36 +0100986 break
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +0100987
Philipp Wollermanndcaddd92018-02-21 14:13:43 +0100988 try:
989 try_publish_binaries(current_build_number, latest_generation)
990 except BinaryUploadRaceException:
991 # Retry.
992 continue
993
994 eprint("Successfully updated '{0}' to binaries from build {1}."
995 .format(bazelci_builds_metadata_url(), current_build_number))
996 break
997 else:
Jakob Buchgraber6104a432018-02-21 21:16:53 +0100998 raise BuildkiteException(
999 "Could not publish binaries, ran out of attempts.")
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01001000
1001
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001002def main(argv=None):
1003 if argv is None:
1004 argv = sys.argv
1005
Jakob Buchgraber6104a432018-02-21 21:16:53 +01001006 parser = argparse.ArgumentParser(
1007 description='Bazel Continuous Integration Script')
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001008
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001009 subparsers = parser.add_subparsers(dest="subparsers_name")
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001010
Jakob Buchgraber6104a432018-02-21 21:16:53 +01001011 bazel_postsubmit_pipeline = subparsers.add_parser(
1012 "bazel_postsubmit_pipeline")
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001013 bazel_postsubmit_pipeline.add_argument("--http_config", type=str)
1014 bazel_postsubmit_pipeline.add_argument("--git_repository", type=str)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001015
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001016 project_pipeline = subparsers.add_parser("project_pipeline")
1017 project_pipeline.add_argument("--project_name", type=str)
1018 project_pipeline.add_argument("--http_config", type=str)
1019 project_pipeline.add_argument("--git_repository", type=str)
Jakob Buchgraber6104a432018-02-21 21:16:53 +01001020 project_pipeline.add_argument(
1021 "--use_but", type=bool, nargs="?", const=True)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001022
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001023 runner = subparsers.add_parser("runner")
Jakob Buchgraber6104a432018-02-21 21:16:53 +01001024 runner.add_argument("--platform", action="store",
1025 choices=list(supported_platforms()))
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001026 runner.add_argument("--http_config", type=str)
1027 runner.add_argument("--git_repository", type=str)
1028 runner.add_argument("--use_but", type=bool, nargs="?", const=True)
1029 runner.add_argument("--save_but", type=bool, nargs="?", const=True)
1030 runner.add_argument("--build_only", type=bool, nargs="?", const=True)
1031 runner.add_argument("--test_only", type=bool, nargs="?", const=True)
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001032
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001033 runner = subparsers.add_parser("publish_binaries")
Jakob Buchgraberd20ffeb2018-02-18 03:16:43 +01001034
Philipp Wollermann598b4a42018-02-19 17:03:36 +01001035 args = parser.parse_args()
Jakob Buchgraber0b6a39d2018-02-17 00:45:14 +01001036
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001037 try:
1038 if args.subparsers_name == "bazel_postsubmit_pipeline":
1039 configs = fetch_configs(args.http_config)
Jakob Buchgraber6104a432018-02-21 21:16:53 +01001040 print_bazel_postsubmit_pipeline(
1041 configs.get("platforms", None), args.http_config)
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001042 elif args.subparsers_name == "project_pipeline":
1043 configs = fetch_configs(args.http_config)
1044 print_project_pipeline(configs.get("platforms", None), args.project_name,
1045 args.http_config, args.git_repository, args.use_but)
1046 elif args.subparsers_name == "runner":
1047 configs = fetch_configs(args.http_config)
1048 execute_commands(configs.get("platforms", None)[args.platform],
1049 args.platform, args.git_repository, args.use_but, args.save_but,
1050 args.build_only, args.test_only)
1051 elif args.subparsers_name == "publish_binaries":
1052 publish_binaries()
1053 else:
1054 parser.print_help()
1055 return 2
1056 except BuildkiteException as e:
1057 eprint(str(e))
1058 return 1
1059 return 0
1060
Jakob Buchgraber95e3d572018-02-21 18:48:49 +01001061
Philipp Wollermanndcaddd92018-02-21 14:13:43 +01001062if __name__ == "__main__":
1063 sys.exit(main())