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
3 changes: 3 additions & 0 deletions apps/cli-docs/src/fragments/commands/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ Many commands take an optional `<org>/<project>` target as their first positiona
|--------|---------|
| _(omitted)_ | Auto-detect the org and project from config, DSNs, or the directory name |
| `https://<org>.sentry.io/...` | A Sentry web URL. Selects the org and project in the URL, or the whole organization when it names no project |
| `<org>/<glob>` | Entities in that organization whose names match the glob, e.g. `<org>/web-*` (list commands that filter by name) |
| `<glob>` | Entities whose names match the glob, in the auto-detected organization (list commands that filter by name) |
| `/<glob>` | Same as `<glob>` |
| `<org>/<project>` | That project in that organization |
| `<org>/<project>,<project>` | Several projects in the same organization (commands that accept several projects) |
| `<org>/<Project Name>` | A project in that organization whose display name matches. A target with a space is a name, not a slug |
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ sentry issue list [<org>/<project>] [--json]
|--------|---------|
| _(omitted)_ | Auto-detect the org and project from config, DSNs, or the directory name |
| `https://<org>.sentry.io/...` | A Sentry web URL. Selects the org and project in the URL, or the whole organization when it names no project |
| `<org>/<glob>` | Entities in that organization whose names match the glob, e.g. `<org>/web-*` (list commands that filter by name) |
| `<glob>` | Entities whose names match the glob, in the auto-detected organization (list commands that filter by name) |
| `/<glob>` | Same as `<glob>` |
| `<org>/<project>` | That project in that organization |
| `<org>/<project>,<project>` | Several projects in the same organization (commands that accept several projects) |
| `<org>/<Project Name>` | A project in that organization whose display name matches. A target with a space is a name, not a slug |
Expand Down
19 changes: 17 additions & 2 deletions packages/cli/grammar/org-project-target.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
// copies this file to src/generated/org-project-target-grammar.d.ts and
// rewrites relative imports to resolve from there.

import type { ParsedOrgProject } from "../src/lib/arg-parsing.js";
import type {
ParsedNameFilter,
ParsedOrgProject,
} from "../src/lib/arg-parsing.js";

/**
* Hooks the target grammar calls for character-level validation, so its
Expand All @@ -11,6 +14,11 @@ import type { ParsedOrgProject } from "../src/lib/arg-parsing.js";
export type OrgProjectTargetGrammarOptions = {
/** Accept `<org>/<project>,<project>` lists. */
multi?: boolean;
/**
* Whether the rest of `[<org>/]<rest>` is a name filter (a glob) rather
* than a project. List commands that filter by name pass it.
*/
isNameFilter?: (value: string) => boolean;
/** Throw when `value` is not a valid slug. */
checkSlug: (value: string, label: string) => void;
/** Throw when `value` starts with `@`. */
Expand All @@ -29,5 +37,12 @@ export declare class SyntaxError extends Error {
/** Parse a non-empty target that is not a URL. */
export declare function parse(
input: string,
options: OrgProjectTargetGrammarOptions,
options: OrgProjectTargetGrammarOptions & { isNameFilter?: undefined },
): Exclude<ParsedOrgProject, { type: "auto-detect" }>;
/** Parse a non-empty list target that is not a URL; globs are name filters. */
export declare function parse(
input: string,
options: OrgProjectTargetGrammarOptions & {
isNameFilter: (value: string) => boolean;
},
): Exclude<ParsedOrgProject, { type: "auto-detect" }> | ParsedNameFilter;
36 changes: 31 additions & 5 deletions packages/cli/grammar/org-project-target.pegjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
// Grammar for the `[<org>/][<project>[,<project>...]]` target positional.
// Grammar for the `[<org>/][<project>[,<project>...]]` target positional,
// and the `[<org>/]<glob>` name filter of list commands.
// `pnpm run generate:grammar` compiles it, with the types in
// org-project-target.d.ts, into the gitignored src/generated/; the build,
// typecheck, and test scripts run it.
//
// `parseOrgProjectArg()` (src/lib/arg-parsing.ts) runs this parser after it
// keeps the first non-blank line and handles the omitted and URL forms. The
// grammar owns the structure; character-level checks go through the
// `checkSlug`, `rejectAt`, and `invalid` hooks in `options`, so its errors
// match the rest of the CLI.
// `checkSlug`, `rejectAt`, `invalid`, and `isNameFilter` hooks in `options`,
// so its errors and glob syntax match the rest of the CLI.
//
// The target syntax tables in the docs are generated from the `@form` lines
// here (script/generate-docs-sections.ts). Every `target` alternative needs
Expand All @@ -22,7 +23,22 @@
// project in the URL, or the whole organization when it names no project

{
const { multi = false, checkSlug, rejectAt, invalid } = options;
const { multi = false, isNameFilter, checkSlug, rejectAt, invalid } =
options;

// List commands pass `isNameFilter`: a target it accepts (a glob, which no
// slug can be) filters names instead of naming a project.
function isFilter(value) {
return isNameFilter !== undefined && isNameFilter(value);
}

function nameFilter(value, org) {
return {
type: "name-filter",
filter: value.trim(),
...(org !== undefined && { org }),
};
}

function slug(value, label) {
rejectAt(value, label);
Expand Down Expand Up @@ -80,8 +96,15 @@
// rejected as an organization slug before it is parsed as a project (covered
// by "@latest throws with redirect to issue view" in arg-parsing.test.ts).
target
// @form `<org>/<glob>` — Entities in that organization whose names match
// the glob, e.g. `<org>/web-*` (list commands that filter by name)
= o:org "/" g:rest &{ return isFilter(g); } { return nameFilter(g, orgSlug(o)); }
// @form `<glob>` — Entities whose names match the glob, in the
// auto-detected organization (list commands that filter by name)
// @form `/<glob>` — Same as `<glob>`
/ "/"? g:rest &{ return isFilter(g); } { return nameFilter(g); }
// @form `<org>/<project>` — That project in that organization
= o:org "/" p:slug !{ return multi && p.includes(","); }
/ o:org "/" p:slug !{ return multi && p.includes(","); }
{ const org = orgSlug(o); return { type: "explicit", org, project: projectSlug(p) }; }
// @form `<org>/<project>,<project>` — Several projects in the same
// organization (commands that accept several projects)
Expand All @@ -106,6 +129,9 @@ target
// Everything before the first slash.
org = $[^/]+

// The rest of the input when it has no more slashes.
rest = $([^/]* !.)

// The rest of the input when it has no spaces. Slashes, commas, and other
// characters are kept so `checkSlug` reports them.
slug = $([^ ]+ !.)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ List installed integrations

| Argument | Description |
|----------|-------------|
| `[<org/project>]` | &lt;org&gt;/ (all projects), &lt;org&gt;/&lt;project&gt;, or &lt;project&gt; (search) |
| `[<org/project>]` | &lt;org&gt;/ (all), &lt;org&gt;/&lt;name&gt; or &lt;name&gt; (a project, else matching names), or a name glob (&lt;org&gt;/web-*) |

**Flags:**
- `-n, --limit <value> - Maximum number of integrations to list - (default: "25")`
Expand Down Expand Up @@ -50,6 +50,12 @@ sentry integration list my-org/
# Fetch the next page
sentry integration list my-org/ -c next

# Only integrations whose name or provider matches a glob
sentry integration list 'my-org/git*'

# Integrations named like 'GitHub' (fuzzy when nothing matches exactly)
sentry integration list my-org/githb

# Output as JSON
sentry integration list --json
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ List cron monitors

| Argument | Description |
|----------|-------------|
| `[<org/project>]` | &lt;org&gt;/ (all projects), &lt;org&gt;/&lt;project&gt;, or &lt;project&gt; (search) |
| `[<org/project>]` | &lt;org&gt;/ (all), &lt;org&gt;/&lt;name&gt; or &lt;name&gt; (a project, else matching names), or a name glob (&lt;org&gt;/web-*) |

**Flags:**
- `-n, --limit <value> - Maximum number of monitors to list - (default: "25")`
Expand Down Expand Up @@ -84,6 +84,12 @@ sentry monitor list my-org/
# Fetch the next page
sentry monitor list my-org/ -c next

# Only monitors whose slug or name matches a glob
sentry monitor list 'my-org/nightly-*'

# Monitors named like 'nightly' (fuzzy when nothing matches exactly)
sentry monitor list my-org/nigthly

# Output as JSON
sentry monitor list --json
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ List projects

| Argument | Description |
|----------|-------------|
| `[<org/project>]` | &lt;org&gt;/ (all projects), &lt;org&gt;/&lt;project&gt;, or &lt;project&gt; (search) |
| `[<org/project>]` | &lt;org&gt;/ (all), &lt;org&gt;/&lt;name&gt; or &lt;name&gt; (a project, else matching names), or a name glob (&lt;org&gt;/web-*) |

**Flags:**
- `-n, --limit <value> - Maximum number of projects to list - (default: "25")`
Expand All @@ -105,6 +105,12 @@ sentry project list my-org/frontend,backend
# Filter by platform
sentry project list my-org/ --platform javascript

# Only projects whose slug or name matches a glob
sentry project list 'my-org/web-*'

# Projects named like 'frontend' (fuzzy when nothing matches exactly)
sentry project list my-org/frontnd

# Find a project across organizations
sentry project list frontend

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ List repositories

| Argument | Description |
|----------|-------------|
| `[<org/project>]` | &lt;org&gt;/ (all projects), &lt;org&gt;/&lt;project&gt;, or &lt;project&gt; (search) |
| `[<org/project>]` | &lt;org&gt;/ (all), &lt;org&gt;/&lt;name&gt; or &lt;name&gt; (a project, else matching names), or a name glob (&lt;org&gt;/web-*) |

**Flags:**
- `-n, --limit <value> - Maximum number of repositories to list - (default: "25")`
Expand Down Expand Up @@ -52,6 +52,12 @@ sentry repo list my-org/
# Fetch the next page
sentry repo list my-org/ -c next

# Only repositories whose name matches a glob
sentry repo list 'my-org/getsentry/*'
Comment thread
sentry-junior[bot] marked this conversation as resolved.

# Repositories named like 'sentry-python' (fuzzy when nothing matches exactly)
sentry repo list my-org/sentry-pyhton

# Output as JSON
sentry repo list --json
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ List teams

| Argument | Description |
|----------|-------------|
| `[<org/project>]` | &lt;org&gt;/ (all projects), &lt;org&gt;/&lt;project&gt;, or &lt;project&gt; (search) |
| `[<org/project>]` | &lt;org&gt;/ (all), &lt;org&gt;/&lt;name&gt; or &lt;name&gt; (a project, else matching names), or a name glob (&lt;org&gt;/web-*) |

**Flags:**
- `-n, --limit <value> - Maximum number of teams to list - (default: "25")`
Expand Down Expand Up @@ -50,6 +50,12 @@ sentry team list my-org/
# Fetch the next page
sentry team list my-org/ -c next

# Only teams whose slug or name matches a glob
sentry team list 'my-org/back*'

# Teams named like 'backend' when no such project exists (fuzzy)
sentry team list my-org/backnd

# Output as JSON
sentry team list --json
```
Expand Down
13 changes: 13 additions & 0 deletions packages/cli/src/commands/integration/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ const integrationListConfig: OrgListConfig<
listForOrg: (org) => listIntegrations(org),
listPaginated: (org, opts) => listIntegrationsPaginated(org, opts),
withOrg: (integration, orgSlug) => ({ ...integration, orgSlug }),
// The install label (e.g. a GitHub org) and the product (`GitHub`), so
// `<org>/git*` finds GitHub installs whatever their label.
namesOf: (integration) => [integration.name, integration.provider.name],
displayTable: (integrations: IntegrationWithOrg[]) =>
formatTable(integrations, INTEGRATION_COLUMNS),
schema: SentryIntegrationSchema,
Expand All @@ -58,6 +61,7 @@ const docs: OrgListCommandDocs = {
fullDescription:
"List integrations installed on an organization (GitHub, GitLab, Slack, Jira, ...).\n\n" +
"Includes integrations that are disabled or pending deletion.\n\n" +
"`<org>/<name>` lists integrations whose name or provider matches `<name>`, a glob (`<org>/git*`) or text: exact or partial matches first, then close (fuzzy) matches. A bare `<name>` that is no project does the same in the detected organizations. Name filters can't be combined with --cursor.\n\n" +
"Alias: `sentry integrations` → `sentry integration list`",
examples: [
{
Expand All @@ -72,6 +76,15 @@ const docs: OrgListCommandDocs = {
description: "Fetch the next page",
command: "sentry integration list my-org/ -c next",
},
{
description: "Only integrations whose name or provider matches a glob",
command: "sentry integration list 'my-org/git*'",
},
{
description:
"Integrations named like 'GitHub' (fuzzy when nothing matches exactly)",
command: "sentry integration list my-org/githb",
},
{
description: "Output as JSON",
command: "sentry integration list --json",
Expand Down
12 changes: 12 additions & 0 deletions packages/cli/src/commands/monitor/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ const monitorListConfig: OrgListConfig<SentryMonitor, MonitorWithOrg> = {
listForOrg: (org) => listMonitors(org),
listPaginated: (org, opts) => listMonitorsPaginated(org, opts),
withOrg: (monitor, orgSlug) => ({ ...monitor, orgSlug }),
namesOf: (monitor) => [monitor.slug, monitor.name],
searchesNames: true,
displayTable: (monitors: MonitorWithOrg[]) =>
formatTable(monitors, MONITOR_COLUMNS),
schema: SentryMonitorSchema,
Expand All @@ -75,6 +77,7 @@ const docs: OrgListCommandDocs = {
brief: "List cron monitors",
fullDescription:
"List cron monitors in an organization.\n\n" +
"`<org>/<name>` lists monitors whose slug or name matches `<name>`, a glob (`<org>/nightly-*`) or text: exact or partial matches first, then close (fuzzy) matches. A bare `<name>` that is no project does the same in the detected organizations. Name filters can't be combined with --cursor.\n\n" +
"Alias: `sentry monitors` → `sentry monitor list`",
examples: [
{
Expand All @@ -89,6 +92,15 @@ const docs: OrgListCommandDocs = {
description: "Fetch the next page",
command: "sentry monitor list my-org/ -c next",
},
{
description: "Only monitors whose slug or name matches a glob",
command: "sentry monitor list 'my-org/nightly-*'",
},
{
description:
"Monitors named like 'nightly' (fuzzy when nothing matches exactly)",
command: "sentry monitor list my-org/nigthly",
},
{ description: "Output as JSON", command: "sentry monitor list --json" },
],
};
Expand Down
Loading
Loading