Add soft_fail option to pipeline steps (#1148)

diff --git a/buildkite/bazelci.py b/buildkite/bazelci.py
index 2d7eaec..60658fd 100755
--- a/buildkite/bazelci.py
+++ b/buildkite/bazelci.py
@@ -2095,7 +2095,7 @@
             process.kill()
 
 
-def create_step(label, commands, platform, shards=1):
+def create_step(label, commands, platform, shards=1, soft_fail=None):
     if "docker-image" in PLATFORMS[platform]:
         step = create_docker_step(
             label, image=PLATFORMS[platform]["docker-image"], commands=commands
@@ -2111,6 +2111,9 @@
         step["label"] += " (shard %n)"
         step["parallelism"] = shards
 
+    if soft_fail is not None:
+        step["soft_fail"] = soft_fail
+
     # Enforce a global 8 hour job timeout.
     step["timeout_in_minutes"] = 8 * 60
 
@@ -2235,6 +2238,7 @@
     for task, task_config in task_configs.items():
         platform = get_platform_for_task(task, task_config)
         task_name = task_config.get("name")
+        soft_fail = task_config.get("soft_fail")
 
         # We override the Bazel version in downstream pipelines. This means that two tasks that
         # only differ in the value of their explicit "bazel" field will be identical in the
@@ -2275,6 +2279,7 @@
             use_but=use_but,
             incompatible_flags=incompatible_flags,
             shards=shards,
+            soft_fail=soft_fail,
         )
         pipeline_steps.append(step)
 
@@ -2470,6 +2475,7 @@
     use_but=False,
     incompatible_flags=None,
     shards=1,
+    soft_fail=None,
 ):
     command = PLATFORMS[platform]["python"] + " bazelci.py runner --task=" + task
     if http_config:
@@ -2488,7 +2494,7 @@
         command += " --incompatible_flag=" + flag
     label = create_label(platform, project_name, task_name=task_name)
     return create_step(
-        label=label, commands=[fetch_bazelcipy_command(), command], platform=platform, shards=shards
+        label=label, commands=[fetch_bazelcipy_command(), command], platform=platform, shards=shards, soft_fail=soft_fail
     )