Skip to content

Commit b14520f

Browse files
committed
fix(profile): address PR review comments
- Fix mismatched default periods: both list and view now use 24h default - Handle duplicate segments with numeric suffixes (issues, issues2, etc.) - Add --web/-w flag to profile list command - Fix schema repair for transaction_aliases to use custom DDL with composite primary key
1 parent 7068f49 commit b14520f

File tree

4 files changed

+91
-4
lines changed

4 files changed

+91
-4
lines changed

src/commands/profile/list.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { buildCommand, numberParser } from "@stricli/core";
99
import type { SentryContext } from "../../context.js";
1010
import { getProject, listProfiledTransactions } from "../../lib/api-client.js";
1111
import { parseOrgProjectArg } from "../../lib/arg-parsing.js";
12+
import { openInBrowser } from "../../lib/browser.js";
1213
import {
1314
buildTransactionFingerprint,
1415
setTransactionAliases,
@@ -23,13 +24,15 @@ import {
2324
writeJson,
2425
} from "../../lib/formatters/index.js";
2526
import { resolveOrgAndProject } from "../../lib/resolve-target.js";
27+
import { buildProfilingSummaryUrl } from "../../lib/sentry-urls.js";
2628
import { buildTransactionAliases } from "../../lib/transaction-alias.js";
2729
import type { TransactionAliasEntry, Writer } from "../../types/index.js";
2830

2931
type ListFlags = {
3032
readonly period: string;
3133
readonly limit: number;
3234
readonly json: boolean;
35+
readonly web: boolean;
3336
};
3437

3538
/** Valid period values */
@@ -101,8 +104,13 @@ export const listCommand = buildCommand({
101104
brief: "Output as JSON",
102105
default: false,
103106
},
107+
web: {
108+
kind: "boolean",
109+
brief: "Open in browser",
110+
default: false,
111+
},
104112
},
105-
aliases: { n: "limit" },
113+
aliases: { n: "limit", w: "web" },
106114
},
107115
async func(
108116
this: SentryContext,
@@ -147,6 +155,16 @@ export const listCommand = buildCommand({
147155
// Set telemetry context
148156
setContext([resolvedTarget.org], [resolvedTarget.project]);
149157

158+
// Open in browser if requested
159+
if (flags.web) {
160+
await openInBrowser(
161+
stdout,
162+
buildProfilingSummaryUrl(resolvedTarget.org, resolvedTarget.project),
163+
"profiling"
164+
);
165+
return;
166+
}
167+
150168
// Get project to retrieve numeric ID (required for profile API)
151169
const project = await getProject(
152170
resolvedTarget.org,

src/commands/profile/view.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export const viewCommand = buildCommand({
9292
kind: "parsed",
9393
parse: parsePeriod,
9494
brief: "Stats period: 1h, 24h, 7d, 14d, 30d",
95-
default: "7d",
95+
default: "24h",
9696
},
9797
limit: {
9898
kind: "parsed",

src/lib/db/schema.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,8 +372,33 @@ export type RepairResult = {
372372
failed: string[];
373373
};
374374

375+
/** Tables that require custom DDL (not auto-generated from TABLE_SCHEMAS) */
376+
const CUSTOM_DDL_TABLES = new Set(["transaction_aliases"]);
377+
378+
function repairTransactionAliasesTable(
379+
db: Database,
380+
result: RepairResult
381+
): void {
382+
if (tableExists(db, "transaction_aliases")) {
383+
return;
384+
}
385+
try {
386+
db.exec(TRANSACTION_ALIASES_DDL);
387+
db.exec(TRANSACTION_ALIASES_INDEX);
388+
result.fixed.push("Created table transaction_aliases");
389+
} catch (e) {
390+
const msg = e instanceof Error ? e.message : String(e);
391+
result.failed.push(`Failed to create table transaction_aliases: ${msg}`);
392+
}
393+
}
394+
375395
function repairMissingTables(db: Database, result: RepairResult): void {
376396
for (const [tableName, ddl] of Object.entries(EXPECTED_TABLES)) {
397+
// Skip tables that need custom DDL
398+
if (CUSTOM_DDL_TABLES.has(tableName)) {
399+
continue;
400+
}
401+
377402
if (tableExists(db, tableName)) {
378403
continue;
379404
}
@@ -385,6 +410,9 @@ function repairMissingTables(db: Database, result: RepairResult): void {
385410
result.failed.push(`Failed to create table ${tableName}: ${msg}`);
386411
}
387412
}
413+
414+
// Handle tables with custom DDL
415+
repairTransactionAliasesTable(db, result);
388416
}
389417

390418
function repairMissingColumns(db: Database, result: RepairResult): void {

src/lib/transaction-alias.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,36 @@ type TransactionInput = {
7878
projectSlug: string;
7979
};
8080

81+
/**
82+
* Disambiguate duplicate segments by appending numeric suffixes.
83+
* e.g., ["issues", "events", "issues"] → ["issues", "events", "issues2"]
84+
*
85+
* @param segments - Array of extracted segments (may contain duplicates)
86+
* @returns Array of unique segments with numeric suffixes for duplicates
87+
*/
88+
function disambiguateSegments(segments: string[]): string[] {
89+
const seen = new Map<string, number>();
90+
const result: string[] = [];
91+
92+
for (const segment of segments) {
93+
const count = seen.get(segment) ?? 0;
94+
seen.set(segment, count + 1);
95+
96+
if (count === 0) {
97+
result.push(segment);
98+
} else {
99+
// Append numeric suffix for duplicates (issues2, issues3, etc.)
100+
result.push(`${segment}${count + 1}`);
101+
}
102+
}
103+
104+
return result;
105+
}
106+
81107
/**
82108
* Build aliases for a list of transactions.
83109
* Uses shortest unique prefix algorithm on extracted segments.
110+
* Handles duplicate segments by appending numeric suffixes.
84111
*
85112
* @param transactions - Array of transaction inputs with org/project context
86113
* @returns Array of TransactionAliasEntry with idx, alias, and transaction
@@ -94,6 +121,17 @@ type TransactionInput = {
94121
* // { idx: 1, alias: "i", transaction: "/api/0/organizations/{org}/issues/", ... },
95122
* // { idx: 2, alias: "e", transaction: "/api/0/projects/{org}/{proj}/events/", ... },
96123
* // ]
124+
*
125+
* @example
126+
* // Duplicate segments get numeric suffixes
127+
* buildTransactionAliases([
128+
* { transaction: "/api/v1/issues/", ... },
129+
* { transaction: "/api/v2/issues/", ... },
130+
* ])
131+
* // => [
132+
* // { idx: 1, alias: "i", ... }, // from "issues"
133+
* // { idx: 2, alias: "is", ... }, // from "issues2" (disambiguated)
134+
* // ]
97135
*/
98136
export function buildTransactionAliases(
99137
transactions: TransactionInput[]
@@ -103,11 +141,14 @@ export function buildTransactionAliases(
103141
}
104142

105143
// Extract segments from each transaction
106-
const segments = transactions.map((t) =>
144+
const rawSegments = transactions.map((t) =>
107145
extractTransactionSegment(t.transaction)
108146
);
109147

110-
// Find shortest unique prefixes for the segments
148+
// Disambiguate duplicate segments with numeric suffixes
149+
const segments = disambiguateSegments(rawSegments);
150+
151+
// Find shortest unique prefixes for the disambiguated segments
111152
const prefixMap = findShortestUniquePrefixes(segments);
112153

113154
// Build result with 1-based indices

0 commit comments

Comments
 (0)