Skip to content

Commit 25cd39f

Browse files
fix: address second round of review findings
- Fix metric edit validateMetricBody using invalid fallback values (skip validation for fields not present in the document) - Fix bare org slug in metrics create misrouted to project-search (append trailing slash for org-all mode) - Fix status check defaulting to 'disabled' when API omits status field — invert to check for disabled (status=1) explicitly - Fix metric view/edit/delete using resolveTargetsFromParsedArg (project-scoped) instead of resolveOrgOptionalProjectFromArg (org-scoped), avoiding misleading 'no accessible projects' error - Remove unused imports (ContextError, parseOrgProjectArg)
1 parent 8a3e7af commit 25cd39f

4 files changed

Lines changed: 32 additions & 38 deletions

File tree

src/commands/alert/metrics/create.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ export const createCommand = buildCommand({
146146
},
147147
aliases: { ...DRY_RUN_ALIASES, t: "trigger", p: "project" },
148148
},
149+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: inherent per-flag validation and org resolution
149150
async *func(this: SentryContext, flags: CreateFlags, arg: string) {
150151
const { cwd } = this;
151152
if (!flags.name.trim()) {
@@ -166,7 +167,10 @@ export const createCommand = buildCommand({
166167
validateMetricTriggers(triggers);
167168
const projects = normalizeProjectList(flags.project);
168169

169-
const parsed = parseOrgProjectArg(arg);
170+
// Metric alerts are org-scoped — treat a bare slug as org-all to avoid
171+
// misrouting through project-search.
172+
const normalizedArg = arg && !arg.includes("/") ? `${arg}/` : arg;
173+
const parsed = parseOrgProjectArg(normalizedArg);
170174
const { targets } = await resolveTargetsFromParsedArg(parsed, {
171175
cwd,
172176
usageHint: USAGE_HINT,
@@ -213,7 +217,7 @@ export const createCommand = buildCommand({
213217

214218
const created = await createMetricAlertRule(orgSlug, body);
215219
const status: "active" | "disabled" =
216-
created.status === 0 || created.status === "0" ? "active" : "disabled";
220+
created.status === 1 || created.status === "1" ? "disabled" : "active";
217221
yield new CommandOutput({
218222
org: orgSlug,
219223
id: String(created.id ?? ""),

src/commands/alert/metrics/delete.ts

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,14 @@
66

77
import type { SentryContext } from "../../../context.js";
88
import { deleteMetricAlertRule } from "../../../lib/api-client.js";
9-
import { parseOrgProjectArg } from "../../../lib/arg-parsing.js";
10-
import { ContextError } from "../../../lib/errors.js";
119
import { CommandOutput } from "../../../lib/formatters/output.js";
1210
import { logger } from "../../../lib/logger.js";
1311
import {
1412
buildDeleteCommand,
1513
confirmByTyping,
1614
isConfirmationBypassed,
1715
} from "../../../lib/mutate-command.js";
18-
import { resolveTargetsFromParsedArg } from "../../../lib/resolve-target.js";
16+
import { resolveOrgOptionalProjectFromArg } from "../../../lib/resolve-target.js";
1917
import { parseMetricRuleArg, resolveMetricAlertRule } from "./rule-resolve.js";
2018

2119
const USAGE_HINT = "sentry alert metrics delete <org>/<rule-id-or-name>";
@@ -74,15 +72,12 @@ export const deleteCommand = buildDeleteCommand({
7472
async *func(this: SentryContext, flags: DeleteFlags, arg: string) {
7573
const { cwd } = this;
7674
const { ref, targetArg } = parseMetricRuleArg(arg, USAGE_HINT);
77-
const parsed = parseOrgProjectArg(targetArg);
78-
const { targets } = await resolveTargetsFromParsedArg(parsed, {
75+
const { org } = await resolveOrgOptionalProjectFromArg(
76+
targetArg,
7977
cwd,
80-
usageHint: USAGE_HINT,
81-
});
82-
const orgSlugs = [...new Set(targets.map((t) => t.org))];
83-
if (orgSlugs.length === 0) {
84-
throw new ContextError("Organization", USAGE_HINT);
85-
}
78+
"alert metrics delete"
79+
);
80+
const orgSlugs = [org];
8681

8782
const { orgSlug, rule } = await resolveMetricAlertRule(
8883
orgSlugs,

src/commands/alert/metrics/edit.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@ import {
99
getMetricAlertRuleDocument,
1010
putMetricAlertRule,
1111
} from "../../../lib/api-client.js";
12-
import { parseOrgProjectArg } from "../../../lib/arg-parsing.js";
1312
import { buildCommand, numberParser } from "../../../lib/command.js";
14-
import { ContextError, ValidationError } from "../../../lib/errors.js";
13+
import { ValidationError } from "../../../lib/errors.js";
1514
import { CommandOutput } from "../../../lib/formatters/output.js";
16-
import { resolveTargetsFromParsedArg } from "../../../lib/resolve-target.js";
15+
import { resolveOrgOptionalProjectFromArg } from "../../../lib/resolve-target.js";
1716
import {
1817
normalizeProjectList,
1918
parseJsonObjectList,
@@ -130,8 +129,12 @@ function validateMetricBody(body: Record<string, unknown>): void {
130129
validateMetricTriggers(
131130
body.triggers as Record<string, unknown>[] | undefined
132131
);
133-
validateMetricDataset(String(body.dataset ?? ""));
134-
validateMetricTimeWindow(Number(body.timeWindow ?? 0));
132+
if (body.dataset !== undefined) {
133+
validateMetricDataset(String(body.dataset));
134+
}
135+
if (body.timeWindow !== undefined) {
136+
validateMetricTimeWindow(Number(body.timeWindow));
137+
}
135138
if (typeof body.query !== "string" || body.query.trim() === "") {
136139
throw new ValidationError("query must be present and non-empty.", "query");
137140
}
@@ -247,15 +250,12 @@ export const editCommand = buildCommand({
247250
const { cwd } = this;
248251
validateMetricEditFlags(flags);
249252
const { ref, targetArg } = parseMetricRuleArg(arg, USAGE_HINT);
250-
const parsed = parseOrgProjectArg(targetArg);
251-
const { targets } = await resolveTargetsFromParsedArg(parsed, {
253+
const { org } = await resolveOrgOptionalProjectFromArg(
254+
targetArg,
252255
cwd,
253-
usageHint: USAGE_HINT,
254-
});
255-
const orgSlugs = [...new Set(targets.map((t) => t.org))];
256-
if (orgSlugs.length === 0) {
257-
throw new ContextError("Organization", USAGE_HINT);
258-
}
256+
"alert metrics edit"
257+
);
258+
const orgSlugs = [org];
259259
const { orgSlug, rule } = await resolveMetricAlertRule(
260260
orgSlugs,
261261
ref,
@@ -273,7 +273,7 @@ export const editCommand = buildCommand({
273273
org: orgSlug,
274274
id: String(updated.id ?? rule.id),
275275
status:
276-
updated.status === 0 || updated.status === "0" ? "active" : "disabled",
276+
updated.status === 1 || updated.status === "1" ? "disabled" : "active",
277277
} satisfies EditResult);
278278
},
279279
});

src/commands/alert/metrics/view.ts

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import type { SentryContext } from "../../../context.js";
2-
import { parseOrgProjectArg } from "../../../lib/arg-parsing.js";
32
import { openInBrowser } from "../../../lib/browser.js";
43
import { buildCommand } from "../../../lib/command.js";
5-
import { ContextError } from "../../../lib/errors.js";
64
import { CommandOutput } from "../../../lib/formatters/output.js";
7-
import { resolveTargetsFromParsedArg } from "../../../lib/resolve-target.js";
5+
import { resolveOrgOptionalProjectFromArg } from "../../../lib/resolve-target.js";
86
import { buildMetricAlertsUrl } from "../../../lib/sentry-urls.js";
97
import {
108
type MetricRuleResolution,
@@ -81,15 +79,12 @@ export const viewCommand = buildCommand({
8179
async *func(this: SentryContext, flags: ViewFlags, arg: string) {
8280
const { cwd } = this;
8381
const { ref, targetArg } = parseMetricRuleArg(arg, USAGE_HINT);
84-
const parsed = parseOrgProjectArg(targetArg);
85-
const { targets } = await resolveTargetsFromParsedArg(parsed, {
82+
const { org } = await resolveOrgOptionalProjectFromArg(
83+
targetArg,
8684
cwd,
87-
usageHint: USAGE_HINT,
88-
});
89-
const orgSlugs = [...new Set(targets.map((target) => target.org))];
90-
if (orgSlugs.length === 0) {
91-
throw new ContextError("Organization", USAGE_HINT);
92-
}
85+
"alert metrics view"
86+
);
87+
const orgSlugs = [org];
9388

9489
const result = await resolveMetricAlertRule(orgSlugs, ref, USAGE_HINT);
9590
if (flags.web) {

0 commit comments

Comments
 (0)