You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat: add pull requests endpoint under v1-alpha - #2240
Adds GET /v1-alpha/projects/{slug}/development/pull-requests, the port of the Nuxt pull-requests widget handler (frontend/server/api/widget/development/pull-requests.get.ts) to the api package.
openedSummary, mergedSummary, closedSummary: PeriodSummary blocks (current and previous counts, signed percentageChange, changeValue, ISO periodFrom/periodTo)
avgResolveTimeSeconds: average time to resolve a pull request in the period, in seconds; null when nothing was resolved
data[]: one { startDate, endDate, open, merged, closed } per granularity bucket, dates as ISO-8601 UTC
Changes against the Nuxt handler
The top-level summary is dropped; it duplicated openedSummary.
avgVelocityInDays is renamed avgResolveTimeSeconds; the pipe value was already in seconds.
percentageChange is signed (Nuxt used Math.abs).
Summary and bucket dates are ISO-8601 UTC; Nuxt returned '' and bare YYYY-MM-DD.
An unknown slug returns 200 with zero summaries and an empty series, per the epic's definition of done; Nuxt returned 404.
Every Tinybird failure, the bucket lookup included, returns 503 upstream_unavailable; Tinybird's own status never reaches the caller.
An empty repos= is dropped instead of being forwarded as a filter that matches nothing (Ajv coerces it to ['']); Nuxt dropped it too.
Decisions
Bucket resolved once per request. The Tinybird client resolves a bucketId before every query that carries project, so a naive port would make 20 HTTP calls. The route calls getBucketIdForProject once and passes the id to the ten pipe queries, which run concurrently with Promise.all as in Nuxt. A null bucket is the unknown-slug case. No response caching in this PR (T-090 load test tracks this endpoint); the route description states the 11-call cost.
granularity is required. Without one the activities_count pipe returns a single summary row instead of a series, so a missing value is a 400. This matches IN-1331, IN-1332 and IN-1334.
The resolved current range is always sent. With dates omitted the route sends 2010-01-01 through today, so periodFrom/periodTo describe the range that was queried.
Bucket key stays open. The ticket lists the renames explicitly; the field description states it is the count of pull requests opened in the bucket. Renaming it to opened is a candidate for the /v1 graduation review.
Series merged by bucket start over their union. Whether the pipe emits a row for an empty bucket is undocumented, so data covers every bucket start any of the three series reports, matched by the normalised start instant and ordered by it; a count missing from a series is 0. Nuxt anchored on the opened series and joined by index, which could misplace or drop merged and closed activity.
Helpers (Tinybird date formatting, ISO conversion, granularity query schema, 503 wrapper, bucket-once fan-out) live in the route file per the parallel-PR rules; the consolidation chore after the five Development PRs merge moves them to a shared module.
Tests
api/tests/development-pull-requests.test.ts: 33 cases, all green. Stubs global fetch at the HTTP boundary and routes by pipe, so the real Tinybird client builds the URLs, resolves the bucket and classifies the errors. Covers the exact 11 calls and their params, concurrency, the repos filter, defaults, unknown slug, empty data, validation (400), every Tinybird failure class (503), Cache-Control, the OpenAPI entry (tag, descriptions, nullable, required granularity) and field stripping.
pnpm test, pnpm tsc-check, pnpm lint and pnpm format:check pass in api/.
Includes the routing-test parser fix from the base branch (62b136b).
Based on main, which includes #2241 (IN-1348, directory-based route registration) as dd37a7a. Jira: IN-1333
The reason will be displayed to describe this comment to others. Learn more.
Copilot review overview
🔵 Needs a closer look
The response documentation misstates sparse bucket and call-count behavior, and the default-date test can fail across UTC midnight.
Review effort: Balanced Findings: None
Previously missed (3)
In code that hasn't changed since last review
Avoid UTC date mismatch when test crosses midnight
api/tests/development-pull-requests.test.ts:431
This captures the UTC day when the test module loads, while the handler derives it during the request. A run crossing UTC midnight can compare different dates; freeze time or accept the before/after days as period.test.ts:131-135 does.
Document that empty granularity buckets may be omitted
This promises an entry for every granularity bucket, but the merger only emits bucket starts returned by at least one series, so fully empty buckets can be omitted. Document the series as sparse so clients do not assume continuity.
Qualify call count as applying only to known projects
The call-count statement excludes the unknown-slug path: queryPipes returns after one bucket lookup, as the test at lines 471-480 asserts. Qualify the 11-call cost as applying to known projects.
The reason will be displayed to describe this comment to others. Learn more.
Traced the bucket-merge logic and the Tinybird failure mapping against the tests, both hold up. Good coverage on the union-merge edge cases and the concurrency check.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds
GET /v1-alpha/projects/{slug}/development/pull-requests, the port of the Nuxt pull-requests widget handler (frontend/server/api/widget/development/pull-requests.get.ts) to the api package.Query:
repos[],startDate,endDate(UTC calendar days,YYYY-MM-DD) andgranularity(daily | weekly | monthly | quarterly | yearly, required).Response:
openedSummary,mergedSummary,closedSummary:PeriodSummaryblocks (current and previous counts, signedpercentageChange,changeValue, ISOperiodFrom/periodTo)avgResolveTimeSeconds: average time to resolve a pull request in the period, in seconds;nullwhen nothing was resolveddata[]: one{ startDate, endDate, open, merged, closed }per granularity bucket, dates as ISO-8601 UTCChanges against the Nuxt handler
summaryis dropped; it duplicatedopenedSummary.avgVelocityInDaysis renamedavgResolveTimeSeconds; the pipe value was already in seconds.percentageChangeis signed (Nuxt usedMath.abs).''and bareYYYY-MM-DD.upstream_unavailable; Tinybird's own status never reaches the caller.repos=is dropped instead of being forwarded as a filter that matches nothing (Ajv coerces it to['']); Nuxt dropped it too.Decisions
bucketIdbefore every query that carriesproject, so a naive port would make 20 HTTP calls. The route callsgetBucketIdForProjectonce and passes the id to the ten pipe queries, which run concurrently withPromise.allas in Nuxt. Anullbucket is the unknown-slug case. No response caching in this PR (T-090 load test tracks this endpoint); the route description states the 11-call cost.granularityis required. Without one theactivities_countpipe returns a single summary row instead of a series, so a missing value is a 400. This matches IN-1331, IN-1332 and IN-1334.2010-01-01through today, soperiodFrom/periodTodescribe the range that was queried.open. The ticket lists the renames explicitly; the field description states it is the count of pull requests opened in the bucket. Renaming it toopenedis a candidate for the/v1graduation review.datacovers every bucket start any of the three series reports, matched by the normalised start instant and ordered by it; a count missing from a series is 0. Nuxt anchored on the opened series and joined by index, which could misplace or drop merged and closed activity.Helpers (Tinybird date formatting, ISO conversion, granularity query schema, 503 wrapper, bucket-once fan-out) live in the route file per the parallel-PR rules; the consolidation chore after the five Development PRs merge moves them to a shared module.
Tests
api/tests/development-pull-requests.test.ts: 33 cases, all green. Stubs globalfetchat the HTTP boundary and routes by pipe, so the real Tinybird client builds the URLs, resolves the bucket and classifies the errors. Covers the exact 11 calls and their params, concurrency, the repos filter, defaults, unknown slug, empty data, validation (400), every Tinybird failure class (503), Cache-Control, the OpenAPI entry (tag, descriptions, nullable, required granularity) and field stripping.pnpm test,pnpm tsc-check,pnpm lintandpnpm format:checkpass inapi/.Includes the routing-test parser fix from the base branch (62b136b).
Based on main, which includes #2241 (IN-1348, directory-based route registration) as dd37a7a. Jira: IN-1333
main