Repository navigation
feat(tools): expose selected package versions for exact events #1293
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
f7ae542
2a7311a
151d53d
11929e5
3260660
09e25a0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,58 @@ | ||||||
| import { z } from "zod"; | ||||||
| import type { Event } from "../api-client/types"; | ||||||
|
|
||||||
| export const SelectedEventPackagesSchema = z.object({ | ||||||
| metadataAvailable: z.boolean(), | ||||||
| packages: z.array( | ||||||
| z.discriminatedUnion("status", [ | ||||||
| z.object({ | ||||||
| name: z.string(), | ||||||
| status: z.literal("recorded"), | ||||||
| version: z.string(), | ||||||
| truncated: z.boolean(), | ||||||
| }), | ||||||
| z.object({ | ||||||
| name: z.string(), | ||||||
| status: z.enum(["not_listed", "version_not_recorded"]), | ||||||
| version: z.null(), | ||||||
| truncated: z.literal(false), | ||||||
| }), | ||||||
| ]), | ||||||
| ), | ||||||
| }); | ||||||
|
|
||||||
| /** Select once for both structured and Markdown output, without exposing the full map. */ | ||||||
| export function selectEventPackages( | ||||||
| packages: Event["packages"], | ||||||
| packageNames?: string[], | ||||||
| ): z.infer<typeof SelectedEventPackagesSchema> | undefined { | ||||||
| if (!packageNames?.length) { | ||||||
| return undefined; | ||||||
| } | ||||||
| if (!packages || Object.keys(packages).length === 0) { | ||||||
| return { metadataAvailable: false, packages: [] }; | ||||||
| } | ||||||
|
|
||||||
| return { | ||||||
| metadataAvailable: true, | ||||||
| packages: [...new Set(packageNames)].map((name) => { | ||||||
| const version = Object.hasOwn(packages, name) | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||
| ? packages[name] | ||||||
| : undefined; | ||||||
| if (version === undefined || !version?.trim()) { | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. First check is redundant.
Suggested change
|
||||||
| return { | ||||||
| name, | ||||||
| status: version === undefined ? "not_listed" : "version_not_recorded", | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, do |
||||||
| version: null, | ||||||
| truncated: false, | ||||||
| }; | ||||||
| } | ||||||
| return { | ||||||
| name, | ||||||
| status: "recorded", | ||||||
| version: version.slice(0, 256), | ||||||
| truncated: version.length > 256, | ||||||
| }; | ||||||
| }), | ||||||
| }; | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,6 +30,7 @@ import type { | |
| TraceSpan, | ||
| } from "../api-client/types"; | ||
| import { logIssue } from "../telem/logging"; | ||
| import { selectEventPackages } from "./event-packages"; | ||
| import { | ||
| type CodeLocation, | ||
| findMostRelevantInAppFrame, | ||
|
|
@@ -1970,6 +1971,38 @@ function formatSeerSummary(autofixState: AutofixRunState | undefined): string { | |
| return `${parts.join("\n")}\n\n`; | ||
| } | ||
|
|
||
| function formatEventPackages(event: Event, packageNames: string[]): string { | ||
| const selection = selectEventPackages(event.packages, packageNames); | ||
| if (!selection) { | ||
| return ""; | ||
| } | ||
| let output = "\n### Selected Package Versions\n\n"; | ||
| if (!selection.metadataAvailable) { | ||
| return `${output}Package metadata is unavailable for this event.\n\n`; | ||
| } | ||
|
|
||
| for (const entry of selection.packages) { | ||
| const value = | ||
| entry.status === "recorded" | ||
| ? entry.truncated | ||
| ? `${entry.version}… (truncated)` | ||
| : entry.version | ||
| : entry.status === "not_listed" | ||
| ? "Not listed in this event's package metadata" | ||
| : "Version not recorded"; | ||
| output += `- ${formatPackageText(entry.name)}: ${formatPackageText(value)}\n`; | ||
|
Comment on lines
+1985
to
+1993
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These nested ternaries are blowing my mind. I feel like this calls for a |
||
| } | ||
| return `${output}\n`; | ||
| } | ||
|
|
||
| function formatPackageText(value: string): string { | ||
| return value | ||
| .replace(/[\r\n\t]/g, " ") | ||
| .replace(/&/g, "&") | ||
| .replace(/</g, "<") | ||
| .replace(/([\\`*_[\]|>])/g, "\\$1"); | ||
| } | ||
|
Comment on lines
+1998
to
+2004
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this doing? Don't we already have proper markdown/HTML escaping and building blocks in the repo? |
||
|
|
||
| /** Projects the suspect commit consistently for structured and markdown issue details. */ | ||
| export function getSuspectCommit(committers: CommitterList | undefined) { | ||
| // The endpoint currently returns the issue's latest suspect commit, grouped by author. | ||
|
|
@@ -1994,6 +2027,7 @@ export function getSuspectCommit(committers: CommitterList | undefined) { | |
| * @returns Formatted markdown string with complete issue information | ||
| */ | ||
| export function formatIssueOutput({ | ||
| packageNames, | ||
| organizationSlug, | ||
| issue, | ||
| event, | ||
|
|
@@ -2009,6 +2043,7 @@ export function formatIssueOutput({ | |
| availableToolNames, | ||
| directToolNames, | ||
| }: { | ||
| packageNames?: string[]; | ||
| organizationSlug: string; | ||
| issue: Issue; | ||
| event: Event; | ||
|
|
@@ -2159,6 +2194,10 @@ export function formatIssueOutput({ | |
| .join(""); | ||
| } | ||
|
|
||
| if (packageNames?.length) { | ||
| output += formatEventPackages(event, packageNames); | ||
| } | ||
|
|
||
| // For unsupported event types, return early without trying to render event details | ||
| return output; | ||
| } | ||
|
|
@@ -2200,6 +2239,10 @@ export function formatIssueOutput({ | |
| }, | ||
| }); | ||
|
|
||
| if (packageNames?.length) { | ||
| output += formatEventPackages(event, packageNames); | ||
| } | ||
|
|
||
| // Add Seer context if available | ||
| if (autofixState) { | ||
| output += formatSeerSummary(autofixState); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.