[ci_yaml] Include protoc dependency

Test: https://chromium-swarm.appspot.com/task?id=54fde1e160e87110
Bug: https://github.com/flutter/flutter/issues/84998
Change-Id: Icaf4492cef3def183af555539774c66d9d1ec450
Reviewed-on: https://flutter-review.googlesource.com/c/recipes/+/16125
Reviewed-by: Keyong Han <keyonghan@google.com>
Commit-Queue: Casey Hillers <chillers@google.com>
diff --git a/recipes/infra/ci_yaml.expected/basic.json b/recipes/infra/ci_yaml.expected/basic.json
index 3f8ee15..3dcf8e5 100644
--- a/recipes/infra/ci_yaml.expected/basic.json
+++ b/recipes/infra/ci_yaml.expected/basic.json
@@ -334,6 +334,34 @@
   },
   {
     "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/protoc",
+      "-ensure-file",
+      "infra/3pp/tools/protoc/${platform} version:2@3.17.3",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "name": "ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:2@3.17.3\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/3pp/tools/protoc/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
       "flutter",
       "doctor"
     ],
@@ -443,6 +471,11 @@
       "[START_DIR]/cocoon/app_dart/lib/src/model/proto/internal/scheduler.proto",
       "[START_DIR]/infra/config/lib/ci_yaml"
     ],
+    "env_prefixes": {
+      "PATH": [
+        "[START_DIR]/protoc/bin"
+      ]
+    },
     "name": "Roll scheduler.proto"
   },
   {
@@ -450,6 +483,11 @@
       "bash",
       "[START_DIR]/infra/config/lib/ci_yaml/compile_proto.sh"
     ],
+    "env_prefixes": {
+      "PATH": [
+        "[START_DIR]/protoc/bin"
+      ]
+    },
     "name": "Compile scheduler.proto"
   },
   {
diff --git a/recipes/infra/ci_yaml.py b/recipes/infra/ci_yaml.py
index 548c45c..0601908 100644
--- a/recipes/infra/ci_yaml.py
+++ b/recipes/infra/ci_yaml.py
@@ -10,6 +10,7 @@
     'fuchsia/auto_roller',
     'fuchsia/cl_util',
     'recipe_engine/buildbucket',
+    'recipe_engine/cipd',
     'recipe_engine/context',
     'recipe_engine/file',
     'recipe_engine/json',
@@ -47,6 +48,15 @@
       ref='refs/heads/main'
   )
 
+  # Install protoc to compile latest scheduler.proto
+  protoc_path = start_path.join('protoc')
+  api.cipd.ensure(
+      protoc_path,
+      api.cipd.EnsureFile().add_package(
+          'infra/3pp/tools/protoc/${platform}', 'version:2@3.17.3'
+      )
+  )
+
   # gitiles commit info
   commit_sha = api.buildbucket.gitiles_commit.id
   gitiles_repo = api.buildbucket.gitiles_commit.project
@@ -63,11 +73,12 @@
     jspb_step = api.step('generate jspb', cmd=['dart', generate_jspb_path, repo, commit_sha], stdout=api.raw_io.output_text(), stderr=api.raw_io.output_text())
     api.file.write_raw('write jspb', infra_config_path, jspb_step.stdout)
 
-  # Roll scheduler.proto
-  scheduler_proto_src = cocoon_path.join('app_dart', 'lib', 'src', 'model', 'proto', 'internal', 'scheduler.proto')
-  scheduler_proto_dst = infra_path.join('config', 'lib', 'ci_yaml')
-  api.step('Roll scheduler.proto', ['cp', scheduler_proto_src, scheduler_proto_dst])
-  api.step('Compile scheduler.proto', ['bash', scheduler_proto_dst.join('compile_proto.sh')])
+# Roll scheduler.proto
+  with api.context(env_prefixes={'PATH': [protoc_path.join('bin')]}):
+    scheduler_proto_src = cocoon_path.join('app_dart', 'lib', 'src', 'model', 'proto', 'internal', 'scheduler.proto')
+    scheduler_proto_dst = infra_path.join('config', 'lib', 'ci_yaml')
+    api.step('Roll scheduler.proto', ['cp', scheduler_proto_src, scheduler_proto_dst])
+    api.step('Compile scheduler.proto', ['bash', scheduler_proto_dst.join('compile_proto.sh')])
 
   with api.context(cwd=infra_path):
     # Generate luci configs