Bug 1626795: [hg-push] Pull push info from hg.mozilla.org; r=aki
authorTom Prince <mozilla@hocat.ca>
Thu, 02 Apr 2020 20:12:01 +0000
changeset 212 dd04f10e617d6f7447b620a91aeabfe30addaf6e
parent 211 01a05a3f70795a27d17355ba3079282ed6b594b8
child 213 ec62d2df61eeb3b4297deafbf8e314bc17e98d1d
push id153
push usermozilla@hocat.ca
push dateMon, 06 Apr 2020 17:31:35 +0000
treeherderci-admin@ec62d2df61ee [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaki
bugs1626795
Bug 1626795: [hg-push] Pull push info from hg.mozilla.org; r=aki Differential Revision: https://phabricator.services.mozilla.com/D69292
taskcluster/docker/hg-push/make_decision.py
--- a/taskcluster/docker/hg-push/make_decision.py
+++ b/taskcluster/docker/hg-push/make_decision.py
@@ -27,50 +27,73 @@ adapter = HTTPAdapter(
         backoff_factor=0.3,
         status_forcelist=(500, 502, 503, 504),
     )
 )
 SESSION.mount("http://", adapter)
 SESSION.mount("https://", adapter)
 
 
-def get_tc_yml(pulse_payload):
+def get_push_info(head_rev):
+    repo = os.environ["REPO_URL"]
+    res = SESSION.get(
+        "{}/json-pushes?version=2&changeset={}&tipsonly=1".format(repo, head_rev)
+    )
+    res.raise_for_status()
+    pushes = res.json()["pushes"]
+    if len(pushes) != 1:
+        print(
+            "Changeset {} has {} associated pushes; "
+            "only one supported".format(head_rev, len(pushes))
+        )
+        raise SystemExit(1)
+    [(push_id, push_info)] = pushes.items()
+    if head_rev not in push_info["changesets"]:
+        print(
+            "Changeset {} is not the tip {} of the associated push.".format(
+                head_rev, push_info["changesets"][0]
+            )
+        )
+        raise SystemExit(1)
+    return {"user": push_info["user"], "pushid": push_id, "date": push_info["date"]}
+
+
+def get_tc_yml(head_rev):
     """
     Fetch .taskcluster.yml from the repository and parse it
 
     If TASKCLUSTER_YML_REPO is set, the file is fetched from the default branch
     of that repository; otherwise it is fetched from the repository where the
     push took place.
     """
     if "TASKCLUSTER_YML_REPO" in os.environ:
         repo = os.environ["TASKCLUSTER_YML_REPO"]
         head_rev = "default"
     else:
         repo = os.environ["REPO_URL"]
-        head_rev = pulse_payload["data"]["heads"][0]
     res = SESSION.get("{}/raw-file/{}/.taskcluster.yml".format(repo, head_rev))
     res.raise_for_status()
     tcyml = res.text
     return yaml.safe_load(tcyml)
 
 
-def render_tc_yml(tc_yml, push, head_rev):
+def render_tc_yml(tc_yml, push_info, head_rev):
     """
     Render .taskcluster.yml into an array of tasks.  This provides a context
     that is similar to that provided by actions and crons, but with `tasks-for`
     set to `hg-push`.
     """
     ownTaskId = slugid.nice()
     context = dict(
         tasks_for="hg-push",
         push=dict(
             revision=head_rev,
-            owner=push["user"],
-            pushlog_id=push["pushid"],
-            pushdate=push["time"],
+            owner=push_info["user"],
+            pushlog_id=push_info["pushid"],
+            pushdate=push_info["date"],
         ),
         repository=dict(
             url=os.environ["REPO_URL"],
             project=os.environ["PROJECT"],
             level=os.environ["LEVEL"],
         ),
         ownTaskId=ownTaskId,
     )
@@ -92,21 +115,23 @@ def main():
         print("Message has {} pushes; only one supported".format(push_count))
         return
 
     head_count = len(pulse_payload["data"]["heads"])
     if head_count != 1:
         print("Message has {} heads; only one supported".format(head_count))
         return
 
-    rendered = render_tc_yml(
-        get_tc_yml(pulse_payload),
-        pulse_payload["data"]["pushlog_pushes"][0],
-        pulse_payload["data"]["heads"][0],
-    )
+    # The hg-push hook can be triggered manually, so we throw out everything
+    # from the input, other than the revision, and get the pushinfo from
+    # hg.mozilla.org.
+    head_rev = pulse_payload["data"]["heads"][0]
+    push_info = get_push_info(head_rev)
+
+    rendered = render_tc_yml(get_tc_yml(head_rev), push_info, head_rev)
 
     task_count = len(rendered["tasks"])
     if task_count != 1:
         print("Rendered result has {} tasks; only one supported".format(task_count))
         return
     task = rendered["tasks"][0]
     taskId = task.pop("taskId")