Repository navigation
feat(api): Move the @sentry/api package into static/packages/api - #130472
sentry-junior[bot] wants to merge 16 commits into
Conversation
|
🚨 Warning: This pull request contains Frontend and Backend changes! It's discouraged to make changes to Sentry's Frontend and Backend in a single pull request. The Frontend and Backend are not atomically deployed. If the changes are interdependent of each other, they must be separated into two pull requests and be made forward or backwards compatible, such that the Backend or Frontend can be safely deployed independently. Have questions? Please ask in the |
Sentry Snapshot Testing
|
68de88b to
6470e77
Compare
6470e77 to
21b537f
Compare
21b537f to
74efdbf
Compare
Ported from getsentry/sentry#130518, per @BYK's request there: get the docs aligned here first, then move `@sentry/api` into getsentry/sentry. The commit applied cleanly on top of 2.0.0. Cursor Bugbot found the bug while reviewing the move ([thread](getsentry/sentry#130472 (comment))). It ships in the published `@sentry/api` 2.0.0. ## Bug `listPage` asked each later page for only the rows still missing: `per_page = min(100, limit - items.length)`. `listProjects`, `listTeams` and `listOrganizations` are served by Sentry's `OffsetPaginator`. Its cursor is `<page size>:<page>:<is_prev>`. When `per_page` doesn't match the cursor's page size, it reads the cursor's window and keeps only the last `per_page` rows (`src/sentry/api/paginator.py` in getsentry/sentry). So `100:1:0` with `per_page=50` returns rows 150–199, and rows 100–149 are lost. Any `limit` above 100 dropped rows without an error. ## Fix `listPage` now walks through the package's existing `paginate`, which: - uses one `per_page` for the whole walk. A fresh walk splits `limit` evenly: 150 becomes 2 × 75. - reuses the page size that an offset cursor encodes when resuming, whatever the new `limit` is. - returns a cursor that resumes at the first row not returned, including partway through a page. `listPage` still validates each page with the schema, and still rejects a page with more rows than requested or a repeated cursor. One behavior changes: if a walk reaches `MAX_LIST_PAGES`, it now returns the rows it has and a resume cursor instead of throwing. Before this change, a stable page size couldn't hit that cap in a normal walk. Now a resumed small-page cursor can, for example `25:1:0` with `limit: 5000`. ## Tests - `test/api-client/core.test.ts` models `OffsetPaginator`. It confirms that `100:1:0` with `per_page=50` reads rows 150–199. Then it checks two things: - a 150-row walk and its resume return rows 0–299 in order, all with `per_page=75`; - resuming `100:1:0` with `limit: 50` returns rows 100–149, then 150–199, both requested with `per_page=100`. - The `listOrganizations` test now expects `per_page` to stay at 3 on the second request. It was 1, which was the bug. `pnpm build`, `pnpm typecheck` and `pnpm test` pass locally (53 files, 675 tests). No UI change. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com> <!-- junior-session-footer:start --> <!-- junior-conversation-id:agent%3A69da19b385017e68b7f9eace56e9477f --> -- [View Session](https://junior-prod.sentry.dev/conversations/agent%3A69da19b385017e68b7f9eace56e9477f) [[Sentry]](https://sentry.sentry.io/explore/conversations/agent%3A69da19b385017e68b7f9eace56e9477f/?project=4510944073809921) <!-- junior-session-footer:end --> Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com> Co-authored-by: BYK <126780+BYK@users.noreply.github.com>
74efdbf to
e9fc941
Compare
Move the generated TypeScript client for Sentry's public API from getsentry/sentry-api-schema into this repository, next to the spec it is built from. - Build it from tests/apidocs/openapi-derefed.json, upgraded to TypeScript 6 with exact dev tool pins and zod 4.6.7. - Ship the spec, the API ownership stats and the RPC method schema under @sentry/api/spec/ so consumers can read them from npm. - Add a required api-client job to backend.yml that builds, typechecks and tests the client on spec or package changes. - Pack it in package-pack.yml and release it from openapi.yml when what it ships changes. Releases stay off until the first api@ tag is cut by hand. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
Stop the path parameter pattern from backtracking on runs of '{', and write
the generated-code match in build step generate-request-preparation as a plain
string so CodeQL does not read its template escapes as regex escapes.
Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
Keep the npm package at its 1.54.0 size. The pack job adds the spec, API ownership stats and RPC schema to the release artifact, so craft's github target attaches them to each api@ release while npm takes only the tarball. The release preflight now compares against those release assets. Also make ocpo a code owner of static/packages/api alongside owners-api. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
…c files Treating a release without its spec files as "everything changed" would cut a minor release with nothing in it. Craft attaches the files before it merges the release branch, so this only happens when something went wrong, and a failed run is easier to notice than an empty release.
e9fc941 to
8fd09f3
Compare
Sentry's spec now declares /api/0 in its server URL and ships relative paths (#131065), so the build no longer found the /api/0-prefixed routes it expected, such as the resizable pagination routes. Port getsentry/sentry-api-schema#148: read the base path from the server URL (or the paths, for older specs), export it as API_BASE_PATH, and make operation paths relative to it.
Each published api@ release waits for its npm version, then dispatches sentry-docs' Bump @sentry/api workflow by file name. Craft runs the github target before npm for static/packages/*, so the wait keeps the bump from reading the previous version. This replaces the dispatch in getsentry/sentry-api-schema at cutover. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
Brings static/packages/api level with getsentry/sentry-api-schema main (2.3.1): - @sentry/api/docs exports the API reference data (getsentry/sentry-api-schema#150), with the no-typescript-source-strings lint rule, which the api client CI job now runs. - listPage keeps per_page stable across offset cursors (getsentry/sentry-api-schema#149). - ApiPermissionError carries the scopes from a 403 insufficient_scope challenge (getsentry/sentry-api-schema#146). - Union fields and annotated single-member allOf fields keep their own descriptions. The version moves to 2.3.1, so craft's first api@ release bumps from sentry-api-schema's latest npm version. The release check no longer cuts a patch for API ownership stats alone: the asset stays on each release for ad-hoc use, but nothing reads it on a schedule. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
…paration The port brought back the template literal that CodeQL misreads as a regular expression. The plain string has the same value.
`openapi-diff` compared every backend PR with getsentry/sentry-api-schema `main`, which is the latest master and not where the PR branched off, so its diff also showed unrelated master changes. Its `json-diff` step exits 1 on any difference, so the job failed on every PR that changes the spec. That's why develop-docs calls the failure expected, and also why the RPC breaking-change step after it was **skipped on exactly those PRs**. In the 100 runs I sampled, 69 hit the `api_docs` filter. 27 failed at json-diff, and the RPC check was skipped in all 27. The other 42 ran the RPC check and passed. #130472 moves `@sentry/api` into `static/packages/api`, which gives master a second baseline source besides sentry-api-schema: the `api@` release assets. ## What changes - **Baselines come from the PR's merge-base.** `openapi.yml` now uploads `tests/apidocs/openapi-derefed.json` and `rpc_method_schema.json` from each master build as an `api-schemas` artifact, kept for 30 days. `scripts/openapi-diff.sh baseline` gets the merge-base from the compare API and walks back up to 30 master commits to the closest one with that artifact. Every commit that can change the schemas uploads one. Fallbacks, in order: 1. the newest `api@` GitHub release, picked by listing releases, since `releases/latest` is sentry's calver release; 2. sentry-api-schema `main`, for as long as it still receives the spec. The job summary says which baseline it used. Each source writes to a scratch directory, so a source that fails halfway leaves nothing behind. - **The public spec diff is a changelog.** The `changelog` job writes an `oasdiff changelog --format markdown` to the job summary, capped below GitHub's 1 MiB limit, and never fails. A missing baseline or an oasdiff error becomes a note in the summary. - **The RPC check runs in its own job.** The `rpc-breaking` job runs `oasdiff breaking --fail-on WARN` on the RPC schema, so nothing upstream can skip it. Control and cell silos deploy separately, and the new required `api-client` check (#130472) doesn't cover RPC. - **One build.** The `build` job still builds the spec and RPC schema once, with `setup-sentry`. The two compare jobs only download its artifact and run the oasdiff image, so CI cost stays about the same. - **`make diff-api-docs`** runs the same script: the merge-base baseline, then the changelog. It needs gh and docker. That replaces `api-docs/openapi-diff.ts` and its `json-diff` dependency, so the lockfile only loses the `json-diff` subtree. - A new `make build-rpc-schema` writes `.artifacts/rpc_method_schema.json`. It's the same target #130472 adds. - A shellcheck pre-commit hook (`--shell=sh --enable=check-extra-masked-returns`) covers the new script. The develop-docs text that says this check is expected to fail is updated in getsentry/sentry-docs#20679, which already rewrites that section. ## Interaction with #130472 This PR is off master and doesn't depend on #130472, but the two touch neighboring lines in `openapi.yml` and `Makefile`. - **If #130472 lands first:** keep its `build-rpc-schema` target, and point the `api-schemas` upload at `static/packages/api/spec/` or `.artifacts/rpc_method_schema.json`. The baseline script finds both files by name inside the artifact, so their paths don't matter. - **If this one lands first:** #130472 resolves the same two spots. ## Verification - shellcheck (`--shell=sh --enable=check-extra-masked-returns`) is clean. actionlint reports nothing new; its only finding is the existing `ubuntu-26.04-arm` label. knip is clean. - **Baseline lookup, run for real under dash** with #130472's base and head SHAs: no `api-schemas` artifact exists yet and there's no `api@` release, so it fell back to sentry-api-schema `main` (15.8 MB spec plus RPC schema) in 18 s. - **Baseline lookup, run with a stubbed gh:** - the artifact is on the second commit back: it's used; - the artifact is missing a file and an `api@` release exists: it uses the release; - every source fails: it exits 1 and leaves no partial files behind; - gh fails: it exits 1. - **Changelog and RPC check, run with the real oasdiff v1.33.0 binary:** - a real spec diff gives an 8.8 KB Markdown changelog; - identical specs give "No changes detected"; - a missing baseline or a bad JSON spec gives a note, and every one of these exits 0; - `rpc-breaking` on identical schemas exits 0, and on a schema with a removed method it prints `::error` and exits 1. - No UI change. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com> <!-- junior-request-attribution:start --> via @BYK. <!-- junior-request-attribution:end --> <!-- junior-session-footer:start --> <!-- junior-conversation-id:agent%3A69da19b385017e68b7f9eace56e9477f --> -- [View Session in Sentry](https://sentry.sentry.io/explore/conversations/agent%3A69da19b385017e68b7f9eace56e9477f/?project=4510944073809921) <!-- junior-session-footer:end --> --------- Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com> Co-authored-by: BYK <126780+BYK@users.noreply.github.com>
# Conflicts: # Makefile # pnpm-lock.yaml
Craft's github target publishes the release inside its own step, so with github listed first, `release: published` fired before npm had the version. Listing npm first means bump-sentry-docs.yml can dispatch right away, so the wait-for-npm-version script goes away. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit cc36203. Configure here.
`make build-rpc-schema` writes .artifacts/rpc_method_schema.json, so the api-schemas upload no longer found it at the repository root. Upload the copy under static/packages/api/spec/ instead: upload-artifact skips hidden directories such as .artifacts/. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
… path The generated buildUrl appended API_BASE_PATH to baseUrl as is, so a base URL with trailing slashes, such as a per-request one or one with more than the single slash mergeConfigs strips, produced `//api/0`. The new withApiBasePath helper trims them first and gives `/api/0` when no base URL is set. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
With craft's auto changelog policy, a non-empty Unreleased section replaces the notes craft generates from commits, so it would have been the whole changelog for the first api@ release. The fix's commit is in those generated notes already. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>

Moves
@sentry/api, the generated TypeScript client for Sentry's public API, from getsentry/sentry-api-schema tostatic/packages/api. It builds fromtests/apidocs/openapi-derefed.json, the spec this repository generates. The npm name stays@sentry/api, so getsentry/toolkit, sentry-docs and other consumers don't change. This PR replaces the pre-merge check from #130450, which was closed.This PR doesn't publish anything. Releases from here stay off until a person cuts the first
api@tag (see the cutover section).Package
mainat 2.3.1, including the@sentry/api/docsAPI reference export (feat(api): Export API reference data as @sentry/api/docs sentry-api-schema#150), thelistPageper_pagefix (fix(api): Keep per_page stable when listPage walks offset cursors sentry-api-schema#149) andinsufficient_scopehandling onApiPermissionError(feat(api-client): Carry the scopes a 403 insufficient_scope challenge accepts sentry-api-schema#146).main: the generatedbuildUrltrims trailing slashes from the base URL before appending/api/0(withApiBasePathinlib/api-client/api-base-url.ts), sohttps://sentry.io/no longer requestshttps://sentry.io//api/0. Published 2.x versions keep that bug; the fix ships with the firstapi@release from here.package.jsonis at 2.3.1, the latest npm version. Craft bumps from it while there is noapi@tag, so the first release from here lands after sentry-api-schema's.@typescript/typescript6alias, and zod 4.6.7, the versionstatic/app, gsApp, gsAdmin and scraps already pin. The other dev tools are pinned to exact versions, and oxlint matches the repo's 1.90.0.lib/spec-files.mjsand collects them underspec/.source-analysisuses a path-parameter pattern that can't backtrack on runs of{, for a CodeQL alert the move raised.test:vitestandlint:js, nottestandlint. The repo'stest-ciandtest-allpass Jest flags to every workspace'stestscript, and the repo'slint:jsruns each workspace'slint:js.Spec files on GitHub releases
Each
api@x.y.zGitHub release gets the files that version was built from as assets. The pack job adds them to the release artifact; craft's github target attaches every file in it, and its npm target publishes only the tarball:openapi-derefed.json, the dereferenced OpenAPI spec.rpc_method_schema.json, for the openapi-diff/RPC check. It comes from a newmake build-rpc-schematarget.api_ownership_stats_dont_modify.json, whichmake build-api-docsstill generates. No known consumer reads it; it is kept for ad-hoc and future use.For example:
https://github.com/getsentry/sentry/releases/download/api@x.y.z/openapi-derefed.json. The npm package doesn't include them.CI:
api clientis a required checkThe new
api-clientjob inbackend.ymlbuilds, typechecks, lints and tests the client against the PR's own spec. It is part ofbackend-required-check. A spec change that broke the client once stalled releases for 2 days with nothing catching it before merge; this check catches that class of change.api-docsjob (shared as a workflow artifact), so the spec isn't built twice.api_clientfilter matches: the existingapi_docspaths plusstatic/packages/api/**. On other PRs both jobs are skipped, andbackend-required-checkcounts skipped jobs as passing.Releases
package-pack.ymlsets up the Python env forapi, then builds the spec, the RPC schema and the package beforepnpm pack.release-api-packagejob inopenapi.ymlruns after the master spec build whenever the spec or the package might have changed. It runs.github/workflows/scripts/api-package-release-preflight.sh, thencraft preparewithgetsentry/publish. The preflight skips the release when:api@tag yet, so the job stays inert until the first release is cut by hand;api/release/*branch is still pending. When that release merges back, its own run releases whatever landed in the meantime;api@tag;cancel-in-progress: false, so a burst of merges produces one release.static/packages/apioption.bump-sentry-docs.ymlruns on each publishedapi@release..craft.ymllists the npm target before github forstatic/packages/*, so the version is already on npm when the release is published (the same order applies to icons, scraps and search-syntax, and nothing in them needs the tag before the npm publish). It dispatches sentry-docs'bump-api-schema-sha.ymlby file name with the existingSENTRY_API_SCHEMA_UPDATERapp. sentry-docs' bump reads the version from npm, so it works the same after the move.api_clientfilter, and the release doesn't wait for it.Cutover (in this order)
apiscommand. ci(openapi-diff): Compare API schemas with the PR's merge-base #130541 falls back to sentry-api-schemamainuntil anapi@release exists.auto-approve-repos.txt, replace thegetsentry/sentry-api-schemaline with this repo'sstatic/packages/apientry.api@release by hand: run the Release workflow with workspacestatic/packages/api. Check that the version it picks is above sentry-api-schema's last npm release. From then on,openapi.ymlreleases on change.openapi.yml, and the sentry-api-schema links in the getsentry/toolkit docs, getsentry/skillsdocument-api-endpointand devinfra-mcpdocs/sentry/ci.md.SENTRY_API_SCHEMA_UPDATER_*credentials can go with it.static/packages/api/is owned by @getsentry/owners-api and @getsentry/ocpo in CODEOWNERS.This PR touches
static/as well as backend CI files. The package is a standalone npm package and isn't part of either deploy, so splitting it wouldn't change what gets deployed.No UI change.
via @BYK.
--
View Session [Sentry]