activate new script
diff --git a/buildkite/pipelines/bazelci.py b/buildkite/pipelines/bazelci.py
index 34fb04b..9005167 100644
--- a/buildkite/pipelines/bazelci.py
+++ b/buildkite/pipelines/bazelci.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
import argparse
import codecs
import json
@@ -5,95 +6,251 @@
import shutil
import subprocess
import sys
+import stat
import tempfile
import urllib.request
from shutil import copyfile
from urllib.parse import urlparse
+def downstream_projects():
+ return {
+ "BUILD_file_generator" : {
+ "git_repository" : "https://github.com/bazelbuild/BUILD_file_generator.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/BUILD_file_generator-postsubmit.json"
+ },
+ "buildtools" : {
+ "git_repository" : "https://github.com/bazelbuild/buildtools.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/buildtools-postsubmit.json"
+ },
+ "examples" : {
+ "git_repository" : "https://github.com/bazelbuild/examples.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/examples-postsubmit.json"
+ },
+ "migration-tooling" : {
+ "git_repository" : "https://github.com/bazelbuild/migration-tooling.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/migration-tooling-postsubmit.json"
+ },
+ "protobuf" : {
+ "git_repository" : "https://github.com/google/protobuf.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/protobuf-postsubmit.json"
+ },
+ "re2" : {
+ "git_repository" : "https://github.com/google/re2.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/re2-postsubmit.json"
+ },
+ "rules_appengine" : {
+ "git_repository" : "https://github.com/bazelbuild/rules_appengine.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_appengine-postsubmit.json"
+ },
+ "rules_closure" : {
+ "git_repository" : "https://github.com/bazelbuild/rules_closure.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_closure-postsubmit.json"
+ },
+ "rules_go" : {
+ "git_repository" : "https://github.com/bazelbuild/rules_go.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_go-postsubmit.json"
+ },
+ "rules_groovy" : {
+ "git_repository" : "https://github.com/bazelbuild/rules_groovy.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_groovy-postsubmit.json"
+ },
+ "rules_gwt" : {
+ "git_repository" : "https://github.com/bazelbuild/rules_gwt.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_gwt-postsubmit.json"
+ },
+ "rules_jsonnet" : {
+ "git_repository" : "https://github.com/bazelbuild/rules_jsonnet.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_jsonnet-postsubmit.json"
+ },
+ "rules_k8s" : {
+ "git_repository" : "https://github.com/bazelbuild/rules_k8s.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_k8s-postsubmit.json"
+ },
+ "rules_nodejs" : {
+ "git_repository" : "https://github.com/bazelbuild/rules_nodejs.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_nodejs-postsubmit.json"
+ },
+ "rules_perl" : {
+ "git_repository" : "https://github.com/bazelbuild/rules_perl.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_perl-postsubmit.json"
+ },
+ "rules_python" : {
+ "git_repository" : "https://github.com/bazelbuild/rules_python.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_python-postsubmit.json"
+ },
+ "rules_scala" : {
+ "git_repository" : "https://github.com/bazelbuild/rules_scala.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_scala-postsubmit.json"
+ },
+ "rules_typescript" : {
+ "git_repository" : "https://github.com/bazelbuild/rules_typescript.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_typescript-postsubmit.json"
+ },
+ "skydoc" : {
+ "git_repository" : "https://github.com/bazelbuild/skydoc.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/skydoc-postsubmit.json"
+ },
+ "subpar" : {
+ "git_repository" : "https://github.com/google/subpar.git",
+ "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/subpar-postsubmit.json"
+ }
+ }
+
+def python_binary():
+ return "python3.6"
+
+def bazelcipy_url():
+ '''
+ URL to the latest version of this script.
+ '''
+ return "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/bazelci1.py"
+
+def eprint(*args, **kwargs):
+ '''
+ Print to stderr and exit the process.
+ '''
+ print(*args, file=sys.stderr, **kwargs)
+ exit(1)
+
def supported_platforms():
+ '''
+ Returns a map containing all supported platform names as keys, with the
+ values being the platform name in a human readable format.
+ '''
return {
"ubuntu1404" : "Ubuntu 14.04",
"ubuntu1604" : "Ubuntu 16.04",
"macos" : "macOS"
}
-def fetch_configs(http_config):
- if http_config is None:
+def git_clone_path():
+ return "project-under-test"
+
+def fetch_configs(http_url):
+ '''
+ If specified fetches the build configuration from http_url, else tries to
+ read it from .bazelci/config.json.
+ Returns the json configuration as a python data structure.
+ '''
+ if http_url is None:
with open(".bazelci/config.json", "r") as fd:
return json.load(fd)
- with urllib.request.urlopen(http_config) as resp:
+ with urllib.request.urlopen(http_url) as resp:
reader = codecs.getreader("utf-8")
return json.load(reader(resp))
-def run(config, platform, bazel_binary, git_repository):
- exit_code = 0
+def execute_commands(config, platform, git_repository, use_but, save_but,
+ build_only, test_only):
+ exit_code = -1
tmpdir = None
+ bazel_binary = "bazel"
try:
tmpdir = tempfile.mkdtemp()
+ if use_but:
+ source_step = create_label(supported_platforms()[platform], "Bazel",
+ build_only=True, test_only=False)
+ bazel_binary = download_bazel_binary(tmpdir, source_step)
if git_repository:
- if os.path.exists("downstream-repo"):
- shutil.rmtree("downstream-repo")
- clone_repository(git_repository)
+ clone_git_repository(git_repository)
+ os.chdir(git_clone_path())
cleanup(bazel_binary)
else:
cleanup(bazel_binary)
- shell_commands(config.get("shell_commands", None))
- bazel_run(bazel_binary, config.get("run_targets", None))
- bazel_build(bazel_binary, config.get("build_flags", []), config.get("build_targets", None))
- bep_file = os.path.join(tmpdir, "build_event_json_file.json")
- exit_code = bazel_test(bazel_binary, config.get("test_flags", []), config.get("test_targets", None), bep_file)
- upload_failed_test_logs(bep_file, tmpdir)
- if git_repository:
- delete_repository(git_repository)
+ execute_shell_commands(config.get("shell_commands", None))
+ execute_bazel_run(bazel_binary, config.get("run_targets", None))
+ if not test_only:
+ execute_bazel_build(bazel_binary, config.get("build_flags", []),
+ config.get("build_targets", None))
+ if save_but:
+ upload_bazel_binary()
+ if not build_only:
+ bep_file = os.path.join(tmpdir, "build_event_json_file.json")
+ exit_code = execute_bazel_test(bazel_binary, config.get("test_flags", []),
+ config.get("test_targets", None), bep_file)
+ upload_failed_test_logs(bep_file, tmpdir)
finally:
+ if git_repository:
+ os.chdir("..")
+ delete_git_checkout()
if tmpdir:
shutil.rmtree(tmpdir)
- cleanup(bazel_binary)
- exit(exit_code)
+ if exit_code > -1:
+ exit(exit_code)
-def clone_repository(git_repository):
- fail_if_nonzero(run_command(["git", "clone", git_repository, "downstream-repo"]))
- os.chdir("downstream-repo")
+def upload_bazel_binary():
+ print("\n--- Uploading Bazel under test")
+ fail_if_nonzero(execute_command(["buildkite-agent", "artifact", "upload",
+ "bazel-bin/src/bazel"]))
-def delete_repository(git_repository):
+def download_bazel_binary(dest_dir, source_step):
+ print("\n--- Downloading Bazel under test")
+ fail_if_nonzero(execute_command(["buildkite-agent", "artifact", "download",
+ "bazel-bin/src/bazel", dest_dir, "--step", source_step]))
+ bazel_binary_path = os.path.join(dest_dir, "bazel-bin/src/bazel")
+ st = os.stat(bazel_binary_path)
+ os.chmod(bazel_binary_path, st.st_mode | stat.S_IEXEC)
+ return bazel_binary_path
+
+def clone_git_repository(git_repository):
+ delete_git_checkout()
+ fail_if_nonzero(execute_command(["git", "clone", git_repository,
+ git_clone_path()]))
+
+def delete_git_checkout():
+ if os.path.exists(git_clone_path()):
+ shutil.rmtree(git_clone_path())
+
+def cleanup(bazel_binary):
+ print("\n--- Cleanup")
+ if os.path.exists("WORKSPACE"):
+ fail_if_nonzero(execute_command([bazel_binary, "clean", "--expunge"]))
+ delete_git_checkout()
+
+def delete_git_repository(git_repository):
os.chdir("..")
- shutil.rmtree("downstream-repo")
+ shutil.rmtree(git_clone_path())
-def shell_commands(commands):
+def execute_shell_commands(commands):
if not commands:
return
print("\n--- Shell Commands")
shell_command = "\n".join(commands)
- fail_if_nonzero(run_command([shell_command], shell=True))
+ fail_if_nonzero(execute_command([shell_command], shell=True))
-def bazel_run(bazel_binary, targets):
+def execute_bazel_run(bazel_binary, targets):
if not targets:
return
print("\n--- Run Targets")
for target in targets:
- fail_if_nonzero(run_command([bazel_binary, "run", target]))
+ fail_if_nonzero(execute_command([bazel_binary, "run", target]))
-def bazel_build(bazel_binary, flags, targets):
+def execute_bazel_build(bazel_binary, flags, targets):
if not targets:
return
print("\n+++ Build")
- fail_if_nonzero(run_command([bazel_binary, "build", "--color=yes", "--keep_going"] + flags + targets))
+ fail_if_nonzero(execute_command([bazel_binary, "build", "--color=yes",
+ "--keep_going"] + flags + targets))
-def bazel_test(bazel_binary, flags, targets, bep_file):
+def execute_bazel_test(bazel_binary, flags, targets, bep_file):
if not targets:
- return
+ return 0
print("\n+++ Test")
- return run_command([bazel_binary, "test", "--color=yes", "--keep_going", "--build_tests_only", "--build_event_json_file=" + bep_file] + flags + targets)
+ return execute_command([bazel_binary, "test", "--color=yes", "--keep_going",
+ "--build_tests_only", "--build_event_json_file=" + bep_file] + flags +
+ targets)
def fail_if_nonzero(exitcode):
if exitcode is not 0:
exit(exitcode)
def upload_failed_test_logs(bep_file, tmpdir):
- for logfile in failed_test_logs(bep_file, tmpdir):
- fail_if_nonzero(run_command(["buildkite-agent", "artifact", "upload", logfile]))
+ if not os.path.exists(bep_file):
+ return
+ for logfile in failed_logs_from_bep(bep_file, tmpdir):
+ fail_if_nonzero(execute_command(["buildkite-agent", "artifact", "upload",
+ logfile]))
-def failed_test_logs(bep_file, tmpdir):
+def failed_logs_from_bep(bep_file, tmpdir):
test_logs = []
raw_data = ""
with open(bep_file) as f:
@@ -122,74 +279,173 @@
path = path.replace(":", "/")
return os.path.join(tmpdir, path + ".log")
-def cleanup(bazel_binary):
- print("\n--- Cleanup")
- if os.path.exists("WORKSPACE"):
- fail_if_nonzero(run_command([bazel_binary, "clean", "--expunge"]))
- if os.path.exists("downstream-repo"):
- shutil.rmtree("downstream-repo")
-
-def run_command(args, shell=False):
+def execute_command(args, shell=False):
print(" ".join(args))
res = subprocess.run(args, shell=shell)
return res.returncode
-def generate_pipeline(configs, http_config):
- if not configs:
- print("The CI config is empty.")
- exit(1)
+def print_project_pipeline(platform_configs, project_name, http_config,
+ git_repository, use_but):
pipeline_steps = []
- for platform, config in configs.items():
- if platform not in supported_platforms():
- print("'{0}' is not a supported platform on Bazel CI".format(platform))
- exit(1)
- pipeline_steps.append(command_step(supported_platforms()[platform], platform, http_config))
- if not pipeline_steps:
- print("The CI config is empty.")
- exit(1)
- write_pipeline_file(pipeline_steps)
+ for platform, config in platform_configs.items():
+ step = runner_step(platform, project_name, http_config, git_repository,
+ use_but)
+ pipeline_steps.append(step)
-def write_pipeline_file(steps):
+ print_pipeline(pipeline_steps)
+
+def runner_step(platform, project_name=None, http_config=None,
+ git_repository=None, use_but=False, save_but=False, build_only=False,
+ test_only=False):
+ command = python_binary() + " bazelci.py runner --platform=" + platform
+ if http_config:
+ command = command + " --http_config=" + http_config
+ if git_repository:
+ command = command + " --git_repository=" + git_repository
+ if use_but:
+ command = command + " --use_but"
+ if save_but:
+ command = command + " --save_but"
+ if build_only:
+ command = command + " --build_only"
+ if test_only:
+ command = command + " --test_only"
+ platform_name = supported_platforms()[platform]
+ label = create_label(platform_name, project_name, build_only, test_only)
+ return """
+ - label: \"{0}\"
+ command: \"{1}\\n{2}\"
+ agents:
+ - \"os={3}\"""".format(label, fetch_bazelcipy_command(), command, platform)
+
+def print_pipeline(steps):
print("steps:")
for step in steps:
print(step)
-def command_step(label, platform, http_config):
+def wait_step():
return """
- - label: \"{0}\"
- command: \"curl -s https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/bazelci.py > bazelci.py\\n{1}\"
- agents:
- - \"os={2}\"""".format(label, "{0} --platform={1} {2} ".format(runner_command(platform), platform, http_config_flag(http_config)), platform)
-
-def runner_command(platform):
- return "python3.6 bazelci.py --runner=true"
+ - wait"""
def http_config_flag(http_config):
if http_config is not None:
return "--http_config=" + http_config
return ""
+def fetch_bazelcipy_command():
+ return "curl -s {0} > bazelci.py".format(bazelcipy_url())
+
+def upload_project_pipeline_step(project_name, git_repository, http_config):
+ pipeline_command = ("{0} bazelci.py project_pipeline --project_name=\\\"{1}\\\" " +
+ "--use_but --git_repository={2}").format(python_binary(), project_name,
+ git_repository)
+ if http_config:
+ pipeline_command = pipeline_command + " --http_config=" + http_config
+ pipeline_command = pipeline_command + " | buildkite-agent pipeline upload"
+
+ return """
+ - label: \"Setup {0}\"
+ command: \"{1}\\n{2}\"
+ agents:
+ - \"pipeline=true\"""".format(project_name, fetch_bazelcipy_command(),
+ pipeline_command)
+
+def create_label(platform_name, project_name=None, build_only=False,
+ test_only=False):
+ label = ""
+ if build_only:
+ label = "Build "
+ if test_only:
+ label = "Test "
+ if project_name:
+ label = label + "{0} ({1})".format(project_name, platform_name)
+ else:
+ label = label + platform_name
+ return label
+
+def bazel_build_step(platform_name, platform, project_name, http_config=None,
+ build_only=False, test_only=False):
+ pipeline_command = python_binary() + " bazelci.py runner"
+ if build_only:
+ pipeline_command = pipeline_command + " --build_only --save_but"
+ if test_only:
+ pipeline_command = pipeline_command + " --test_only"
+ if http_config:
+ pipeline_command = pipeline_command + " --http_config=" + http_config
+ label = create_label(platform_name, project_name, build_only=build_only,
+ test_only=test_only)
+ pipeline_command = pipeline_command + " --platform=" + platform
+
+ return """
+ - label: \"{0}\"
+ command: \"{1}\\n{2}\"
+ agents:
+ - \"os={3}\"""".format(label, fetch_bazelcipy_command(),
+ pipeline_command, platform)
+
+def print_bazel_postsubmit_pipeline(configs, http_config):
+ if not configs:
+ eprint("Bazel postsubmit pipeline configuration is empty.")
+ if set(configs.keys()) != set(supported_platforms().keys()):
+ eprint("Bazel postsubmit pipeline needs to build Bazel on all " +
+ "supported platforms.")
+
+ pipeline_steps = []
+ for platform, config in configs.items():
+ platform_name = supported_platforms()[platform]
+ pipeline_steps.append(bazel_build_step(platform_name, platform, "Bazel",
+ http_config, build_only=True))
+ pipeline_steps.append(wait_step())
+ for platform, config in configs.items():
+ platform_name = supported_platforms()[platform]
+ pipeline_steps.append(bazel_build_step(platform_name, platform, "Bazel",
+ http_config, test_only=True))
+ for project, config in downstream_projects().items():
+ git_repository = config["git_repository"]
+ http_config = config.get("http_config", None)
+ pipeline_steps.append(upload_project_pipeline_step(project,
+ git_repository, http_config))
+
+ print_pipeline(pipeline_steps)
+
if __name__ == "__main__":
- parser = argparse.ArgumentParser(description='Bazel Continous Integration Runner')
- parser.add_argument("--generate_pipeline", type=bool)
- parser.add_argument("--runner", type=bool)
- parser.add_argument("--platform", type=str, help="The platform the script is running on. Required.")
- parser.add_argument("--bazel_binary", type=str, help="The path to the Bazel binary. Optional.")
- parser.add_argument("--http_config", type=str, help="The URL of the config file. Optional.")
+ parser = argparse.ArgumentParser(description='Bazel Continuous Integration Script')
+
+ subparsers = parser.add_subparsers(dest="subparsers_name")
+ bazel_postsubmit_pipeline = subparsers.add_parser("bazel_postsubmit_pipeline")
+ bazel_postsubmit_pipeline.add_argument("--http_config", type=str)
+ bazel_postsubmit_pipeline.add_argument("--git_repository", type=str)
+
+ project_pipeline = subparsers.add_parser("project_pipeline")
+ project_pipeline.add_argument("--project_name", type=str)
+ project_pipeline.add_argument("--http_config", type=str)
+ project_pipeline.add_argument("--git_repository", type=str)
+ project_pipeline.add_argument("--use_but", type=bool, nargs="?", const=True)
+
+ runner = subparsers.add_parser("runner")
+ runner.add_argument("--platform", action="store",
+ choices=list(supported_platforms()))
+ runner.add_argument("--http_config", type=str)
+ runner.add_argument("--git_repository", type=str)
+ runner.add_argument("--use_but", type=bool, nargs="?", const=True)
+ runner.add_argument("--save_but", type=bool, nargs="?", const=True)
+ runner.add_argument("--build_only", type=bool, nargs="?", const=True)
+ runner.add_argument("--test_only", type=bool, nargs="?", const=True)
+
args = parser.parse_args()
- if args.generate_pipeline:
+ if args.subparsers_name == "bazel_postsubmit_pipeline":
configs = fetch_configs(args.http_config)
- generate_pipeline(configs.get("platforms", None), args.http_config)
- elif args.runner:
+ print_bazel_postsubmit_pipeline(configs.get("platforms", None),
+ args.http_config)
+ elif args.subparsers_name == "project_pipeline":
configs = fetch_configs(args.http_config)
- bazel_binary = "bazel"
- if args.bazel_binary is not None:
- bazel_binary = args.bazel_binary
- git_repository = configs.get("git_repository", None)
- if args.platform not in configs["platforms"]:
- print("No configuration exists for '{0}'".format(args.platform))
- run(configs["platforms"][args.platform], args.platform, bazel_binary, git_repository)
+ print_project_pipeline(configs.get("platforms", None), args.project_name,
+ args.http_config, args.git_repository, args.use_but)
+ elif args.subparsers_name == "runner":
+ configs = fetch_configs(args.http_config)
+ execute_commands(configs.get("platforms", None)[args.platform],
+ args.platform, args.git_repository, args.use_but, args.save_but,
+ args.build_only, args.test_only)
else:
- print("Need to specify either --runner or --generate_pipeline")
- exit(1)
+ parser.print_help()
\ No newline at end of file
diff --git a/buildkite/pipelines/bazelci1.py b/buildkite/pipelines/bazelci1.py
deleted file mode 100644
index 9005167..0000000
--- a/buildkite/pipelines/bazelci1.py
+++ /dev/null
@@ -1,451 +0,0 @@
-from __future__ import print_function
-import argparse
-import codecs
-import json
-import os.path
-import shutil
-import subprocess
-import sys
-import stat
-import tempfile
-import urllib.request
-from shutil import copyfile
-from urllib.parse import urlparse
-
-def downstream_projects():
- return {
- "BUILD_file_generator" : {
- "git_repository" : "https://github.com/bazelbuild/BUILD_file_generator.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/BUILD_file_generator-postsubmit.json"
- },
- "buildtools" : {
- "git_repository" : "https://github.com/bazelbuild/buildtools.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/buildtools-postsubmit.json"
- },
- "examples" : {
- "git_repository" : "https://github.com/bazelbuild/examples.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/examples-postsubmit.json"
- },
- "migration-tooling" : {
- "git_repository" : "https://github.com/bazelbuild/migration-tooling.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/migration-tooling-postsubmit.json"
- },
- "protobuf" : {
- "git_repository" : "https://github.com/google/protobuf.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/protobuf-postsubmit.json"
- },
- "re2" : {
- "git_repository" : "https://github.com/google/re2.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/re2-postsubmit.json"
- },
- "rules_appengine" : {
- "git_repository" : "https://github.com/bazelbuild/rules_appengine.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_appengine-postsubmit.json"
- },
- "rules_closure" : {
- "git_repository" : "https://github.com/bazelbuild/rules_closure.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_closure-postsubmit.json"
- },
- "rules_go" : {
- "git_repository" : "https://github.com/bazelbuild/rules_go.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_go-postsubmit.json"
- },
- "rules_groovy" : {
- "git_repository" : "https://github.com/bazelbuild/rules_groovy.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_groovy-postsubmit.json"
- },
- "rules_gwt" : {
- "git_repository" : "https://github.com/bazelbuild/rules_gwt.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_gwt-postsubmit.json"
- },
- "rules_jsonnet" : {
- "git_repository" : "https://github.com/bazelbuild/rules_jsonnet.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_jsonnet-postsubmit.json"
- },
- "rules_k8s" : {
- "git_repository" : "https://github.com/bazelbuild/rules_k8s.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_k8s-postsubmit.json"
- },
- "rules_nodejs" : {
- "git_repository" : "https://github.com/bazelbuild/rules_nodejs.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_nodejs-postsubmit.json"
- },
- "rules_perl" : {
- "git_repository" : "https://github.com/bazelbuild/rules_perl.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_perl-postsubmit.json"
- },
- "rules_python" : {
- "git_repository" : "https://github.com/bazelbuild/rules_python.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_python-postsubmit.json"
- },
- "rules_scala" : {
- "git_repository" : "https://github.com/bazelbuild/rules_scala.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_scala-postsubmit.json"
- },
- "rules_typescript" : {
- "git_repository" : "https://github.com/bazelbuild/rules_typescript.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_typescript-postsubmit.json"
- },
- "skydoc" : {
- "git_repository" : "https://github.com/bazelbuild/skydoc.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/skydoc-postsubmit.json"
- },
- "subpar" : {
- "git_repository" : "https://github.com/google/subpar.git",
- "http_config" : "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/subpar-postsubmit.json"
- }
- }
-
-def python_binary():
- return "python3.6"
-
-def bazelcipy_url():
- '''
- URL to the latest version of this script.
- '''
- return "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/bazelci1.py"
-
-def eprint(*args, **kwargs):
- '''
- Print to stderr and exit the process.
- '''
- print(*args, file=sys.stderr, **kwargs)
- exit(1)
-
-def supported_platforms():
- '''
- Returns a map containing all supported platform names as keys, with the
- values being the platform name in a human readable format.
- '''
- return {
- "ubuntu1404" : "Ubuntu 14.04",
- "ubuntu1604" : "Ubuntu 16.04",
- "macos" : "macOS"
- }
-
-def git_clone_path():
- return "project-under-test"
-
-def fetch_configs(http_url):
- '''
- If specified fetches the build configuration from http_url, else tries to
- read it from .bazelci/config.json.
- Returns the json configuration as a python data structure.
- '''
- if http_url is None:
- with open(".bazelci/config.json", "r") as fd:
- return json.load(fd)
- with urllib.request.urlopen(http_url) as resp:
- reader = codecs.getreader("utf-8")
- return json.load(reader(resp))
-
-def execute_commands(config, platform, git_repository, use_but, save_but,
- build_only, test_only):
- exit_code = -1
- tmpdir = None
- bazel_binary = "bazel"
- try:
- tmpdir = tempfile.mkdtemp()
- if use_but:
- source_step = create_label(supported_platforms()[platform], "Bazel",
- build_only=True, test_only=False)
- bazel_binary = download_bazel_binary(tmpdir, source_step)
- if git_repository:
- clone_git_repository(git_repository)
- os.chdir(git_clone_path())
- cleanup(bazel_binary)
- else:
- cleanup(bazel_binary)
- execute_shell_commands(config.get("shell_commands", None))
- execute_bazel_run(bazel_binary, config.get("run_targets", None))
- if not test_only:
- execute_bazel_build(bazel_binary, config.get("build_flags", []),
- config.get("build_targets", None))
- if save_but:
- upload_bazel_binary()
- if not build_only:
- bep_file = os.path.join(tmpdir, "build_event_json_file.json")
- exit_code = execute_bazel_test(bazel_binary, config.get("test_flags", []),
- config.get("test_targets", None), bep_file)
- upload_failed_test_logs(bep_file, tmpdir)
- finally:
- if git_repository:
- os.chdir("..")
- delete_git_checkout()
- if tmpdir:
- shutil.rmtree(tmpdir)
- if exit_code > -1:
- exit(exit_code)
-
-def upload_bazel_binary():
- print("\n--- Uploading Bazel under test")
- fail_if_nonzero(execute_command(["buildkite-agent", "artifact", "upload",
- "bazel-bin/src/bazel"]))
-
-def download_bazel_binary(dest_dir, source_step):
- print("\n--- Downloading Bazel under test")
- fail_if_nonzero(execute_command(["buildkite-agent", "artifact", "download",
- "bazel-bin/src/bazel", dest_dir, "--step", source_step]))
- bazel_binary_path = os.path.join(dest_dir, "bazel-bin/src/bazel")
- st = os.stat(bazel_binary_path)
- os.chmod(bazel_binary_path, st.st_mode | stat.S_IEXEC)
- return bazel_binary_path
-
-def clone_git_repository(git_repository):
- delete_git_checkout()
- fail_if_nonzero(execute_command(["git", "clone", git_repository,
- git_clone_path()]))
-
-def delete_git_checkout():
- if os.path.exists(git_clone_path()):
- shutil.rmtree(git_clone_path())
-
-def cleanup(bazel_binary):
- print("\n--- Cleanup")
- if os.path.exists("WORKSPACE"):
- fail_if_nonzero(execute_command([bazel_binary, "clean", "--expunge"]))
- delete_git_checkout()
-
-def delete_git_repository(git_repository):
- os.chdir("..")
- shutil.rmtree(git_clone_path())
-
-def execute_shell_commands(commands):
- if not commands:
- return
- print("\n--- Shell Commands")
- shell_command = "\n".join(commands)
- fail_if_nonzero(execute_command([shell_command], shell=True))
-
-def execute_bazel_run(bazel_binary, targets):
- if not targets:
- return
- print("\n--- Run Targets")
- for target in targets:
- fail_if_nonzero(execute_command([bazel_binary, "run", target]))
-
-def execute_bazel_build(bazel_binary, flags, targets):
- if not targets:
- return
- print("\n+++ Build")
- fail_if_nonzero(execute_command([bazel_binary, "build", "--color=yes",
- "--keep_going"] + flags + targets))
-
-def execute_bazel_test(bazel_binary, flags, targets, bep_file):
- if not targets:
- return 0
- print("\n+++ Test")
- return execute_command([bazel_binary, "test", "--color=yes", "--keep_going",
- "--build_tests_only", "--build_event_json_file=" + bep_file] + flags +
- targets)
-
-def fail_if_nonzero(exitcode):
- if exitcode is not 0:
- exit(exitcode)
-
-def upload_failed_test_logs(bep_file, tmpdir):
- if not os.path.exists(bep_file):
- return
- for logfile in failed_logs_from_bep(bep_file, tmpdir):
- fail_if_nonzero(execute_command(["buildkite-agent", "artifact", "upload",
- logfile]))
-
-def failed_logs_from_bep(bep_file, tmpdir):
- test_logs = []
- raw_data = ""
- with open(bep_file) as f:
- raw_data = f.read()
- decoder = json.JSONDecoder()
-
- pos = 0
- while pos < len(raw_data):
- json_dict, size = decoder.raw_decode(raw_data[pos:])
- if "testResult" in json_dict:
- test_result = json_dict["testResult"]
- if test_result["status"] != "PASSED":
- outputs = test_result["testActionOutput"]
- for output in outputs:
- if output["name"] == "test.log":
- new_path = label_to_path(tmpdir, json_dict["id"]["testResult"]["label"])
- os.makedirs(os.path.dirname(new_path), exist_ok=True)
- copyfile(urlparse(output["uri"]).path, new_path)
- test_logs.append(new_path)
- pos += size + 1
- return test_logs
-
-def label_to_path(tmpdir, label):
- # remove leading //
- path = label[2:]
- path = path.replace(":", "/")
- return os.path.join(tmpdir, path + ".log")
-
-def execute_command(args, shell=False):
- print(" ".join(args))
- res = subprocess.run(args, shell=shell)
- return res.returncode
-
-def print_project_pipeline(platform_configs, project_name, http_config,
- git_repository, use_but):
- pipeline_steps = []
- for platform, config in platform_configs.items():
- step = runner_step(platform, project_name, http_config, git_repository,
- use_but)
- pipeline_steps.append(step)
-
- print_pipeline(pipeline_steps)
-
-def runner_step(platform, project_name=None, http_config=None,
- git_repository=None, use_but=False, save_but=False, build_only=False,
- test_only=False):
- command = python_binary() + " bazelci.py runner --platform=" + platform
- if http_config:
- command = command + " --http_config=" + http_config
- if git_repository:
- command = command + " --git_repository=" + git_repository
- if use_but:
- command = command + " --use_but"
- if save_but:
- command = command + " --save_but"
- if build_only:
- command = command + " --build_only"
- if test_only:
- command = command + " --test_only"
- platform_name = supported_platforms()[platform]
- label = create_label(platform_name, project_name, build_only, test_only)
- return """
- - label: \"{0}\"
- command: \"{1}\\n{2}\"
- agents:
- - \"os={3}\"""".format(label, fetch_bazelcipy_command(), command, platform)
-
-def print_pipeline(steps):
- print("steps:")
- for step in steps:
- print(step)
-
-def wait_step():
- return """
- - wait"""
-
-def http_config_flag(http_config):
- if http_config is not None:
- return "--http_config=" + http_config
- return ""
-
-def fetch_bazelcipy_command():
- return "curl -s {0} > bazelci.py".format(bazelcipy_url())
-
-def upload_project_pipeline_step(project_name, git_repository, http_config):
- pipeline_command = ("{0} bazelci.py project_pipeline --project_name=\\\"{1}\\\" " +
- "--use_but --git_repository={2}").format(python_binary(), project_name,
- git_repository)
- if http_config:
- pipeline_command = pipeline_command + " --http_config=" + http_config
- pipeline_command = pipeline_command + " | buildkite-agent pipeline upload"
-
- return """
- - label: \"Setup {0}\"
- command: \"{1}\\n{2}\"
- agents:
- - \"pipeline=true\"""".format(project_name, fetch_bazelcipy_command(),
- pipeline_command)
-
-def create_label(platform_name, project_name=None, build_only=False,
- test_only=False):
- label = ""
- if build_only:
- label = "Build "
- if test_only:
- label = "Test "
- if project_name:
- label = label + "{0} ({1})".format(project_name, platform_name)
- else:
- label = label + platform_name
- return label
-
-def bazel_build_step(platform_name, platform, project_name, http_config=None,
- build_only=False, test_only=False):
- pipeline_command = python_binary() + " bazelci.py runner"
- if build_only:
- pipeline_command = pipeline_command + " --build_only --save_but"
- if test_only:
- pipeline_command = pipeline_command + " --test_only"
- if http_config:
- pipeline_command = pipeline_command + " --http_config=" + http_config
- label = create_label(platform_name, project_name, build_only=build_only,
- test_only=test_only)
- pipeline_command = pipeline_command + " --platform=" + platform
-
- return """
- - label: \"{0}\"
- command: \"{1}\\n{2}\"
- agents:
- - \"os={3}\"""".format(label, fetch_bazelcipy_command(),
- pipeline_command, platform)
-
-def print_bazel_postsubmit_pipeline(configs, http_config):
- if not configs:
- eprint("Bazel postsubmit pipeline configuration is empty.")
- if set(configs.keys()) != set(supported_platforms().keys()):
- eprint("Bazel postsubmit pipeline needs to build Bazel on all " +
- "supported platforms.")
-
- pipeline_steps = []
- for platform, config in configs.items():
- platform_name = supported_platforms()[platform]
- pipeline_steps.append(bazel_build_step(platform_name, platform, "Bazel",
- http_config, build_only=True))
- pipeline_steps.append(wait_step())
- for platform, config in configs.items():
- platform_name = supported_platforms()[platform]
- pipeline_steps.append(bazel_build_step(platform_name, platform, "Bazel",
- http_config, test_only=True))
- for project, config in downstream_projects().items():
- git_repository = config["git_repository"]
- http_config = config.get("http_config", None)
- pipeline_steps.append(upload_project_pipeline_step(project,
- git_repository, http_config))
-
- print_pipeline(pipeline_steps)
-
-if __name__ == "__main__":
- parser = argparse.ArgumentParser(description='Bazel Continuous Integration Script')
-
- subparsers = parser.add_subparsers(dest="subparsers_name")
- bazel_postsubmit_pipeline = subparsers.add_parser("bazel_postsubmit_pipeline")
- bazel_postsubmit_pipeline.add_argument("--http_config", type=str)
- bazel_postsubmit_pipeline.add_argument("--git_repository", type=str)
-
- project_pipeline = subparsers.add_parser("project_pipeline")
- project_pipeline.add_argument("--project_name", type=str)
- project_pipeline.add_argument("--http_config", type=str)
- project_pipeline.add_argument("--git_repository", type=str)
- project_pipeline.add_argument("--use_but", type=bool, nargs="?", const=True)
-
- runner = subparsers.add_parser("runner")
- runner.add_argument("--platform", action="store",
- choices=list(supported_platforms()))
- runner.add_argument("--http_config", type=str)
- runner.add_argument("--git_repository", type=str)
- runner.add_argument("--use_but", type=bool, nargs="?", const=True)
- runner.add_argument("--save_but", type=bool, nargs="?", const=True)
- runner.add_argument("--build_only", type=bool, nargs="?", const=True)
- runner.add_argument("--test_only", type=bool, nargs="?", const=True)
-
- args = parser.parse_args()
-
- if args.subparsers_name == "bazel_postsubmit_pipeline":
- configs = fetch_configs(args.http_config)
- print_bazel_postsubmit_pipeline(configs.get("platforms", None),
- args.http_config)
- elif args.subparsers_name == "project_pipeline":
- configs = fetch_configs(args.http_config)
- print_project_pipeline(configs.get("platforms", None), args.project_name,
- args.http_config, args.git_repository, args.use_but)
- elif args.subparsers_name == "runner":
- configs = fetch_configs(args.http_config)
- execute_commands(configs.get("platforms", None)[args.platform],
- args.platform, args.git_repository, args.use_but, args.save_but,
- args.build_only, args.test_only)
- else:
- parser.print_help()
\ No newline at end of file