Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 1 | # Copyright 2018 The Bazel Authors. All rights reserved. |
| 2 | # |
| 3 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | # you may not use this file except in compliance with the License. |
| 5 | # You may obtain a copy of the License at |
| 6 | # |
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | # |
| 9 | # Unless required by applicable law or agreed to in writing, software |
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | # See the License for the specific language governing permissions and |
| 13 | # limitations under the License. |
| 14 | |
| 15 | from __future__ import print_function |
| 16 | import argparse |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 17 | import base64 |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 18 | import codecs |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 19 | import hashlib |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 20 | import json |
| 21 | import os.path |
Jakob Buchgraber | 6db0f26 | 2018-02-17 15:45:54 +0100 | [diff] [blame] | 22 | import multiprocessing |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 23 | import re |
| 24 | import shutil |
| 25 | import subprocess |
| 26 | import sys |
| 27 | import stat |
| 28 | import tempfile |
| 29 | import urllib.request |
| 30 | from shutil import copyfile |
| 31 | from urllib.parse import urlparse |
| 32 | |
| 33 | |
| 34 | def downstream_projects(): |
| 35 | return { |
| 36 | "BUILD_file_generator": { |
| 37 | "git_repository": "https://github.com/bazelbuild/BUILD_file_generator.git", |
| 38 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/BUILD_file_generator-postsubmit.json" |
| 39 | }, |
| 40 | "bazel-toolchains": { |
| 41 | "git_repository": "https://github.com/bazelbuild/bazel-toolchains.git", |
| 42 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/bazel-toolchains-postsubmit.json" |
| 43 | }, |
| 44 | "buildtools": { |
| 45 | "git_repository": "https://github.com/bazelbuild/buildtools.git", |
| 46 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/buildtools-postsubmit.json" |
| 47 | }, |
| 48 | "CLion Plugin": { |
| 49 | "git_repository": "https://github.com/bazelbuild/intellij.git", |
| 50 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/clion-postsubmit.json" |
| 51 | }, |
| 52 | "Eclipse Plugin": { |
| 53 | "git_repository": "https://github.com/bazelbuild/eclipse.git", |
| 54 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/eclipse-postsubmit.json" |
| 55 | }, |
| 56 | "Gerrit": { |
| 57 | "git_repository": "https://gerrit.googlesource.com/gerrit.git", |
| 58 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/gerrit-postsubmit.json" |
| 59 | }, |
| 60 | "Google Logging": { |
| 61 | "git_repository": "https://github.com/google/glog.git", |
| 62 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/glog-postsubmit.json" |
| 63 | }, |
| 64 | "IntelliJ Plugin": { |
| 65 | "git_repository": "https://github.com/bazelbuild/intellij.git", |
| 66 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/intellij-postsubmit.json" |
| 67 | }, |
| 68 | "migration-tooling": { |
| 69 | "git_repository": "https://github.com/bazelbuild/migration-tooling.git", |
| 70 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/migration-tooling-postsubmit.json" |
| 71 | }, |
| 72 | "protobuf": { |
| 73 | "git_repository": "https://github.com/google/protobuf.git", |
| 74 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/protobuf-postsubmit.json" |
| 75 | }, |
| 76 | "re2": { |
| 77 | "git_repository": "https://github.com/google/re2.git", |
| 78 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/re2-postsubmit.json" |
| 79 | }, |
| 80 | "rules_appengine": { |
| 81 | "git_repository": "https://github.com/bazelbuild/rules_appengine.git", |
| 82 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_appengine-postsubmit.json" |
| 83 | }, |
| 84 | "rules_closure": { |
| 85 | "git_repository": "https://github.com/bazelbuild/rules_closure.git", |
| 86 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_closure-postsubmit.json" |
| 87 | }, |
| 88 | "rules_d": { |
| 89 | "git_repository": "https://github.com/bazelbuild/rules_d.git", |
| 90 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_d-postsubmit.json" |
| 91 | }, |
| 92 | "rules_go": { |
| 93 | "git_repository": "https://github.com/bazelbuild/rules_go.git", |
| 94 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_go-postsubmit.json" |
| 95 | }, |
| 96 | "rules_groovy": { |
| 97 | "git_repository": "https://github.com/bazelbuild/rules_groovy.git", |
| 98 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_groovy-postsubmit.json" |
| 99 | }, |
| 100 | "rules_gwt": { |
| 101 | "git_repository": "https://github.com/bazelbuild/rules_gwt.git", |
| 102 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_gwt-postsubmit.json" |
| 103 | }, |
| 104 | "rules_jsonnet": { |
| 105 | "git_repository": "https://github.com/bazelbuild/rules_jsonnet.git", |
| 106 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_jsonnet-postsubmit.json" |
| 107 | }, |
| 108 | "rules_k8s": { |
| 109 | "git_repository": "https://github.com/bazelbuild/rules_k8s.git", |
| 110 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_k8s-postsubmit.json" |
| 111 | }, |
| 112 | "rules_nodejs": { |
| 113 | "git_repository": "https://github.com/bazelbuild/rules_nodejs.git", |
| 114 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_nodejs-postsubmit.json" |
| 115 | }, |
| 116 | "rules_perl": { |
| 117 | "git_repository": "https://github.com/bazelbuild/rules_perl.git", |
| 118 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_perl-postsubmit.json" |
| 119 | }, |
| 120 | "rules_python": { |
| 121 | "git_repository": "https://github.com/bazelbuild/rules_python.git", |
| 122 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_python-postsubmit.json" |
| 123 | }, |
| 124 | "rules_rust": { |
| 125 | "git_repository": "https://github.com/bazelbuild/rules_rust.git", |
| 126 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_rust-postsubmit.json" |
| 127 | }, |
| 128 | "rules_sass": { |
| 129 | "git_repository": "https://github.com/bazelbuild/rules_sass.git", |
| 130 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_sass-postsubmit.json" |
| 131 | }, |
| 132 | "rules_scala": { |
| 133 | "git_repository": "https://github.com/bazelbuild/rules_scala.git", |
| 134 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_scala-postsubmit.json" |
| 135 | }, |
| 136 | "rules_typescript": { |
| 137 | "git_repository": "https://github.com/bazelbuild/rules_typescript.git", |
| 138 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_typescript-postsubmit.json" |
| 139 | }, |
Jakob Buchgraber | d2522ec | 2018-02-18 17:56:36 +0100 | [diff] [blame] | 140 | # Enable once is resolved: https://github.com/bazelbuild/continuous-integration/issues/191 |
| 141 | # "rules_webtesting": { |
| 142 | # "git_repository": "https://github.com/bazelbuild/rules_webtesting.git", |
| 143 | # "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_webtesting-postsubmit.json" |
| 144 | # }, |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 145 | "skydoc": { |
| 146 | "git_repository": "https://github.com/bazelbuild/skydoc.git", |
| 147 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/skydoc-postsubmit.json" |
| 148 | }, |
| 149 | "subpar": { |
| 150 | "git_repository": "https://github.com/google/subpar.git", |
| 151 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/subpar-postsubmit.json" |
| 152 | }, |
| 153 | "TensorFlow": { |
| 154 | "git_repository": "https://github.com/tensorflow/tensorflow.git", |
| 155 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/tensorflow-postsubmit.json" |
| 156 | }, |
| 157 | "TensorFlow Serving": { |
| 158 | "git_repository": "https://github.com/tensorflow/serving.git", |
| 159 | "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/tensorflow-serving-postsubmit.json" |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | |
| 164 | def python_binary(): |
| 165 | return "python3.6" |
| 166 | |
| 167 | |
| 168 | def bazelcipy_url(): |
| 169 | ''' |
| 170 | URL to the latest version of this script. |
| 171 | ''' |
Jakob Buchgraber | 371d622 | 2018-02-17 00:56:13 +0100 | [diff] [blame] | 172 | return "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/bazelci.py" |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 173 | |
| 174 | |
| 175 | def eprint(*args, **kwargs): |
| 176 | ''' |
| 177 | Print to stderr and exit the process. |
| 178 | ''' |
| 179 | print(*args, file=sys.stderr, **kwargs) |
| 180 | exit(1) |
| 181 | |
| 182 | |
| 183 | def platforms_info(): |
| 184 | ''' |
| 185 | Returns a map containing all supported platform names as keys, with the |
| 186 | values being the platform name in a human readable format, and a the |
| 187 | buildkite-agent's working directory. |
| 188 | ''' |
| 189 | return { |
| 190 | "ubuntu1404": |
| 191 | { |
| 192 | "name": "Ubuntu 14.04", |
Jakob Buchgraber | 9c83de7 | 2018-02-18 15:32:44 +0100 | [diff] [blame] | 193 | "agent-directory": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/" |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 194 | }, |
| 195 | "ubuntu1604": |
| 196 | { |
| 197 | "name": "Ubuntu 16.04", |
Jakob Buchgraber | 9c83de7 | 2018-02-18 15:32:44 +0100 | [diff] [blame] | 198 | "agent-directory": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/" |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 199 | }, |
| 200 | "macos": |
| 201 | { |
| 202 | "name": "macOS", |
Jakob Buchgraber | 9c83de7 | 2018-02-18 15:32:44 +0100 | [diff] [blame] | 203 | "agent-directory": "/usr/local/var/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/" |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 204 | } |
| 205 | } |
| 206 | |
Jakob Buchgraber | 6db0f26 | 2018-02-17 15:45:54 +0100 | [diff] [blame] | 207 | |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 208 | def downstream_projects_root(platform): |
| 209 | downstream_projects_dir = os.path.expandvars( |
| 210 | "${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects") |
| 211 | path = os.path.join(agent_directory(platform), downstream_projects_dir) |
| 212 | if not os.path.exists(path): |
| 213 | os.makedirs(path) |
| 214 | return path |
| 215 | |
| 216 | |
| 217 | def agent_directory(platform): |
| 218 | return os.path.expandvars(platforms_info()[platform]["agent-directory"]) |
| 219 | |
| 220 | |
| 221 | def supported_platforms(): |
| 222 | return set(platforms_info().keys()) |
| 223 | |
| 224 | |
| 225 | def platform_name(platform): |
| 226 | return platforms_info()[platform]["name"] |
| 227 | |
| 228 | |
| 229 | def fetch_configs(http_url): |
| 230 | ''' |
| 231 | If specified fetches the build configuration from http_url, else tries to |
| 232 | read it from .bazelci/config.json. |
| 233 | Returns the json configuration as a python data structure. |
| 234 | ''' |
| 235 | if http_url is None: |
| 236 | with open(".bazelci/config.json", "r") as fd: |
| 237 | return json.load(fd) |
| 238 | with urllib.request.urlopen(http_url) as resp: |
| 239 | reader = codecs.getreader("utf-8") |
| 240 | return json.load(reader(resp)) |
| 241 | |
Jakob Buchgraber | 9c83de7 | 2018-02-18 15:32:44 +0100 | [diff] [blame] | 242 | |
Jakob Buchgraber | 3120f7a | 2018-02-18 13:28:02 +0100 | [diff] [blame] | 243 | def print_collapsed_group(name): |
| 244 | print("\n--- {0}\n".format(name)) |
| 245 | |
Jakob Buchgraber | 9c83de7 | 2018-02-18 15:32:44 +0100 | [diff] [blame] | 246 | |
Jakob Buchgraber | 3120f7a | 2018-02-18 13:28:02 +0100 | [diff] [blame] | 247 | def print_expanded_group(name): |
| 248 | print("\n+++ {0}\n".format(name)) |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 249 | |
Jakob Buchgraber | 9c83de7 | 2018-02-18 15:32:44 +0100 | [diff] [blame] | 250 | |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 251 | def execute_commands(config, platform, git_repository, use_but, save_but, |
| 252 | build_only, test_only): |
| 253 | exit_code = -1 |
| 254 | tmpdir = None |
| 255 | bazel_binary = "bazel" |
| 256 | try: |
Jakob Buchgraber | db20a86 | 2018-02-17 17:40:27 +0100 | [diff] [blame] | 257 | if git_repository: |
| 258 | clone_git_repository(git_repository, platform) |
| 259 | cleanup(platform) |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 260 | tmpdir = tempfile.mkdtemp() |
| 261 | if use_but: |
Jakob Buchgraber | 3120f7a | 2018-02-18 13:28:02 +0100 | [diff] [blame] | 262 | print_collapsed_group("Downloading Bazel under test") |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 263 | bazel_binary = download_bazel_binary(tmpdir, platform) |
Jakob Buchgraber | 7e690a7 | 2018-02-18 13:22:15 +0100 | [diff] [blame] | 264 | print_bazel_version_info(bazel_binary) |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 265 | execute_shell_commands(config.get("shell_commands", None)) |
| 266 | execute_bazel_run(bazel_binary, config.get("run_targets", None)) |
| 267 | if not test_only: |
| 268 | execute_bazel_build(bazel_binary, config.get("build_flags", []), |
| 269 | config.get("build_targets", None)) |
| 270 | if save_but: |
| 271 | upload_bazel_binary() |
| 272 | if not build_only: |
| 273 | bep_file = os.path.join(tmpdir, "build_event_json_file.json") |
| 274 | exit_code = execute_bazel_test(bazel_binary, config.get("test_flags", []), |
| 275 | config.get("test_targets", None), bep_file) |
Jakob Buchgraber | 02e0722 | 2018-02-19 15:05:56 +0100 | [diff] [blame] | 276 | # Fail the pipeline if there were any flaky tests. |
| 277 | if has_flaky_tests() and exit_code == 0: |
| 278 | exit_code = 1 |
| 279 | upload_test_logs(bep_file, tmpdir) |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 280 | finally: |
| 281 | if tmpdir: |
| 282 | shutil.rmtree(tmpdir) |
Jakob Buchgraber | 1554bfb | 2018-02-17 17:36:36 +0100 | [diff] [blame] | 283 | cleanup(platform) |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 284 | if exit_code > -1: |
| 285 | exit(exit_code) |
| 286 | |
| 287 | |
Jakob Buchgraber | 02e0722 | 2018-02-19 15:05:56 +0100 | [diff] [blame] | 288 | def has_flaky_tests(bep_file): |
| 289 | return len(test_logs_for_status(bep_file, status="FLAKY")) > 0 |
| 290 | |
| 291 | |
Jakob Buchgraber | 7e690a7 | 2018-02-18 13:22:15 +0100 | [diff] [blame] | 292 | def print_bazel_version_info(bazel_binary): |
Jakob Buchgraber | 3120f7a | 2018-02-18 13:28:02 +0100 | [diff] [blame] | 293 | print_collapsed_group("Bazel Info") |
Jakob Buchgraber | 7e690a7 | 2018-02-18 13:22:15 +0100 | [diff] [blame] | 294 | fail_if_nonzero(execute_command([bazel_binary, "version"])) |
| 295 | fail_if_nonzero(execute_command([bazel_binary, "info"])) |
| 296 | |
| 297 | |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 298 | def upload_bazel_binary(): |
Jakob Buchgraber | 3120f7a | 2018-02-18 13:28:02 +0100 | [diff] [blame] | 299 | print_collapsed_group("Uploading Bazel under test") |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 300 | fail_if_nonzero(execute_command(["buildkite-agent", "artifact", "upload", |
| 301 | "bazel-bin/src/bazel"])) |
| 302 | |
| 303 | |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 304 | def download_bazel_binary(dest_dir, platform): |
| 305 | source_step = create_label(platform_name(platform), "Bazel", build_only=True, |
| 306 | test_only=False) |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 307 | fail_if_nonzero(execute_command(["buildkite-agent", "artifact", "download", |
| 308 | "bazel-bin/src/bazel", dest_dir, "--step", source_step])) |
| 309 | bazel_binary_path = os.path.join(dest_dir, "bazel-bin/src/bazel") |
| 310 | st = os.stat(bazel_binary_path) |
| 311 | os.chmod(bazel_binary_path, st.st_mode | stat.S_IEXEC) |
| 312 | return bazel_binary_path |
| 313 | |
| 314 | |
| 315 | def clone_git_repository(git_repository, platform): |
| 316 | root = downstream_projects_root(platform) |
| 317 | project_name = re.search("/([^/]+)\.git$", git_repository).group(1) |
| 318 | clone_path = os.path.join(root, project_name) |
Jakob Buchgraber | 288d87f | 2018-02-18 13:30:33 +0100 | [diff] [blame] | 319 | print_collapsed_group("Fetching " + project_name + " sources") |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 320 | if os.path.exists(clone_path): |
| 321 | os.chdir(clone_path) |
| 322 | fail_if_nonzero(execute_command( |
| 323 | ["git", "remote", "set-url", "origin", git_repository])) |
| 324 | fail_if_nonzero(execute_command(["git", "clean", "-fdqx"])) |
| 325 | fail_if_nonzero(execute_command( |
| 326 | ["git", "submodule", "foreach", "--recursive", "git", "clean", "-fdqx"])) |
| 327 | # sync to the latest commit of HEAD. Unlikely git pull this also works after |
| 328 | # a force push. |
| 329 | fail_if_nonzero(execute_command(["git", "fetch", "origin"])) |
| 330 | remote_head = subprocess.check_output( |
| 331 | ["git", "symbolic-ref", "refs/remotes/origin/HEAD"]) |
| 332 | remote_head = remote_head.decode("utf-8") |
| 333 | remote_head = remote_head.rstrip() |
Jakob Buchgraber | 7e690a7 | 2018-02-18 13:22:15 +0100 | [diff] [blame] | 334 | fail_if_nonzero(execute_command( |
| 335 | ["git", "reset", remote_head, "--hard"])) |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 336 | fail_if_nonzero(execute_command( |
| 337 | ["git", "submodule", "sync", "--recursive"])) |
| 338 | fail_if_nonzero(execute_command( |
| 339 | ["git", "submodule", "update", "--init", "--recursive", "--force"])) |
| 340 | fail_if_nonzero(execute_command( |
| 341 | ["git", "submodule", "foreach", "--recursive", "git", "reset", "--hard"])) |
| 342 | fail_if_nonzero(execute_command(["git", "clean", "-fdqx"])) |
| 343 | fail_if_nonzero(execute_command( |
| 344 | ["git", "submodule", "foreach", "--recursive", "git", "clean", "-fdqx"])) |
| 345 | else: |
| 346 | fail_if_nonzero(execute_command( |
| 347 | ["git", "clone", "--recurse-submodules", git_repository, clone_path])) |
| 348 | os.chdir(clone_path) |
| 349 | |
| 350 | |
Jakob Buchgraber | 9f53b3a | 2018-02-17 17:30:00 +0100 | [diff] [blame] | 351 | def cleanup(platform): |
Jakob Buchgraber | 3120f7a | 2018-02-18 13:28:02 +0100 | [diff] [blame] | 352 | print_collapsed_group("Cleanup") |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 353 | if os.path.exists("WORKSPACE"): |
Jakob Buchgraber | 9f53b3a | 2018-02-17 17:30:00 +0100 | [diff] [blame] | 354 | fail_if_nonzero(execute_command(["bazel", "clean", "--expunge"])) |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 355 | |
Jakob Buchgraber | fd1eaca | 2018-02-17 17:27:14 +0100 | [diff] [blame] | 356 | |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 357 | def execute_shell_commands(commands): |
| 358 | if not commands: |
| 359 | return |
Jakob Buchgraber | 3120f7a | 2018-02-18 13:28:02 +0100 | [diff] [blame] | 360 | print_collapsed_group("Setup (Shell Commands)") |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 361 | shell_command = "\n".join(commands) |
| 362 | fail_if_nonzero(execute_command([shell_command], shell=True)) |
| 363 | |
| 364 | |
| 365 | def execute_bazel_run(bazel_binary, targets): |
| 366 | if not targets: |
| 367 | return |
Jakob Buchgraber | 3120f7a | 2018-02-18 13:28:02 +0100 | [diff] [blame] | 368 | print_collapsed_group("Setup (Run Targets)") |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 369 | for target in targets: |
Jakob Buchgraber | d332b3f | 2018-02-19 15:18:44 +0100 | [diff] [blame] | 370 | fail_if_nonzero(execute_command([bazel_binary, "run", "--curses=yes", |
| 371 | "--color=yes", "--verbose_failurs", target])) |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 372 | |
| 373 | |
| 374 | def execute_bazel_build(bazel_binary, flags, targets): |
| 375 | if not targets: |
| 376 | return |
Jakob Buchgraber | 3120f7a | 2018-02-18 13:28:02 +0100 | [diff] [blame] | 377 | print_expanded_group("Build") |
Jakob Buchgraber | 7b685c0 | 2018-02-17 16:05:22 +0100 | [diff] [blame] | 378 | num_jobs = str(multiprocessing.cpu_count()) |
Jakob Buchgraber | d332b3f | 2018-02-19 15:18:44 +0100 | [diff] [blame] | 379 | common_flags = ["--curses=yes", "--color=yes", "--keep_going", |
| 380 | "--verbose_failures", "--jobs=" + num_jobs] |
Jakob Buchgraber | 6db0f26 | 2018-02-17 15:45:54 +0100 | [diff] [blame] | 381 | fail_if_nonzero(execute_command( |
| 382 | [bazel_binary, "build"] + common_flags + flags + targets)) |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 383 | |
| 384 | |
| 385 | def execute_bazel_test(bazel_binary, flags, targets, bep_file): |
| 386 | if not targets: |
| 387 | return 0 |
Jakob Buchgraber | 3120f7a | 2018-02-18 13:28:02 +0100 | [diff] [blame] | 388 | print_expanded_group("Test") |
Jakob Buchgraber | 7b685c0 | 2018-02-17 16:05:22 +0100 | [diff] [blame] | 389 | num_jobs = str(multiprocessing.cpu_count()) |
Jakob Buchgraber | d332b3f | 2018-02-19 15:18:44 +0100 | [diff] [blame] | 390 | common_flags = ["--curses=yes", "--color=yes", "--keep_going", "--verbose_failures", |
Jakob Buchgraber | 02e0722 | 2018-02-19 15:05:56 +0100 | [diff] [blame] | 391 | "--flaky_test_attempts=3", "--build_tests_only", |
| 392 | "--jobs=" + num_jobs, "--local_test_jobs=" + num_jobs, |
| 393 | "--build_event_json_file=" + bep_file] |
Jakob Buchgraber | 6db0f26 | 2018-02-17 15:45:54 +0100 | [diff] [blame] | 394 | return execute_command([bazel_binary, "test"] + common_flags + flags + targets) |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 395 | |
| 396 | |
| 397 | def fail_if_nonzero(exitcode): |
| 398 | if exitcode is not 0: |
| 399 | exit(exitcode) |
| 400 | |
| 401 | |
Jakob Buchgraber | 02e0722 | 2018-02-19 15:05:56 +0100 | [diff] [blame] | 402 | def upload_test_logs(bep_file, tmpdir): |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 403 | if not os.path.exists(bep_file): |
| 404 | return |
Jakob Buchgraber | 02e0722 | 2018-02-19 15:05:56 +0100 | [diff] [blame] | 405 | test_logs = test_logs_to_upload(bep_file, tmpdir) |
| 406 | if test_logs: |
Jakob Buchgraber | 699aece | 2018-02-19 12:49:30 +0100 | [diff] [blame] | 407 | cwd = os.getcwd() |
| 408 | try: |
| 409 | os.chdir(tmpdir) |
Jakob Buchgraber | 02e0722 | 2018-02-19 15:05:56 +0100 | [diff] [blame] | 410 | print_collapsed_group("Uploading test logs") |
| 411 | for logfile in test_logs: |
Jakob Buchgraber | c0d736c | 2018-02-19 14:21:43 +0100 | [diff] [blame] | 412 | relative_path = os.path.relpath(logfile, tmpdir) |
Jakob Buchgraber | 699aece | 2018-02-19 12:49:30 +0100 | [diff] [blame] | 413 | fail_if_nonzero(execute_command(["buildkite-agent", "artifact", "upload", |
Jakob Buchgraber | c0d736c | 2018-02-19 14:21:43 +0100 | [diff] [blame] | 414 | relative_path])) |
Jakob Buchgraber | 699aece | 2018-02-19 12:49:30 +0100 | [diff] [blame] | 415 | finally: |
| 416 | os.chdir(cwd) |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 417 | |
| 418 | |
Jakob Buchgraber | 02e0722 | 2018-02-19 15:05:56 +0100 | [diff] [blame] | 419 | def test_logs_to_upload(bep_file, tmpdir): |
| 420 | failed = test_logs_for_status(bep_file, status="FAILED") |
| 421 | timed_out = test_logs_for_status(bep_file, status="TIMEOUT") |
| 422 | flaky = test_logs_for_status(bep_file, status="FLAKY") |
| 423 | # Rename the test.log files to the target that created them |
| 424 | # so that it's easy to associate test.log and target. |
| 425 | new_paths = [] |
| 426 | for label, test_logs in (failed + timed_out + flaky): |
| 427 | attempt = 0 |
| 428 | if len(test_logs) > 1: |
| 429 | attempt = 1 |
| 430 | for test_log in test_logs: |
| 431 | new_path = test_label_to_path(tmpdir, label, attempt) |
| 432 | os.makedirs(os.path.dirname(new_path), exist_ok=True) |
| 433 | copyfile(test_logs, new_path) |
| 434 | new_paths.append(new_path) |
| 435 | attempt = attempt + 1 |
| 436 | return new_paths |
Jakob Buchgraber | 699aece | 2018-02-19 12:49:30 +0100 | [diff] [blame] | 437 | |
| 438 | |
Jakob Buchgraber | 02e0722 | 2018-02-19 15:05:56 +0100 | [diff] [blame] | 439 | def test_label_to_path(tmpdir, label, attempt): |
Jakob Buchgraber | 699aece | 2018-02-19 12:49:30 +0100 | [diff] [blame] | 440 | # remove leading // |
| 441 | path = label[2:] |
| 442 | path = path.replace(":", "/") |
Jakob Buchgraber | 02e0722 | 2018-02-19 15:05:56 +0100 | [diff] [blame] | 443 | if attempt == 0: |
| 444 | path = os.path.join(path, "test.log") |
| 445 | else: |
| 446 | path = os.path.join(path, "attempt_" + str(attempt) + ".log") |
Jakob Buchgraber | 699aece | 2018-02-19 12:49:30 +0100 | [diff] [blame] | 447 | return os.path.join(tmpdir, path) |
| 448 | |
| 449 | |
Jakob Buchgraber | 02e0722 | 2018-02-19 15:05:56 +0100 | [diff] [blame] | 450 | def test_logs_for_status(bep_file, status): |
Jakob Buchgraber | 699aece | 2018-02-19 12:49:30 +0100 | [diff] [blame] | 451 | targets = [] |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 452 | raw_data = "" |
| 453 | with open(bep_file) as f: |
| 454 | raw_data = f.read() |
| 455 | decoder = json.JSONDecoder() |
| 456 | |
| 457 | pos = 0 |
| 458 | while pos < len(raw_data): |
Jakob Buchgraber | 699aece | 2018-02-19 12:49:30 +0100 | [diff] [blame] | 459 | bep_obj, size = decoder.raw_decode(raw_data[pos:]) |
| 460 | if "testResult" in bep_obj: |
Jakob Buchgraber | 02e0722 | 2018-02-19 15:05:56 +0100 | [diff] [blame] | 461 | test_target = bep_obj["id"]["testResult"]["label"] |
Jakob Buchgraber | 699aece | 2018-02-19 12:49:30 +0100 | [diff] [blame] | 462 | test_result = bep_obj["testResult"] |
| 463 | if test_result["status"] == status: |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 464 | outputs = test_result["testActionOutput"] |
Jakob Buchgraber | 02e0722 | 2018-02-19 15:05:56 +0100 | [diff] [blame] | 465 | test_logs = [] |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 466 | for output in outputs: |
| 467 | if output["name"] == "test.log": |
Jakob Buchgraber | 02e0722 | 2018-02-19 15:05:56 +0100 | [diff] [blame] | 468 | test_logs.append(urlparse(output["uri"]).path) |
| 469 | if test_logs: |
| 470 | targets.append((test_target, test_logs)) |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 471 | pos += size + 1 |
Jakob Buchgraber | 699aece | 2018-02-19 12:49:30 +0100 | [diff] [blame] | 472 | return targets |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 473 | |
| 474 | |
| 475 | def execute_command(args, shell=False): |
| 476 | print(" ".join(args)) |
| 477 | res = subprocess.run(args, shell=shell) |
| 478 | return res.returncode |
| 479 | |
| 480 | |
| 481 | def print_project_pipeline(platform_configs, project_name, http_config, |
| 482 | git_repository, use_but): |
| 483 | pipeline_steps = [] |
| 484 | for platform, config in platform_configs.items(): |
| 485 | step = runner_step(platform, project_name, http_config, git_repository, |
| 486 | use_but) |
| 487 | pipeline_steps.append(step) |
| 488 | |
| 489 | print_pipeline(pipeline_steps) |
| 490 | |
| 491 | |
| 492 | def runner_step(platform, project_name=None, http_config=None, |
| 493 | git_repository=None, use_but=False, save_but=False, build_only=False, |
| 494 | test_only=False): |
| 495 | command = python_binary() + " bazelci.py runner --platform=" + platform |
| 496 | if http_config: |
| 497 | command = command + " --http_config=" + http_config |
| 498 | if git_repository: |
| 499 | command = command + " --git_repository=" + git_repository |
| 500 | if use_but: |
| 501 | command = command + " --use_but" |
| 502 | if save_but: |
| 503 | command = command + " --save_but" |
| 504 | if build_only: |
| 505 | command = command + " --build_only" |
| 506 | if test_only: |
| 507 | command = command + " --test_only" |
| 508 | label = create_label(platform_name(platform), |
| 509 | project_name, build_only, test_only) |
| 510 | return """ |
| 511 | - label: \"{0}\" |
| 512 | command: \"{1}\\n{2}\" |
| 513 | agents: |
| 514 | - \"os={3}\"""".format(label, fetch_bazelcipy_command(), command, platform) |
| 515 | |
| 516 | |
| 517 | def print_pipeline(steps): |
| 518 | print("steps:") |
| 519 | for step in steps: |
| 520 | print(step) |
| 521 | |
| 522 | |
| 523 | def wait_step(): |
| 524 | return """ |
| 525 | - wait""" |
| 526 | |
| 527 | |
| 528 | def http_config_flag(http_config): |
| 529 | if http_config is not None: |
| 530 | return "--http_config=" + http_config |
| 531 | return "" |
| 532 | |
| 533 | |
| 534 | def fetch_bazelcipy_command(): |
Jakob Buchgraber | 1f92611 | 2018-02-19 15:51:54 +0100 | [diff] [blame] | 535 | return "curl -s {0} -o bazelci.py".format(bazelcipy_url()) |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 536 | |
| 537 | |
| 538 | def upload_project_pipeline_step(project_name, git_repository, http_config): |
| 539 | pipeline_command = ("{0} bazelci.py project_pipeline --project_name=\\\"{1}\\\" " + |
| 540 | "--use_but --git_repository={2}").format(python_binary(), project_name, |
| 541 | git_repository) |
| 542 | if http_config: |
| 543 | pipeline_command = pipeline_command + " --http_config=" + http_config |
| 544 | pipeline_command = pipeline_command + " | buildkite-agent pipeline upload" |
| 545 | |
| 546 | return """ |
| 547 | - label: \"Setup {0}\" |
| 548 | command: \"{1}\\n{2}\" |
| 549 | agents: |
| 550 | - \"pipeline=true\"""".format(project_name, fetch_bazelcipy_command(), |
| 551 | pipeline_command) |
| 552 | |
| 553 | |
| 554 | def create_label(platform_name, project_name=None, build_only=False, |
| 555 | test_only=False): |
| 556 | label = "" |
| 557 | if build_only: |
| 558 | label = "Build " |
| 559 | if test_only: |
| 560 | label = "Test " |
| 561 | if project_name: |
| 562 | label = label + "{0} ({1})".format(project_name, platform_name) |
| 563 | else: |
| 564 | label = label + platform_name |
| 565 | return label |
| 566 | |
| 567 | |
| 568 | def bazel_build_step(platform, project_name, http_config=None, |
| 569 | build_only=False, test_only=False): |
| 570 | pipeline_command = python_binary() + " bazelci.py runner" |
| 571 | if build_only: |
| 572 | pipeline_command = pipeline_command + " --build_only --save_but" |
| 573 | if test_only: |
| 574 | pipeline_command = pipeline_command + " --test_only" |
| 575 | if http_config: |
| 576 | pipeline_command = pipeline_command + " --http_config=" + http_config |
| 577 | label = create_label(platform_name(platform), project_name, build_only=build_only, |
| 578 | test_only=test_only) |
| 579 | pipeline_command = pipeline_command + " --platform=" + platform |
| 580 | |
| 581 | return """ |
| 582 | - label: \"{0}\" |
| 583 | command: \"{1}\\n{2}\" |
| 584 | agents: |
| 585 | - \"os={3}\"""".format(label, fetch_bazelcipy_command(), |
| 586 | pipeline_command, platform) |
| 587 | |
| 588 | |
Jakob Buchgraber | 76381e0 | 2018-02-19 16:19:56 +0100 | [diff] [blame^] | 589 | def publish_bazel_binaries_step(): |
| 590 | command = python_binary() + " bazelci.py publish_binaries" |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 591 | return """ |
Jakob Buchgraber | 76381e0 | 2018-02-19 16:19:56 +0100 | [diff] [blame^] | 592 | - label: \"Publish Bazel Binaries\" |
| 593 | command: \"{0}\\n{1}\" |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 594 | agents: |
Jakob Buchgraber | 76381e0 | 2018-02-19 16:19:56 +0100 | [diff] [blame^] | 595 | - \"pipeline=true\"""".format(fetch_bazelcipy_command(), command) |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 596 | |
| 597 | |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 598 | def print_bazel_postsubmit_pipeline(configs, http_config): |
| 599 | if not configs: |
| 600 | eprint("Bazel postsubmit pipeline configuration is empty.") |
| 601 | if set(configs.keys()) != set(supported_platforms()): |
| 602 | eprint("Bazel postsubmit pipeline needs to build Bazel on all " + |
| 603 | "supported platforms.") |
| 604 | |
| 605 | pipeline_steps = [] |
| 606 | for platform, config in configs.items(): |
| 607 | pipeline_steps.append(bazel_build_step(platform, "Bazel", |
| 608 | http_config, build_only=True)) |
| 609 | pipeline_steps.append(wait_step()) |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 610 | |
Jakob Buchgraber | c0ccfbb | 2018-02-18 04:39:20 +0100 | [diff] [blame] | 611 | # todo move this to the end with a wait step. |
Jakob Buchgraber | 76381e0 | 2018-02-19 16:19:56 +0100 | [diff] [blame^] | 612 | pipeline_steps.append(publish_bazel_binaries_step()) |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 613 | |
Jakob Buchgraber | c0ccfbb | 2018-02-18 04:39:20 +0100 | [diff] [blame] | 614 | for platform, config in configs.items(): |
| 615 | pipeline_steps.append(bazel_build_step(platform, "Bazel", |
| 616 | http_config, test_only=True)) |
| 617 | for project, config in downstream_projects().items(): |
| 618 | git_repository = config["git_repository"] |
| 619 | http_config = config.get("http_config", None) |
| 620 | pipeline_steps.append(upload_project_pipeline_step(project, |
| 621 | git_repository, http_config)) |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 622 | |
| 623 | print_pipeline(pipeline_steps) |
| 624 | |
| 625 | |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 626 | def bazelci_builds_download_url(platform, build_number): |
Jakob Buchgraber | 76381e0 | 2018-02-19 16:19:56 +0100 | [diff] [blame^] | 627 | return "https://storage.googleapis.com/bazel-builds/artifacts/{0}/{1}/bazel".format(platform, build_number) |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 628 | |
| 629 | |
| 630 | def bazelci_builds_upload_url(platform, build_number): |
Jakob Buchgraber | 455dd18 | 2018-02-18 13:39:31 +0100 | [diff] [blame] | 631 | return "gs://bazel-builds/artifacts/{0}/{1}/bazel".format(build_number, platform) |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 632 | |
| 633 | |
Jakob Buchgraber | 76381e0 | 2018-02-19 16:19:56 +0100 | [diff] [blame^] | 634 | def bazelci_builds_metadata_url(): |
| 635 | return "gs://bazel-builds/metadata/latest_fully_tested.json" |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 636 | |
| 637 | |
Jakob Buchgraber | 76381e0 | 2018-02-19 16:19:56 +0100 | [diff] [blame^] | 638 | def latest_generation_and_build_number(): |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 639 | output = None |
| 640 | attempt = 0 |
| 641 | while attempt < 5: |
| 642 | output = subprocess.check_output( |
Jakob Buchgraber | 76381e0 | 2018-02-19 16:19:56 +0100 | [diff] [blame^] | 643 | ["gsutil", "stat", bazelci_builds_metadata_url()]) |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 644 | match = re.search("Generation:[ ]*([0-9]+)", output.decode("utf-8")) |
| 645 | if not match: |
| 646 | eprint("Couldn't parse generation. gsutil output format changed?") |
| 647 | generation = match.group(1) |
| 648 | |
| 649 | match = re.search("Hash \(md5\):[ ]*([^\s]+)", output.decode("utf-8")) |
| 650 | if not match: |
| 651 | eprint("Couldn't parse md5 hash. gsutil output format changed?") |
| 652 | expected_md5hash = base64.b64decode(match.group(1)) |
| 653 | |
| 654 | output = subprocess.check_output( |
Jakob Buchgraber | 76381e0 | 2018-02-19 16:19:56 +0100 | [diff] [blame^] | 655 | ["gsutil", "cat", bazelci_builds_metadata_url()]) |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 656 | hasher = hashlib.md5() |
| 657 | hasher.update(output) |
| 658 | actual_md5hash = hasher.digest() |
| 659 | |
| 660 | if expected_md5hash == actual_md5hash: |
| 661 | break |
| 662 | attempt = attempt + 1 |
| 663 | info = json.loads(output.decode("utf-8")) |
| 664 | return (generation, info["build_number"]) |
| 665 | |
Jakob Buchgraber | 699aece | 2018-02-19 12:49:30 +0100 | [diff] [blame] | 666 | |
Jakob Buchgraber | 88083fd | 2018-02-18 17:23:35 +0100 | [diff] [blame] | 667 | def sha256_hexdigest(filename): |
Jakob Buchgraber | 699aece | 2018-02-19 12:49:30 +0100 | [diff] [blame] | 668 | sha256 = hashlib.sha256() |
| 669 | with open(filename, 'rb') as f: |
| 670 | for block in iter(lambda: f.read(65536), b''): |
| 671 | sha256.update(block) |
| 672 | return sha256.hexdigest() |
| 673 | |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 674 | |
Jakob Buchgraber | 76381e0 | 2018-02-19 16:19:56 +0100 | [diff] [blame^] | 675 | def try_publish_binaries(build_number, expected_generation): |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 676 | tmpdir = None |
| 677 | try: |
| 678 | tmpdir = tempfile.mkdtemp() |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 679 | info = { |
| 680 | "build_number": build_number, |
Jakob Buchgraber | 88083fd | 2018-02-18 17:23:35 +0100 | [diff] [blame] | 681 | "git_commit": os.environ["BUILDKITE_COMMIT"], |
Jakob Buchgraber | 76381e0 | 2018-02-19 16:19:56 +0100 | [diff] [blame^] | 682 | "platforms": {} |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 683 | } |
Jakob Buchgraber | 76381e0 | 2018-02-19 16:19:56 +0100 | [diff] [blame^] | 684 | for platform in supported_platforms(): |
| 685 | bazel_binary_path = download_bazel_binary(tmpdir, platform) |
| 686 | fail_if_nonzero(execute_command(["gsutil", "cp", "-a", "public-read", bazel_binary_path, |
| 687 | bazelci_builds_upload_url(platform, build_number)])) |
| 688 | info["platforms"][platform] = { |
| 689 | "url": bazelci_builds_download_url(platform, build_number), |
| 690 | "sha256": sha256_hexdigest(bazel_binary_path), |
| 691 | } |
| 692 | |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 693 | info_file = os.path.join(tmpdir, "info.json") |
Jakob Buchgraber | 7e690a7 | 2018-02-18 13:22:15 +0100 | [diff] [blame] | 694 | with open(info_file, mode="w", encoding="utf-8") as fp: |
| 695 | json.dump(info, fp) |
Jakob Buchgraber | 4680fdf | 2018-02-18 17:04:27 +0100 | [diff] [blame] | 696 | exitcode = execute_command(["gsutil", "-h", "x-goog-if-generation-match:" + expected_generation, |
| 697 | "-h", "Content-Type:application/json", "cp", "-a", |
| 698 | "public-read", info_file, bazelci_builds_metadata_url(platform)]) |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 699 | return exitcode == 0 |
| 700 | finally: |
| 701 | if tmpdir: |
Jakob Buchgraber | 24bf36d | 2018-02-18 03:50:25 +0100 | [diff] [blame] | 702 | shutil.rmtree(tmpdir) |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 703 | |
| 704 | |
Jakob Buchgraber | 76381e0 | 2018-02-19 16:19:56 +0100 | [diff] [blame^] | 705 | def publish_binaries(): |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 706 | ''' |
Jakob Buchgraber | 76381e0 | 2018-02-19 16:19:56 +0100 | [diff] [blame^] | 707 | Publish Bazel binaries to GCS. |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 708 | ''' |
| 709 | attempt = 0 |
| 710 | while attempt < 5: |
Jakob Buchgraber | 76381e0 | 2018-02-19 16:19:56 +0100 | [diff] [blame^] | 711 | latest_generation, latest_build_number = latest_generation_and_build_number() |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 712 | |
| 713 | current_build_number = os.environ.get("BUILDKITE_BUILD_NUMBER", None) |
| 714 | if not current_build_number: |
| 715 | eprint("Not running inside Buildkite") |
| 716 | current_build_number = int(current_build_number) |
| 717 | if current_build_number <= latest_build_number: |
| 718 | print(("Current build '{0}' is not newer than latest published '{1}'. " + |
| 719 | "Skipping publishing of binaries.").format(current_build_number, |
| 720 | latest_build_number)) |
| 721 | break |
| 722 | |
Jakob Buchgraber | 76381e0 | 2018-02-19 16:19:56 +0100 | [diff] [blame^] | 723 | if try_publish_binaries(current_build_number, latest_generation): |
| 724 | print("Successfully updated '{0}' to binaries from build {1}." |
| 725 | .format(bazelci_builds_metadata_url(), current_build_number)) |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 726 | break |
| 727 | attempt = attempt + 1 |
| 728 | |
| 729 | |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 730 | if __name__ == "__main__": |
| 731 | parser = argparse.ArgumentParser( |
| 732 | description='Bazel Continuous Integration Script') |
| 733 | |
| 734 | subparsers = parser.add_subparsers(dest="subparsers_name") |
| 735 | bazel_postsubmit_pipeline = subparsers.add_parser( |
| 736 | "bazel_postsubmit_pipeline") |
| 737 | bazel_postsubmit_pipeline.add_argument("--http_config", type=str) |
| 738 | bazel_postsubmit_pipeline.add_argument("--git_repository", type=str) |
| 739 | |
| 740 | project_pipeline = subparsers.add_parser("project_pipeline") |
| 741 | project_pipeline.add_argument("--project_name", type=str) |
| 742 | project_pipeline.add_argument("--http_config", type=str) |
| 743 | project_pipeline.add_argument("--git_repository", type=str) |
| 744 | project_pipeline.add_argument( |
| 745 | "--use_but", type=bool, nargs="?", const=True) |
| 746 | |
| 747 | runner = subparsers.add_parser("runner") |
| 748 | runner.add_argument("--platform", action="store", |
| 749 | choices=list(supported_platforms())) |
| 750 | runner.add_argument("--http_config", type=str) |
| 751 | runner.add_argument("--git_repository", type=str) |
| 752 | runner.add_argument("--use_but", type=bool, nargs="?", const=True) |
| 753 | runner.add_argument("--save_but", type=bool, nargs="?", const=True) |
| 754 | runner.add_argument("--build_only", type=bool, nargs="?", const=True) |
| 755 | runner.add_argument("--test_only", type=bool, nargs="?", const=True) |
| 756 | |
Jakob Buchgraber | 76381e0 | 2018-02-19 16:19:56 +0100 | [diff] [blame^] | 757 | runner = subparsers.add_parser("publish_binaries") |
Jakob Buchgraber | d20ffeb | 2018-02-18 03:16:43 +0100 | [diff] [blame] | 758 | |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 759 | args = parser.parse_args() |
| 760 | |
| 761 | if args.subparsers_name == "bazel_postsubmit_pipeline": |
| 762 | configs = fetch_configs(args.http_config) |
| 763 | print_bazel_postsubmit_pipeline(configs.get("platforms", None), |
| 764 | args.http_config) |
| 765 | elif args.subparsers_name == "project_pipeline": |
| 766 | configs = fetch_configs(args.http_config) |
| 767 | print_project_pipeline(configs.get("platforms", None), args.project_name, |
| 768 | args.http_config, args.git_repository, args.use_but) |
| 769 | elif args.subparsers_name == "runner": |
| 770 | configs = fetch_configs(args.http_config) |
| 771 | execute_commands(configs.get("platforms", None)[args.platform], |
| 772 | args.platform, args.git_repository, args.use_but, args.save_but, |
| 773 | args.build_only, args.test_only) |
Jakob Buchgraber | 76381e0 | 2018-02-19 16:19:56 +0100 | [diff] [blame^] | 774 | elif args.subparsers_name == "publish_binaries": |
| 775 | publish_binaries() |
Jakob Buchgraber | 0b6a39d | 2018-02-17 00:45:14 +0100 | [diff] [blame] | 776 | else: |
| 777 | parser.print_help() |