Add config import feature.

This feature allows configuration files to import other yml files.
diff --git a/buildkite/bazelci.py b/buildkite/bazelci.py
index d7f4bfd..2f95a24 100755
--- a/buildkite/bazelci.py
+++ b/buildkite/bazelci.py
@@ -600,7 +600,18 @@
     if file_config is not None and http_url is not None:
         raise BuildkiteException("file_config and http_url cannot be set at the same time")
 
-    config = load_config(http_url, file_config)
+    return load_config(http_url, file_config)
+
+
+def load_config(http_url, file_config, allow_imports=True):
+    config = None
+    if http_url:
+        config = load_remote_yaml_file(http_url)
+    else:
+        file_config = file_config or ".bazelci/presubmit.yml"
+        with open(file_config, "r") as fd:
+            config = yaml.safe_load(fd)
+
     # Legacy mode means that there is exactly one task per platform (e.g. ubuntu1604_nojdk),
     # which means that we can get away with using the platform name as task ID.
     # No other updates are needed since get_platform_for_task() falls back to using the
@@ -608,25 +619,54 @@
     if "platforms" in config:
         config["tasks"] = config.pop("platforms")
 
+    if "tasks" not in config:
+        config["tasks"] = {}
+
+    imports = config.pop("imports", None)
+    if imports:
+        if not allow_imports:
+            raise BuildkiteException("Nested imports are not allowed")
+
+        for i in imports:
+            imported_tasks = load_imported_tasks(i, http_url, file_config)
+            config["tasks"].update(imported_tasks)
+
     return config
 
 
-def load_config(http_url, file_config):
-    if file_config is not None:
-        with open(file_config, "r") as fd:
-            return yaml.safe_load(fd)
-    if http_url is not None:
-        return load_remote_yaml_file(http_url)
-    with open(".bazelci/presubmit.yml", "r") as fd:
-        return yaml.safe_load(fd)
-
-
 def load_remote_yaml_file(http_url):
     with urllib.request.urlopen(http_url) as resp:
         reader = codecs.getreader("utf-8")
         return yaml.safe_load(reader(resp))
 
 
+def load_imported_tasks(import_name, http_url, file_config):
+    if "/" in import_name:
+        raise BuildkiteException("Invalid import '%s'" % import_name)
+
+    old_path = http_url or file_config
+    new_path = "%s%s" % (old_path[: old_path.rfind("/") + 1], import_name)
+    if http_url:
+        http_url = new_path
+    else:
+        file_config = new_path
+
+    imported_config = load_config(http_url=http_url, file_config=file_config, allow_imports=False)
+
+    namespace = import_name.partition(".")[0]
+    tasks = {}
+    for task_name, task_config in imported_config["tasks"].items():
+        if "platform" not in task_config:
+            task_config["platform"] = task_name
+        for field in ["name", "working_directory"]:
+            if field not in task_config:
+                task_config[field] = namespace
+
+        tasks["%s_%s" % (namespace, task_name)] = task_config
+
+    return tasks
+
+
 def print_collapsed_group(name):
     eprint("\n\n--- {0}\n\n".format(name))