Adding BCID stage reporting to devicelab_drone and adhoc_validation.

The BCID reporting stages start in the devicelab_drone script, but compilation and uploading are delegated to the adhoc_validation script. Both changes are captured in this CL.
Successful led run: https://chromium-swarm.appspot.com/task?id=5e9a55c444478d10

Tracking issue: https://github.com/flutter/flutter/issues/115096
Change-Id: Ie3ca8c5787b156bb2e76e8785b640b2576bf86de
Reviewed-on: https://flutter-review.googlesource.com/c/recipes/+/36120
Reviewed-by: Drew Roen <drewroen@google.com>
Reviewed-by: Godofredo Contreras <godofredoc@google.com>
Commit-Queue: Jesse Seales <jseales@google.com>
diff --git a/recipe_modules/adhoc_validation/__init__.py b/recipe_modules/adhoc_validation/__init__.py
index 5ab5be1..9952250 100644
--- a/recipe_modules/adhoc_validation/__init__.py
+++ b/recipe_modules/adhoc_validation/__init__.py
@@ -1,4 +1,5 @@
 DEPS = [
+    'flutter/flutter_bcid',
     'flutter/bucket_util',
     'flutter/firebase',
     'flutter/flutter_deps',
diff --git a/recipe_modules/adhoc_validation/api.py b/recipe_modules/adhoc_validation/api.py
index 00b0af9..b6a415f 100644
--- a/recipe_modules/adhoc_validation/api.py
+++ b/recipe_modules/adhoc_validation/api.py
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 from recipe_engine import recipe_api
+from RECIPE_MODULES.flutter.flutter_bcid.api import BcidStage
 
 
 class AddhocValidationApi(recipe_api.RecipeApi):
@@ -56,6 +57,7 @@
               env, env_prefixes, checkout_path.join('dev', 'ci', 'mac')
           )
           with self.m.context(env=env, env_prefixes=env_prefixes):
+            self.m.flutter_bcid.report_stage(BcidStage.COMPILE.value)
             self.m.test_utils.run_test(
               validation,
               [resource_name],
@@ -80,7 +82,11 @@
             docs_path = checkout_path.join('dev', 'docs')
             # Do not upload on docs_deploy.
             if not validation == 'docs_deploy':
-              self.m.bucket_util.upload_folder('Upload API Docs', docs_path, 'doc', "api_docs.zip")
+              self.m.flutter_bcid.report_stage(BcidStage.UPLOAD.value)
+              dst = self.m.bucket_util.upload_folder('Upload API Docs', docs_path,
+                'doc', "api_docs.zip")
+              self.m.flutter_bcid.upload_provenance(docs_path, dst)
+              self.m.flutter_bcid.report_stage(BcidStage.UPLOAD_COMPLETE.value)
             project = self.m.properties.get('firebase_project')
             # Only deploy to firebase directly if this is master or main.
             if ((self.m.properties.get('git_branch') in ['master', 'main']) or
diff --git a/recipe_modules/adhoc_validation/examples/full.expected/invalid_validation.json b/recipe_modules/adhoc_validation/examples/full.expected/invalid_validation.json
index d3ad326..532d800 100644
--- a/recipe_modules/adhoc_validation/examples/full.expected/invalid_validation.json
+++ b/recipe_modules/adhoc_validation/examples/full.expected/invalid_validation.json
@@ -17,9 +17,9 @@
       "The recipe has crashed at point 'Uncaught exception'!",
       "",
       "Traceback (most recent call last):",
-      "  File \"RECIPE_REPO[flutter]/recipe_modules/adhoc_validation/examples/full.py\", line 24, in RunSteps",
+      "  File \"RECIPE_REPO[flutter]/recipe_modules/adhoc_validation/examples/full.py\", line 26, in RunSteps",
       "    api.adhoc_validation.run('Docs', validation, {}, {})",
-      "  File \"RECIPE_REPO[flutter]/recipe_modules/adhoc_validation/api.py\", line 36, in run",
+      "  File \"RECIPE_REPO[flutter]/recipe_modules/adhoc_validation/api.py\", line 37, in run",
       "    raise AssertionError(msg)",
       "AssertionError('invalid is not listed in available_validations.')"
     ]
diff --git a/recipe_modules/adhoc_validation/examples/full.py b/recipe_modules/adhoc_validation/examples/full.py
index 239c8c2..b45672a 100644
--- a/recipe_modules/adhoc_validation/examples/full.py
+++ b/recipe_modules/adhoc_validation/examples/full.py
@@ -7,11 +7,13 @@
 DEPS = [
     'flutter/adhoc_validation',
     'flutter/repo_util',
+    'recipe_engine/buildbucket',
     'recipe_engine/context',
     'recipe_engine/path',
     'recipe_engine/platform',
     'recipe_engine/properties',
     'recipe_engine/raw_io',
+    'recipe_engine/runtime',
 ]
 
 
diff --git a/recipes/devicelab/devicelab_drone.expected/no-task-name.json b/recipes/devicelab/devicelab_drone.expected/no-task-name.json
index 4a7aeea..1b63109 100644
--- a/recipes/devicelab/devicelab_drone.expected/no-task-name.json
+++ b/recipes/devicelab/devicelab_drone.expected/no-task-name.json
@@ -19,7 +19,7 @@
       "The recipe has crashed at point 'Uncaught exception'!",
       "",
       "Traceback (most recent call last):",
-      "  File \"RECIPE_REPO[flutter]/recipes/devicelab/devicelab_drone.py\", line 40, in RunSteps",
+      "  File \"RECIPE_REPO[flutter]/recipes/devicelab/devicelab_drone.py\", line 43, in RunSteps",
       "    raise ValueError('A task_name property is required')",
       "ValueError('A task_name property is required')"
     ]
diff --git a/recipes/devicelab/devicelab_drone.py b/recipes/devicelab/devicelab_drone.py
index b36e497..b208bd7 100644
--- a/recipes/devicelab/devicelab_drone.py
+++ b/recipes/devicelab/devicelab_drone.py
@@ -3,9 +3,11 @@
 # found in the LICENSE file.
 
 from recipe_engine.recipe_api import Property
+from RECIPE_MODULES.flutter.flutter_bcid.api import BcidStage
 
 DEPS = [
     'flutter/devicelab_osx_sdk',
+    'flutter/flutter_bcid',
     'flutter/flutter_deps',
     'flutter/logs_util',
     'flutter/os_utils',
@@ -32,6 +34,7 @@
 MAX_TIMEOUT_SECS = 30 * 60
 
 def RunSteps(api):
+  api.flutter_bcid.report_stage(BcidStage.START.value)
   # Collect memory/cpu/process before task execution.
   api.os_utils.collect_os_info()
 
@@ -41,6 +44,7 @@
 
   api.os_utils.print_pub_certs()
 
+  api.flutter_bcid.report_stage(BcidStage.FETCH.value)
   flutter_path = api.path.mkdtemp().join('flutter sdk')
   api.repo_util.checkout(
       'flutter',
@@ -151,8 +155,8 @@
   with api.context(env=env, env_prefixes=env_prefixes, cwd=devicelab_path):
     uploadResults(
         api, env, env_prefixes, results_path, test_status == 'flaky',
-        git_branch, api.properties.get('buildername'), commit_time, task_name,
-        benchmark_tags, suppress_log=suppress_log
+        git_branch, api.properties.get('buildername'), commit_time,
+        task_name, benchmark_tags, suppress_log=suppress_log
     )
     uploadMetricsToCas(api, results_path)