Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/lib/api/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,10 +252,10 @@ export async function listIssueEvents(

// Trim to exact limit. Unlike listIssuesAllPages (which controls per_page),
// the issue events endpoint has no per-page parameter, so the API may return
// more items than requested. We preserve nextCursor so the command-level
// cursor stack can navigate to subsequent pages.
const trimmed =
allEvents.length > limit ? allEvents.slice(0, limit) : allEvents;

return { data: trimmed, nextCursor };
// more items than requested. When trimming, drop nextCursor — it points past
// the trimmed items and would cause the cursor stack to skip events.
if (allEvents.length > limit) {
return { data: allEvents.slice(0, limit) };
}
return { data: allEvents, nextCursor };
}
14 changes: 13 additions & 1 deletion src/lib/db/pagination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@

import { ValidationError } from "../errors.js";
import { CURSOR_KEYWORDS } from "../list-command.js";
import { logger } from "../logger.js";
import { getApiBaseUrl } from "../sentry-client.js";
import { getDatabase } from "./index.js";
import { runUpsert } from "./utils.js";

const log = logger.withTag("pagination");

/** Default TTL for stored cursors: 5 minutes */
const CURSOR_TTL_MS = 5 * 60 * 1000;

Expand Down Expand Up @@ -84,7 +87,16 @@ export function getPaginationState(
return;
}

const stack = JSON.parse(row.cursor_stack) as string[];
let stack: string[];
try {
stack = JSON.parse(row.cursor_stack) as string[];
} catch {
log.debug("Corrupt cursor_stack in pagination DB, clearing state");
db.query(
"DELETE FROM pagination_cursors WHERE command_key = ? AND context = ?"
).run(commandKey, contextKey);
return;
}
return { stack, index: row.page_index };
}

Expand Down
22 changes: 16 additions & 6 deletions test/lib/formatters/colors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,21 +114,31 @@ describe("fixabilityColor", () => {
});

describe("terminalLink", () => {
/** Save/restore isTTY and env around TTY-specific tests */
/** Save/restore isTTY and all plain-output env vars around TTY-specific tests */
function withTTY(fn: () => void): void {
const savedTTY = process.stdout.isTTY;
const savedPlain = process.env.SENTRY_PLAIN_OUTPUT;
const savedNoColor = process.env.NO_COLOR;
const savedForceColor = process.env.FORCE_COLOR;
process.stdout.isTTY = true;
delete process.env.SENTRY_PLAIN_OUTPUT;
delete process.env.NO_COLOR;
delete process.env.FORCE_COLOR;
try {
fn();
} finally {
process.stdout.isTTY = savedTTY;
if (savedPlain !== undefined) {
process.env.SENTRY_PLAIN_OUTPUT = savedPlain;
} else {
delete process.env.SENTRY_PLAIN_OUTPUT;
}
restoreEnv("SENTRY_PLAIN_OUTPUT", savedPlain);
restoreEnv("NO_COLOR", savedNoColor);
restoreEnv("FORCE_COLOR", savedForceColor);
}
}

function restoreEnv(key: string, saved: string | undefined): void {
if (saved !== undefined) {
process.env[key] = saved;
} else {
delete process.env[key];
}
}

Expand Down
Loading