From 43f2f79fd69fc51a67964505b529293d86720cc7 Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Thu, 13 Aug 2026 15:05:53 -0400 Subject: [PATCH] bug-2060967: link crash stack source files to searchfox instead of github Firefox symbol files now use git paths like git paths in the mozilla-firefox/firefox repository, so stack frames linked to github.com. Searchfox is preferable for reading crash stacks, so map that repository to searchfox instead. All of searchfox's firefox-* trees share a single clone which has refs for main, beta, release and the esr branches, and the /rev/ endpoint resolves any commit in that clone. Since mozilla-firefox/firefox holds every release branch, the firefox-main tree covers all channels. To express a mapping for one repository rather than a whole server, enhance_frame() now looks up the full root before falling back to the server, which leaves other github.com repositories pointing at github. While here, apply the 'show the basename' fallback whenever no mapping is found instead of only when the vcs type is unknown; previously a git: path with an unrecognized server rendered the raw 'git:server/repo:file:rev' string in the stack table. --- .../crashstats/crashstats/tests/test_utils.py | 66 ++++++++++++++++++- webapp/crashstats/crashstats/utils.py | 28 ++++---- webapp/crashstats/settings/base.py | 8 +++ 3 files changed, 87 insertions(+), 15 deletions(-) diff --git a/webapp/crashstats/crashstats/tests/test_utils.py b/webapp/crashstats/crashstats/tests/test_utils.py index 47fe3e7fa1..b861fdb04e 100644 --- a/webapp/crashstats/crashstats/tests/test_utils.py +++ b/webapp/crashstats/crashstats/tests/test_utils.py @@ -38,7 +38,58 @@ }, ), ( - # Now with a file that has VCS info but isn't in vcs_mappings. + # Test that firefox source files link to searchfox rather than the + # github.com repo they came from. + { + "frame": 0, + "module": "xul.dll", + "function": "Func", + "file": ( + "git:github.com/mozilla-firefox/firefox" + ":dom/base/StructuredCloneBlob.cpp" + ":ed6cfb3b73cb602ed2b8a75b1721c95b8e820322" + ), + "line": 253, + }, + { + "function": "Func", + "short_signature": "Func", + "line": 253, + "source_link": ( + "https://searchfox.org/firefox-main/rev" + "/ed6cfb3b73cb602ed2b8a75b1721c95b8e820322" + "/dom/base/StructuredCloneBlob.cpp#253" + ), + "file": "dom/base/StructuredCloneBlob.cpp", + "frame": 0, + "signature": "Func", + "module": "xul.dll", + }, + ), + ( + # Test that other github.com repos still link to github.com. + { + "frame": 0, + "module": "bad.dll", + "function": "Func", + "file": "git:github.com/some/project:dname/fname:rev", + "line": 576, + }, + { + "function": "Func", + "short_signature": "Func", + "line": 576, + "source_link": ( + "https://github.com/some/project/blob/rev/dname/fname#L576" + ), + "file": "dname/fname", + "frame": 0, + "signature": "Func", + "module": "bad.dll", + }, + ), + ( + # Now with a file whose server has no entry in vcs_mappings. { "frame": 0, "module": "bad.dll", @@ -140,7 +191,15 @@ def test_enhance_frame(data, expected): "hg.m.org": ( "http://hg.m.org/%(repo)s/file/%(revision)s/%(file)s#l%(line)s" ) - } + }, + "git": { + "github.com/mozilla-firefox/firefox": ( + "https://searchfox.org/firefox-main/rev/%(revision)s/%(file)s#%(line)s" + ), + "github.com": ( + "https://github.com/%(repo)s/blob/%(revision)s/%(file)s#L%(line)s" + ), + }, } # NOTE(willkg): data is modified in-place @@ -180,7 +239,8 @@ def test_enhance_frame_s3_generated_sources(): utils.enhance_frame(frame, {}) # Because it can't find a mapping in 'vcs_mappings', the frame's # 'file', the default behavior is to extract just the file's basename. - frame["file"] = "PCompositorBridgeChild.cpp" + assert frame["file"] == "PCompositorBridgeChild.cpp" + assert "source_link" not in frame # Try again, now with 's3' in vcs_mappings. frame = copy.copy(original_frame) diff --git a/webapp/crashstats/crashstats/utils.py b/webapp/crashstats/crashstats/utils.py index 869e903e03..137ec3ddd6 100644 --- a/webapp/crashstats/crashstats/utils.py +++ b/webapp/crashstats/crashstats/utils.py @@ -326,19 +326,23 @@ def enhance_frame(frame, vcs_mappings): # Leave it as is if it's not unweildly long. vcs_source_file_display = vcs_source_file - if vcstype in vcs_mappings: - if server in vcs_mappings[vcstype]: - link = vcs_mappings[vcstype][server] - frame["file"] = vcs_source_file_display - frame["source_link"] = link % { - "repo": repo, - "file": vcs_source_file, - "revision": revision, - "line": frame["line"], - } + mappings = vcs_mappings.get(vcstype, {}) + # Prefer a mapping for the specific repository (e.g. + # "github.com/mozilla-firefox/firefox") over one for the whole + # server (e.g. "github.com") + link = mappings.get(root) or mappings.get(server) + if link: + frame["file"] = vcs_source_file_display + frame["source_link"] = link % { + "repo": repo, + "file": vcs_source_file, + "revision": revision, + "line": frame["line"], + } else: - path_parts = vcs_source_file.split("/") - frame["file"] = path_parts.pop() + # Without a mapping there's nothing to link to, so just show the + # file's basename + frame["file"] = vcs_source_file.split("/")[-1] def enhance_json_dump(dump, vcs_mappings): diff --git a/webapp/crashstats/settings/base.py b/webapp/crashstats/settings/base.py index 572e853740..2f03ce42dd 100644 --- a/webapp/crashstats/settings/base.py +++ b/webapp/crashstats/settings/base.py @@ -302,6 +302,14 @@ def filter(self, record): "git.mozilla.org": ( "http://git.mozilla.org/?p=%(repo)s;a=blob;f=%(file)s;h=%(revision)s#l%(line)s" # noqa ), + # Firefox source links go to searchfox rather than GitHub. Searchfox + # serves the source for any revision in the mozilla-firefox/firefox + # repository from any of its firefox-* trees, since those trees share a + # single clone which has all the release branches. That means the + # "firefox-main" tree works for beta, release and esr revisions too. + "github.com/mozilla-firefox/firefox": ( + "https://searchfox.org/firefox-main/rev/%(revision)s/%(file)s#%(line)s" + ), "github.com": ( "https://github.com/%(repo)s/blob/%(revision)s/%(file)s#L%(line)s" ),