From 50aa0b035a1325dfdcfa75fc3e0802bfa3bb04ef Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Wed, 28 Oct 2026 21:35:01 +0000 Subject: [PATCH 1/2] feat(runner)!: Rename the sentry console script to sentry-server The server's `sentry` entry point shadows the Sentry CLI (getsentry/cli) in dev venvs. Rename it to `sentry-server` and stop deleting other `sentry` binaries in .envrc and postinstall so the CLI can win. devenv sync removes the stale `.venv/bin/sentry` that fast_editable leaves behind. The self-hosted image keeps a deprecated `sentry` symlink for existing manifests. Co-Authored-By: David Cramer --- .agents/skills/cell-architecture/SKILL.md | 2 +- .agents/skills/generate-migration/SKILL.md | 10 ++--- .../references/backfill.md | 2 +- .agents/skills/setup-dev/SKILL.md | 14 +++---- .../setup-dev/references/orbstack-fix.md | 4 +- .envrc | 31 ++------------- .github/actions/setup-sentry/action.yml | 2 +- .github/workflows/backend.yml | 2 +- .github/workflows/migrations.yml | 2 +- .github/workflows/openapi-diff.yml | 2 +- .github/workflows/openapi.yml | 2 +- .github/workflows/scripts/migration-check.sh | 6 +-- .vscode/launch.json | 4 +- Makefile | 16 ++++---- bin/dump-command-help | 2 +- devenv/sync.py | 11 +++++- devservices/config.yml | 38 +++++++++---------- package.json | 3 +- scripts/lib.sh | 8 ++-- self-hosted/Dockerfile | 8 +++- self-hosted/config.yml | 2 +- self-hosted/docker_entrypoint.py | 7 ++-- setup.cfg | 2 +- src/sentry/backup/scopes.py | 4 +- src/sentry/build/dump_cli_commands.py | 4 +- src/sentry/conf/server.py | 6 +-- src/sentry/consumers/__init__.py | 4 +- src/sentry/data/config/config.yml.default | 2 +- src/sentry/issue_detection/README.md | 2 +- src/sentry/logging/README.rst | 2 +- src/sentry/models/importchunk.py | 2 +- src/sentry/options/defaults.py | 2 +- src/sentry/receivers/users.py | 2 +- src/sentry/runner/boot_gc.py | 2 +- src/sentry/runner/commands/deletions.py | 2 +- src/sentry/runner/commands/devserver.py | 12 +++--- src/sentry/runner/commands/devservices.py | 2 +- src/sentry/runner/commands/exec.py | 8 ++-- src/sentry/runner/commands/notifications.py | 12 +++--- .../commands/presenters/consolepresenter.py | 2 +- .../commands/presenters/webhookpresenter.py | 2 +- src/sentry/runner/commands/run.py | 8 ++-- src/sentry/runner/commands/start.py | 7 ++-- src/sentry/runner/initializer.py | 2 +- src/sentry/runner/main.py | 2 +- src/sentry/runner/settings.py | 4 +- src/sentry/signals.py | 2 +- src/sentry/silo/README.md | 8 ++-- src/sentry/wsgi.py | 2 +- tests/sentry/runner/commands/test_backup.py | 8 ++-- tests/sentry/test_wsgi.py | 2 +- 51 files changed, 142 insertions(+), 155 deletions(-) diff --git a/.agents/skills/cell-architecture/SKILL.md b/.agents/skills/cell-architecture/SKILL.md index 8c1e488a350e..2e7c5d230f50 100644 --- a/.agents/skills/cell-architecture/SKILL.md +++ b/.agents/skills/cell-architecture/SKILL.md @@ -140,7 +140,7 @@ Project.objects.filter(teams__organizationmember__user_id=user_id) ```bash devservices up --mode cell-routing # brings up synapse + deps -SENTRY_CELL_ROUTING=1 sentry devserver --client-hostname=dev.getsentry.net # or devservices serve +SENTRY_CELL_ROUTING=1 sentry-server devserver --client-hostname=dev.getsentry.net # or devservices serve ``` Only cell-scoped API XHRs (`/api/0/organizations/{slug}/*`) cross to Synapse on `:13000`; UI HTML and control API stay on the sentry devserver at `:8000`. The env var gates a block in `src/sentry/conf/server.py` that sets `system.region-api-url-template` to the Synapse port and flips `system:multi-region`. The frontend reads `regionUrl` from the bootstrap blob and routes cell XHRs there per `static/app/api.tsx:715`. diff --git a/.agents/skills/generate-migration/SKILL.md b/.agents/skills/generate-migration/SKILL.md index f572f3b9661d..a0eba2aeff28 100644 --- a/.agents/skills/generate-migration/SKILL.md +++ b/.agents/skills/generate-migration/SKILL.md @@ -10,27 +10,27 @@ description: Generate or review Django database migrations for Sentry. Use when Generate migrations automatically based on model changes: ```bash -sentry django makemigrations +sentry-server django makemigrations ``` For a specific app: ```bash -sentry django makemigrations +sentry-server django makemigrations ``` Generate an empty migration (for data migrations or custom work): ```bash -sentry django makemigrations --empty +sentry-server django makemigrations --empty ``` ## After Generating 1. If you added a new model, ensure it's imported in the app's `__init__.py` 2. Review the generated migration for correctness -3. Run `sentry django sqlmigrate ` to verify the SQL -4. Apply the migration locally with `sentry django migrate ` — Sentry's migration framework runs its safety checks on apply, so this catches unsafe ops (missing `is_post_deployment`, unsafe column changes, etc.) before CI does. +3. Run `sentry-server django sqlmigrate ` to verify the SQL +4. Apply the migration locally with `sentry-server django migrate ` — Sentry's migration framework runs its safety checks on apply, so this catches unsafe ops (missing `is_post_deployment`, unsafe column changes, etc.) before CI does. When editing a generated migration (e.g. swapping `DeleteModel` for `SafeDeleteModel`), **leave the auto-generated `is_post_deployment` comment block in place**. It documents a non-obvious flag with concrete guidance for future migration authors — useful context, not fluff. Only remove a comment if it's stale or contradicts the code. diff --git a/.agents/skills/hybrid-cloud-outboxes/references/backfill.md b/.agents/skills/hybrid-cloud-outboxes/references/backfill.md index 35028239e75f..a56b83cc2c83 100644 --- a/.agents/skills/hybrid-cloud-outboxes/references/backfill.md +++ b/.agents/skills/hybrid-cloud-outboxes/references/backfill.md @@ -80,7 +80,7 @@ This two-step process allows deploying code first, then enabling the backfill se ### Self-Hosted (Synchronous) -On self-hosted instances, backfills run synchronously during `sentry upgrade` via the `run_outbox_replications_for_self_hosted` function (connected to the `post_upgrade` signal). This function: +On self-hosted instances, backfills run synchronously during `sentry-server upgrade` via the `run_outbox_replications_for_self_hosted` function (connected to the `post_upgrade` signal). This function: 1. Calls `backfill_outboxes_for(force_synchronous=True)` — bypasses options, uses `model.replication_version` directly 2. Drains all pending outbox shards diff --git a/.agents/skills/setup-dev/SKILL.md b/.agents/skills/setup-dev/SKILL.md index d650a84e48f2..7c7745f4d1f5 100644 --- a/.agents/skills/setup-dev/SKILL.md +++ b/.agents/skills/setup-dev/SKILL.md @@ -40,7 +40,7 @@ which colima 2>/dev/null && colima status 2>/dev/null which direnv 2>/dev/null # Check if repo is already set up -ls .venv/bin/sentry 2>/dev/null && ls node_modules/.bin 2>/dev/null +ls .venv/bin/sentry-server 2>/dev/null && ls node_modules/.bin 2>/dev/null ``` Based on results, skip to the appropriate step. If everything is installed, jump to Step 6. @@ -235,17 +235,17 @@ If only Colima is checked, patch it to support all runtimes. Read `references/or If this is a first-time setup, the database needs seeding: ```bash -.venv/bin/sentry upgrade --noinput +.venv/bin/sentry-server upgrade --noinput ``` This runs all Django migrations AND creates default data (organizations, roles, projects). Without this, the dev server will 500 on every page. -**Do NOT just run `sentry django migrate`** — that only runs migrations without seeding the required default data. +**Do NOT just run `sentry-server django migrate`** — that only runs migrations without seeding the required default data. ### Create Superuser ```bash -.venv/bin/sentry createuser --superuser --email admin@sentry.io --password admin --no-input +.venv/bin/sentry-server createuser --superuser --email admin@sentry.io --password admin --no-input ``` ## Step 7: Start the Dev Server @@ -257,7 +257,7 @@ devservices serve Or directly: ```bash -.venv/bin/sentry devserver +.venv/bin/sentry-server devserver ``` ### What to Expect on Startup @@ -317,8 +317,8 @@ Each worktree has its own `.venv`. When you create a worktree with `git worktree | direnv hangs | Docker runtime not running | Start OrbStack / Colima | | `devenv sync` fails with version error | Outdated devenv | `devenv update` or reinstall | | `devservices up` says "colima not running" | Using OrbStack, script only checks Colima | Patch `devservices.py` — see Step 6 | -| Server 500s on every page | DB not seeded | `.venv/bin/sentry upgrade --noinput` | -| `relation "sentry_organization" does not exist` | Migrations not run | `.venv/bin/sentry upgrade --noinput` | +| Server 500s on every page | DB not seeded | `.venv/bin/sentry-server upgrade --noinput` | +| `relation "sentry_organization" does not exist` | Migrations not run | `.venv/bin/sentry-server upgrade --noinput` | | White/blank screen in browser | Cookie Sync extension missing | Install the Chrome extension | | Kafka topic warnings on startup | Normal first-boot behavior | Wait 30-60 seconds | | Port already in use | Stale containers | `docker rm -f $(docker ps -aq)` then retry | diff --git a/.agents/skills/setup-dev/references/orbstack-fix.md b/.agents/skills/setup-dev/references/orbstack-fix.md index 9a51b3c3f4ae..cf9de8811cba 100644 --- a/.agents/skills/setup-dev/references/orbstack-fix.md +++ b/.agents/skills/setup-dev/references/orbstack-fix.md @@ -1,6 +1,6 @@ # OrbStack Docker Socket Fix -When `devservices serve` or `sentry devserver` fails with "Make sure colima is running" for OrbStack users, the issue is in `src/sentry/runner/commands/devservices.py`. +When `devservices serve` or `sentry-server devserver` fails with "Make sure colima is running" for OrbStack users, the issue is in `src/sentry/runner/commands/devservices.py`. ## The Problem @@ -49,4 +49,4 @@ After patching: 1. Remove any symlinks: `rm -f ~/.colima/default/docker.sock` (if it was a symlink to OrbStack) 2. Ensure OrbStack is running: `orbctl status` -3. Run: `.venv/bin/sentry devserver` — should detect OrbStack's socket automatically +3. Run: `.venv/bin/sentry-server devserver` — should detect OrbStack's socket automatically diff --git a/.envrc b/.envrc index 274704dc0ac3..9b5debc85011 100644 --- a/.envrc +++ b/.envrc @@ -126,8 +126,7 @@ PATH_rm "/opt/homebrew/bin" # homebrew must not be searched first, we need venv and devenv to take precedence PATH_add "/opt/homebrew/bin" -# PATH_add prepends, so entries listed earlier rank lower. npm ships a binary -# named `sentry`, which must not shadow the venv's. +# PATH_add prepends, so entries listed earlier rank lower. PATH_add node_modules/.bin ### Python ### @@ -150,8 +149,8 @@ https://github.com/getsentry/devenv#install ' fi -if ! [ -x "${VIRTUAL_ENV}/bin/sentry" ]; then - warn "Your virtualenv is activated, but sentry doesn't seem to be installed." +if ! [ -x "${VIRTUAL_ENV}/bin/sentry-server" ]; then + warn "Your virtualenv is activated, but sentry-server doesn't seem to be installed." commands_to_run+=("devenv sync") fi @@ -161,30 +160,6 @@ PATH_add "${PWD}/.devenv/bin" # gcloud and friends PATH_add "/opt/homebrew/share/google-cloud-sdk/bin" -# pnpm prepends node_modules/.bin to PATH, even when the venv comes first here. -rm -f node_modules/.bin/sentry -hash -r - -# Only remove shadowing executables once the expected command is installed. -if [ -x "${VIRTUAL_ENV}/bin/sentry" ]; then - while [ "$(command -v sentry)" != "${VIRTUAL_ENV}/bin/sentry" ]; do - sentry_path="$(command -v sentry || true)" - if [ "$(type -t sentry)" != "file" ] || [ ! -f "$sentry_path" ] || [ "$sentry_path" -ef "${VIRTUAL_ENV}/bin/sentry" ]; then - die "Expected sentry to resolve to ${VIRTUAL_ENV}/bin/sentry, got: ${sentry_path:-not found}" - fi - # Resolve parent directories, not the executable: unlinking a local shim - # is safe, but following a directory symlink could delete a global tool. - sentry_dir="$(cd -- "$(dirname -- "$sentry_path")" && pwd -P)" - case "$sentry_dir/" in - "$(pwd -P)/"*) ;; - *) die "Refusing to remove $sentry_path outside this checkout. Adjust PATH so ${VIRTUAL_ENV}/bin/sentry takes precedence." ;; - esac - info "Removing $sentry_path: it shadows ${VIRTUAL_ENV}/bin/sentry" - rm -f -- "$sentry_path" - hash -r - done -fi - ### prek ### debug "Checking prek..." diff --git a/.github/actions/setup-sentry/action.yml b/.github/actions/setup-sentry/action.yml index a806960c3758..673406bec987 100644 --- a/.github/actions/setup-sentry/action.yml +++ b/.github/actions/setup-sentry/action.yml @@ -158,7 +158,7 @@ runs: DEVSERVICES_MODE: ${{ inputs.mode }} GITHUB_TOKEN: ${{ github.token }} run: | - sentry init + sentry-server init if [ "$EARLY_DEVSERVICES" = true ]; then python3 "$ACTION_PATH/devservices-bg.py" wait diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml index cff0e58eb5e5..688f7492376f 100644 --- a/.github/workflows/backend.yml +++ b/.github/workflows/backend.yml @@ -626,7 +626,7 @@ jobs: - name: setup sentry (lite) run: | python3 -m tools.fast_editable --path . - sentry init + sentry-server init - run: PYTHONWARNINGS=error::RuntimeWarning mypy id: run diff --git a/.github/workflows/migrations.yml b/.github/workflows/migrations.yml index 4a1f51d0a037..81f7f82ac7e4 100644 --- a/.github/workflows/migrations.yml +++ b/.github/workflows/migrations.yml @@ -57,7 +57,7 @@ jobs: - name: Apply migrations run: | - sentry upgrade --noinput + sentry-server upgrade --noinput # Checkout the current ref - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 diff --git a/.github/workflows/openapi-diff.yml b/.github/workflows/openapi-diff.yml index 08f985e903dd..9f599adbaa05 100644 --- a/.github/workflows/openapi-diff.yml +++ b/.github/workflows/openapi-diff.yml @@ -61,7 +61,7 @@ jobs: if: steps.changes.outputs.api_docs == 'true' run: | mkdir schemas - sentry rpcschema --loglevel=WARNING > rpc_method_schema.json + sentry-server rpcschema --loglevel=WARNING > rpc_method_schema.json # Runs oasdiff directly from the getsentry/image-mirror copy instead of # oasdiff/oasdiff-action, which builds FROM tufin/oasdiff:main on Docker Hub. diff --git a/.github/workflows/openapi.yml b/.github/workflows/openapi.yml index dd0acd33f667..0b30befceefb 100644 --- a/.github/workflows/openapi.yml +++ b/.github/workflows/openapi.yml @@ -61,7 +61,7 @@ jobs: - name: Build RPC method schema if: steps.changes.outputs.api_docs == 'true' run: | - sentry rpcschema --loglevel=WARNING > rpc_method_schema.json + sentry-server rpcschema --loglevel=WARNING > rpc_method_schema.json - name: Copy artifacts into getsentry/sentry-api-schema if: steps.changes.outputs.api_docs == 'true' diff --git a/.github/workflows/scripts/migration-check.sh b/.github/workflows/scripts/migration-check.sh index f98212055a9d..0fa9c6d2f3b3 100755 --- a/.github/workflows/scripts/migration-check.sh +++ b/.github/workflows/scripts/migration-check.sh @@ -4,12 +4,12 @@ set -eu # This will fail if a migration or the lockfile are missing in the PR exit_code=0 -sentry django makemigrations --check --dry-run --no-input || exit_code=$? +sentry-server django makemigrations --check --dry-run --no-input || exit_code=$? if [ "$exit_code" == 1 ]; then echo -e "::error::Error: Migration required -- to generate a migration, run:\n" \ - "sentry django makemigrations -n && git add migrations_lockfile.txt" >&2 + "sentry-server django makemigrations -n && git add migrations_lockfile.txt" >&2 elif [ "$exit_code" == 2 ]; then echo -e "::error::Error: Migration lockfile mismatch -- run:\n" \ - "sentry django makemigrations -n && git add migrations_lockfile.txt" >&2 + "sentry-server django makemigrations -n && git add migrations_lockfile.txt" >&2 fi exit $exit_code diff --git a/.vscode/launch.json b/.vscode/launch.json index cadc0e95369c..d877c35e1d20 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -16,7 +16,7 @@ "type": "python", "request": "launch", "stopOnEntry": true, - "program": "${workspaceRoot}/.venv/bin/sentry", + "program": "${workspaceRoot}/.venv/bin/sentry-server", "args": ["devserver"], "cwd": "${workspaceRoot}", "debugOptions": [ @@ -29,7 +29,7 @@ "name": "sentry backend debug", "type": "python", "request": "launch", - "program": "${workspaceRoot}/.venv/bin/sentry", + "program": "${workspaceRoot}/.venv/bin/sentry-server", "args": ["devserver", "--debug-server", "--no-pretty"], "cwd": "${workspaceRoot}" }, diff --git a/Makefile b/Makefile index 5ae653eb2238..5809fd8a7fcb 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ build-js-po: build-spectacular-docs: @echo "--> Building drf-spectacular openapi spec (combines with deprecated docs)" - @OPENAPIGENERATE=1 sentry django spectacular --file tests/apidocs/openapi-spectacular.json --format openapi-json --validate --fail-on-warn + @OPENAPIGENERATE=1 sentry-server django spectacular --file tests/apidocs/openapi-spectacular.json --format openapi-json --validate --fail-on-warn build-deprecated-docs: @echo "--> Building deprecated openapi spec from json files" @@ -51,7 +51,7 @@ build-api-docs: build-deprecated-docs build-spectacular-docs # Opt-in private schema for local review; never included in the public docs build. build-investigation-api-docs: build-deprecated-docs @mkdir -p .artifacts/investigation-api-docs - @OPENAPIGENERATE=1 sentry django spectacular --custom-settings sentry.investigations.apidocs.PRIVATE_SCHEMA_SETTINGS --file .artifacts/investigation-api-docs/openapi.json --format openapi-json --validate --fail-on-warn + @OPENAPIGENERATE=1 sentry-server django spectacular --custom-settings sentry.investigations.apidocs.PRIVATE_SCHEMA_SETTINGS --file .artifacts/investigation-api-docs/openapi.json --format openapi-json --validate --fail-on-warn pnpm exec node api-docs/index.ts .artifacts/investigation-api-docs/openapi.json .artifacts/investigation-api-docs/openapi-derefed.json pnpm --filter @sentry-internal/api-docs exec openapi-examples-validator ../.artifacts/investigation-api-docs/openapi-derefed.json --no-additional-properties @@ -71,13 +71,13 @@ build: locale merge-locale-catalogs: build-js-po uv pip install Babel - cd src/sentry && sentry django makemessages -i static -l en + cd src/sentry && sentry-server django makemessages -i static -l en ./bin/merge-catalogs en compile-locale: uv pip install Babel ./bin/find-good-catalogs src/sentry/locale/catalogs.json - cd src/sentry && sentry django compilemessages + cd src/sentry && sentry-server django compilemessages install-transifex: uv pip install transifex-client @@ -107,10 +107,10 @@ test-cli: create-db @echo "--> Testing CLI" rm -rf test_cli mkdir test_cli - cd test_cli && sentry init test_conf - cd test_cli && sentry --config=test_conf help - cd test_cli && sentry --config=test_conf upgrade --traceback --noinput - cd test_cli && sentry --config=test_conf export --help + cd test_cli && sentry-server init test_conf + cd test_cli && sentry-server --config=test_conf help + cd test_cli && sentry-server --config=test_conf upgrade --traceback --noinput + cd test_cli && sentry-server --config=test_conf export --help rm -r test_cli @echo "" diff --git a/bin/dump-command-help b/bin/dump-command-help index e79057617a8f..2ef71282f16e 100755 --- a/bin/dump-command-help +++ b/bin/dump-command-help @@ -108,7 +108,7 @@ def dump_command(out, cmd, path): @click.command() @click.option("--output-path", "out", type=click.Path(), default="build/cli-help") def cli(out): - dump_command(out, root_command, ["sentry"]) + dump_command(out, root_command, ["sentry-server"]) if __name__ == "__main__": diff --git a/devenv/sync.py b/devenv/sync.py index 3becdd58229b..8c357b964895 100644 --- a/devenv/sync.py +++ b/devenv/sync.py @@ -306,6 +306,13 @@ def main(context: dict[str, str]) -> int: ): return 1 + # fast_editable never deletes console scripts, so the pre-rename `sentry` script + # would linger and shadow the Sentry CLI. TODO: Remove once venvs have synced. + try: + os.remove(f"{venv_dir}/bin/sentry") + except FileNotFoundError: + pass + # Agent skills are non-fatal — private skill repos may not be accessible in CI if os.path.exists(f"{reporoot}/agents.toml") and shutil.which( "pnpm", path=f"{reporoot}/.devenv/bin" @@ -330,7 +337,7 @@ def main(context: dict[str, str]) -> int: if not os.path.exists(f"{sentry_conf}/config.yml") or not os.path.exists( f"{sentry_conf}/sentry.conf.py" ): - proc.run((f"{venv_dir}/bin/sentry", "init", "--dev")) + proc.run((f"{venv_dir}/bin/sentry-server", "init", "--dev")) if not run_procs( repo, @@ -386,7 +393,7 @@ def main(context: dict[str, str]) -> int: if stdout != "t": proc.run( ( - f"{venv_dir}/bin/sentry", + f"{venv_dir}/bin/sentry-server", "createuser", "--superuser", "--email", diff --git a/devservices/config.yml b/devservices/config.yml index 8bfa916cfe5f..32c7ea44e318 100644 --- a/devservices/config.yml +++ b/devservices/config.yml @@ -398,43 +398,43 @@ x-sentry-service-config: x-programs: devserver: - command: sentry devserver + command: sentry-server devserver taskworker: - command: sentry run taskworker --autoreload + command: sentry-server run taskworker --autoreload taskworker-sentry: - command: sentry run taskworker --autoreload --rpc-host localhost:50052 + command: sentry-server run taskworker --autoreload --rpc-host localhost:50052 taskworker-scheduler: - command: sentry run taskworker-scheduler + command: sentry-server run taskworker-scheduler ingest-events: - command: sentry run consumer ingest-events --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset + command: sentry-server run consumer ingest-events --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset ingest-attachments: - command: sentry run consumer ingest-attachments --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset + command: sentry-server run consumer ingest-attachments --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset ingest-transactions: - command: sentry run consumer ingest-transactions --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset + command: sentry-server run consumer ingest-transactions --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset ingest-monitors: - command: sentry run consumer ingest-monitors --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset + command: sentry-server run consumer ingest-monitors --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset monitors-clock-tick: - command: sentry run consumer monitors-clock-tick --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset + command: sentry-server run consumer monitors-clock-tick --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset monitors-clock-tasks: - command: sentry run consumer monitors-clock-tasks --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset + command: sentry-server run consumer monitors-clock-tasks --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset monitors-incident-occurrences: - command: sentry run consumer monitors-incident-occurrences --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset + command: sentry-server run consumer monitors-incident-occurrences --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset ingest-occurrences: - command: sentry run consumer ingest-occurrences --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset + command: sentry-server run consumer ingest-occurrences --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset process-spans: - command: sentry run consumer process-spans --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset + command: sentry-server run consumer process-spans --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset ingest-metrics: - command: sentry run consumer ingest-metrics --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset + command: sentry-server run consumer ingest-metrics --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset uptime-results: - command: sentry run consumer uptime-results --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset + command: sentry-server run consumer uptime-results --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset post-process-forwarder-errors: - command: sentry run consumer post-process-forwarder-errors --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset + command: sentry-server run consumer post-process-forwarder-errors --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset post-process-forwarder-transactions: - command: sentry run consumer post-process-forwarder-transactions --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset + command: sentry-server run consumer post-process-forwarder-transactions --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset post-process-forwarder-issue-platform: - command: sentry run consumer post-process-forwarder-issue-platform --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset + command: sentry-server run consumer post-process-forwarder-issue-platform --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset ingest-feedback-events: - command: sentry run consumer ingest-feedback-events --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset + command: sentry-server run consumer ingest-feedback-events --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset services: bigtable: image: 'ghcr.io/getsentry/cbtemulator:d28ad6b63e461e8c05084b8c83f1c06627068c04' diff --git a/package.json b/package.json index d5515d059db8..ef916a6cad32 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,6 @@ }, "type": "module", "scripts": { - "postinstall": "rm -f node_modules/.bin/sentry", "typecheck": "tsc --build tsconfig.json static/app/serviceWorker/worker/tsconfig.json --builders 2", "figma": "pnpm dlx @figma/code-connect@1.4.8 connect", "type-coverage": "node scripts/type-coverage.ts -p tsconfig.json", @@ -32,7 +31,7 @@ "fix": "pnpm run fix:format && pnpm run fix:oxlint", "fix:oxlint": "pnpm run lint:js --fix", "fix:format": "oxfmt", - "dev": "pnpm install --frozen-lockfile && sentry devserver", + "dev": "pnpm install --frozen-lockfile && sentry-server devserver", "dev-ui": "SENTRY_UI_DEV_ONLY=1 SENTRY_UI_HOT_RELOAD=1 node scripts/dev-ui-server.ts", "dev-ui-production": "NODE_ENV=production SENTRY_UI_DEV_ONLY=1 SENTRY_WEBPACK_PROXY_PORT=7999 SENTRY_UI_HOT_RELOAD=1 rsbuild dev", "dev-ui-admin": "SENTRY_ADMIN_UI_DEV=1 pnpm run dev-ui", diff --git a/scripts/lib.sh b/scripts/lib.sh index 521b260a4720..807b04f4032c 100755 --- a/scripts/lib.sh +++ b/scripts/lib.sh @@ -36,7 +36,7 @@ sudo-askpass() { } init-config() { - sentry init --dev --no-clobber + sentry-server init --dev --no-clobber } run-dependent-services() { @@ -56,15 +56,15 @@ create-db() { apply-migrations() { create-db echo "--> Applying migrations" - sentry upgrade --noinput + sentry-server upgrade --noinput } create-superuser() { echo "--> Creating a superuser account" if [[ -n "${GITHUB_ACTIONS+x}" ]]; then - sentry createuser --superuser --email foo@tbd.com --no-password --no-input + sentry-server createuser --superuser --email foo@tbd.com --no-password --no-input else - sentry createuser --superuser --email admin@sentry.io --password admin --no-input + sentry-server createuser --superuser --email admin@sentry.io --password admin --no-input echo "Password is admin." fi } diff --git a/self-hosted/Dockerfile b/self-hosted/Dockerfile index ff5bee8eff08..38fabb40a350 100644 --- a/self-hosted/Dockerfile +++ b/self-hosted/Dockerfile @@ -71,6 +71,10 @@ RUN set -x \ COPY . . RUN : \ && python3 -m tools.fast_editable --path . \ + # Deprecated alias: self-hosted and production manifests still invoke + # `sentry`. Only images get it, so it can't shadow the Sentry CLI in dev venvs. + # TODO: Remove once those callers use `sentry-server`. + && ln -s sentry-server /.venv/bin/sentry \ && python3 -m compileall -q src/ \ && python3 -m sentry.build.dump_cli_commands > /sentry-commands.txt @@ -81,7 +85,7 @@ RUN : double-check some built files are available \ && test -f /usr/src/sentry/src/sentry/loader/_registry.json \ && test -f /usr/src/sentry/src/sentry/integration-docs/python.json \ && test -f /usr/src/sentry/src/sentry/static/sentry/dist/entrypoints/app.js \ - && sentry help + && sentry-server help # Pre-create /data owned by sentry so fresh named volumes are initialized # with the right ownership. This must happen before the VOLUME instruction. @@ -133,7 +137,7 @@ ENV PATH="/.venv/bin:$PATH" \ USER sentry -RUN ["sentry", "help"] +RUN ["sentry-server", "help"] EXPOSE 9000 VOLUME /data diff --git a/self-hosted/config.yml b/self-hosted/config.yml index cf879d971e02..b6edfac155cf 100644 --- a/self-hosted/config.yml +++ b/self-hosted/config.yml @@ -51,7 +51,7 @@ releasefile.cache-path: '/data/releasefile-cache' # If this file ever becomes compromised, it's important to regenerate your a new key # Changing this value will result in all current sessions being invalidated. -# A new key can be generated with `$ sentry config generate-secret-key` +# A new key can be generated with `$ sentry-server config generate-secret-key` # system.secret-key: 'changeme' # The ``redis.clusters`` setting is used, unsurprisingly, to configure Redis diff --git a/self-hosted/docker_entrypoint.py b/self-hosted/docker_entrypoint.py index b34c0b8aee73..fe2366864e11 100644 --- a/self-hosted/docker_entrypoint.py +++ b/self-hosted/docker_entrypoint.py @@ -10,12 +10,13 @@ def main(argv: list[str]) -> None: if not argv: return - # Flags and sentry subcommands, e.g. `--help` or `run web`, go to sentry. + # Flags and sentry-server subcommands, e.g. `--help` or `run web`, go to sentry-server. if argv[0].startswith("-") or argv[0] in SENTRY_COMMANDS: - argv = ["sentry", *argv] + argv = ["sentry-server", *argv] # tini reaps zombies and forwards signals when sentry runs as PID 1. - if argv[0] == "sentry": + # `sentry` is the deprecated alias for `sentry-server`, see self-hosted/Dockerfile. + if argv[0] in ("sentry", "sentry-server"): argv = ["tini", "--", *argv] os.execvp(argv[0], argv) diff --git a/setup.cfg b/setup.cfg index 8a158cb0455d..ea35746461e2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,7 +32,7 @@ where = src [options.entry_points] console_scripts = - sentry = sentry.__main__:main + sentry-server = sentry.__main__:main sentry.apps = # TODO: This can be removed once the getsentry tests no longer check for this app auth_activedirectory = sentry.auth.providers.saml2.activedirectory diff --git a/src/sentry/backup/scopes.py b/src/sentry/backup/scopes.py index 8a5678481f59..86251daed877 100644 --- a/src/sentry/backup/scopes.py +++ b/src/sentry/backup/scopes.py @@ -36,7 +36,7 @@ class RelocationScope(Enum): @unique class ExportScope(Enum): """ - When executing the `sentry export` command, these scopes specify which of the above + When executing the `sentry-server export` command, these scopes specify which of the above `RelocationScope`s should be included in the final export. The basic idea is that each of these scopes is inclusive of its predecessor in terms of which `RelocationScope`s it accepts. """ @@ -55,7 +55,7 @@ class ExportScope(Enum): @unique class ImportScope(Enum): """ - When executing the `sentry import` command, these scopes specify which of the above + When executing the `sentry-server import` command, these scopes specify which of the above `RelocationScope`s should be included in the final upload. The basic idea is that each of these scopes is inclusive of its predecessor in terms of which `RelocationScope`s it accepts. """ diff --git a/src/sentry/build/dump_cli_commands.py b/src/sentry/build/dump_cli_commands.py index d43ce7077fe2..d34267f0d722 100644 --- a/src/sentry/build/dump_cli_commands.py +++ b/src/sentry/build/dump_cli_commands.py @@ -1,7 +1,7 @@ -"""Print the top-level `sentry` CLI commands, one per line. +"""Print the top-level `sentry-server` CLI commands, one per line. self-hosted/Dockerfile saves this list so docker_entrypoint.py can route -e.g. `docker run upgrade` to `sentry upgrade`. +e.g. `docker run upgrade` to `sentry-server upgrade`. """ import click diff --git a/src/sentry/conf/server.py b/src/sentry/conf/server.py index 73dce6eacaef..8e67b92ea969 100644 --- a/src/sentry/conf/server.py +++ b/src/sentry/conf/server.py @@ -761,7 +761,7 @@ def SOCIAL_AUTH_DEFAULT_USERNAME() -> str: # Hybrid cloud multi-silo configuration # -# Defined by `sentry devserver` to enable siloed local development +# Defined by `sentry-server devserver` to enable siloed local development SILO_DEVSERVER = os.environ.get("SENTRY_SILO_DEVSERVER", False) # Which silo this instance runs as (CONTROL|REGION|MONOLITH|None) are the expected values @@ -3484,7 +3484,7 @@ def custom_parameter_sort(parameter: dict) -> tuple[str, int]: # Necessary for getsentry to define custom consumers. SENTRY_KAFKA_CONSUMERS: Mapping[str, ConsumerDefinition] = {} -# sentry devserver should _always_ start the following consumers, identified by +# sentry-server devserver should _always_ start the following consumers, identified by # key in SENTRY_KAFKA_CONSUMERS or sentry.consumers.KAFKA_CONSUMERS DEVSERVER_START_KAFKA_CONSUMERS: MutableSequence[str] = [] @@ -3496,7 +3496,7 @@ def custom_parameter_sort(parameter: dict) -> tuple[str, int]: BROKEN_TIMEOUT_THRESHOLD = 1000 # This webhook url can be configured to log the changes made to runtime options as they -# are changed by sentry configoptions. +# are changed by sentry-server configoptions. OPTIONS_AUTOMATOR_SLACK_WEBHOOK_URL: str | None = None OPTIONS_AUTOMATOR_HMAC_SECRET: str | None = None diff --git a/src/sentry/consumers/__init__.py b/src/sentry/consumers/__init__.py index e65fe1ea7d71..8db375392168 100644 --- a/src/sentry/consumers/__init__.py +++ b/src/sentry/consumers/__init__.py @@ -360,7 +360,7 @@ def ingest_events_options() -> list[click.Option]: "click_options": uptime_options(), "pass_consumer_group": True, }, - # Known differences to 'sentry run occurrences-ingest-consumer': + # Known differences to 'sentry-server run occurrences-ingest-consumer': # - ingest_consumer_types metric tag is missing. Use the kafka_topic and # group_id tags provided by run_basic_consumer instead "ingest-occurrences": { @@ -499,7 +499,7 @@ def get_stream_processor( except KeyError: raise click.ClickException( f"No consumer named {consumer_name} in sentry.consumers.KAFKA_CONSUMERS. " - f"Most likely there is another subcommand in 'sentry run' " + f"Most likely there is another subcommand in 'sentry-server run' " f"responsible for this consumer" ) try: diff --git a/src/sentry/data/config/config.yml.default b/src/sentry/data/config/config.yml.default index 8f7aa19ba053..1c082d171593 100644 --- a/src/sentry/data/config/config.yml.default +++ b/src/sentry/data/config/config.yml.default @@ -33,7 +33,7 @@ mail.backend: '%(mail.backend)s' # Use dummy if you want to disable email entir # If this file ever becomes compromised, it's important to regenerate your a new key # Changing this value will result in all current sessions being invalidated. -# A new key can be generated with `$ sentry config generate-secret-key` +# A new key can be generated with `$ sentry-server config generate-secret-key` system.secret-key: '%(secret_key)s' # The ``redis.clusters`` setting is used, unsurprisingly, to configure Redis diff --git a/src/sentry/issue_detection/README.md b/src/sentry/issue_detection/README.md index 343eca406e44..a26078d22033 100644 --- a/src/sentry/issue_detection/README.md +++ b/src/sentry/issue_detection/README.md @@ -95,7 +95,7 @@ One note though, you may want to keep an eye on the metrics for `run_detector_on To start ingesting user data, you can use the issue platform [release flags](https://develop.sentry.dev/backend/issue-platform/#releasing-your-issue-type): ```sh -sentry createissueflag --slug= --owner= +sentry-server createissueflag --slug= --owner= ``` These flags don't need to be defined in `sentry`, you just have to add them to Flagpole. diff --git a/src/sentry/logging/README.rst b/src/sentry/logging/README.rst index c8a5578c6487..ac512935d97a 100644 --- a/src/sentry/logging/README.rst +++ b/src/sentry/logging/README.rst @@ -157,7 +157,7 @@ Since the logging component is only ever used elsewhere, it is better to refer t developmental cycle of the relevant component. That being said, if you are having any trouble with believing something should appear, -it is always recommended that you use ``sentry shell`` to manually instantiate a logger +it is always recommended that you use ``sentry-server shell`` to manually instantiate a logger that matches the name of the one you're using and inspect it for the relevant handlers and set logging level. diff --git a/src/sentry/models/importchunk.py b/src/sentry/models/importchunk.py index f9f71bb0542b..e20f0496cc25 100644 --- a/src/sentry/models/importchunk.py +++ b/src/sentry/models/importchunk.py @@ -17,7 +17,7 @@ class BaseImportChunk(DefaultFieldsModelExisting): # Every import has a UUID assigned to it. If the import was triggered by a relocation, this UUID # simply inherits from the `Relocation` model, and can be used to connect back to it. If it is - # not done via the `Relocation` pathway (that is, someone triggered it using a `sentry import` + # not done via the `Relocation` pathway (that is, someone triggered it using a `sentry-server import` # command via the CLI), it is randomly generated, but shared between all chunks of the same # import. import_uuid = UUIDField(db_index=True) diff --git a/src/sentry/options/defaults.py b/src/sentry/options/defaults.py index 70b269082817..4b3d3e258307 100644 --- a/src/sentry/options/defaults.py +++ b/src/sentry/options/defaults.py @@ -458,7 +458,7 @@ type=Bool, flags=FLAG_AUTOMATOR_MODIFIABLE, ) -# Notification Platform thread retention, run by `sentry cleanup`. Dry-run is on by +# Notification Platform thread retention, run by `sentry-server cleanup`. Dry-run is on by # default so deletion volume can be measured before anything is removed. register( "cleanup.notification-thread.dry-run", diff --git a/src/sentry/receivers/users.py b/src/sentry/receivers/users.py index e6cdebb00e11..853e341c8828 100644 --- a/src/sentry/receivers/users.py +++ b/src/sentry/receivers/users.py @@ -20,7 +20,7 @@ def create_first_user(**kwargs): if not click.confirm("\nWould you like to create a user account now?", default=True): # Not using `abort=1` because we don't want to exit out from further execution - click.echo("\nRun `sentry createuser` to do this later.\n") + click.echo("\nRun `sentry-server createuser` to do this later.\n") return from sentry.runner import call_command diff --git a/src/sentry/runner/boot_gc.py b/src/sentry/runner/boot_gc.py index 7809b8d2161c..e9df4537ba15 100644 --- a/src/sentry/runner/boot_gc.py +++ b/src/sentry/runner/boot_gc.py @@ -14,7 +14,7 @@ cheaper (they also run more often, because the unfrozen old generation is small); - processes forked after the freeze (e.g. granian web workers started by - `sentry run web` with the "fork" start method) don't write GC bookkeeping + `sentry-server run web` with the "fork" start method) don't write GC bookkeeping into pages they share with their parent; - interpreter shutdown doesn't walk the frozen heap, which makes exiting spawned children and CLI commands one to two seconds faster. diff --git a/src/sentry/runner/commands/deletions.py b/src/sentry/runner/commands/deletions.py index 78e600568fd1..e7921f64c924 100644 --- a/src/sentry/runner/commands/deletions.py +++ b/src/sentry/runner/commands/deletions.py @@ -97,7 +97,7 @@ def run_deletions( if not any([deletion_id, cell_deletion_id, model, run_all]): raise click.UsageError( "Provide one of: --id, --cid, --model, or --all. " - "Use `sentry deletions list` to see pending deletions." + "Use `sentry-server deletions list` to see pending deletions." ) if deletion_id or cell_deletion_id: diff --git a/src/sentry/runner/commands/devserver.py b/src/sentry/runner/commands/devserver.py index 0e524fab267d..70745b5df5f5 100644 --- a/src/sentry/runner/commands/devserver.py +++ b/src/sentry/runner/commands/devserver.py @@ -20,9 +20,9 @@ # If you are looking to add a kafka consumer, please do not create a new click # subcommand. Instead, use sentry.consumers. _DEFAULT_DAEMONS = { - "server": ["sentry", "run", "web"], - "taskworker": ["sentry", "run", "taskworker"], - "taskworker-scheduler": ["sentry", "run", "taskworker-scheduler"], + "server": ["sentry-server", "run", "web"], + "taskworker": ["sentry-server", "run", "taskworker"], + "taskworker-scheduler": ["sentry-server", "run", "taskworker-scheduler"], } @@ -75,7 +75,7 @@ def _get_taskworker_daemon(reload: bool) -> tuple[str, list[str]]: @click.option( "--dev-consumer/--no-dev-consumer", default=False, - help="Fold multiple kafka consumers into one process using 'sentry run dev-consumer'.", + help="Fold multiple kafka consumers into one process using 'sentry-server run dev-consumer'.", ) @click.option( "--pretty/--no-pretty", @@ -393,7 +393,7 @@ def devserver( daemons.append( ( "dev-consumer", - ["sentry", "run", "dev-consumer"] + list(kafka_consumers), + ["sentry-server", "run", "dev-consumer"] + list(kafka_consumers), ) ) else: @@ -402,7 +402,7 @@ def devserver( ( name, [ - "sentry", + "sentry-server", "run", "consumer", name, diff --git a/src/sentry/runner/commands/devservices.py b/src/sentry/runner/commands/devservices.py index 2e3cdd968c34..8a99f9b92f6a 100644 --- a/src/sentry/runner/commands/devservices.py +++ b/src/sentry/runner/commands/devservices.py @@ -64,5 +64,5 @@ def _client() -> ContextManager[docker.DockerClient]: @click.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1, type=click.UNPROCESSED) def devservices(args: tuple[str, ...]) -> None: - click.echo("note: sentry devservices is deprecated; execing devservices") + click.echo("note: sentry-server devservices is deprecated; execing devservices") os.execvp("devservices", ("devservices", *args)) diff --git a/src/sentry/runner/commands/exec.py b/src/sentry/runner/commands/exec.py index 31e09378b8ca..838d575aeba5 100644 --- a/src/sentry/runner/commands/exec.py +++ b/src/sentry/runner/commands/exec.py @@ -24,7 +24,7 @@ def exec_(c: str, file: str | None) -> None: """ Execute a script. - Also compatible with hashbang `#!/usr/bin/env sentry exec` + Also compatible with hashbang `#!/usr/bin/env sentry-server exec` For convenience, the following example is attached to scripts: @@ -36,9 +36,9 @@ def exec_(c: str, file: str | None) -> None: Examples: \b - $ sentry exec -c 'print(Project.objects.count())' - $ echo 'print(Project.objects.count())' | sentry exec - $ sentry exec something.py + $ sentry-server exec -c 'print(Project.objects.count())' + $ echo 'print(Project.objects.count())' | sentry-server exec + $ sentry-server exec something.py Note: All scripts are assumed utf-8. """ diff --git a/src/sentry/runner/commands/notifications.py b/src/sentry/runner/commands/notifications.py index 2bb8337401eb..4dbb16d701b4 100644 --- a/src/sentry/runner/commands/notifications.py +++ b/src/sentry/runner/commands/notifications.py @@ -22,7 +22,7 @@ def send_cmd() -> None: @click.option( "-s", "--source", - help="Registered template source (see `sentry notifications list registry`)", + help="Registered template source (see `sentry-server notifications list registry`)", default="error-alert-service", ) @click.option("-e", "--email", help="Recipient email address", default="user@example.com") @@ -95,7 +95,7 @@ def _send_slack_notification( click.echo( f"\nThis command requires a {provider_label} integration name." "\nProvide it with the `-i` flag or by setting `slack.debug-workspace` in .sentry/config.yml." - f"\nBrowse the local integrations with `sentry notifications list integrations -o {organization_slug}`." + f"\nBrowse the local integrations with `sentry-server notifications list integrations -o {organization_slug}`." ) return @@ -144,7 +144,7 @@ def _send_slack_notification( @click.option( "-s", "--source", - help="Registered template source (see `sentry notifications list registry`)", + help="Registered template source (see `sentry-server notifications list registry`)", default="error-alert-service", ) @click.option("-o", "--organization_slug", help="Organization slug") @@ -179,7 +179,7 @@ def send_slack( @click.option( "-s", "--source", - help="Registered template source (see `sentry notifications list registry`)", + help="Registered template source (see `sentry-server notifications list registry`)", default="error-alert-service", ) @click.option("-o", "--organization_slug", help="Organization slug") @@ -222,7 +222,7 @@ def send_msteams() -> None: @click.option( "-s", "--source", - help="Registered template source (see `sentry notifications list registry`)", + help="Registered template source (see `sentry-server notifications list registry`)", default="error-alert-service", ) @click.option("-o", "--organization_slug", help="Organization slug", required=True) @@ -265,7 +265,7 @@ def send_discord( click.echo( "\nThis command requires a discord integration name." "\nProvide it with the `-i` flag or by setting `discord.debug-server` in .sentry/config.yml." - f"\nBrowse the local integrations with `sentry notifications list integrations -o {organization_slug}`." + f"\nBrowse the local integrations with `sentry-server notifications list integrations -o {organization_slug}`." ) return diff --git a/src/sentry/runner/commands/presenters/consolepresenter.py b/src/sentry/runner/commands/presenters/consolepresenter.py index c20c0087cced..b9679f53e75d 100644 --- a/src/sentry/runner/commands/presenters/consolepresenter.py +++ b/src/sentry/runner/commands/presenters/consolepresenter.py @@ -8,7 +8,7 @@ class ConsolePresenter(OptionsPresenter): """ - Formats and outputs the changes made via sentry configoptions to the + Formats and outputs the changes made via sentry-server configoptions to the Console, specifically Click and Logging. """ diff --git a/src/sentry/runner/commands/presenters/webhookpresenter.py b/src/sentry/runner/commands/presenters/webhookpresenter.py index 3ef198110bbd..a20f519ec239 100644 --- a/src/sentry/runner/commands/presenters/webhookpresenter.py +++ b/src/sentry/runner/commands/presenters/webhookpresenter.py @@ -13,7 +13,7 @@ class WebhookPresenter(OptionsPresenter): """ - Sends changes of runtime options made via sentry configoptions + Sends changes of runtime options made via sentry-server configoptions to a webhook url in json format. The webhook url can be configured to your liking. diff --git a/src/sentry/runner/commands/run.py b/src/sentry/runner/commands/run.py index 8a897d9191a4..922a0fe5019a 100644 --- a/src/sentry/runner/commands/run.py +++ b/src/sentry/runner/commands/run.py @@ -647,18 +647,18 @@ def basic_consumer( Example: - sentry run consumer ingest-occurrences --consumer-group ingest-occurrences + sentry-server run consumer ingest-occurrences --consumer-group ingest-occurrences runs the ingest-occurrences consumer with the consumer group ingest-occurrences. Consumers are defined in 'sentry.consumers'. Each consumer can take additional CLI options. Those can be passed after '--': - sentry run consumer ingest-occurrences --consumer-group occurrence-consumer -- --processes 1 + sentry-server run consumer ingest-occurrences --consumer-group occurrence-consumer -- --processes 1 Consumer-specific arguments can be viewed with: - sentry run consumer ingest-occurrences --consumer-group occurrence-consumer -- --help + sentry-server run consumer ingest-occurrences --consumer-group occurrence-consumer -- --help """ from sentry.consumers import get_stream_processor from sentry.metrics.middleware import add_global_tags @@ -707,7 +707,7 @@ def dev_consumer(consumer_names: tuple[str, ...]) -> None: """ Launch multiple "new-style" consumers in the same thread. - This does the same thing as 'sentry run consumer', but is not configurable, + This does the same thing as 'sentry-server run consumer', but is not configurable, hardcodes consumer groups and is highly imperformant. """ diff --git a/src/sentry/runner/commands/start.py b/src/sentry/runner/commands/start.py index 57270ac3b2ee..d8832cd7c264 100644 --- a/src/sentry/runner/commands/start.py +++ b/src/sentry/runner/commands/start.py @@ -21,14 +21,15 @@ @click.argument("service", default="http", type=click.Choice(sorted(SERVICES.keys()))) @configuration def start(service: str, bind: str | None, workers: int, upgrade: bool, noinput: bool) -> None: - "DEPRECATED see `sentry run` instead." + "DEPRECATED see `sentry-server run` instead." from sentry.runner.initializer import show_big_error show_big_error( [ - "`sentry start%s` is deprecated." % (" " + service if "http" in sys.argv else ""), - "Use `sentry run %s` instead." % {"http": "web"}.get(service, service), + "`sentry-server start%s` is deprecated." + % (" " + service if "http" in sys.argv else ""), + "Use `sentry-server run %s` instead." % {"http": "web"}.get(service, service), ] ) diff --git a/src/sentry/runner/initializer.py b/src/sentry/runner/initializer.py index df5b8dc584e0..3d687b1887a7 100644 --- a/src/sentry/runner/initializer.py +++ b/src/sentry/runner/initializer.py @@ -742,7 +742,7 @@ def apply_legacy_settings(settings: Any) -> None: # trigger the Installation Wizard, not abort startup. if not settings.SENTRY_OPTIONS.get("system.secret-key"): raise ConfigurationError( - "`system.secret-key` MUST be set. Use 'sentry config generate-secret-key' to get one." + "`system.secret-key` MUST be set. Use 'sentry-server config generate-secret-key' to get one." ) diff --git a/src/sentry/runner/main.py b/src/sentry/runner/main.py index 9bb7258d5c31..73bc75758ba6 100644 --- a/src/sentry/runner/main.py +++ b/src/sentry/runner/main.py @@ -115,7 +115,7 @@ def _get_prog() -> str: return "%s -m sentry" % sys.executable except (AttributeError, TypeError, IndexError): pass - return "sentry" + return "sentry-server" def main() -> None: diff --git a/src/sentry/runner/settings.py b/src/sentry/runner/settings.py index 89b47841c92d..e42bfa4ab7a2 100644 --- a/src/sentry/runner/settings.py +++ b/src/sentry/runner/settings.py @@ -103,7 +103,7 @@ def _configure( if not os.path.exists(py): if ctx: raise click.ClickException( - "Configuration file does not exist. Use 'sentry init' to initialize the file." + "Configuration file does not exist. Use 'sentry-server init' to initialize the file." ) raise ValueError( "Configuration file does not exist at '%s'" % click.format_filename(py) @@ -111,7 +111,7 @@ def _configure( elif not os.path.exists(yaml) and not os.path.exists(py): if ctx: raise click.ClickException( - "Configuration file does not exist. Use 'sentry init' to initialize the file." + "Configuration file does not exist. Use 'sentry-server init' to initialize the file." ) raise ValueError("Configuration file does not exist at '%s'" % click.format_filename(yaml)) diff --git a/src/sentry/signals.py b/src/sentry/signals.py index a70422ee152d..ec3acc573c26 100644 --- a/src/sentry/signals.py +++ b/src/sentry/signals.py @@ -187,5 +187,5 @@ def _log_robust_failure(self, receiver: object, err: Exception) -> None: # Fired after an update is performed on a `PostUpdateQuerySet`. Separate to a `.update` call on a model. post_update = BetterSignal() # [sender: Model, updated_fields: list[str], model_ids: list[int]] -# After `sentry upgrade` has completed. Better than post_migrate because it won't run in tests. +# After `sentry-server upgrade` has completed. Better than post_migrate because it won't run in tests. post_upgrade = BetterSignal() # [] diff --git a/src/sentry/silo/README.md b/src/sentry/silo/README.md index 7080c1414399..fa0d4499b9de 100644 --- a/src/sentry/silo/README.md +++ b/src/sentry/silo/README.md @@ -39,8 +39,8 @@ $ bin/split-silo-database To spin up the silos, run: ```sh -sentry devserver --silo=control --task-scheduler --workers -sentry devserver --silo=region --task-scheduler --workers --ingest +sentry-server devserver --silo=control --task-scheduler --workers +sentry-server devserver --silo=region --task-scheduler --workers --ingest ``` This will expose the following ports: @@ -95,6 +95,6 @@ ngrok start --all Now start your siloed servers: ```sh -sentry devserver --ngrok=acme.ngrok.dev --silo=control -sentry devserver --ngrok=acme.ngrok.dev --silo=region +sentry-server devserver --ngrok=acme.ngrok.dev --silo=control +sentry-server devserver --ngrok=acme.ngrok.dev --silo=region ``` diff --git a/src/sentry/wsgi.py b/src/sentry/wsgi.py index 9c459bf922ba..c84fb7bb2fc8 100644 --- a/src/sentry/wsgi.py +++ b/src/sentry/wsgi.py @@ -13,7 +13,7 @@ # Each granian worker imports this module after it starts. When granian is run # directly (`granian ... sentry.wsgi:application`), or its workers are spawned, # a worker starts without Sentry configured: configure() runs inside this block -# and is frozen with the warmup. Under `sentry run web` with the "fork" start +# and is frozen with the warmup. Under `sentry-server run web` with the "fork" start # method, workers are forked from a master that already ran configure() (and # froze it), so configure() is skipped here and this block freezes what the # warmup loads: about 40% more long-lived objects on top of configure(). See diff --git a/tests/sentry/runner/commands/test_backup.py b/tests/sentry/runner/commands/test_backup.py index 4041e634b200..3b87713cdd0c 100644 --- a/tests/sentry/runner/commands/test_backup.py +++ b/tests/sentry/runner/commands/test_backup.py @@ -113,7 +113,7 @@ def mock_gcp_kms_asymmetric_decrypt( class GoodCompareCommandTests(TestCase): """ - Test success cases of the `sentry backup compare` CLI command. + Test success cases of the `sentry-server backup compare` CLI command. """ def test_compare_equal(self) -> None: @@ -265,7 +265,7 @@ def test_compare_decrypt_with_gcp_kms(self, fake_kms_client: mock.Mock) -> None: class GoodEncryptDecryptCommandTests(TransactionTestCase): """ - Test the `sentry backup encrypt ...` and `sentry backup decrypt` commands + Test the `sentry-server backup encrypt ...` and `sentry-server backup decrypt` commands """ def test_use_local(self) -> None: @@ -376,7 +376,7 @@ def test_use_gcp_kms(self, fake_kms_client: mock.Mock) -> None: class GoodSanitizeCommandTests(TestCase): """ - Test success cases of the `sentry backup sanitize` CLI command. + Test success cases of the `sentry-server backup sanitize` CLI command. """ def test_sanitize(self) -> None: @@ -530,7 +530,7 @@ def cli_import_then_export( class GoodImportExportCommandTests(TransactionTestCase): """ - Test success cases of the `sentry import` and `sentry export` CLI command. We're not asserting + Test success cases of the `sentry-server import` and `sentry-server export` CLI command. We're not asserting against the content of any of the imports/exports (we have other tests for that in `tests/sentry/backup`), we just want to make sure invoking all reasonable variants of the commands occurs without error. diff --git a/tests/sentry/test_wsgi.py b/tests/sentry/test_wsgi.py index 3ddef2a220d0..023b4bf39f7d 100644 --- a/tests/sentry/test_wsgi.py +++ b/tests/sentry/test_wsgi.py @@ -53,7 +53,7 @@ assert len(gc.get_objects()) < gc.get_freeze_count() // 10 """ -# Shaped like a fork worker of `sentry run web`: the master already ran +# Shaped like a fork worker of `sentry-server run web`: the master already ran # configure(), so importing sentry.wsgi must freeze what the warmup loaded on top # of it. SUBPROCESS_TEST_WSGI_AFTER_CONFIGURE = """ From 650b00a2f7e69ad31b66c32e857833e97ea82c32 Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Wed, 28 Oct 2026 21:36:51 +0000 Subject: [PATCH 2/2] ref(runner): Keep sentry as a deprecated alias for sentry-server getsentry builds against sentry master and its image, CI, and options scripts still call `sentry` directly, so a hard cut would break it. Keep both console scripts for now; the alias, and cleanup of stale `.venv/bin/sentry` scripts, go away in a follow-up. Co-Authored-By: Joshua Li <14209781+joshuarli@users.noreply.github.com> --- devenv/sync.py | 7 ------- self-hosted/Dockerfile | 4 ---- self-hosted/docker_entrypoint.py | 2 +- setup.cfg | 3 +++ 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/devenv/sync.py b/devenv/sync.py index 8c357b964895..10953ea128e3 100644 --- a/devenv/sync.py +++ b/devenv/sync.py @@ -306,13 +306,6 @@ def main(context: dict[str, str]) -> int: ): return 1 - # fast_editable never deletes console scripts, so the pre-rename `sentry` script - # would linger and shadow the Sentry CLI. TODO: Remove once venvs have synced. - try: - os.remove(f"{venv_dir}/bin/sentry") - except FileNotFoundError: - pass - # Agent skills are non-fatal — private skill repos may not be accessible in CI if os.path.exists(f"{reporoot}/agents.toml") and shutil.which( "pnpm", path=f"{reporoot}/.devenv/bin" diff --git a/self-hosted/Dockerfile b/self-hosted/Dockerfile index 38fabb40a350..9858e0c74858 100644 --- a/self-hosted/Dockerfile +++ b/self-hosted/Dockerfile @@ -71,10 +71,6 @@ RUN set -x \ COPY . . RUN : \ && python3 -m tools.fast_editable --path . \ - # Deprecated alias: self-hosted and production manifests still invoke - # `sentry`. Only images get it, so it can't shadow the Sentry CLI in dev venvs. - # TODO: Remove once those callers use `sentry-server`. - && ln -s sentry-server /.venv/bin/sentry \ && python3 -m compileall -q src/ \ && python3 -m sentry.build.dump_cli_commands > /sentry-commands.txt diff --git a/self-hosted/docker_entrypoint.py b/self-hosted/docker_entrypoint.py index fe2366864e11..11faa358375c 100644 --- a/self-hosted/docker_entrypoint.py +++ b/self-hosted/docker_entrypoint.py @@ -15,7 +15,7 @@ def main(argv: list[str]) -> None: argv = ["sentry-server", *argv] # tini reaps zombies and forwards signals when sentry runs as PID 1. - # `sentry` is the deprecated alias for `sentry-server`, see self-hosted/Dockerfile. + # `sentry` is the deprecated alias for `sentry-server`, see setup.cfg. if argv[0] in ("sentry", "sentry-server"): argv = ["tini", "--", *argv] diff --git a/setup.cfg b/setup.cfg index ea35746461e2..ad84a5bdaf39 100644 --- a/setup.cfg +++ b/setup.cfg @@ -33,6 +33,9 @@ where = src [options.entry_points] console_scripts = sentry-server = sentry.__main__:main + # Deprecated alias for sentry-server. It shadows the Sentry CLI, so remove it + # once getsentry, ops manifests, and self-hosted no longer call `sentry`. + sentry = sentry.__main__:main sentry.apps = # TODO: This can be removed once the getsentry tests no longer check for this app auth_activedirectory = sentry.auth.providers.saml2.activedirectory