Skip to content

Consolidate target parsing into positional parsers #1564

Closed

Description

@sentry-junior

parseOrgTarget and parseOrgProjectTarget (packages/cli/src/lib/completion-target.ts, added in #1557) are identity parsers. They only mark a positional's completion kind. Each command still parses and validates the raw string itself inside func, using parseOrgProjectArg, parseSlashSeparatedArg, parseIssueArg, and similar helpers from src/lib/arg-parsing.ts.

  • Commands that share a target syntax repeat the same parse call, and the positional definition and its parsing live in different places.
  • Some flows depend on the raw string reaching func today: buildListCommand rewrites the first positional to catch plural-alias subcommand typos, maybeRecoverWithHelp treats a literal help argument as --help, and some commands auto-recover from the wrong entity type. Parse failures currently surface as CliError subclasses with specific exit codes. Errors thrown from a Stricli parser go through Stricli's argument-error handling instead.

Raised by BYK in review of #1557.

via byk.

--

View Junior Session in Sentry

Activity

  1. linear-code commented on Oct 20, 2026

    @linear-code
  2. sentry-junior commented on Oct 23, 2026

    @sentry-junior
    ContributorAuthor

    Fixed by #1594 (merged 2026-10-23), which adds the target positional parser and moves trace list, replay list, feedback list, project view and project delete onto it. The PR used Refs #1564, so it didn't close this automatically. Closing per @BYK.

  3. sentry-junior commented on Oct 23, 2026

    @sentry-junior
    ContributorAuthor

    Reopening: #1594 landed the lazy parsed/resolved positional mechanism and migrated trace list, replay list, feedback list, project view and project delete, but the migration and some hardening are still open.

    Open PRs that this issue depends on

    New PRs

    Next, in priority order

    1. Harden destructive checks: right now the guard only runs when a destructive command reads .resolved. A command that reads .parsed and then mutates skips it. buildListCommand's re-wrap also drops the destructive mark (no destructive list commands exist today, so this can't trigger yet). The require-target-resolution lint rule is easy to get around.
    2. LazyPositional: memoize parse failures (a failing .parsed re-parses on every read) and avoid unhandled rejections when .resolved is read but never awaited.
    3. Migrate any remaining unblocked positionals. log list, replay view and replay download are variadic or depend on the number of arguments, so they stay in func.

    I'll link the new PRs here as I open them.

  4. sentry-junior commented on Oct 25, 2026

    @sentry-junior
    ContributorAuthor

    Status update:

    Still to do: migrate LIST_TARGET_POSITIONAL users, including agent-conversation list, once #1575 lands, and look at the issue and dashboard targets after #1572. log list, replay view and replay download keep parsing in func.

  5. 16 remaining items

  6. sentry-junior commented on Oct 30, 2026

    @sentry-junior
    ContributorAuthor

    Done. Every target and ID positional in the CLI is now parsed before the command runs, through shared bound parsers. The lint rules that enforce this have no allow-list.

    What changed

    • Target positionals ([<org>/][<project>], org-only, releases, alert rules) use the parsers in src/lib/target-positional.ts / boundPositional / boundArguments. func reads await target.resolved and never parses or resolves by hand.
    • ID positionals go through parseIdArguments() and the shared grammar/id-arguments.pegjs. Issues have their own grammar. Parsing has no side effects: a pasted URL's server is applied when the target resolves, after the auth guard.
    • sentry-cli/require-target-resolution and sentry-cli/no-ad-hoc-id-arguments reject hand parsing in src/commands/, with no exemptions. Before this work, 45 command files used hand-parsing helpers. Now none do.
    • test/lib/argument-conventions.test.ts checks the same argument forms across commands.
    • Every bound parser carries its shell-completion kind. That made the follow-up completion work (feat(cli): Declare a completion kind for every positional #1751) a declaration per argument.

    PRs
    #1711, #1728, #1729, #1730, #1733, #1738, #1739, #1742, #1744, #1745, #1746, #1747, #1749, and the cleanup #1750 (removed the unused completion-only parsers).

    Two regressions came in during the migration and were fixed right after (#1738, #1749).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions