Skip to content

Commit b42d164

Browse files
betegoncursoragent
andcommitted
fix(resolve): preserve org-only usage hints
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent b787657 commit b42d164

2 files changed

Lines changed: 35 additions & 6 deletions

File tree

‎packages/cli/src/lib/resolve-target.ts‎

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2014,6 +2014,8 @@ export type ResolveProjectBoundTargetOptions = {
20142014
* lookups and fuzzy recovery.
20152015
*/
20162016
projectSearchResolution?: ProjectSearchTargetResolution;
2017+
/** Usage example supplied by the calling command. */
2018+
usageHint?: string;
20172019
};
20182020

20192021
/**
@@ -2041,7 +2043,8 @@ export async function resolveProjectBoundTarget(
20412043
commandName: string,
20422044
options: ResolveProjectBoundTargetOptions = {}
20432045
): Promise<ResolvedProjectBoundTarget> {
2044-
const usageHint = `sentry ${commandName} <org>/<project>`;
2046+
const usageHint =
2047+
options.usageHint ?? `sentry ${commandName} <org>/<project>`;
20452048

20462049
switch (parsed.type) {
20472050
case "explicit": {
@@ -2087,7 +2090,7 @@ export async function resolveProjectBoundTarget(
20872090
throw new ResolutionError(
20882091
`Project '${resolution.displaySlug}'`,
20892092
"not found",
2090-
`sentry ${commandName} <org>/${parsed.projectSlug}`,
2093+
usageHint,
20912094
resolution.suggestions.length > 0 ? resolution.suggestions : fallback
20922095
);
20932096
}
@@ -2432,7 +2435,8 @@ export type ResolvedOrgOptionalTarget = {
24322435
export async function resolveOrgOptionalTarget(
24332436
parsed: ParsedOrgProject,
24342437
cwd: string,
2435-
commandName: string
2438+
commandName: string,
2439+
usageHint = `sentry ${commandName} <target>`
24362440
): Promise<ResolvedOrgOptionalTarget> {
24372441
// org-all: resolve the org slug only
24382442
if (parsed.type === "org-all") {
@@ -2444,7 +2448,7 @@ export async function resolveOrgOptionalTarget(
24442448
if (parsed.type === "auto-detect") {
24452449
const resolved = await resolveOrg({ cwd });
24462450
if (!resolved) {
2447-
throw new ContextError("Organization", `sentry ${commandName} <target>`, [
2451+
throw new ContextError("Organization", usageHint, [
24482452
"SENTRY_ORG environment variable",
24492453
"sentry cli defaults",
24502454
]);
@@ -2468,11 +2472,12 @@ export async function resolveOrgOptionalTarget(
24682472
}
24692473
return resolveProjectBoundTarget(parsed, cwd, commandName, {
24702474
projectSearchResolution: resolution,
2475+
usageHint,
24712476
});
24722477
}
24732478

24742479
// explicit, scoped search, and display names
2475-
return resolveProjectBoundTarget(parsed, cwd, commandName);
2480+
return resolveProjectBoundTarget(parsed, cwd, commandName, { usageHint });
24762481
}
24772482

24782483
/**
@@ -2495,7 +2500,12 @@ export async function resolveOrgOnlyTarget(
24952500
}
24962501
return resolved.org;
24972502
}
2498-
const resolved = await resolveOrgOptionalTarget(parsed, cwd, commandName);
2503+
const resolved = await resolveOrgOptionalTarget(
2504+
parsed,
2505+
cwd,
2506+
commandName,
2507+
usageHint
2508+
);
24992509
return resolved.org;
25002510
}
25012511

‎packages/cli/test/lib/resolve-target-listing.test.ts‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ vi.mock("../../src/lib/resolve-target.js", async (importOriginal) => {
6868
import * as resolveTargetModule from "../../src/lib/resolve-target.js";
6969
import {
7070
classifyProjectSearchTarget,
71+
resolveOrgOnlyTarget,
7172
resolveOrgOptionalTarget,
7273
resolveOrgProjectOrGuide,
7374
resolveOrgsForListing,
@@ -755,4 +756,22 @@ describe("resolveOrgOptionalTarget bare org slug", () => {
755756
expect(result).toMatchObject({ org: "acme-corp", project: "frontend" });
756757
expect(findProjectsBySlugSpy).toHaveBeenCalledTimes(1);
757758
});
759+
760+
test("org-only mode preserves its usage hint when a bare target is missing", async () => {
761+
findProjectsBySlugSpy.mockResolvedValue({ projects: [], orgs: [] });
762+
const usageHint = "sentry alert metrics create <org>/";
763+
764+
try {
765+
await resolveOrgOnlyTarget(
766+
{ type: "project-search", projectSlug: "missing" },
767+
CWD,
768+
"alert metrics create",
769+
usageHint
770+
);
771+
expect.unreachable("should have thrown");
772+
} catch (error) {
773+
expect(error).toBeInstanceOf(ResolutionError);
774+
expect((error as ResolutionError).hint).toBe(usageHint);
775+
}
776+
});
758777
});

0 commit comments

Comments
 (0)