-
Notifications
You must be signed in to change notification settings - Fork 728
feat: tb endpoints for new widgets #3667
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| DESCRIPTION > | ||
| - `median_time_to_merge.pipe` serves the "Median time to merge" widget in the Development tab. | ||
| - Calculates the median time in seconds from PR opening to merge for the selected time period. | ||
| - **When `granularity` is NOT provided, returns a single KPI value** (median) across the entire time range. | ||
| - **When `granularity` is provided, returns time-series data** showing median time to merge aggregated by different time periods (daily, weekly, monthly, quarterly, yearly). | ||
| - Uses `generate_timeseries` pipe to create consistent time periods and left joins PR data to handle periods with no merged PRs. | ||
| - Only includes PRs that have been merged (`isNotNull(pra.mergedAt)`) to ensure accurate merge time calculations. | ||
| - Replaces the deprecated `averageTimeToMerge` widget with more robust median-based statistics. | ||
| - Available for projects connected with Gerrit, GitHub, or GitLab platforms. | ||
| - Primary use case: monitoring code review and merge cycle time, identifying bottlenecks in the merge process. | ||
| - Parameters: | ||
| - `project`: Required string for project slug (e.g., 'k8s', 'tensorflow') - inherited from `segments_filtered` | ||
| - `repos`: Optional array of repository URLs for filtering (e.g., ['https://github.com/kubernetes/kubernetes']) | ||
| - `startDate`: Optional DateTime filter for PRs opened after timestamp (e.g., '2024-01-01 00:00:00') | ||
| - `endDate`: Optional DateTime filter for PRs opened before timestamp (e.g., '2024-12-31 23:59:59') | ||
| - `platform`: Optional string filter for source platform (e.g., 'gerrit', 'github', 'gitlab') | ||
| - `granularity`: Optional string for time aggregation ('daily', 'weekly', 'monthly', 'quarterly', 'yearly') | ||
| - Response: | ||
| - Without granularity: `medianTimeToMergeSeconds` (median value in seconds) | ||
| - With granularity: `startDate`, `endDate`, and `medianTimeToMergeSeconds` for each time period | ||
|
|
||
| TAGS "Widget", "Pull requests", "Development metrics", "Merge time" | ||
|
|
||
| NODE timeseries_generation_for_median_time_to_merge | ||
| SQL > | ||
| % | ||
| {% if defined(granularity) %} | ||
| SELECT | ||
| ds."startDate", | ||
| ds."endDate", | ||
| ifNull(round(median(prf.mergedInSeconds)), 0) AS "medianTimeToMergeSeconds" | ||
| FROM generate_timeseries ds | ||
| LEFT JOIN | ||
| pull_requests_filtered prf | ||
| ON CASE | ||
| WHEN {{ granularity }} = 'daily' | ||
| THEN toDate(prf.openedAt) | ||
| WHEN {{ granularity }} = 'weekly' | ||
| THEN toStartOfWeek(prf.openedAt) | ||
| WHEN {{ granularity }} = 'monthly' | ||
| THEN toStartOfMonth(prf.openedAt) | ||
| WHEN {{ granularity }} = 'quarterly' | ||
| THEN toStartOfQuarter(prf.openedAt) | ||
| WHEN {{ granularity }} = 'yearly' | ||
| THEN toStartOfYear(prf.openedAt) | ||
| END | ||
| = ds."startDate" | ||
| AND isNotNull(prf.mergedAt) | ||
| AND isNotNull(prf.mergedInSeconds) | ||
| {% if defined(platform) %} | ||
| AND prf.platform | ||
| = {{ | ||
| String( | ||
| platform, | ||
| description="Filter by platform (e.g., 'gerrit', 'github', 'gitlab')", | ||
| required=False, | ||
| ) | ||
| }} | ||
| {% end %} | ||
| {% if defined(startDate) %} | ||
| AND prf.openedAt | ||
| >= {{ | ||
| DateTime( | ||
| startDate, | ||
| description="Filter PRs opened after this timestamp", | ||
| required=False, | ||
| ) | ||
| }} | ||
| {% end %} | ||
| {% if defined(endDate) %} | ||
| AND prf.openedAt | ||
| <= {{ | ||
| DateTime( | ||
| endDate, | ||
| description="Filter PRs opened before this timestamp", | ||
| required=False, | ||
| ) | ||
| }} | ||
| {% end %} | ||
| GROUP BY ds."startDate", ds."endDate" | ||
| ORDER BY ds."startDate" | ||
| {% else %} SELECT 1 | ||
| {% end %} | ||
|
|
||
| NODE median_time_to_merge_merged | ||
| SQL > | ||
| % | ||
| {% if not defined(granularity) %} | ||
| SELECT round(median(prf.mergedInSeconds)) AS "medianTimeToMergeSeconds" | ||
| FROM pull_requests_filtered prf | ||
| WHERE | ||
| isNotNull(prf.mergedAt) AND isNotNull(prf.mergedInSeconds) | ||
| {% if defined(platform) %} | ||
| AND prf.platform | ||
| = {{ | ||
| String( | ||
| platform, | ||
| description="Filter by platform (e.g., 'gerrit', 'github', 'gitlab')", | ||
| required=False, | ||
| ) | ||
| }} | ||
| {% end %} | ||
| {% if defined(startDate) %} | ||
| AND prf.openedAt | ||
| >= {{ | ||
| DateTime( | ||
| startDate, | ||
| description="Filter PRs opened after this timestamp", | ||
| required=False, | ||
| ) | ||
| }} | ||
| {% end %} | ||
| {% if defined(endDate) %} | ||
| AND prf.openedAt | ||
| <= {{ | ||
| DateTime( | ||
| endDate, | ||
| description="Filter PRs opened before this timestamp", | ||
| required=False, | ||
| ) | ||
| }} | ||
| {% end %} | ||
| {% else %} SELECT * FROM timeseries_generation_for_median_time_to_merge | ||
| {% end %} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| DESCRIPTION > | ||
| - `median_time_to_review.pipe` serves the "Median time to review" widget in the Development tab. | ||
| - Calculates the median time in seconds from PR opening to first review for the selected time period. | ||
| - **When `granularity` is NOT provided, returns a single KPI value** (median) across the entire time range. | ||
| - **When `granularity` is provided, returns time-series data** showing median time to review aggregated by different time periods (daily, weekly, monthly, quarterly, yearly). | ||
| - Uses `generate_timeseries` pipe to create consistent time periods and left joins PR data to handle periods with no reviewed PRs. | ||
| - Only includes PRs that have been reviewed (`isNotNull(pra.reviewedAt)`) to ensure accurate review time calculations. | ||
| - Replaces the deprecated `waitTimeFor1stReview` widget with more robust median-based statistics. | ||
| - Available for projects connected with Gerrit, GitHub, or GitLab platforms. | ||
| - Primary use case: monitoring code review responsiveness and identifying delays in the review process. | ||
| - Parameters: | ||
| - `project`: Required string for project slug (e.g., 'k8s', 'tensorflow') - inherited from `segments_filtered` | ||
| - `repos`: Optional array of repository URLs for filtering (e.g., ['https://github.com/kubernetes/kubernetes']) | ||
| - `startDate`: Optional DateTime filter for PRs opened after timestamp (e.g., '2024-01-01 00:00:00') | ||
| - `endDate`: Optional DateTime filter for PRs opened before timestamp (e.g., '2024-12-31 23:59:59') | ||
| - `platform`: Optional string filter for source platform (e.g., 'gerrit', 'github', 'gitlab') | ||
| - `granularity`: Optional string for time aggregation ('daily', 'weekly', 'monthly', 'quarterly', 'yearly') | ||
| - Response: | ||
| - Without granularity: `medianTimeToReviewSeconds` (median value in seconds) | ||
| - With granularity: `startDate`, `endDate`, and `medianTimeToReviewSeconds` for each time period | ||
|
|
||
| TAGS "Widget", "Pull requests", "Development metrics", "Review time" | ||
|
|
||
| NODE timeseries_generation_for_median_time_to_review | ||
| SQL > | ||
| % | ||
| {% if defined(granularity) %} | ||
| SELECT | ||
| ds."startDate", | ||
| ds."endDate", | ||
| ifNull(round(median(prf.reviewedInSeconds)), 0) AS "medianTimeToReviewSeconds" | ||
| FROM generate_timeseries ds | ||
| LEFT JOIN | ||
| pull_requests_filtered prf | ||
| ON CASE | ||
| WHEN {{ granularity }} = 'daily' | ||
| THEN toDate(prf.openedAt) | ||
| WHEN {{ granularity }} = 'weekly' | ||
| THEN toStartOfWeek(prf.openedAt) | ||
| WHEN {{ granularity }} = 'monthly' | ||
| THEN toStartOfMonth(prf.openedAt) | ||
| WHEN {{ granularity }} = 'quarterly' | ||
| THEN toStartOfQuarter(prf.openedAt) | ||
| WHEN {{ granularity }} = 'yearly' | ||
| THEN toStartOfYear(prf.openedAt) | ||
| END | ||
| = ds."startDate" | ||
| AND isNotNull(prf.reviewedAt) | ||
| AND isNotNull(prf.reviewedInSeconds) | ||
| {% if defined(platform) %} | ||
| AND prf.platform | ||
| = {{ | ||
| String( | ||
| platform, | ||
| description="Filter by platform (e.g., 'gerrit', 'github', 'gitlab')", | ||
| required=False, | ||
| ) | ||
| }} | ||
| {% end %} | ||
| {% if defined(startDate) %} | ||
| AND prf.openedAt | ||
| >= {{ | ||
| DateTime( | ||
| startDate, | ||
| description="Filter PRs opened after this timestamp", | ||
| required=False, | ||
| ) | ||
| }} | ||
| {% end %} | ||
| {% if defined(endDate) %} | ||
| AND prf.openedAt | ||
| <= {{ | ||
| DateTime( | ||
| endDate, | ||
| description="Filter PRs opened before this timestamp", | ||
| required=False, | ||
| ) | ||
| }} | ||
| {% end %} | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Time window uses opened date, not reviewThe time bucketing and Additional Locations (1) |
||
| GROUP BY ds."startDate", ds."endDate" | ||
| ORDER BY ds."startDate" | ||
| {% else %} SELECT 1 | ||
| {% end %} | ||
|
|
||
| NODE median_time_to_review_merged | ||
| SQL > | ||
| % | ||
| {% if not defined(granularity) %} | ||
| SELECT round(median(prf.reviewedInSeconds)) AS "medianTimeToReviewSeconds" | ||
| FROM pull_requests_filtered prf | ||
| WHERE | ||
| isNotNull(prf.reviewedAt) AND isNotNull(prf.reviewedInSeconds) | ||
| {% if defined(platform) %} | ||
| AND prf.platform | ||
| = {{ | ||
| String( | ||
| platform, | ||
| description="Filter by platform (e.g., 'gerrit', 'github', 'gitlab')", | ||
| required=False, | ||
| ) | ||
| }} | ||
| {% end %} | ||
| {% if defined(startDate) %} | ||
| AND prf.openedAt | ||
| >= {{ | ||
| DateTime( | ||
| startDate, | ||
| description="Filter PRs opened after this timestamp", | ||
| required=False, | ||
| ) | ||
| }} | ||
| {% end %} | ||
| {% if defined(endDate) %} | ||
| AND prf.openedAt | ||
| <= {{ | ||
| DateTime( | ||
| endDate, | ||
| description="Filter PRs opened before this timestamp", | ||
| required=False, | ||
| ) | ||
| }} | ||
| {% end %} | ||
| {% else %} SELECT * FROM timeseries_generation_for_median_time_to_review | ||
| {% end %} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| DESCRIPTION > | ||
| - `patchsets_per_review.pipe` serves the "Patchsets per review" widget in the Development tab. | ||
| - Calculates median or average number of patchsets per review for Gerrit changesets in the selected time period. | ||
| - **When `granularity` is NOT provided, returns a single KPI value** (median or average) across the entire time range. | ||
| - **When `granularity` is provided, returns time-series data** showing patchsets per review aggregated by different time periods (daily, weekly, monthly, quarterly, yearly). | ||
| - Uses `generate_timeseries` pipe to create consistent time periods and left joins PR data to handle periods with no data. | ||
| - Only includes Gerrit changesets with patchset data (`platform = 'gerrit'` and `isNotNull(numberOfPatchsets)`) to ensure accurate calculations. | ||
| - Primary use case: analyzing code review iteration patterns and review efficiency specifically for Gerrit changesets. | ||
| - Parameters: | ||
| - `project`: Required string for project slug (e.g., 'k8s', 'tensorflow') - inherited from `segments_filtered` | ||
| - `repos`: Optional array of repository URLs for filtering (e.g., ['https://gerrit.example.com/repo']) | ||
| - `startDate`: Optional DateTime filter for changesets opened after timestamp (e.g., '2024-01-01 00:00:00') | ||
| - `endDate`: Optional DateTime filter for changesets opened before timestamp (e.g., '2024-12-31 23:59:59') | ||
| - `granularity`: Optional string for time aggregation ('daily', 'weekly', 'monthly', 'quarterly', 'yearly') | ||
| - `dataType`: Optional string to select calculation method ('median' or 'average'), defaults to 'median' | ||
| - Response: | ||
| - Without granularity: `patchsetsPerReview` (median or average value) | ||
| - With granularity: `startDate`, `endDate`, and `patchsetsPerReview` for each time period | ||
|
|
||
| TAGS "Widget", "Pull requests", "Development metrics", "Code review", "Gerrit" | ||
|
|
||
| NODE timeseries_generation_for_patchsets_per_review | ||
| SQL > | ||
| % | ||
| {% if defined(granularity) %} | ||
| {% set dataType_val = 'median' %} | ||
| {% if defined(dataType) %} {% set dataType_val = dataType %} {% end %} | ||
| SELECT | ||
| ds."startDate", | ||
| ds."endDate", | ||
| {% if dataType_val == 'average' %} | ||
| ifNull(round(avg(prf.numberOfPatchsets), 2), 0) AS "patchsetsPerReview" | ||
| {% else %} ifNull(round(median(prf.numberOfPatchsets), 2), 0) AS "patchsetsPerReview" | ||
| {% end %} | ||
| FROM generate_timeseries ds | ||
| LEFT JOIN | ||
| pull_requests_filtered prf | ||
| ON CASE | ||
| WHEN {{ granularity }} = 'daily' | ||
| THEN toDate(prf.openedAt) | ||
| WHEN {{ granularity }} = 'weekly' | ||
| THEN toStartOfWeek(prf.openedAt) | ||
| WHEN {{ granularity }} = 'monthly' | ||
| THEN toStartOfMonth(prf.openedAt) | ||
| WHEN {{ granularity }} = 'quarterly' | ||
| THEN toStartOfQuarter(prf.openedAt) | ||
| WHEN {{ granularity }} = 'yearly' | ||
| THEN toStartOfYear(prf.openedAt) | ||
| END | ||
| = ds."startDate" | ||
| AND prf.platform = 'gerrit' | ||
| AND isNotNull(prf.numberOfPatchsets) | ||
| {% if defined(startDate) %} | ||
| AND prf.openedAt | ||
| >= {{ | ||
| DateTime( | ||
| startDate, | ||
| description="Filter changesets opened after this timestamp", | ||
| required=False, | ||
| ) | ||
| }} | ||
| {% end %} | ||
| {% if defined(endDate) %} | ||
| AND prf.openedAt | ||
| <= {{ | ||
| DateTime( | ||
| endDate, | ||
| description="Filter changesets opened before this timestamp", | ||
| required=False, | ||
| ) | ||
| }} | ||
| {% end %} | ||
| GROUP BY ds."startDate", ds."endDate" | ||
| ORDER BY ds."startDate" | ||
| {% else %} SELECT 1 | ||
| {% end %} | ||
|
|
||
| NODE patchsets_per_review_merged | ||
| SQL > | ||
| % | ||
| {% if not defined(granularity) %} | ||
| {% set dataType_val = 'median' %} | ||
| {% if defined(dataType) %} {% set dataType_val = dataType %} {% end %} | ||
| SELECT | ||
| {% if dataType_val == 'average' %} | ||
| round(avg(prf.numberOfPatchsets), 2) AS "patchsetsPerReview" | ||
| {% else %} round(median(prf.numberOfPatchsets), 2) AS "patchsetsPerReview" | ||
| {% end %} | ||
| FROM pull_requests_filtered prf | ||
| WHERE | ||
| prf.platform = 'gerrit' AND isNotNull(prf.numberOfPatchsets) | ||
| {% if defined(startDate) %} | ||
| AND prf.openedAt | ||
| >= {{ | ||
| DateTime( | ||
| startDate, | ||
| description="Filter changesets opened after this timestamp", | ||
| required=False, | ||
| ) | ||
| }} | ||
| {% end %} | ||
| {% if defined(endDate) %} | ||
| AND prf.openedAt | ||
| <= {{ | ||
| DateTime( | ||
| endDate, | ||
| description="Filter changesets opened before this timestamp", | ||
| required=False, | ||
| ) | ||
| }} | ||
| {% end %} | ||
| {% else %} SELECT * FROM timeseries_generation_for_patchsets_per_review | ||
| {% end %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Time window uses opened date, not merge
The time bucketing and
startDate/endDatefiltering useprf.openedAtwhile the metric is “time to merge”. This makes results depend on when PRs were opened rather than when they merged, so PRs opened in-range but merged later can appear, and PRs opened earlier but merged in-range are excluded, changing the meaning vs the widget being replaced.Additional Locations (1)
services/libs/tinybird/pipes/median_time_to_merge.pipe#L87-L122