Skip to content
Merged
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
7 changes: 4 additions & 3 deletions src/lib/formatters/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,12 @@ export const boldUnderline = (text: string): string =>
* `string-width` treats OSC 8 sequences as zero-width, so column sizing
* in tables is not affected.
*
* @param text - Display text
* @param url - Target URL
* @param text - Display text (also used as the link target when `url` is omitted)
* @param url - Target URL. Defaults to `text`, which is convenient when the
* display text is already the full URL.
* @returns Text wrapped in OSC 8 hyperlink escape sequences
*/
export function terminalLink(text: string, url: string): string {
export function terminalLink(text: string, url: string = text): string {
// OSC 8 ; params ; URI BEL text OSC 8 ; ; BEL
// \x1b] opens the OSC sequence; \x07 (BEL) terminates it.
// Using BEL instead of ST (\x1b\\) for broad terminal compatibility.
Expand Down
3 changes: 2 additions & 1 deletion src/lib/init/clack-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

import { cancel, isCancel } from "@clack/prompts";
import { terminalLink } from "../formatters/colors.js";
import { SENTRY_DOCS_URL } from "./constants.js";

export class WizardCancelledError extends Error {
Expand All @@ -17,7 +18,7 @@ export class WizardCancelledError extends Error {
export function abortIfCancelled<T>(value: T | symbol): T {
if (isCancel(value)) {
cancel(
`Setup cancelled. You can visit ${SENTRY_DOCS_URL} to set up manually.`
`Setup cancelled. You can visit ${terminalLink(SENTRY_DOCS_URL)} to set up manually.`
);
throw new WizardCancelledError();
}
Expand Down
7 changes: 4 additions & 3 deletions src/lib/init/formatters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

import { cancel, log, note, outro } from "@clack/prompts";
import { terminalLink } from "../formatters/colors.js";
import { featureLabel } from "./clack-utils.js";
import {
EXIT_DEPENDENCY_INSTALL_FAILED,
Expand Down Expand Up @@ -41,10 +42,10 @@ function buildSummaryLines(output: WizardOutput): string[] {
lines.push(`Commands: ${output.commands.join("; ")}`);
}
if (output.sentryProjectUrl) {
lines.push(`Project: ${output.sentryProjectUrl}`);
lines.push(`Project: ${terminalLink(output.sentryProjectUrl)}`);
}
if (output.docsUrl) {
lines.push(`Docs: ${output.docsUrl}`);
lines.push(`Docs: ${terminalLink(output.docsUrl)}`);
}

const changedFiles = output.changedFiles;
Expand Down Expand Up @@ -103,7 +104,7 @@ export function formatError(result: WorkflowRunResult): void {

const docsUrl = inner?.docsUrl;
if (docsUrl) {
log.info(`Docs: ${docsUrl}`);
log.info(`Docs: ${terminalLink(docsUrl)}`);
}

cancel("Setup failed");
Expand Down
3 changes: 2 additions & 1 deletion src/lib/init/wizard-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { captureException } from "@sentry/bun";
import { formatBanner } from "../banner.js";
import { CLI_VERSION } from "../constants.js";
import { getAuthToken } from "../db/auth.js";
import { terminalLink } from "../formatters/colors.js";
import {
abortIfCancelled,
STEP_LABELS,
Expand Down Expand Up @@ -251,7 +252,7 @@ export async function runWizard(options: WizardOptions): Promise<void> {

log.info(
"This wizard uses AI to analyze your project and configure Sentry." +
`\nFor manual setup: ${SENTRY_DOCS_URL}`
`\nFor manual setup: ${terminalLink(SENTRY_DOCS_URL)}`
);

const tracingOptions = {
Expand Down
9 changes: 9 additions & 0 deletions test/lib/formatters/colors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,13 @@ describe("terminalLink", () => {
const stripped = result.replace(/\x1b\]8;;[^\x07]*\x07/g, "");
expect(stripped).toBe("display");
});

test("uses text as URL when url is omitted", () => {
const result = terminalLink("https://example.com");
expect(result).toContain("]8;;https://example.com");
expect(result).toContain("https://example.com");
expect(result).toBe(
terminalLink("https://example.com", "https://example.com")
);
});
});
Loading