checkout: Write JSON file with commit metadata

Write a JSON file with metadata about the triggering commit.

Bug: b/265795959
Change-Id: If6491ace7e475798e064838ef671f786adabfa7e
Reviewed-on: https://pigweed-review.googlesource.com/c/infra/recipes/+/127082
Pigweed-Auto-Submit: Rob Mohr <mohrr@google.com>
Reviewed-by: Ted Pudlik <tpudlik@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
diff --git a/recipe_modules/checkout/api.py b/recipe_modules/checkout/api.py
index 72b95ef..8cf9dcd 100644
--- a/recipe_modules/checkout/api.py
+++ b/recipe_modules/checkout/api.py
@@ -182,6 +182,9 @@
     # Parsed repo manifest.
     manifest = attr.ib(default=None)
 
+    # Path to a JSON file containing metadata about the triggering changes.
+    changes_json = attr.ib(default=None)
+
     # Current revision number.
     def revision(self):
         if hasattr(self, '_revision'):
@@ -1043,6 +1046,21 @@
 
                 ctx.status = self._check_unapplied_changes(ctx.changes)
 
+                def _vars_primitive_only(x):
+                    return {
+                        k: v
+                        for k, v in vars(x).items()
+                        if isinstance(v, (int, str, bool, type(None)))
+                    }
+
+                applied_changes = [
+                    _vars_primitive_only(x) for x in ctx.changes if x.applied
+                ]
+                ctx.changes_json = self.m.path.mkstemp()
+                self.m.file.write_json(
+                    'write changes.json', ctx.changes_json, applied_changes,
+                )
+
             # Run git log for both the top-level checkout and every submodule.
             with self.m.step.nest('git log'):
                 self.m.git(str(ctx.root), 'log', '--oneline', '-n', '10')
diff --git a/recipe_modules/checkout/tests/git.expected/ci.json b/recipe_modules/checkout/tests/git.expected/ci.json
index 6a4c612..6ea84b5 100644
--- a/recipe_modules/checkout/tests/git.expected/ci.json
+++ b/recipe_modules/checkout/tests/git.expected/ci.json
@@ -1272,6 +1272,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipe_modules/checkout/tests/git.expected/not_in_gerrit.json b/recipe_modules/checkout/tests/git.expected/not_in_gerrit.json
index 29401fc..60e8e99 100644
--- a/recipe_modules/checkout/tests/git.expected/not_in_gerrit.json
+++ b/recipe_modules/checkout/tests/git.expected/not_in_gerrit.json
@@ -866,6 +866,26 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 0, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 0, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipe_modules/checkout/tests/git.expected/other.json b/recipe_modules/checkout/tests/git.expected/other.json
index 2b70e68..c665bad 100644
--- a/recipe_modules/checkout/tests/git.expected/other.json
+++ b/recipe_modules/checkout/tests/git.expected/other.json
@@ -871,6 +871,26 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipe_modules/checkout/tests/git.expected/try.json b/recipe_modules/checkout/tests/git.expected/try.json
index e02bd6f..818c9a0 100644
--- a/recipe_modules/checkout/tests/git.expected/try.json
+++ b/recipe_modules/checkout/tests/git.expected/try.json
@@ -1514,6 +1514,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"MERGEBASE_MERGEBASE_MERGEBASE_MERGEBASE_\", \"base_type\": \"merge-base\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": true, \"number\": 123456, \"rebase\": false, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"MERGEBASE_MERGEBASE_MERGEBASE_MERGEBASE_\", \"base_type\": \"merge-base\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": true, \"number\": 123456, \"rebase\": false, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipe_modules/checkout/tests/submodule.expected/submodule-ci.json b/recipe_modules/checkout/tests/submodule.expected/submodule-ci.json
index df36b08..6a24c2e 100644
--- a/recipe_modules/checkout/tests/submodule.expected/submodule-ci.json
+++ b/recipe_modules/checkout/tests/submodule.expected/submodule-ci.json
@@ -1278,6 +1278,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"x\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://x.googlesource.com/b/c/d\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"x\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://x.googlesource.com/b/c/d\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipe_modules/checkout/tests/submodule.expected/submodule-repeated-match.json b/recipe_modules/checkout/tests/submodule.expected/submodule-repeated-match.json
index a3da2d9..fc35179 100644
--- a/recipe_modules/checkout/tests/submodule.expected/submodule-repeated-match.json
+++ b/recipe_modules/checkout/tests/submodule.expected/submodule-repeated-match.json
@@ -1511,6 +1511,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"x\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://x.googlesource.com/foo\", \"submitted\": false}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"x\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://x.googlesource.com/foo\", \"submitted\": false}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipe_modules/checkout/tests/submodule.expected/submodule-try-equivalent.json b/recipe_modules/checkout/tests/submodule.expected/submodule-try-equivalent.json
index 6e23160..adab710 100644
--- a/recipe_modules/checkout/tests/submodule.expected/submodule-try-equivalent.json
+++ b/recipe_modules/checkout/tests/submodule.expected/submodule-try-equivalent.json
@@ -1543,6 +1543,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"z\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://z.googlesource.com/foo\", \"submitted\": false}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"z\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://z.googlesource.com/foo\", \"submitted\": false}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipe_modules/checkout/tests/submodule.expected/submodule-try-excluded.json b/recipe_modules/checkout/tests/submodule.expected/submodule-try-excluded.json
index 9ce44c0..fa274b5 100644
--- a/recipe_modules/checkout/tests/submodule.expected/submodule-try-excluded.json
+++ b/recipe_modules/checkout/tests/submodule.expected/submodule-try-excluded.json
@@ -1282,6 +1282,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipe_modules/checkout/tests/submodule.expected/submodule-try-included.json b/recipe_modules/checkout/tests/submodule.expected/submodule-try-included.json
index 93956cb..7ed9fee 100644
--- a/recipe_modules/checkout/tests/submodule.expected/submodule-try-included.json
+++ b/recipe_modules/checkout/tests/submodule.expected/submodule-try-included.json
@@ -1249,6 +1249,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipe_modules/checkout/tests/submodule.expected/submodule-try-multiple-cqdeps.json b/recipe_modules/checkout/tests/submodule.expected/submodule-try-multiple-cqdeps.json
index 162086d..050d4b7 100644
--- a/recipe_modules/checkout/tests/submodule.expected/submodule-try-multiple-cqdeps.json
+++ b/recipe_modules/checkout/tests/submodule.expected/submodule-try-multiple-cqdeps.json
@@ -2771,6 +2771,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"x\", \"is_merge\": false, \"number\": 1234, \"rebase\": true, \"ref\": \"refs/changes/34/1234/1\", \"remote\": \"https://x.googlesource.com/foo\", \"submitted\": false}, {\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"x\", \"is_merge\": false, \"number\": 2345, \"rebase\": true, \"ref\": \"refs/changes/45/2345/1\", \"remote\": \"https://x.googlesource.com/bar\", \"submitted\": false}, {\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 3456, \"rebase\": true, \"ref\": \"refs/changes/56/3456/1\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"x\", \"is_merge\": false, \"number\": 1234, \"rebase\": true, \"ref\": \"refs/changes/34/1234/1\", \"remote\": \"https://x.googlesource.com/foo\", \"submitted\": false}, {\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"x\", \"is_merge\": false, \"number\": 2345, \"rebase\": true, \"ref\": \"refs/changes/45/2345/1\", \"remote\": \"https://x.googlesource.com/bar\", \"submitted\": false}, {\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 3456, \"rebase\": true, \"ref\": \"refs/changes/56/3456/1\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipe_modules/checkout/tests/submodule.expected/submodule-try-multiple-one-missing-one-forbidden-cqdeps.json b/recipe_modules/checkout/tests/submodule.expected/submodule-try-multiple-one-missing-one-forbidden-cqdeps.json
index f03783a..fc19d8f 100644
--- a/recipe_modules/checkout/tests/submodule.expected/submodule-try-multiple-one-missing-one-forbidden-cqdeps.json
+++ b/recipe_modules/checkout/tests/submodule.expected/submodule-try-multiple-one-missing-one-forbidden-cqdeps.json
@@ -2508,6 +2508,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"x\", \"is_merge\": false, \"number\": 1234, \"rebase\": true, \"ref\": \"refs/changes/34/1234/1\", \"remote\": \"https://x.googlesource.com/foo\", \"submitted\": false}, {\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 3456, \"rebase\": true, \"ref\": \"refs/changes/56/3456/1\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"x\", \"is_merge\": false, \"number\": 1234, \"rebase\": true, \"ref\": \"refs/changes/34/1234/1\", \"remote\": \"https://x.googlesource.com/foo\", \"submitted\": false}, {\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 3456, \"rebase\": true, \"ref\": \"refs/changes/56/3456/1\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipe_modules/checkout/tests/submodule.expected/submodule-try-multiple-one-missing.json b/recipe_modules/checkout/tests/submodule.expected/submodule-try-multiple-one-missing.json
index 12eb7f7..9d34d93 100644
--- a/recipe_modules/checkout/tests/submodule.expected/submodule-try-multiple-one-missing.json
+++ b/recipe_modules/checkout/tests/submodule.expected/submodule-try-multiple-one-missing.json
@@ -2054,6 +2054,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"x\", \"is_merge\": false, \"number\": 1234, \"rebase\": true, \"ref\": \"refs/changes/34/1234/1\", \"remote\": \"https://x.googlesource.com/foo\", \"submitted\": false}, {\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 3456, \"rebase\": true, \"ref\": \"refs/changes/56/3456/1\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"x\", \"is_merge\": false, \"number\": 1234, \"rebase\": true, \"ref\": \"refs/changes/34/1234/1\", \"remote\": \"https://x.googlesource.com/foo\", \"submitted\": false}, {\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 3456, \"rebase\": true, \"ref\": \"refs/changes/56/3456/1\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipe_modules/checkout/tests/submodule.expected/submodule-try-multiple.json b/recipe_modules/checkout/tests/submodule.expected/submodule-try-multiple.json
index 8a7c508..8abda9a 100644
--- a/recipe_modules/checkout/tests/submodule.expected/submodule-try-multiple.json
+++ b/recipe_modules/checkout/tests/submodule.expected/submodule-try-multiple.json
@@ -2425,6 +2425,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"x\", \"is_merge\": false, \"number\": 1234, \"rebase\": true, \"ref\": \"refs/changes/34/1234/1\", \"remote\": \"https://x.googlesource.com/foo\", \"submitted\": false}, {\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"x\", \"is_merge\": false, \"number\": 2345, \"rebase\": true, \"ref\": \"refs/changes/45/2345/1\", \"remote\": \"https://x.googlesource.com/bar\", \"submitted\": false}, {\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 3456, \"rebase\": true, \"ref\": \"refs/changes/56/3456/1\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"x\", \"is_merge\": false, \"number\": 1234, \"rebase\": true, \"ref\": \"refs/changes/34/1234/1\", \"remote\": \"https://x.googlesource.com/foo\", \"submitted\": false}, {\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"x\", \"is_merge\": false, \"number\": 2345, \"rebase\": true, \"ref\": \"refs/changes/45/2345/1\", \"remote\": \"https://x.googlesource.com/bar\", \"submitted\": false}, {\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 3456, \"rebase\": true, \"ref\": \"refs/changes/56/3456/1\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipe_modules/checkout/tests/submodule.expected/submodule-try.json b/recipe_modules/checkout/tests/submodule.expected/submodule-try.json
index 73a0556..aca540d 100644
--- a/recipe_modules/checkout/tests/submodule.expected/submodule-try.json
+++ b/recipe_modules/checkout/tests/submodule.expected/submodule-try.json
@@ -1543,6 +1543,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"x\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://x.googlesource.com/baz\", \"submitted\": false}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"x\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://x.googlesource.com/baz\", \"submitted\": false}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/build.expected/basic.json b/recipes/build.expected/basic.json
index 201a016..c91dacb 100644
--- a/recipes/build.expected/basic.json
+++ b/recipes/build.expected/basic.json
@@ -1272,6 +1272,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/build.expected/skip_archive.json b/recipes/build.expected/skip_archive.json
index 3847824..3569088 100644
--- a/recipes/build.expected/skip_archive.json
+++ b/recipes/build.expected/skip_archive.json
@@ -1272,6 +1272,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/docs_builder.expected/docs.json b/recipes/docs_builder.expected/docs.json
index 0aaa22e..ed21531 100644
--- a/recipes/docs_builder.expected/docs.json
+++ b/recipes/docs_builder.expected/docs.json
@@ -871,6 +871,26 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/docs_builder.expected/docs_dry_run.json b/recipes/docs_builder.expected/docs_dry_run.json
index 1c1c87c..25e1fe5 100644
--- a/recipes/docs_builder.expected/docs_dry_run.json
+++ b/recipes/docs_builder.expected/docs_dry_run.json
@@ -871,6 +871,26 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/envtest.expected/environment_variables.json b/recipes/envtest.expected/environment_variables.json
index 006c5bd..d002e7b 100644
--- a/recipes/envtest.expected/environment_variables.json
+++ b/recipes/envtest.expected/environment_variables.json
@@ -871,6 +871,26 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/envtest.expected/fail.json b/recipes/envtest.expected/fail.json
index a651453..9768eb7 100644
--- a/recipes/envtest.expected/fail.json
+++ b/recipes/envtest.expected/fail.json
@@ -1272,6 +1272,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/envtest.expected/pigweed.json b/recipes/envtest.expected/pigweed.json
index ac38243..33713ae 100644
--- a/recipes/envtest.expected/pigweed.json
+++ b/recipes/envtest.expected/pigweed.json
@@ -1272,6 +1272,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/envtest.expected/windows.json b/recipes/envtest.expected/windows.json
index b195974..d5c6568 100644
--- a/recipes/envtest.expected/windows.json
+++ b/recipes/envtest.expected/windows.json
@@ -1272,6 +1272,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]\\resources\\fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]\\tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]\\co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/luci_config.expected/starlark.json b/recipes/luci_config.expected/starlark.json
index e286463..bd0a8a6 100644
--- a/recipes/luci_config.expected/starlark.json
+++ b/recipes/luci_config.expected/starlark.json
@@ -1537,6 +1537,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/pw_presubmit.expected/one_step.json b/recipes/pw_presubmit.expected/one_step.json
index 5b11b1c..1a53d63 100644
--- a/recipes/pw_presubmit.expected/one_step.json
+++ b/recipes/pw_presubmit.expected/one_step.json
@@ -1537,6 +1537,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/pw_presubmit.expected/sign.json b/recipes/pw_presubmit.expected/sign.json
index 9977172..c378f89 100644
--- a/recipes/pw_presubmit.expected/sign.json
+++ b/recipes/pw_presubmit.expected/sign.json
@@ -1272,6 +1272,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/pw_presubmit.expected/two_steps.json b/recipes/pw_presubmit.expected/two_steps.json
index 34f1e06..4b6efa9 100644
--- a/recipes/pw_presubmit.expected/two_steps.json
+++ b/recipes/pw_presubmit.expected/two_steps.json
@@ -1473,6 +1473,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"Build-Errors: continue\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"Build-Errors: continue\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/recipes.expected/cq_try.json b/recipes/recipes.expected/cq_try.json
index b9e144a..6616827 100644
--- a/recipes/recipes.expected/cq_try.json
+++ b/recipes/recipes.expected/cq_try.json
@@ -1537,6 +1537,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/run_script.expected/run_script.json b/recipes/run_script.expected/run_script.json
index 4a7f7b5..7bc3f1d 100644
--- a/recipes/run_script.expected/run_script.json
+++ b/recipes/run_script.expected/run_script.json
@@ -871,6 +871,26 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/run_script.expected/variable_substitution.json b/recipes/run_script.expected/variable_substitution.json
index a5239de..c9ca6af 100644
--- a/recipes/run_script.expected/variable_substitution.json
+++ b/recipes/run_script.expected/variable_substitution.json
@@ -871,6 +871,26 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/target_to_cipd.expected/pw-presubmit.json b/recipes/target_to_cipd.expected/pw-presubmit.json
index b51544f..f21141b 100644
--- a/recipes/target_to_cipd.expected/pw-presubmit.json
+++ b/recipes/target_to_cipd.expected/pw-presubmit.json
@@ -871,6 +871,26 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/tokendb_check.expected/addition.json b/recipes/tokendb_check.expected/addition.json
index 1564aa4..f759a41 100644
--- a/recipes/tokendb_check.expected/addition.json
+++ b/recipes/tokendb_check.expected/addition.json
@@ -1662,6 +1662,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/tokendb_check.expected/no-change.json b/recipes/tokendb_check.expected/no-change.json
index fbe2533..0882275 100644
--- a/recipes/tokendb_check.expected/no-change.json
+++ b/recipes/tokendb_check.expected/no-change.json
@@ -1662,6 +1662,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/tokendb_check.expected/removal.json b/recipes/tokendb_check.expected/removal.json
index e08c933..3b1fd2d 100644
--- a/recipes/tokendb_check.expected/removal.json
+++ b/recipes/tokendb_check.expected/removal.json
@@ -1662,6 +1662,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/tokendb_check.expected/update.json b/recipes/tokendb_check.expected/update.json
index 43799dd..7984ad1 100644
--- a/recipes/tokendb_check.expected/update.json
+++ b/recipes/tokendb_check.expected/update.json
@@ -1662,6 +1662,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/tokendb_updater.expected/dry-run.json b/recipes/tokendb_updater.expected/dry-run.json
index dbb40e1..667e213 100644
--- a/recipes/tokendb_updater.expected/dry-run.json
+++ b/recipes/tokendb_updater.expected/dry-run.json
@@ -871,6 +871,26 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/tokendb_updater.expected/separate-repo.json b/recipes/tokendb_updater.expected/separate-repo.json
index d14dc38..ceebad2 100644
--- a/recipes/tokendb_updater.expected/separate-repo.json
+++ b/recipes/tokendb_updater.expected/separate-repo.json
@@ -871,6 +871,26 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/tokendb_updater.expected/simple.json b/recipes/tokendb_updater.expected/simple.json
index 21ff274..d548c55 100644
--- a/recipes/tokendb_updater.expected/simple.json
+++ b/recipes/tokendb_updater.expected/simple.json
@@ -871,6 +871,26 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/txt_roller.expected/backwards.json b/recipes/txt_roller.expected/backwards.json
index 2ed56d0..ff13af9 100644
--- a/recipes/txt_roller.expected/backwards.json
+++ b/recipes/txt_roller.expected/backwards.json
@@ -1371,6 +1371,26 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"foo\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://foo.googlesource.com/foo\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/project",
+    "infra_step": true,
+    "name": "checkout foo.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"foo\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://foo.googlesource.com/foo\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout foo.git log",
     "~followup_annotations": [
diff --git a/recipes/txt_roller.expected/no-trigger.json b/recipes/txt_roller.expected/no-trigger.json
index 1337a38..77978da 100644
--- a/recipes/txt_roller.expected/no-trigger.json
+++ b/recipes/txt_roller.expected/no-trigger.json
@@ -1371,6 +1371,26 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"foo\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://foo.googlesource.com/foo\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/project",
+    "infra_step": true,
+    "name": "checkout foo.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"foo\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://foo.googlesource.com/foo\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout foo.git log",
     "~followup_annotations": [
diff --git a/recipes/txt_roller.expected/success.json b/recipes/txt_roller.expected/success.json
index cfe96cd..4156313 100644
--- a/recipes/txt_roller.expected/success.json
+++ b/recipes/txt_roller.expected/success.json
@@ -2040,6 +2040,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"foo\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://foo.googlesource.com/foo\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/project",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout foo.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"foo\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"remote\": \"https://foo.googlesource.com/foo\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout foo.git log",
     "~followup_annotations": [
diff --git a/recipes/update_python_versions.expected/simple.json b/recipes/update_python_versions.expected/simple.json
index 3952462..23a3ad8 100644
--- a/recipes/update_python_versions.expected/simple.json
+++ b/recipes/update_python_versions.expected/simple.json
@@ -871,6 +871,26 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/xrefs.expected/dry_run.json b/recipes/xrefs.expected/dry_run.json
index 935b2f7..de6e6fe 100644
--- a/recipes/xrefs.expected/dry_run.json
+++ b/recipes/xrefs.expected/dry_run.json
@@ -871,6 +871,26 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/xrefs.expected/kythe.json b/recipes/xrefs.expected/kythe.json
index eba362a..634e35d 100644
--- a/recipes/xrefs.expected/kythe.json
+++ b/recipes/xrefs.expected/kythe.json
@@ -871,6 +871,26 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\", \"base_type\": \"submitted_commit_hash\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 1234, \"rebase\": false, \"ref\": \"h3ll0\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": true}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [
diff --git a/recipes/xrefs.expected/tryjob.json b/recipes/xrefs.expected/tryjob.json
index 4599021..06036f4 100644
--- a/recipes/xrefs.expected/tryjob.json
+++ b/recipes/xrefs.expected/tryjob.json
@@ -1537,6 +1537,38 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]",
+      "[CLEANUP]/tmp_tmp_1"
+    ],
+    "cwd": "[START_DIR]/co",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "checkout pigweed.write changes.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@tmp_tmp_1@[{\"applied\": true, \"base\": \"REMOTE_BRANCH_REMOTE_BRANCH_REMOTE_BRANCH_\", \"base_type\": \"remote_branch_tip\", \"branch\": \"main\", \"commit_message\": \"\", \"gerrit_name\": \"pigweed\", \"is_merge\": false, \"number\": 123456, \"rebase\": true, \"ref\": \"refs/changes/56/123456/7\", \"remote\": \"https://pigweed.googlesource.com/pigweed/pigweed\", \"submitted\": false}]@@@",
+      "@@@STEP_LOG_END@tmp_tmp_1@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "checkout pigweed.git log",
     "~followup_annotations": [