rebaseline_server: include setA/setB descriptions in output JSON

This is needed for rebaselining using the shared rebaseline_server instance:
by telling the client which git revision was used to fetch expectations, we
allow the client to pass that back along with new baselines (so the server
knows which revision to patch).

This is also handy in that it allows the server to tell the client more about the
different result sets (which files they were generated from).

BUG=skia:1918
NOTRY=true
R=rmistry@google.com

Author: epoger@google.com

Review URL: https://codereview.chromium.org/474813002
diff --git a/gm/gm_json.py b/gm/gm_json.py
index 3f43b34..62d5755 100644
--- a/gm/gm_json.py
+++ b/gm/gm_json.py
@@ -163,11 +163,14 @@
 
 def LoadFromString(file_contents):
   """Loads the JSON summary written out by the GM tool.
+
      Returns a dictionary keyed by the values listed as JSONKEY_ constants
-     above."""
+     above; if file_contents is empty, returns None."""
   # TODO(epoger): we should add a version number to the JSON file to ensure
   # that the writer and reader agree on the schema (raising an exception
   # otherwise).
+  if not file_contents:
+    return None
   json_dict = json.loads(file_contents)
   return json_dict
 
diff --git a/gm/rebaseline_server/compare_configs.py b/gm/rebaseline_server/compare_configs.py
index cdc19dd..202eec7 100755
--- a/gm/rebaseline_server/compare_configs.py
+++ b/gm/rebaseline_server/compare_configs.py
@@ -48,6 +48,7 @@
       builder_regex_list: List of regular expressions specifying which builders
           we will process. If None, process all builders.
     """
+    super(ConfigComparisons, self).__init__()
     time_start = int(time.time())
     if builder_regex_list != None:
       self.set_match_builders_pattern_list(builder_regex_list)
diff --git a/gm/rebaseline_server/compare_rendered_pictures.py b/gm/rebaseline_server/compare_rendered_pictures.py
index 85dff27..265f997 100755
--- a/gm/rebaseline_server/compare_rendered_pictures.py
+++ b/gm/rebaseline_server/compare_rendered_pictures.py
@@ -16,6 +16,7 @@
 import logging
 import os
 import shutil
+import subprocess
 import tempfile
 import time
 
@@ -23,6 +24,7 @@
 import fix_pythonpath  # pylint: disable=W0611
 
 # Imports from within Skia
+from py.utils import git_utils
 from py.utils import gs_utils
 from py.utils import url_utils
 import buildbot_globals
@@ -148,15 +150,37 @@
     try:
       setA_root = os.path.join(tempdir, 'setA')
       setB_root = os.path.join(tempdir, 'setB')
+      setA_repo_revision = None
+      setB_repo_revision = None
       for source_dir in setA_dirs:
         self._copy_dir_contents(source_dir=source_dir, dest_dir=setA_root)
+        # TODO(stephana): There is a potential race condition here... we copy
+        # the contents out of the source_dir, and THEN we get the commithash
+        # of source_dir.  If source_dir points at a git checkout, and that
+        # checkout is updated (by a different thread/process) during this
+        # operation, then the contents and commithash will be out of sync.
+        setA_repo_revision = self._get_repo_revision(
+            source_dir=source_dir, assert_if_not=setA_repo_revision)
       for source_dir in setB_dirs:
         self._copy_dir_contents(source_dir=source_dir, dest_dir=setB_root)
+        setB_repo_revision = self._get_repo_revision(
+            source_dir=source_dir, assert_if_not=setB_repo_revision)
+
+      self._setA_descriptions = {
+          results.KEY__SET_DESCRIPTIONS__DIR: setA_dirs,
+          results.KEY__SET_DESCRIPTIONS__REPO_REVISION: setA_repo_revision,
+          results.KEY__SET_DESCRIPTIONS__SECTION: setA_section,
+      }
+      self._setB_descriptions = {
+          results.KEY__SET_DESCRIPTIONS__DIR: setB_dirs,
+          results.KEY__SET_DESCRIPTIONS__REPO_REVISION: setB_repo_revision,
+          results.KEY__SET_DESCRIPTIONS__SECTION: setB_section,
+      }
 
       time_start = int(time.time())
       self._results = self._load_result_pairs(
-          setA_root=setA_root, setA_section=setA_section,
-          setB_root=setB_root, setB_section=setB_section)
+          setA_root=setA_root, setB_root=setB_root,
+          setA_section=setA_section, setB_section=setB_section)
       if self._results:
         self._timestamp = int(time.time())
         logging.info('Number of download file collisions: %s' %
@@ -166,15 +190,18 @@
     finally:
       shutil.rmtree(tempdir)
 
-  def _load_result_pairs(self, setA_root, setA_section, setB_root,
-                         setB_section):
+  def _load_result_pairs(self, setA_root, setB_root,
+                         setA_section, setB_section):
     """Loads all JSON image summaries from 2 directory trees and compares them.
 
+    TODO(stephana): This method is only called from within __init__(); it might
+    make more sense to just roll the content of this method into __init__().
+
     Args:
       setA_root: root directory containing JSON summaries of rendering results
+      setB_root: root directory containing JSON summaries of rendering results
       setA_section: which section (gm_json.JSONKEY_ACTUALRESULTS or
           gm_json.JSONKEY_EXPECTEDRESULTS) to load from the summaries in setA
-      setB_root: root directory containing JSON summaries of rendering results
       setB_section: which section (gm_json.JSONKEY_ACTUALRESULTS or
           gm_json.JSONKEY_EXPECTEDRESULTS) to load from the summaries in setB
 
@@ -400,3 +427,24 @@
       shutil.copytree(repo_dir, dest_dir)
     else:
       shutil.copytree(source_dir, dest_dir)
+
+  def _get_repo_revision(self, source_dir, assert_if_not=None):
+    """Get the commit hash of source_dir, IF it refers to a git checkout.
+
+    Args:
+      source_dir: path to source dir (GS URL, local filepath, or a special
+          "repo:" URL type that points at a file within our Skia checkout;
+          only the "repo:" URL type will have a commit hash.
+      assert_if_not: if not None, raise an Exception if source_dir has a
+          commit hash and that hash is not equal to this
+    """
+    if source_dir.lower().startswith(REPO_URL_PREFIX):
+      repo_dir = os.path.join(REPO_BASEPATH, source_dir[len(REPO_URL_PREFIX):])
+      revision = subprocess.check_output(
+          args=[git_utils.GIT, 'rev-parse', 'HEAD'], cwd=repo_dir).strip()
+      if assert_if_not and revision != assert_if_not:
+        raise Exception('found revision %s that did not match %s' % (
+            revision, assert_if_not))
+      return revision
+    else:
+      return None
diff --git a/gm/rebaseline_server/compare_rendered_pictures_test.py b/gm/rebaseline_server/compare_rendered_pictures_test.py
index 6a057d2..c8f47e3 100755
--- a/gm/rebaseline_server/compare_rendered_pictures_test.py
+++ b/gm/rebaseline_server/compare_rendered_pictures_test.py
@@ -65,6 +65,14 @@
         diff_base_url='/static/generated-images')
     results_obj.get_timestamp = mock_get_timestamp
 
+    # Overwrite elements within the results that change from one test run
+    # to the next.
+    # pylint: disable=W0212
+    results_obj._setA_descriptions[results.KEY__SET_DESCRIPTIONS__DIR] = [
+        'before-patch-fake-dir']
+    results_obj._setB_descriptions[results.KEY__SET_DESCRIPTIONS__DIR] = [
+        'after-patch-fake-dir']
+
     gm_json.WriteToFile(
         results_obj.get_packaged_results_of_type(
             results.KEY__HEADER__RESULTS_ALL),
@@ -83,6 +91,14 @@
         diff_base_url='/static/generated-images')
     results_obj.get_timestamp = mock_get_timestamp
 
+    # Overwrite elements within the results that change from one test run
+    # to the next.
+    # pylint: disable=W0212
+    results_obj._setA_descriptions\
+        [results.KEY__SET_DESCRIPTIONS__REPO_REVISION] = 'fake-repo-revision'
+    results_obj._setB_descriptions\
+        [results.KEY__SET_DESCRIPTIONS__REPO_REVISION] = 'fake-repo-revision'
+
     gm_json.WriteToFile(
         results_obj.get_packaged_results_of_type(
             results.KEY__HEADER__RESULTS_ALL),
diff --git a/gm/rebaseline_server/compare_to_expectations.py b/gm/rebaseline_server/compare_to_expectations.py
index cdd03be..34b248c 100755
--- a/gm/rebaseline_server/compare_to_expectations.py
+++ b/gm/rebaseline_server/compare_to_expectations.py
@@ -78,6 +78,7 @@
       builder_regex_list: List of regular expressions specifying which builders
           we will process. If None, process all builders.
     """
+    super(ExpectationComparisons, self).__init__()
     time_start = int(time.time())
     if builder_regex_list != None:
       self.set_match_builders_pattern_list(builder_regex_list)
diff --git a/gm/rebaseline_server/results.py b/gm/rebaseline_server/results.py
index 347666a..b577a92 100755
--- a/gm/rebaseline_server/results.py
+++ b/gm/rebaseline_server/results.py
@@ -23,7 +23,7 @@
 
 # Keys used to link an image to a particular GM test.
 # NOTE: Keep these in sync with static/constants.js
-VALUE__HEADER__SCHEMA_VERSION = 4
+VALUE__HEADER__SCHEMA_VERSION = 5
 KEY__EXPECTATIONS__BUGS = gm_json.JSONKEY_EXPECTEDRESULTS_BUGS
 KEY__EXPECTATIONS__IGNOREFAILURE = gm_json.JSONKEY_EXPECTEDRESULTS_IGNOREFAILURE
 KEY__EXPECTATIONS__REVIEWED = gm_json.JSONKEY_EXPECTEDRESULTS_REVIEWED
@@ -38,6 +38,8 @@
 KEY__HEADER__RESULTS_ALL = 'all'
 KEY__HEADER__RESULTS_FAILURES = 'failures'
 KEY__HEADER__SCHEMA_VERSION = 'schemaVersion'
+KEY__HEADER__SET_A_DESCRIPTIONS = 'setA'
+KEY__HEADER__SET_B_DESCRIPTIONS = 'setB'
 KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE = 'timeNextUpdateAvailable'
 KEY__HEADER__TIME_UPDATED = 'timeUpdated'
 KEY__HEADER__TYPE = 'type'
@@ -45,6 +47,9 @@
 KEY__RESULT_TYPE__FAILUREIGNORED = gm_json.JSONKEY_ACTUALRESULTS_FAILUREIGNORED
 KEY__RESULT_TYPE__NOCOMPARISON = gm_json.JSONKEY_ACTUALRESULTS_NOCOMPARISON
 KEY__RESULT_TYPE__SUCCEEDED = gm_json.JSONKEY_ACTUALRESULTS_SUCCEEDED
+KEY__SET_DESCRIPTIONS__DIR = 'dir'
+KEY__SET_DESCRIPTIONS__REPO_REVISION = 'repoRevision'
+KEY__SET_DESCRIPTIONS__SECTION = 'section'
 
 IMAGE_FILENAME_RE = re.compile(gm_json.IMAGE_FILENAME_PATTERN)
 IMAGE_FILENAME_FORMATTER = '%s_%s.png'  # pass in (testname, config)
@@ -68,6 +73,11 @@
   """Base class for generating summary of comparisons between two image sets.
   """
 
+  def __init__(self):
+    """Base constructor; most subclasses will override."""
+    self._setA_descriptions = None
+    self._setB_descriptions = None
+
   def get_results_of_type(self, results_type):
     """Return results of some/all tests (depending on 'results_type' parameter).
 
@@ -94,7 +104,7 @@
     """
     response_dict = self._results[results_type]
     time_updated = self.get_timestamp()
-    response_dict[imagepairset.KEY__ROOT__HEADER] = {
+    header_dict = {
         KEY__HEADER__SCHEMA_VERSION: (
             VALUE__HEADER__SCHEMA_VERSION),
 
@@ -119,6 +129,11 @@
         # Whether the service is accessible from other hosts.
         KEY__HEADER__IS_EXPORTED: is_exported,
     }
+    if self._setA_descriptions:
+      header_dict[KEY__HEADER__SET_A_DESCRIPTIONS] = self._setA_descriptions
+    if self._setB_descriptions:
+      header_dict[KEY__HEADER__SET_B_DESCRIPTIONS] = self._setB_descriptions
+    response_dict[imagepairset.KEY__ROOT__HEADER] = header_dict
     return response_dict
 
   def get_timestamp(self):
diff --git a/gm/rebaseline_server/server.py b/gm/rebaseline_server/server.py
index f2ba822..cd0b6eb 100755
--- a/gm/rebaseline_server/server.py
+++ b/gm/rebaseline_server/server.py
@@ -116,6 +116,9 @@
 # Ultimately, we will depend on buildbot steps linking to their own diffs on
 # the shared rebaseline_server instance.
 _SKP_BASE_GS_URL = 'gs://' + buildbot_globals.Get('skp_summaries_bucket')
+_SKP_BASE_REPO_URL = (
+    compare_rendered_pictures.REPO_URL_PREFIX + posixpath.join(
+        'expectations', 'skp'))
 _SKP_PLATFORMS = [
     'Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug',
     'Test-Ubuntu12-ShuttleA-GTX660-x86-Release',
@@ -222,7 +225,7 @@
                 LIVE_PARAM__SET_A_SECTION:
                     gm_json.JSONKEY_EXPECTEDRESULTS,
                 LIVE_PARAM__SET_A_DIR:
-                    posixpath.join(_SKP_BASE_GS_URL, builder),
+                    posixpath.join(_SKP_BASE_REPO_URL, builder),
                 LIVE_PARAM__SET_B_SECTION:
                     gm_json.JSONKEY_ACTUALRESULTS,
                 LIVE_PARAM__SET_B_DIR:
@@ -588,13 +591,14 @@
     download_all_images = (
         param_dict.get(LIVE_PARAM__DOWNLOAD_ONLY_DIFFERING, [''])[0].lower()
         not in ['1', 'true'])
+    setA_dirs = param_dict[LIVE_PARAM__SET_A_DIR]
+    setB_dirs = param_dict[LIVE_PARAM__SET_B_DIR]
     setA_section = self._validate_summary_section(
         param_dict.get(LIVE_PARAM__SET_A_SECTION, [None])[0])
     setB_section = self._validate_summary_section(
         param_dict.get(LIVE_PARAM__SET_B_SECTION, [None])[0])
     results_obj = compare_rendered_pictures.RenderedPicturesComparisons(
-        setA_dirs=param_dict[LIVE_PARAM__SET_A_DIR],
-        setB_dirs=param_dict[LIVE_PARAM__SET_B_DIR],
+        setA_dirs=setA_dirs, setB_dirs=setB_dirs,
         setA_section=setA_section, setB_section=setB_section,
         image_diff_db=_SERVER.image_diff_db,
         diff_base_url='/static/generated-images',
@@ -604,7 +608,7 @@
       self.send_response(200)
     else:
       self.send_json_dict(results_obj.get_packaged_results_of_type(
-          results_mod.KEY__HEADER__RESULTS_ALL))
+          results_type=results_mod.KEY__HEADER__RESULTS_ALL))
 
   def do_GET_live_results(self, url_remainder):
     """ Handle a GET request for live-generated image diff data.
diff --git a/gm/rebaseline_server/static/constants.js b/gm/rebaseline_server/static/constants.js
index c397452..55964b0 100644
--- a/gm/rebaseline_server/static/constants.js
+++ b/gm/rebaseline_server/static/constants.js
@@ -61,15 +61,21 @@
     KEY__HEADER__RESULTS_ALL: 'all',
     KEY__HEADER__RESULTS_FAILURES: 'failures',
     KEY__HEADER__SCHEMA_VERSION: 'schemaVersion',
+    KEY__HEADER__SET_A_DESCRIPTIONS: 'setA',
+    KEY__HEADER__SET_B_DESCRIPTIONS: 'setB',
     KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE: 'timeNextUpdateAvailable',
     KEY__HEADER__TIME_UPDATED: 'timeUpdated',
     KEY__HEADER__TYPE: 'type',
-    VALUE__HEADER__SCHEMA_VERSION: 4,
+    VALUE__HEADER__SCHEMA_VERSION: 5,
     //
     KEY__RESULT_TYPE__FAILED: 'failed',
     KEY__RESULT_TYPE__FAILUREIGNORED: 'failure-ignored',
     KEY__RESULT_TYPE__NOCOMPARISON: 'no-comparison',
     KEY__RESULT_TYPE__SUCCEEDED: 'succeeded',
+    //
+    KEY__SET_DESCRIPTIONS__DIR: 'dir',
+    KEY__SET_DESCRIPTIONS__REPO_REVISION: 'repoRevision',
+    KEY__SET_DESCRIPTIONS__SECTION: 'section',
 
     // NOTE: Keep these in sync with ../server.py
     KEY__EDITS__MODIFICATIONS: 'modifications',
diff --git a/gm/rebaseline_server/static/live-view.html b/gm/rebaseline_server/static/live-view.html
index c9598fa..721ca2e 100644
--- a/gm/rebaseline_server/static/live-view.html
+++ b/gm/rebaseline_server/static/live-view.html
@@ -48,8 +48,14 @@
     </div>
 
     <div ng-show="header[constants.KEY__HEADER__TIME_UPDATED]">
-      setA: "{{setASection}}" within {{setADir}}<br>
-      setB: "{{setBSection}}" within {{setBDir}}<br>
+      setA: "{{header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__SECTION]}}"
+      within {{header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__DIR]}}
+      <span ng-show="header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__REPO_REVISION]">at <a href="https://skia.googlesource.com/skia/+/{{header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__REPO_REVISION]}}">rev {{header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__REPO_REVISION]}}</a></span>
+      <br>
+      setB: "{{header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__SECTION]}}"
+      within {{header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__DIR]}}
+      <span ng-show="header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__REPO_REVISION]">at <a href="https://skia.googlesource.com/skia/+/{{header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__REPO_REVISION]}}">rev {{header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__REPO_REVISION]}}</a></span>
+      <br>
       <a href="{{liveQueryUrl}}">latest raw JSON diffs between these two sets</a><br>
       These results current as of
       {{localTimeString(header[constants.KEY__HEADER__TIME_UPDATED])}}
@@ -267,7 +273,7 @@
             <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__IMAGEPAIRS__IMAGE_A_URL)"
                ng-click="sortResultsBy('none', constants.KEY__IMAGEPAIRS__IMAGE_A_URL)"
                href=""
-               title="setA: '{{setASection}}' within {{setADir}}"
+               title="setA: '{{header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__SECTION]}}' within {{header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__DIR]}}"
                class="sortable-header">
                    {{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_A][constants.KEY__IMAGESETS__FIELD__DESCRIPTION]}}
             </a>
@@ -276,7 +282,7 @@
             <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__IMAGEPAIRS__IMAGE_B_URL)"
                ng-click="sortResultsBy('none', constants.KEY__IMAGEPAIRS__IMAGE_B_URL)"
                href=""
-               title="setB: '{{setBSection}}' within {{setBDir}}"
+               title="setB: '{{header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__SECTION]}}' within {{header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__DIR]}}"
                class="sortable-header">
                   {{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_B][constants.KEY__IMAGESETS__FIELD__DESCRIPTION]}}
             </a>
diff --git a/gm/rebaseline_server/testdata/outputs/expected/compare_configs_test.CompareConfigsTest.test_gm/gm.json b/gm/rebaseline_server/testdata/outputs/expected/compare_configs_test.CompareConfigsTest.test_gm/gm.json
index 2dc6e6b..9dd1681 100644
--- a/gm/rebaseline_server/testdata/outputs/expected/compare_configs_test.CompareConfigsTest.test_gm/gm.json
+++ b/gm/rebaseline_server/testdata/outputs/expected/compare_configs_test.CompareConfigsTest.test_gm/gm.json
@@ -107,7 +107,7 @@
     "dataHash": "-5829724510169924592", 
     "isEditable": false, 
     "isExported": true, 
-    "schemaVersion": 4, 
+    "schemaVersion": 5, 
     "timeNextUpdateAvailable": null, 
     "timeUpdated": 12345678, 
     "type": "all"
diff --git a/gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_endToEnd/compare_rendered_pictures.json b/gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_endToEnd/compare_rendered_pictures.json
index 8cfdbe6..c334459 100644
--- a/gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_endToEnd/compare_rendered_pictures.json
+++ b/gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_endToEnd/compare_rendered_pictures.json
@@ -79,7 +79,21 @@
     "dataHash": "-4754972663365911725", 
     "isEditable": false, 
     "isExported": true, 
-    "schemaVersion": 4, 
+    "schemaVersion": 5, 
+    "setA": {
+      "dir": [
+        "before-patch-fake-dir"
+      ], 
+      "repoRevision": null, 
+      "section": "actual-results"
+    }, 
+    "setB": {
+      "dir": [
+        "after-patch-fake-dir"
+      ], 
+      "repoRevision": null, 
+      "section": "actual-results"
+    }, 
     "timeNextUpdateAvailable": null, 
     "timeUpdated": 12345678, 
     "type": "all"
diff --git a/gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_repo_url/compare_rendered_pictures.json b/gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_repo_url/compare_rendered_pictures.json
index da517c9..099e995 100644
--- a/gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_repo_url/compare_rendered_pictures.json
+++ b/gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_repo_url/compare_rendered_pictures.json
@@ -79,7 +79,21 @@
     "dataHash": "-4754972663365911725", 
     "isEditable": false, 
     "isExported": true, 
-    "schemaVersion": 4, 
+    "schemaVersion": 5, 
+    "setA": {
+      "dir": [
+        "repo:gm/rebaseline_server/testdata/inputs/skp-summaries/expectations"
+      ], 
+      "repoRevision": "fake-repo-revision", 
+      "section": "expected-results"
+    }, 
+    "setB": {
+      "dir": [
+        "repo:gm/rebaseline_server/testdata/inputs/skp-summaries/actuals"
+      ], 
+      "repoRevision": "fake-repo-revision", 
+      "section": "actual-results"
+    }, 
     "timeNextUpdateAvailable": null, 
     "timeUpdated": 12345678, 
     "type": "all"
diff --git a/gm/rebaseline_server/testdata/outputs/expected/compare_to_expectations_test.CompareToExpectationsTest.test_gm/gm.json b/gm/rebaseline_server/testdata/outputs/expected/compare_to_expectations_test.CompareToExpectationsTest.test_gm/gm.json
index d20a3a3..23dca28 100644
--- a/gm/rebaseline_server/testdata/outputs/expected/compare_to_expectations_test.CompareToExpectationsTest.test_gm/gm.json
+++ b/gm/rebaseline_server/testdata/outputs/expected/compare_to_expectations_test.CompareToExpectationsTest.test_gm/gm.json
@@ -123,7 +123,7 @@
     "dataHash": "-7804718549064096650", 
     "isEditable": false, 
     "isExported": true, 
-    "schemaVersion": 4, 
+    "schemaVersion": 5, 
     "timeNextUpdateAvailable": null, 
     "timeUpdated": 12345678, 
     "type": "all"