From a672eab5cf08aa6354fb5d853e370737c3bffa90 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 1 May 2026 18:14:03 +0000 Subject: [PATCH] Handle workflow runs without head commits Co-authored-by: Armen Zambrano G. --- src/github_sdk.py | 17 ++++++++++++++++- tests/test_github_sdk.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/github_sdk.py b/src/github_sdk.py index cf28d01..216fb84 100644 --- a/src/github_sdk.py +++ b/src/github_sdk.py @@ -26,6 +26,21 @@ def get_uuid_from_string(input_string): return uuid.UUID(hash_value[:32]).hex +def _get_author_from_run(runs): + head_commit = runs.get("head_commit") or {} + author = head_commit.get("author") + if author: + return author + + actor = runs.get("actor") or runs.get("triggering_actor") or {} + user = {} + if actor.get("id") is not None: + user["id"] = str(actor["id"]) + if actor.get("login"): + user["username"] = actor["login"] + return user + + class GithubClient: # This transform GH jobs conclusion keywords to Sentry performance status github_status_trace_status = {"success": "ok", "failure": "internal_error"} @@ -53,7 +68,7 @@ def _get_extra_metadata(self, job): repo = runs["repository"]["full_name"] meta = { # "workflow_name": workflow["name"], - "author": runs["head_commit"]["author"], + "author": _get_author_from_run(runs), # https://getsentry.atlassian.net/browse/TET-22 # Tags are not linkified externally, plain text data can be selected in browsers and opened "data": { diff --git a/tests/test_github_sdk.py b/tests/test_github_sdk.py index 7f7e401..214a752 100644 --- a/tests/test_github_sdk.py +++ b/tests/test_github_sdk.py @@ -1,5 +1,6 @@ from __future__ import annotations +import copy import sys from datetime import datetime from unittest.mock import patch @@ -110,6 +111,33 @@ def test_trace_generation_with_failing_steps( assert trace["tags"]["event"] == "push" +@responses.activate +def test_trace_generation_without_head_commit_uses_actor( + failure_job, + failure_runs, + failure_workflow, +): + runs = copy.deepcopy(failure_runs) + runs["head_commit"] = None + + responses.get( + failure_job["run_url"], + json=runs, + ) + responses.get( + runs["workflow_url"], + json=failure_workflow, + ) + + client = GithubClient(dsn=DSN, token=TOKEN) + trace = client._generate_trace(failure_job) + + assert trace["user"] == { + "id": str(runs["actor"]["id"]), + "username": runs["actor"]["login"], + } + + @freeze_time() @responses.activate @patch("src.github_sdk.get_uuid")