add goldctl for flutter recipe

This is to add goldctl to flutter recipes (Windows, Linux, and Web).

Bug: https://github.com/flutter/flutter/issues/64969
Change-Id: Idfb57fc1cb5d475c657d3896cd8b7c4049f087fa
Reviewed-on: https://flutter-review.googlesource.com/c/recipes/+/6200
Reviewed-by: Godofredo Contreras <godofredoc@google.com>
Commit-Queue: Keyong Han <keyonghan@google.com>
diff --git a/recipe_modules/flutter_deps/__init__.py b/recipe_modules/flutter_deps/__init__.py
index e7b8f06..425a4f5 100644
--- a/recipe_modules/flutter_deps/__init__.py
+++ b/recipe_modules/flutter_deps/__init__.py
@@ -4,5 +4,6 @@
     'recipe_engine/file',
     'recipe_engine/path',
     'recipe_engine/platform',
+    'recipe_engine/properties',
     'recipe_engine/step',
 ]
diff --git a/recipe_modules/flutter_deps/api.py b/recipe_modules/flutter_deps/api.py
index 8ce08c1..795605f 100644
--- a/recipe_modules/flutter_deps/api.py
+++ b/recipe_modules/flutter_deps/api.py
@@ -29,6 +29,32 @@
       path.append(java_cache_dir.join('bin'))
       env_prefixes['PATH'] = path
 
+  def goldctl(
+      self,
+      env,
+      env_prefixes,
+      version='git_revision:b57f561ad4ad624bd399b8b7b500aa1955276d41'
+    ):
+    """Downloads goldctl from CIPD and updates the environment variables.
+
+    Args:
+      env(dict): Current environment variables.
+      env_prefixes(dict):  Current environment prefixes variables.
+      version(str): The goldctl version to install.
+    """
+    with self.m.step.nest('Download goldctl'):
+      goldctl_cache_dir = self.m.path['cache'].join('gold')
+      self.m.cipd.ensure(
+        goldctl_cache_dir,
+        self.m.cipd.EnsureFile().add_package(
+            'skia/tools/goldctl/${platform}', version
+        )
+      )
+      env['GOLDCTL'] = goldctl_cache_dir.join('goldctl')
+
+    if self.m.properties.get('git_ref') and self.m.properties.get('gold_tryjob') == True:
+      env['GOLD_TRYJOB'] = self.m.properties.get('git_ref')
+
   def chrome_and_driver(self, env, env_prefixes, version='latest'):
     """Downloads chrome from CIPD and updates the environment variables.
 
diff --git a/recipe_modules/flutter_deps/examples/full.expected/basic.json b/recipe_modules/flutter_deps/examples/full.expected/basic.json
index e2ad066..9103958 100644
--- a/recipe_modules/flutter_deps/examples/full.expected/basic.json
+++ b/recipe_modules/flutter_deps/examples/full.expected/basic.json
@@ -34,6 +34,39 @@
   },
   {
     "cmd": [],
+    "name": "Download goldctl"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[CACHE]/gold",
+      "-ensure-file",
+      "skia/tools/goldctl/${platform} git_revision:b57f561ad4ad624bd399b8b7b500aa1955276d41",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "name": "Download goldctl.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@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-git_revision:b57\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"skia/tools/goldctl/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": [],
     "name": "Chrome and driver dependency"
   },
   {
diff --git a/recipe_modules/flutter_deps/examples/full.expected/goldTryjob.json b/recipe_modules/flutter_deps/examples/full.expected/goldTryjob.json
new file mode 100644
index 0000000..9103958
--- /dev/null
+++ b/recipe_modules/flutter_deps/examples/full.expected/goldTryjob.json
@@ -0,0 +1,271 @@
+[
+  {
+    "cmd": [],
+    "name": "OpenJDK dependency"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[CACHE]/java",
+      "-ensure-file",
+      "flutter_internal/java/openjdk/${platform} version:1.8.0u202-b08",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "name": "OpenJDK dependency.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@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:1.8.0u20\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"flutter_internal/java/openjdk/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": [],
+    "name": "Download goldctl"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[CACHE]/gold",
+      "-ensure-file",
+      "skia/tools/goldctl/${platform} git_revision:b57f561ad4ad624bd399b8b7b500aa1955276d41",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "name": "Download goldctl.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@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-git_revision:b57\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"skia/tools/goldctl/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": [],
+    "name": "Chrome and driver dependency"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[CACHE]/chrome/chrome",
+      "-ensure-file",
+      "flutter_internal/browsers/chrome/${platform} latest",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "name": "Chrome and driver dependency.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@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-latest----------\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"flutter_internal/browsers/chrome/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": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[CACHE]/chrome/drivers",
+      "-ensure-file",
+      "flutter_internal/browser-drivers/chrome/${platform} latest",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "name": "Chrome and driver dependency.ensure_installed (2)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@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-latest----------\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"flutter_internal/browser-drivers/chrome/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": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[CACHE]/go",
+      "-ensure-file",
+      "infra/go/${platform} version:1.12.5",
+      "-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:1.12.5--\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/go/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": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[CLEANUP]/go_path"
+    ],
+    "infra_step": true,
+    "name": "Ensure go path"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[CACHE]/go",
+      "-ensure-file",
+      "infra/go/${platform} version:1.12.5",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "name": "ensure_installed (2)",
+    "~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:1.12.5--\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/go/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": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[CLEANUP]/go_path"
+    ],
+    "infra_step": true,
+    "name": "Ensure go path (2)"
+  },
+  {
+    "cmd": [
+      "go",
+      "get",
+      "-u",
+      "github.com/technosophos/dashing"
+    ],
+    "env": {
+      "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
+      "CHROME_NO_SANDBOX": "true",
+      "GOPATH": "[CLEANUP]/go_path"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/chrome/chrome",
+        "[CACHE]/chrome/drivers",
+        "[CACHE]/go/bin",
+        "[CLEANUP]/go_path",
+        "[CACHE]/go/bin",
+        "[CLEANUP]/go_path"
+      ]
+    },
+    "name": "Install dashing"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[CACHE]/vpython",
+      "-ensure-file",
+      "infra/tools/luci/vpython/${platform} latest",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "name": "ensure_installed (3)",
+    "~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-latest----------\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/vpython/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@@@"
+    ]
+  },
+  {
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipe_modules/flutter_deps/examples/full.py b/recipe_modules/flutter_deps/examples/full.py
index cbd7e33..985dd9b 100644
--- a/recipe_modules/flutter_deps/examples/full.py
+++ b/recipe_modules/flutter_deps/examples/full.py
@@ -6,8 +6,9 @@
 
 DEPS = [
     'flutter/flutter_deps',
-    'recipe_engine/path',
     'recipe_engine/assertions',
+    'recipe_engine/path',
+    'recipe_engine/properties',
 ]
 
 
@@ -16,6 +17,8 @@
   env_prefixes = {}
   api.flutter_deps.open_jdk(env, env_prefixes)
   api.assertions.assertTrue(env.get('JAVA_HOME'))
+  api.flutter_deps.goldctl(env, env_prefixes)
+  api.assertions.assertTrue(env.get('GOLDCTL'))
   api.assertions.assertEqual(
       env_prefixes.get('PATH'), [api.path['cache'].join('java', 'bin')]
   )
@@ -37,3 +40,8 @@
 
 def GenTests(api):
   yield api.test('basic')
+  yield api.test(
+      'goldTryjob',
+      api.properties(
+          gold_tryjob=True,
+          git_ref='refs/pull/1/head'))
diff --git a/recipes/flutter/flutter_drone.expected/android_sdk.json b/recipes/flutter/flutter_drone.expected/android_sdk.json
index 7a54ea0..5cdcbdf 100644
--- a/recipes/flutter/flutter_drone.expected/android_sdk.json
+++ b/recipes/flutter/flutter_drone.expected/android_sdk.json
@@ -183,6 +183,39 @@
     ]
   },
   {
+    "cmd": [],
+    "name": "Download goldctl"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[CACHE]/gold",
+      "-ensure-file",
+      "skia/tools/goldctl/${platform} git_revision:b57f561ad4ad624bd399b8b7b500aa1955276d41",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "name": "Download goldctl.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@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-git_revision:b57\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"skia/tools/goldctl/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"
@@ -192,6 +225,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -218,6 +252,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -256,6 +291,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -304,6 +340,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -352,6 +389,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -400,6 +438,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -451,6 +490,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -487,6 +527,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -525,6 +566,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -558,6 +600,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
diff --git a/recipes/flutter/flutter_drone.expected/no_requirements.json b/recipes/flutter/flutter_drone.expected/no_requirements.json
index e652a4a..1fe0470 100644
--- a/recipes/flutter/flutter_drone.expected/no_requirements.json
+++ b/recipes/flutter/flutter_drone.expected/no_requirements.json
@@ -183,6 +183,39 @@
     ]
   },
   {
+    "cmd": [],
+    "name": "Download goldctl"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[CACHE]/gold",
+      "-ensure-file",
+      "skia/tools/goldctl/${platform} git_revision:b57f561ad4ad624bd399b8b7b500aa1955276d41",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "name": "Download goldctl.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@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-git_revision:b57\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"skia/tools/goldctl/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"
@@ -192,6 +225,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -218,6 +252,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -244,6 +279,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
diff --git a/recipes/flutter/flutter_drone.py b/recipes/flutter/flutter_drone.py
index 85a77b0..5cc9fbf 100644
--- a/recipes/flutter/flutter_drone.py
+++ b/recipes/flutter/flutter_drone.py
@@ -54,6 +54,7 @@
   env, env_prefixes = api.repo_util.flutter_environment(checkout_path)
   api.flutter_deps.chrome_and_driver(env, env_prefixes)
   api.flutter_deps.open_jdk(env, env_prefixes)
+  api.flutter_deps.goldctl(env, env_prefixes)
   # Add shard and subshard.
   env['SHARD'] = api.properties.get('shard')
   env['SUBSHARD'] = api.properties.get('subshard')
diff --git a/recipes/flutter/flutter_drone_1_21_0.expected/android_sdk.json b/recipes/flutter/flutter_drone_1_21_0.expected/android_sdk.json
index 7a54ea0..5cdcbdf 100644
--- a/recipes/flutter/flutter_drone_1_21_0.expected/android_sdk.json
+++ b/recipes/flutter/flutter_drone_1_21_0.expected/android_sdk.json
@@ -183,6 +183,39 @@
     ]
   },
   {
+    "cmd": [],
+    "name": "Download goldctl"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[CACHE]/gold",
+      "-ensure-file",
+      "skia/tools/goldctl/${platform} git_revision:b57f561ad4ad624bd399b8b7b500aa1955276d41",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "name": "Download goldctl.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@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-git_revision:b57\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"skia/tools/goldctl/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"
@@ -192,6 +225,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -218,6 +252,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -256,6 +291,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -304,6 +340,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -352,6 +389,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -400,6 +438,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -451,6 +490,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -487,6 +527,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -525,6 +566,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -558,6 +600,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
diff --git a/recipes/flutter/flutter_drone_1_21_0.expected/no_requirements.json b/recipes/flutter/flutter_drone_1_21_0.expected/no_requirements.json
index e652a4a..1fe0470 100644
--- a/recipes/flutter/flutter_drone_1_21_0.expected/no_requirements.json
+++ b/recipes/flutter/flutter_drone_1_21_0.expected/no_requirements.json
@@ -183,6 +183,39 @@
     ]
   },
   {
+    "cmd": [],
+    "name": "Download goldctl"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[CACHE]/gold",
+      "-ensure-file",
+      "skia/tools/goldctl/${platform} git_revision:b57f561ad4ad624bd399b8b7b500aa1955276d41",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "name": "Download goldctl.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@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-git_revision:b57\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"skia/tools/goldctl/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"
@@ -192,6 +225,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -218,6 +252,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
@@ -244,6 +279,7 @@
       "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
       "CHROME_NO_SANDBOX": "true",
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GOLDCTL": "[CACHE]/gold/goldctl",
       "JAVA_HOME": "[CACHE]/java",
       "PUB_CACHE": "[CACHE]/.pub-cache",
       "SHARD": null,
diff --git a/recipes/flutter/flutter_drone_1_21_0.py b/recipes/flutter/flutter_drone_1_21_0.py
index 85a77b0..5cc9fbf 100644
--- a/recipes/flutter/flutter_drone_1_21_0.py
+++ b/recipes/flutter/flutter_drone_1_21_0.py
@@ -54,6 +54,7 @@
   env, env_prefixes = api.repo_util.flutter_environment(checkout_path)
   api.flutter_deps.chrome_and_driver(env, env_prefixes)
   api.flutter_deps.open_jdk(env, env_prefixes)
+  api.flutter_deps.goldctl(env, env_prefixes)
   # Add shard and subshard.
   env['SHARD'] = api.properties.get('shard')
   env['SUBSHARD'] = api.properties.get('subshard')