add bazelci.py
diff --git a/buildkite/bazelci.py b/buildkite/bazelci.py
new file mode 100644
index 0000000..643412f
--- /dev/null
+++ b/buildkite/bazelci.py
@@ -0,0 +1,593 @@
+# Copyright 2018 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import print_function
+import argparse
+import codecs
+import json
+import os.path
+import re
+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"
+      },
+      "bazel-toolchains": {
+          "git_repository": "https://github.com/bazelbuild/bazel-toolchains.git",
+          "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/bazel-toolchains-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"
+      },
+      "CLion Plugin": {
+          "git_repository": "https://github.com/bazelbuild/intellij.git",
+          "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/clion-postsubmit.json"
+      },
+      "Eclipse Plugin": {
+          "git_repository": "https://github.com/bazelbuild/eclipse.git",
+          "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/eclipse-postsubmit.json"
+      },
+      "Gerrit": {
+          "git_repository": "https://gerrit.googlesource.com/gerrit.git",
+          "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/gerrit-postsubmit.json"
+      },
+      "Google Logging": {
+          "git_repository": "https://github.com/google/glog.git",
+          "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/glog-postsubmit.json"
+      },
+      "IntelliJ Plugin": {
+          "git_repository": "https://github.com/bazelbuild/intellij.git",
+          "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/intellij-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_d": {
+          "git_repository": "https://github.com/bazelbuild/rules_d.git",
+          "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_d-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_rust": {
+          "git_repository": "https://github.com/bazelbuild/rules_rust.git",
+          "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_rust-postsubmit.json"
+      },
+      "rules_sass": {
+          "git_repository": "https://github.com/bazelbuild/rules_sass.git",
+          "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_sass-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"
+      },
+      "rules_webtesting": {
+          "git_repository": "https://github.com/bazelbuild/rules_webtesting.git",
+          "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/rules_webtesting-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"
+      },
+      "TensorFlow": {
+          "git_repository": "https://github.com/tensorflow/tensorflow.git",
+          "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/tensorflow-postsubmit.json"
+      },
+      "TensorFlow Serving": {
+          "git_repository": "https://github.com/tensorflow/serving.git",
+          "http_config": "https://raw.githubusercontent.com/bazelbuild/continuous-integration/master/buildkite/pipelines/tensorflow-serving-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/bazelci.py"
+
+
+def eprint(*args, **kwargs):
+  '''
+  Print to stderr and exit the process.
+  '''
+  print(*args, file=sys.stderr, **kwargs)
+  exit(1)
+
+
+def platforms_info():
+  '''
+  Returns a map containing all supported platform names as keys, with the
+  values being the platform name in a human readable format, and a the
+  buildkite-agent's working directory.
+  '''
+  return {
+      "ubuntu1404":
+      {
+          "name": "Ubuntu 14.04",
+          "agent-directory": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/"
+      },
+      "ubuntu1604":
+      {
+          "name": "Ubuntu 16.04",
+          "agent-directory": "/var/lib/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/"
+      },
+      "macos":
+      {
+          "name": "macOS",
+          "agent-directory": "/usr/local/var/buildkite-agent/builds/${BUILDKITE_AGENT_NAME}/"
+      }
+  }
+
+
+def downstream_projects_root(platform):
+  downstream_projects_dir = os.path.expandvars(
+      "${BUILDKITE_ORGANIZATION_SLUG}-downstream-projects")
+  path = os.path.join(agent_directory(platform), downstream_projects_dir)
+  if not os.path.exists(path):
+    os.makedirs(path)
+  return path
+
+
+def agent_directory(platform):
+  return os.path.expandvars(platforms_info()[platform]["agent-directory"])
+
+
+def supported_platforms():
+  return set(platforms_info().keys())
+
+
+def platform_name(platform):
+  return platforms_info()[platform]["name"]
+
+
+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(platform_name(platform), "Bazel",
+                                 build_only=True, test_only=False)
+      bazel_binary = download_bazel_binary(tmpdir, source_step)
+    if git_repository:
+      clone_git_repository(git_repository, platform)
+      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 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, platform):
+  root = downstream_projects_root(platform)
+  project_name = re.search("/([^/]+)\.git$", git_repository).group(1)
+  clone_path = os.path.join(root, project_name)
+  print("\n--- Fetching " + project_name + " sources")
+  if os.path.exists(clone_path):
+    os.chdir(clone_path)
+    fail_if_nonzero(execute_command(
+        ["git", "remote", "set-url", "origin", git_repository]))
+    fail_if_nonzero(execute_command(["git", "clean", "-fdqx"]))
+    fail_if_nonzero(execute_command(
+        ["git", "submodule", "foreach", "--recursive", "git", "clean", "-fdqx"]))
+    # sync to the latest commit of HEAD. Unlikely git pull this also works after
+    # a force push.
+    fail_if_nonzero(execute_command(["git", "fetch", "origin"]))
+    remote_head = subprocess.check_output(
+        ["git", "symbolic-ref", "refs/remotes/origin/HEAD"])
+    remote_head = remote_head.decode("utf-8")
+    remote_head = remote_head.rstrip()
+    fail_if_nonzero(execute_command(["git", "reset", remote_head, "--hard"]))
+    fail_if_nonzero(execute_command(
+        ["git", "submodule", "sync", "--recursive"]))
+    fail_if_nonzero(execute_command(
+        ["git", "submodule", "update", "--init", "--recursive", "--force"]))
+    fail_if_nonzero(execute_command(
+        ["git", "submodule", "foreach", "--recursive", "git", "reset", "--hard"]))
+    fail_if_nonzero(execute_command(["git", "clean", "-fdqx"]))
+    fail_if_nonzero(execute_command(
+        ["git", "submodule", "foreach", "--recursive", "git", "clean", "-fdqx"]))
+  else:
+    fail_if_nonzero(execute_command(
+        ["git", "clone", "--recurse-submodules", git_repository, clone_path]))
+    os.chdir(clone_path)
+
+
+def cleanup(bazel_binary):
+  if os.path.exists("WORKSPACE"):
+    print("\n--- Cleanup")
+    fail_if_nonzero(execute_command([bazel_binary, "clean", "--expunge"]))
+
+
+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
+  logfiles = failed_logs_from_bep(bep_file, tmpdir)
+  if logfiles:
+    print("\n--- Uploading failed test logs")
+    for logfile in logfiles:
+      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"
+  label = create_label(platform_name(platform),
+                       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, 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(platform), 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()):
+    eprint("Bazel postsubmit pipeline needs to build Bazel on all " +
+           "supported platforms.")
+
+  pipeline_steps = []
+  for platform, config in configs.items():
+    pipeline_steps.append(bazel_build_step(platform, "Bazel",
+                                           http_config, build_only=True))
+  pipeline_steps.append(wait_step())
+  for platform, config in configs.items():
+    pipeline_steps.append(bazel_build_step(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()