@red-hat-developer-hub/backstage-plugin-scorecard-backend 4.1.0 → 4.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +92 -0
- package/README.md +282 -24
- package/config.schema.json +528 -0
- package/dist/actions/getEntityMetrics.cjs.js +4 -1
- package/dist/actions/getEntityMetrics.cjs.js.map +1 -1
- package/dist/actions/listMetrics.cjs.js +4 -1
- package/dist/actions/listMetrics.cjs.js.map +1 -1
- package/dist/database/DatabaseMetricValues.cjs.js +149 -19
- package/dist/database/DatabaseMetricValues.cjs.js.map +1 -1
- package/dist/database/utils/buildScalarTimeSeriesPoints.cjs.js +41 -0
- package/dist/database/utils/buildScalarTimeSeriesPoints.cjs.js.map +1 -0
- package/dist/database/utils/getAggregateExpression.cjs.js +7 -6
- package/dist/database/utils/getAggregateExpression.cjs.js.map +1 -1
- package/dist/database/utils/mapMetricValueRow.cjs.js +5 -2
- package/dist/database/utils/mapMetricValueRow.cjs.js.map +1 -1
- package/dist/index.cjs.js +14 -2
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +12 -1
- package/dist/middlewares/validateTimeSeriesQueryParams.cjs.js +44 -0
- package/dist/middlewares/validateTimeSeriesQueryParams.cjs.js.map +1 -0
- package/dist/plugin.cjs.js +4 -2
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/scheduler/tasks/CleanupExpiredMetricsTask.cjs.js +2 -2
- package/dist/scheduler/tasks/CleanupExpiredMetricsTask.cjs.js.map +1 -1
- package/dist/service/CatalogMetricService.cjs.js +111 -5
- package/dist/service/CatalogMetricService.cjs.js.map +1 -1
- package/dist/service/aggregations/AggregatedMetricLoader.cjs.js +19 -2
- package/dist/service/aggregations/AggregatedMetricLoader.cjs.js.map +1 -1
- package/dist/service/aggregations/AggregationsService.cjs.js +27 -14
- package/dist/service/aggregations/AggregationsService.cjs.js.map +1 -1
- package/dist/service/aggregations/strategies/ScalarAggregationStrategy.cjs.js +45 -2
- package/dist/service/aggregations/strategies/ScalarAggregationStrategy.cjs.js.map +1 -1
- package/dist/service/aggregations/strategies/WeightedStatusScoreAggregationStrategy.cjs.js +9 -18
- package/dist/service/aggregations/strategies/WeightedStatusScoreAggregationStrategy.cjs.js.map +1 -1
- package/dist/service/mappers.cjs.js +38 -4
- package/dist/service/mappers.cjs.js.map +1 -1
- package/dist/service/router.cjs.js +101 -1
- package/dist/service/router.cjs.js.map +1 -1
- package/dist/threshold/ThresholdResolver.cjs.js +4 -0
- package/dist/threshold/ThresholdResolver.cjs.js.map +1 -1
- package/dist/threshold/thresholdAnnotations.cjs.js +25 -0
- package/dist/threshold/thresholdAnnotations.cjs.js.map +1 -0
- package/dist/utils/aggregation/buildAggregationConfig.cjs.js +5 -0
- package/dist/utils/aggregation/buildAggregationConfig.cjs.js.map +1 -1
- package/dist/utils/aggregation/buildAggregationConfigFilter.cjs.js +16 -0
- package/dist/utils/aggregation/buildAggregationConfigFilter.cjs.js.map +1 -0
- package/dist/utils/aggregation/classifyNumberAgainstThresholds.cjs.js +22 -0
- package/dist/utils/aggregation/classifyNumberAgainstThresholds.cjs.js.map +1 -0
- package/dist/utils/aggregation/getAggregationChartDisplayColor.cjs.js +19 -0
- package/dist/utils/aggregation/getAggregationChartDisplayColor.cjs.js.map +1 -0
- package/dist/utils/aggregation/isScalarAggregationType.cjs.js.map +1 -1
- package/dist/utils/aggregation/withStandardThresholdDefaults.cjs.js +32 -0
- package/dist/utils/aggregation/withStandardThresholdDefaults.cjs.js.map +1 -0
- package/dist/utils/metricUtils.cjs.js +6 -0
- package/dist/utils/metricUtils.cjs.js.map +1 -1
- package/dist/utils/normalizeTimestamp.cjs.js +4 -1
- package/dist/utils/normalizeTimestamp.cjs.js.map +1 -1
- package/dist/validation/schemas/aggregationConfigSchemas.cjs.js +5 -11
- package/dist/validation/schemas/aggregationConfigSchemas.cjs.js.map +1 -1
- package/dist/validation/schemas/aggregationFilterSchema.cjs.js +10 -0
- package/dist/validation/schemas/aggregationFilterSchema.cjs.js.map +1 -0
- package/dist/validation/schemas/aggregationThresholdsConfigSchema.cjs.js +16 -0
- package/dist/validation/schemas/aggregationThresholdsConfigSchema.cjs.js.map +1 -0
- package/dist/validation/validateAggregationConfig.cjs.js +13 -9
- package/dist/validation/validateAggregationConfig.cjs.js.map +1 -1
- package/dist/validation/validateScalarAggregationConfig.cjs.js +24 -0
- package/dist/validation/validateScalarAggregationConfig.cjs.js.map +1 -0
- package/dist/validation/validateScalarFilterStatus.cjs.js +22 -0
- package/dist/validation/validateScalarFilterStatus.cjs.js.map +1 -0
- package/migrations/20260804123239_add_entity_metric_timestamp_index.js +33 -0
- package/package.json +14 -14
- package/config.d.ts +0 -136
- package/dist/scheduler/tasks/utils.cjs.js +0 -8
- package/dist/scheduler/tasks/utils.cjs.js.map +0 -1
- package/dist/utils/toIsoTimestamp.cjs.js +0 -8
- package/dist/utils/toIsoTimestamp.cjs.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,97 @@
|
|
|
1
1
|
# @red-hat-developer-hub/backstage-plugin-scorecard-backend
|
|
2
2
|
|
|
3
|
+
## 4.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 52e46db: Fix config schema generation during `prepack` by using string literal aggregation types in `config.d.ts` instead of `typeof aggregationTypes.*` references that Backstage cannot resolve.
|
|
8
|
+
- @red-hat-developer-hub/backstage-plugin-scorecard-common@4.3.1
|
|
9
|
+
- @red-hat-developer-hub/backstage-plugin-scorecard-node@4.3.1
|
|
10
|
+
|
|
11
|
+
## 4.3.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- 9c1936e: Add `GET /aggregations/:aggregationId/time-series` for daily scalar portfolio aggregation (`sum`, `average`, `max`, `min`, `count`). Returns aggregated metric values per UTC days. Days with no data are omitted. Aggregation type `statusGrouped` and `weightedStatusScore` return `400`. Sparkline metrics without a KPI block default to aggregation type `average`.
|
|
16
|
+
|
|
17
|
+
Adds `metadata.visualization` type to `GET /aggregations/:aggregationId/metadata` response.
|
|
18
|
+
|
|
19
|
+
- 2bb0ec5: Entity time-series API (`GET /metrics/catalog/:kind/:namespace/:name/time-series`) now returns entity-resolved `thresholds` and per-point `thresholdEvaluation` (classified at read time against those current thresholds) so clients can render sparkline legends and chart colors without a separate snapshot call. Threshold evaluation failures are returned in the existing per-point `error` field. When entity threshold resolution fails (e.g. malformed annotation overrides), the response sets `thresholdsError` and omits `thresholds` instead of silently falling back to config/provider defaults; points are left unclassified (`thresholdEvaluation` null).
|
|
20
|
+
- 485fadb: Persist DORA collector data in the database and sync incrementally from the last watermark, so metrics reuse stored deployments, incidents, and pull requests instead of refetching the full window every time.
|
|
21
|
+
|
|
22
|
+
The Jira `jira:doraIncidents` collector contract now requires `updatedSince` (ISO datetime) in the input and `updatedAt` (ISO datetime) on each incident in the output. Custom incident collector implementations must provide these fields.
|
|
23
|
+
|
|
24
|
+
- c380e6b: Skip scalar aggregation threshold coloring when no successful samples contributed (`total` is 0). Return a null display color and keep the card grey fallback. Scalar aggregation responses now include `aggregationChartDisplayColor` (threshold-derived chart color, or `null` when `total` is 0).
|
|
25
|
+
|
|
26
|
+
**BREAKING**: Changed types in `scorecard-common` module:
|
|
27
|
+
|
|
28
|
+
- `WeightedStatusScoreAggregationResult.aggregationChartDisplayColor` widened from `string` to `string | null`.
|
|
29
|
+
- `ScalarAggregationResult` gained a required `aggregationChartDisplayColor: string | null` property.
|
|
30
|
+
|
|
31
|
+
These changes are intentional: the API can return `null` when no samples contribute, and scalar KPI results now expose the same display-color field as weighted status score aggregations.
|
|
32
|
+
|
|
33
|
+
- fea86e8: Adds new endpoint `GET /metrics/:metricId/collectors` to list collector id and description for a metric. Composite metrics (like DORA) set optional `collectorIds` on `Metric` from config.
|
|
34
|
+
|
|
35
|
+
**BREAKING**: `ScorecardCollectorsService` now includes `getCollectorMetadata`. The default implementation behind `scorecardCollectorsServiceRef` already provides it, so no change is required unless you registered your own factory for that ref — then implement the new method.
|
|
36
|
+
|
|
37
|
+
- a1c3eb3: Updated DORA Mean Time to Restore to Median Time to Restore.
|
|
38
|
+
- ff6683f: Add DORA metrics and a collectors framework for composing datasource data into metrics.
|
|
39
|
+
|
|
40
|
+
- New `@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-dora` with Deployment Frequency, Median Lead Time for Changes, Mean Time to Restore, and Change Failure Rate
|
|
41
|
+
- New data collectors used by DORA: GitHub deployments, deployment workflow runs, and deployment pull requests; Jira incidents
|
|
42
|
+
- Metric time-series API `/metrics/catalog/:kind/:namespace/:name/time-series`
|
|
43
|
+
- Adds `defaultVisualization` to Metric metadata for sparkline
|
|
44
|
+
|
|
45
|
+
- ecb789b: Select one time-series point per UTC day in the database and include error-only days in the response.
|
|
46
|
+
|
|
47
|
+
- Prefer the latest sample of the day, including calculation errors (`value: null` with `error`)
|
|
48
|
+
- Widen `MetricTimeSeriesPoint` so `value` may be null and `error` is optional
|
|
49
|
+
|
|
50
|
+
- c7b7410: Adds an explicit collectors service factory. Updates default export to include it.
|
|
51
|
+
- f3f71a5: Add unit to metric and display it in threshold legend
|
|
52
|
+
- 50e1563: Add `scorecard.entityAnnotations.thresholds` (and global `entityAnnotations.enabled`) so administrators can disable or restrict per-entity threshold override annotations, using the same pattern as disabled-metrics annotation controls.
|
|
53
|
+
- a7a1b4a: Backstage version bump to v1.54.6
|
|
54
|
+
|
|
55
|
+
### Patch Changes
|
|
56
|
+
|
|
57
|
+
- f2662b4: Rename DORA-specific collector IDs to make their scope explicit and avoid conflicts with potential future generic collectors:
|
|
58
|
+
|
|
59
|
+
- `github:deployments` -> `github:doraDeployments`
|
|
60
|
+
- `github:deploymentWorkflowRuns` -> `github:doraDeploymentWorkflowRuns`
|
|
61
|
+
- `github:deploymentPullRequests` -> `github:doraDeploymentPullRequests`
|
|
62
|
+
- `jira:incidents` -> `jira:doraIncidents`
|
|
63
|
+
|
|
64
|
+
- 47ac76d: Export public `ScalarAggregationType` for scalar aggregation KPI types (`sum`, `average`, `count`, `min`, `max`).
|
|
65
|
+
|
|
66
|
+
Add legacy app E2E coverage for scalar and statusGrouped homepage aggregation KPI cards, including reusable Playwright registration helpers and legacy homepage widget entries for scalar KPIs.
|
|
67
|
+
|
|
68
|
+
- Updated dependencies [9c1936e]
|
|
69
|
+
- Updated dependencies [2bb0ec5]
|
|
70
|
+
- Updated dependencies [485fadb]
|
|
71
|
+
- Updated dependencies [befccc2]
|
|
72
|
+
- Updated dependencies [c380e6b]
|
|
73
|
+
- Updated dependencies [fea86e8]
|
|
74
|
+
- Updated dependencies [ff6683f]
|
|
75
|
+
- Updated dependencies [ecb789b]
|
|
76
|
+
- Updated dependencies [47ac76d]
|
|
77
|
+
- Updated dependencies [c7b7410]
|
|
78
|
+
- Updated dependencies [f3f71a5]
|
|
79
|
+
- Updated dependencies [a7a1b4a]
|
|
80
|
+
- @red-hat-developer-hub/backstage-plugin-scorecard-common@4.3.0
|
|
81
|
+
- @red-hat-developer-hub/backstage-plugin-scorecard-node@4.3.0
|
|
82
|
+
|
|
83
|
+
## 4.2.0
|
|
84
|
+
|
|
85
|
+
### Minor Changes
|
|
86
|
+
|
|
87
|
+
- e486f80: Implemented filter by `status` for scalar aggregation types (`sum`, `average`, `count`, `min`, `max`).
|
|
88
|
+
|
|
89
|
+
### Patch Changes
|
|
90
|
+
|
|
91
|
+
- Updated dependencies [e486f80]
|
|
92
|
+
- @red-hat-developer-hub/backstage-plugin-scorecard-common@4.2.0
|
|
93
|
+
- @red-hat-developer-hub/backstage-plugin-scorecard-node@4.2.0
|
|
94
|
+
|
|
3
95
|
## 4.1.0
|
|
4
96
|
|
|
5
97
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -94,13 +94,14 @@ For more information about schedule configuration options, see the [Metric Colle
|
|
|
94
94
|
|
|
95
95
|
The following metric providers are available:
|
|
96
96
|
|
|
97
|
-
| Provider | Metric ID
|
|
98
|
-
| -------------- |
|
|
99
|
-
| **GitHub** | `github.openPRs`
|
|
100
|
-
| **Filecheck** | `filecheck.*`
|
|
101
|
-
| **Jira** | `jira.openIssues`
|
|
102
|
-
| **OpenSSF** | `openssf.*`
|
|
103
|
-
| **Dependabot** | `dependabot.*`
|
|
97
|
+
| Provider | Metric ID | Title | Description | Type |
|
|
98
|
+
| -------------- | ----------------------------------------------------------------------------------------------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------- |
|
|
99
|
+
| **GitHub** | `github.openPRs` | GitHub open PRs | Count of open Pull Requests in GitHub | number |
|
|
100
|
+
| **Filecheck** | `filecheck.*` | File Checks | Checks whether specific files (e.g., `README.md`, `LICENSE`, `CODEOWNERS`) exist in a repository. | boolean |
|
|
101
|
+
| **Jira** | `jira.openIssues` | Jira open issues | The number of opened issues in Jira | number |
|
|
102
|
+
| **OpenSSF** | `openssf.*` | OpenSSF Security Scorecards | 18 security metrics from OpenSSF Scorecards (e.g., `openssf.codeReview`, `openssf.maintained`). Each returns a score from 0-10. | number |
|
|
103
|
+
| **Dependabot** | `dependabot.*` | Dependabot Alerts | Critical, High, Medium and Low CVE Alerts | number |
|
|
104
|
+
| **DORA** | `dora.deploymentFrequency`, `dora.medianLeadTimeForChanges`, `dora.medianTimeToRestore`, `dora.changeFailureRate` | DORA Metrics | Software delivery performance metrics based on DORA (DevOps Research and Assessment) | number |
|
|
104
105
|
|
|
105
106
|
To use these providers, install the corresponding backend modules:
|
|
106
107
|
|
|
@@ -109,10 +110,11 @@ To use these providers, install the corresponding backend modules:
|
|
|
109
110
|
- OpenSSF: [`@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-openssf`](../scorecard-backend-module-openssf/README.md)
|
|
110
111
|
- Dependabot: [`@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-dependabot`](../scorecard-backend-module-dependabot/README.md)
|
|
111
112
|
- Filecheck: [`@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-filecheck`](../scorecard-backend-module-filecheck/README.md)
|
|
113
|
+
- DORA: [`@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-dora`](../scorecard-backend-module-dora/README.md)
|
|
112
114
|
|
|
113
115
|
### Disabling Metrics
|
|
114
116
|
|
|
115
|
-
Administrators can disable metric checks globally via
|
|
117
|
+
Administrators can disable metric checks globally via `scorecard.disabledMetrics`, and users can disable them per entity via the `scorecard.io/disabled-metrics` annotation. Whether that annotation is honored is controlled by `scorecard.entityAnnotations.enabled` (global switch for all scorecard entity annotations) and `scorecard.entityAnnotations.disabledMetrics` (`enabled` / `except`). For more details, see [disabled-metrics-logic.md](./docs/disabled-metrics-logic.md).
|
|
116
118
|
|
|
117
119
|
## Thresholds
|
|
118
120
|
|
|
@@ -120,7 +122,7 @@ Thresholds define conditions to assign metric values to specific visual categori
|
|
|
120
122
|
|
|
121
123
|
- **Provider Defaults**: Metric providers define default thresholds
|
|
122
124
|
- **App Configuration**: Override defaults through `app-config.yaml`
|
|
123
|
-
- **Entity Annotations**: Override specific thresholds per entity using catalog annotations
|
|
125
|
+
- **Entity Annotations**: Override specific thresholds per entity using catalog annotations, can be disabled or restricted per metric via `scorecard.entityAnnotations.enabled` and `scorecard.entityAnnotations.thresholds`, see [threshold entity annotations](./docs/thresholds.md#3-entity-annotation-overrides)
|
|
124
126
|
|
|
125
127
|
Thresholds are evaluated in order, and the first matching rule determines the category. The plugin supports various operators for number metrics (`>`, `>=`, `<`, `<=`, `==`, `!=`, `-` (range)) and boolean metrics (`==`, `!=`). For **number** metrics, configurations loaded through validated paths must cover the **entire real line** when two or more rules are defined (no gaps between intervals).
|
|
126
128
|
|
|
@@ -177,19 +179,64 @@ scorecard:
|
|
|
177
179
|
- key: error
|
|
178
180
|
expression: '<10'
|
|
179
181
|
color: error.main
|
|
182
|
+
totalCriticalPRs:
|
|
183
|
+
title: Total Critical PRs
|
|
184
|
+
description: Sum of open PRs for entities in error status
|
|
185
|
+
type: sum
|
|
186
|
+
metricId: github.openPRs
|
|
187
|
+
filter:
|
|
188
|
+
status: error
|
|
189
|
+
options:
|
|
190
|
+
thresholds:
|
|
191
|
+
rules:
|
|
192
|
+
- key: success
|
|
193
|
+
expression: '<30'
|
|
194
|
+
color: '#6bb300'
|
|
195
|
+
- key: warning
|
|
196
|
+
expression: '30-80'
|
|
197
|
+
color: 'rgb(224, 189, 108)'
|
|
198
|
+
- key: error
|
|
199
|
+
expression: '>80'
|
|
200
|
+
color: '#be1ec7'
|
|
201
|
+
avgOpenIssues:
|
|
202
|
+
title: Average Open Issues
|
|
203
|
+
description: Mean open issues count per entity
|
|
204
|
+
type: average
|
|
205
|
+
metricId: jira.openIssues
|
|
206
|
+
avgDeploymentFrequency:
|
|
207
|
+
title: Average deployment frequency
|
|
208
|
+
description: Mean weekly production deploys across catalog entities you own.
|
|
209
|
+
type: average
|
|
210
|
+
metricId: dora.deploymentFrequency
|
|
211
|
+
entitiesWithOpenPrs:
|
|
212
|
+
title: Entities with Open PRs
|
|
213
|
+
description: Count of entities with a stored open-prs value
|
|
214
|
+
type: count
|
|
215
|
+
metricId: github.openPRs
|
|
216
|
+
maxOpenPrs:
|
|
217
|
+
title: Maximum Open PRs
|
|
218
|
+
description: Maximum open PR count per entity
|
|
219
|
+
type: max
|
|
220
|
+
metricId: github.openPRs
|
|
221
|
+
minOpenIssues:
|
|
222
|
+
title: Minimum Open Issues
|
|
223
|
+
description: Minimum open issues count per entity
|
|
224
|
+
type: min
|
|
225
|
+
metricId: jira.openIssues
|
|
180
226
|
```
|
|
181
227
|
|
|
182
|
-
| Field | Description
|
|
183
|
-
| ------------- |
|
|
184
|
-
| `title` | Display title for this aggregation (returned in API metadata).
|
|
185
|
-
| `description` | Display description for this aggregation.
|
|
186
|
-
| `type` | Aggregation algorithm: `statusGrouped` (counts per threshold status), `weightedStatusScore` (normalized weighted score), or a **scalar** type — `sum`, `average`, `max`, `min`, `count` (rollup of latest numeric metric values; see [aggregation.md](./docs/aggregation.md#aggregation-types)). Scalar types require a **number** metric.
|
|
187
|
-
| `metricId` | Metric provider id used to load thresholds and compute counts or
|
|
188
|
-
| `
|
|
228
|
+
| Field | Description |
|
|
229
|
+
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
230
|
+
| `title` | Display title for this aggregation (returned in API metadata). |
|
|
231
|
+
| `description` | Display description for this aggregation. |
|
|
232
|
+
| `type` | Aggregation algorithm: `statusGrouped` (counts per threshold status), `weightedStatusScore` (normalized weighted score), or a **scalar** type — `sum`, `average`, `max`, `min`, `count` (rollup of latest numeric metric values; see [aggregation.md](./docs/aggregation.md#aggregation-types)). Scalar types require a **number** metric. |
|
|
233
|
+
| `metricId` | Metric provider id used to load thresholds and compute counts or values. |
|
|
234
|
+
| `filter` | Optional for **scalar types** only (silently ignored on **`statusGrouped`** / **`weightedStatusScore`**). **`filter.status`**: threshold status key (case-sensitive). Only latest rows with that status contribute to **`value`** and **`total`**. Must match a threshold rule **`key`** for **`metricId`** from provider defaults or app-config overrides at **`scorecard.metricProviders.<datasource>.<providerName>.metrics.<metricName>.thresholds`** (or provider-level **`scorecard.metricProviders.<datasource>.<providerName>.thresholds`**) (validated at startup for scalar types). **`entitiesConsidered`** and **`calculationErrorCount`** stay full-portfolio. Returned in API **`metadata.filter`** when set. |
|
|
235
|
+
| `options` | **Optional:** extra configuration attributes required to further configure the aggregated card for a specific type |
|
|
189
236
|
|
|
190
237
|
- **Path**: `scorecard.aggregationKPIs.<aggregationId>`.
|
|
191
|
-
- If **`aggregationKPIs` is omitted** or a given id is not listed,
|
|
192
|
-
- **Startup validation**: the backend validates every **`scorecard.aggregationKPIs`** entry when the plugin loads. Invalid configuration (including **`weightedStatusScore`** KPIs without **`options.statusScores`**, bad expressions, or unregistered **`metricId`**) causes the backend to **fail to start** with a clear error. At runtime, some edge cases may still be logged (for example skipping a KPI with unusable weights); prefer correcting app-config. See [aggregation.md](./docs/aggregation.md#configuration-validation).
|
|
238
|
+
- If **`aggregationKPIs` is omitted** or a given id is not listed, aggregation KPIs still work, See [Default aggregation](./docs/aggregation.md#default-aggregation).
|
|
239
|
+
- **Startup validation**: the backend validates every **`scorecard.aggregationKPIs`** entry when the plugin loads. Invalid configuration (including **`weightedStatusScore`** KPIs without **`options.statusScores`**, non-count scalar types on boolean metrics, invalid **`filter.status`** keys on scalar types, bad threshold expressions, or unregistered **`metricId`**) causes the backend to **fail to start** with a clear error. At runtime, some edge cases may still be logged (for example skipping a KPI with unusable weights); prefer correcting app-config. See [aggregation.md](./docs/aggregation.md#configuration-validation).
|
|
193
240
|
|
|
194
241
|
**Homepage cards** are configured in the app (for example Dynamic Home Page mount points). They should pass **`aggregationId`** matching a key in `aggregationKPIs` or the metric id for the default case. See the [Scorecard frontend plugin README](../scorecard/README.md#homepage-scorecard-cards).
|
|
195
242
|
|
|
@@ -258,16 +305,140 @@ curl -X GET "{{url}}/api/scorecard/metrics/catalog/component/default/my-service?
|
|
|
258
305
|
-H "Authorization: Bearer <token>"
|
|
259
306
|
```
|
|
260
307
|
|
|
308
|
+
### `GET /metrics/catalog/:kind/:namespace/:name/time-series`
|
|
309
|
+
|
|
310
|
+
Returns daily time-series points for one metric on a catalog entity. Each point is the latest sample (`MAX(id)` among success or calculation-error rows) for that UTC calendar day. On a mixed day the later sample wins, so a later error is returned as `{ "value": null, "error": "..." }` (and clients can gap a sparkline). Days with no rows (or only null without `error_message`) are omitted. Returns `200` with `points: []` when the entity and metric are authorized but no data exists in the range.
|
|
311
|
+
|
|
312
|
+
The response also includes entity-resolved `thresholds` (provider defaults, then app-config, then entity annotation overrides) for sparkline legend rendering. Successful points include `thresholdEvaluation`: the matched threshold rule key from **read-time** evaluation of the point's `value` against those current `thresholds` (e.g. `success`, `warning`, `error`). This keeps legend keys and point classifications consistent when config changes. Calculation-error points omit `thresholdEvaluation`. When no rule matches, `thresholdEvaluation` is `null` (no per-point `error`). Threshold evaluation failures set that point's `error` (with `thresholdEvaluation` `null`).
|
|
313
|
+
|
|
314
|
+
When entity threshold resolution fails (e.g. malformed annotation overrides), the response omits `thresholds`, sets top-level `thresholdsError` with the failure message, and leaves successful points unclassified (`thresholdEvaluation` `null`, no per-point `error`). There is no silent fallback to app-config / provider defaults.
|
|
315
|
+
|
|
316
|
+
#### Path Parameters
|
|
317
|
+
|
|
318
|
+
| Parameter | Type | Required | Description |
|
|
319
|
+
| ----------- | ------ | -------- | ---------------------------------- |
|
|
320
|
+
| `kind` | string | Yes | Entity kind (e.g., `component`) |
|
|
321
|
+
| `namespace` | string | Yes | Entity namespace (e.g., `default`) |
|
|
322
|
+
| `name` | string | Yes | Entity name |
|
|
323
|
+
|
|
324
|
+
#### Query Parameters
|
|
325
|
+
|
|
326
|
+
| Parameter | Type | Required | Description |
|
|
327
|
+
| ---------- | ------ | -------- | -------------------------------------------------------------------- |
|
|
328
|
+
| `metricId` | string | Yes | Metric ID (e.g., `github.openPRs`) |
|
|
329
|
+
| `from` | string | Yes | Inclusive range start (ISO-8601) |
|
|
330
|
+
| `to` | string | Yes | Inclusive range end (ISO-8601); must be `>= from`; max span 365 days |
|
|
331
|
+
|
|
332
|
+
#### Permissions
|
|
333
|
+
|
|
334
|
+
Requires `scorecard.metric.read` permission and `catalog.entity.read` permission for the specific entity.
|
|
335
|
+
|
|
336
|
+
#### Example Request
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
curl -X GET "{{url}}/api/scorecard/metrics/catalog/component/default/my-service/time-series?metricId=github.openPRs&from=2026-04-01T00:00:00.000Z&to=2026-04-30T23:59:59.999Z" \
|
|
340
|
+
-H "Authorization: Bearer <token>"
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
#### Example Response
|
|
344
|
+
|
|
345
|
+
```json
|
|
346
|
+
{
|
|
347
|
+
"metricId": "github.openPRs",
|
|
348
|
+
"entityRef": "component:default/my-service",
|
|
349
|
+
"metadata": {
|
|
350
|
+
"title": "GitHub open PRs",
|
|
351
|
+
"description": "The number of open pull requests.",
|
|
352
|
+
"type": "number",
|
|
353
|
+
"history": true,
|
|
354
|
+
"defaultVisualization": "donut"
|
|
355
|
+
},
|
|
356
|
+
"points": [
|
|
357
|
+
{
|
|
358
|
+
"value": 8,
|
|
359
|
+
"timestamp": "2026-04-27T23:10:00.000Z",
|
|
360
|
+
"thresholdEvaluation": "success"
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
"value": null,
|
|
364
|
+
"timestamp": "2026-04-28T16:00:00.000Z",
|
|
365
|
+
"error": "GitHub API 500"
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
"value": 25,
|
|
369
|
+
"timestamp": "2026-04-29T22:55:00.000Z",
|
|
370
|
+
"thresholdEvaluation": "warning"
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
"value": 12,
|
|
374
|
+
"timestamp": "2026-04-30T18:00:00.000Z",
|
|
375
|
+
"thresholdEvaluation": null,
|
|
376
|
+
"error": "Error: Invalid threshold expression"
|
|
377
|
+
}
|
|
378
|
+
],
|
|
379
|
+
"thresholds": {
|
|
380
|
+
"rules": [
|
|
381
|
+
{ "key": "success", "expression": "<10" },
|
|
382
|
+
{ "key": "warning", "expression": "10-50" },
|
|
383
|
+
{ "key": "error", "expression": ">50" }
|
|
384
|
+
]
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### `GET /metrics/:metricId/collectors`
|
|
390
|
+
|
|
391
|
+
Returns the collectors used as data sources for a composite metric calculation.
|
|
392
|
+
|
|
393
|
+
#### Path Parameters
|
|
394
|
+
|
|
395
|
+
| Parameter | Type | Required | Description |
|
|
396
|
+
| ---------- | ------ | -------- | ------------------------------------------------------------ |
|
|
397
|
+
| `metricId` | string | Yes | Metric ID (e.g., `dora.changeFailureRate`, `github.openPRs`) |
|
|
398
|
+
|
|
399
|
+
#### Permissions
|
|
400
|
+
|
|
401
|
+
Requires `scorecard.metric.read` permission for the requested metric.
|
|
402
|
+
|
|
403
|
+
#### Behavior
|
|
404
|
+
|
|
405
|
+
- Returns `{ "collectors": [ ... ] }` with one entry per collector ID on the metric.
|
|
406
|
+
- Metrics that do not use collectors (no `collectorIds`) return `{ "collectors": [] }`.
|
|
407
|
+
- Unknown `metricId` returns `404 NotFoundError`.
|
|
408
|
+
- Missing permission for the metric returns `403 NotAllowedError`.
|
|
409
|
+
- A metric that references a collector ID that is not registered returns `500`.
|
|
410
|
+
|
|
411
|
+
#### Example Request
|
|
412
|
+
|
|
413
|
+
```bash
|
|
414
|
+
curl -X GET "{{url}}/api/scorecard/metrics/dora.changeFailureRate/collectors" \
|
|
415
|
+
-H "Authorization: Bearer <token>"
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
#### Example Response
|
|
419
|
+
|
|
420
|
+
```json
|
|
421
|
+
{
|
|
422
|
+
"collectors": [
|
|
423
|
+
{
|
|
424
|
+
"id": "github:doraDeployments",
|
|
425
|
+
"description": "Collects GitHub deployments."
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
"id": "jira:doraIncidents",
|
|
429
|
+
"description": "Collects Jira incidents."
|
|
430
|
+
}
|
|
431
|
+
]
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
261
435
|
### `GET /aggregations/:aggregationId`
|
|
262
436
|
|
|
263
437
|
Returns aggregated metrics for the authenticated user across all catalog entities they own (same ownership rules as the legacy route; see [aggregation.md](./docs/aggregation.md)).
|
|
264
438
|
|
|
265
|
-
Response **`result`** shape depends on **`metadata.aggregationType`**: status counts for **`statusGrouped`**, weighted score fields for **`weightedStatusScore`**, or scalar fields for **`sum`** / **`average`** / **`max`** / **`min`** / **`count`** — see [Scalar result fields](./docs/aggregation.md#scalar-result-fields).
|
|
266
|
-
|
|
267
|
-
The **`aggregationId`** is either:
|
|
439
|
+
Response **`result`** shape depends on **`metadata.aggregationType`**: status counts for **`statusGrouped`**, weighted score fields for **`weightedStatusScore`**, or scalar fields for **`sum`** / **`average`** / **`max`** / **`min`** / **`count`** — see [Scalar result fields](./docs/aggregation.md#scalar-result-fields). Scalar KPIs may also return **`metadata.filter`** when **`filter.status`** is configured.
|
|
268
440
|
|
|
269
|
-
|
|
270
|
-
- The **metric id** itself when no KPI entry exists (default **statusGrouped** behavior).
|
|
441
|
+
The **`aggregationId`** is a key under **`scorecard.aggregationKPIs`**, or a metric id when no KPI is configured. See [Default aggregation](#default-aggregation).
|
|
271
442
|
|
|
272
443
|
#### Path Parameters
|
|
273
444
|
|
|
@@ -290,15 +461,102 @@ curl -X GET "{{url}}/api/scorecard/aggregations/github.openPRs" \
|
|
|
290
461
|
-H "Authorization: Bearer <token>"
|
|
291
462
|
```
|
|
292
463
|
|
|
464
|
+
### `GET /aggregations/:aggregationId/time-series`
|
|
465
|
+
|
|
466
|
+
Returns a **daily** history of a **scalar** KPI (`sum`, `average`, `max`, `min`, or `count`) across entities you own. Each response point is one UTC day: Scorecard takes **latest stored row** for each owned entity that day (including calculation failures), then rolls successful values up with the KPI’s aggregation type. Optional **`filter.status`** applies only to successes. UTC days with no rows are omitted; a day with only failures is included with **`value: null`**, **`status: error`** and **`errors`** list.
|
|
467
|
+
|
|
468
|
+
Only [scalar](./docs/aggregation.md#scalar-types) aggregation types are supported. **`statusGrouped`** and **`weightedStatusScore`** return **`400 Bad Request`**. See [aggregation.md](./docs/aggregation.md#get-aggregationsaggregationidtime-series) for details.
|
|
469
|
+
|
|
470
|
+
#### Path Parameters
|
|
471
|
+
|
|
472
|
+
| Parameter | Type | Required | Description |
|
|
473
|
+
| --------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
474
|
+
| `aggregationId` | string | Yes | Same as `GET /aggregations/:aggregationId`. Must resolve to a scalar type (`sum`, `average`, `max`, `min`, `count`). |
|
|
475
|
+
|
|
476
|
+
#### Query Parameters
|
|
477
|
+
|
|
478
|
+
| Parameter | Type | Required | Description |
|
|
479
|
+
| --------- | ------ | -------- | -------------------------------------------------------------------- |
|
|
480
|
+
| `from` | string | Yes | Inclusive range start (ISO-8601) |
|
|
481
|
+
| `to` | string | Yes | Inclusive range end (ISO-8601); must be `>= from`; max span 365 days |
|
|
482
|
+
|
|
483
|
+
#### Authentication / permissions
|
|
484
|
+
|
|
485
|
+
Requires user authentication, `scorecard.metric.read` permission, and `catalog.entity.read` permission for each aggregated entity.
|
|
486
|
+
|
|
487
|
+
#### Example Request
|
|
488
|
+
|
|
489
|
+
```bash
|
|
490
|
+
curl -X GET "{{url}}/api/scorecard/aggregations/avgDeploymentFrequency/time-series?from=2026-08-24T00:00:00.000Z&to=2026-08-24T23:59:59.999Z" \
|
|
491
|
+
-H "Authorization: Bearer <token>"
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### Example Response
|
|
495
|
+
|
|
496
|
+
```json
|
|
497
|
+
{
|
|
498
|
+
"id": "avgDeploymentFrequency",
|
|
499
|
+
"metricId": "dora.deploymentFrequency",
|
|
500
|
+
"metadata": {
|
|
501
|
+
"title": "Average Deployment Frequency",
|
|
502
|
+
"description": "This KPI provides average weekly production deploys over a 30-day window per entity.",
|
|
503
|
+
"type": "number",
|
|
504
|
+
"unit": "/week",
|
|
505
|
+
"history": true,
|
|
506
|
+
"visualization": "sparkline",
|
|
507
|
+
"aggregationType": "average"
|
|
508
|
+
},
|
|
509
|
+
"points": [
|
|
510
|
+
{
|
|
511
|
+
"value": 6.8,
|
|
512
|
+
"successCount": 4,
|
|
513
|
+
"errorCount": 3,
|
|
514
|
+
"total": 7,
|
|
515
|
+
"status": "success",
|
|
516
|
+
"timestamp": "2026-08-24T00:00:00.000Z",
|
|
517
|
+
"errors": [
|
|
518
|
+
{ "message": "GitHub API error", "count": 2 },
|
|
519
|
+
{ "message": "timeout", "count": 1 }
|
|
520
|
+
]
|
|
521
|
+
}
|
|
522
|
+
],
|
|
523
|
+
"thresholds": {
|
|
524
|
+
"rules": [
|
|
525
|
+
{
|
|
526
|
+
"key": "elite",
|
|
527
|
+
"expression": ">=7",
|
|
528
|
+
"color": "success.main",
|
|
529
|
+
"icon": "scorecardSuccessStatusIcon"
|
|
530
|
+
},
|
|
531
|
+
{
|
|
532
|
+
"key": "medium",
|
|
533
|
+
"expression": "1-7",
|
|
534
|
+
"color": "warning.main",
|
|
535
|
+
"icon": "scorecardWarningStatusIcon"
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
"key": "error",
|
|
539
|
+
"expression": "<1",
|
|
540
|
+
"color": "error.main",
|
|
541
|
+
"icon": "scorecardErrorStatusIcon"
|
|
542
|
+
}
|
|
543
|
+
]
|
|
544
|
+
},
|
|
545
|
+
"aggregationChartDisplayColor": "warning.main"
|
|
546
|
+
}
|
|
547
|
+
```
|
|
548
|
+
|
|
293
549
|
### `GET /aggregations/:aggregationId/metadata`
|
|
294
550
|
|
|
295
|
-
Returns **title**, **description**, **type**, **history**,
|
|
551
|
+
Returns **title**, **description**, **type**, **unit**, **history**, **visualization**, **aggregationType** for the aggregation without computing full aggregate counts. Includes **`filter`** when the KPI is a scalar type with **`filter.status`** configured. Uses the same resolution rules as `GET /aggregations/:aggregationId` (KPI config vs metric id fallback).
|
|
296
552
|
|
|
297
553
|
```bash
|
|
298
554
|
curl -X GET "{{url}}/api/scorecard/aggregations/openIssuesKpi/metadata" \
|
|
299
555
|
-H "Authorization: Bearer <token>"
|
|
300
556
|
```
|
|
301
557
|
|
|
558
|
+
For endpoint details, see [aggregation.md](./docs/aggregation.md#get-aggregationsaggregationidmetadata).
|
|
559
|
+
|
|
302
560
|
### `GET /metrics/:metricId/catalog/aggregations` (deprecated; removal planned)
|
|
303
561
|
|
|
304
562
|
This endpoint **remains available** for backward compatibility and behaves like the default case of **`GET /aggregations/:metricId`** (status-grouped aggregation for that metric). **It will be removed in a future major release** of the plugin - migrate to **`GET /aggregations/:aggregationId`**.
|