Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions workspaces/scorecard/.changeset/quick-monkeys-wash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
'@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-dora': minor
'@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-github': minor
'@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-jira': minor
'@red-hat-developer-hub/backstage-plugin-scorecard-backend': minor
'@red-hat-developer-hub/backstage-plugin-scorecard-common': minor
'@red-hat-developer-hub/backstage-plugin-scorecard': minor
---

Add DORA metrics and a collectors framework for composing datasource data into metrics.

- 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
- New data collectors used by DORA: GitHub deployments, deployment workflow runs, and deployment pull requests; Jira incidents
- Metric time-series API `/metrics/catalog/:kind/:namespace/:name/time-series`
- Adds `defaultVisualization` to Metric metadata for sparkline
59 changes: 59 additions & 0 deletions workspaces/scorecard/app-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -363,3 +363,62 @@ scorecard:
frequency: { minutes: 5 }
timeout: { minutes: 10 }
initialDelay: { seconds: 10 }
dora:
deploymentFrequency:
options:
collectors:
deployments:
id: github:deployments
# Uncomment the following to use workflow runs
# id: github:deploymentWorkflowRuns
# input:
# workflowName: Create Test Deployment on PR Merge
schedule:
frequency: { minutes: 5 }
timeout: { minutes: 10 }
initialDelay: { seconds: 10 }
medianLeadTimeForChanges:
options:
collectors:
deployments:
id: github:deployments
# Uncomment the following to use workflow runs
# id: github:deploymentWorkflowRuns
# input:
# workflowName: Create Test Deployment on PR Merge
deploymentPullRequests:
id: github:deploymentPullRequests
schedule:
frequency: { minutes: 5 }
timeout: { minutes: 10 }
initialDelay: { seconds: 10 }
changeFailureRate:
options:
collectors:
deployments:
id: github:deployments
# Uncomment the following to use workflow runs
# id: github:deploymentWorkflowRuns
# input:
# workflowName: Create Test Deployment on PR Merge
incidents:
id: jira:incidents
# Optional: override default Incident issue type
# input:
# issueType: ServiceIncident
schedule:
frequency: { minutes: 5 }
timeout: { minutes: 10 }
initialDelay: { seconds: 10 }
meanTimeToRestore:
options:
collectors:
incidents:
id: jira:incidents
# Optional: override default Incident issue type
# input:
# issueType: ServiceIncident
schedule:
frequency: { minutes: 5 }
timeout: { minutes: 10 }
initialDelay: { seconds: 10 }
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ spec:
- ./components/no-scorecards.yaml
- ./components/openssf-scorecard-only.yaml
- ./components/sonarqube-scorecard-only.yaml
- ./components/dora-scorecard.yaml
15 changes: 15 additions & 0 deletions workspaces/scorecard/examples/components/dora-scorecard.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
# Component with DORA Scorecard
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: dora-scorecard
annotations:
github.com/project-slug: dzemanov/test-scorecard-github-dora
backstage.io/source-location: url:https://github.com/dzemanov/test-scorecard-github-dora

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will update source to official rhdh repo in following PR

scorecard.io/dora: 'true'
jira/incident-project-key: RSPT
spec:
type: service
owner: group:development/guests
lifecycle: experimental
1 change: 1 addition & 0 deletions workspaces/scorecard/packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@backstage/plugin-techdocs-backend": "^2.2.1",
"@red-hat-developer-hub/backstage-plugin-scorecard-backend": "workspace:^",
"@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-dependabot": "workspace:^",
"@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-dora": "workspace:^",
"@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-filecheck": "workspace:^",
"@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-github": "workspace:^",
"@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-jira": "workspace:^",
Expand Down
5 changes: 5 additions & 0 deletions workspaces/scorecard/packages/backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,10 @@ backend.add(
'@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-sonarqube'
),
);
backend.add(
import(
'@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-dora'
),
);
backend.add(import('@backstage/plugin-mcp-actions-backend'));
backend.start();
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
163 changes: 163 additions & 0 deletions workspaces/scorecard/plugins/scorecard-backend-module-dora/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# Scorecard Backend Module for DORA

This is an extension module to the `backstage-plugin-scorecard-backend` plugin that provides DORA (DevOps Research and Assessment) metrics – key indicators of software delivery performance.

DORA module uses [**collectors**](../scorecard-backend/docs/collectors.md) – reusable components designed to gather data from various datasources, such as Jira or GitHub. You can create your custom data collector to tailor data collection for DORA metrics calculation for your specific setup.

## Prerequisites

Before installing this module, ensure that the Scorecard backend plugin is integrated into your Backstage instance. Follow the [Scorecard backend plugin README](../scorecard-backend/README.md) for setup instructions.

If you use built-in collectors from GitHub and Jira modules, install the corresponding backend modules so those collectors are registered:

- `@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-github`
- `@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-jira`

## Installation

To install this backend module:

```bash
# From your root directory
yarn workspace backend add @red-hat-developer-hub/backstage-plugin-scorecard-backend-module-dora
```

```ts
// packages/backend/src/index.ts
import { createBackend } from '@backstage/backend-defaults';

const backend = createBackend();

backend.add(
import('@red-hat-developer-hub/backstage-plugin-scorecard-backend'),
);

backend.add(
import(
'@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-dora'
),
);

backend.start();
```

### Entity annotations

DORA metric providers run only for entities that include:

```yaml
metadata:
annotations:
scorecard.io/dora: 'true'
```

## Available Metrics

| Metric ID | Provider ID | Default thresholds | Details |
| ------------------------------- | ------------------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------- |
| `dora.deploymentFrequency` | `dora.deploymentFrequency` | elite `>=7`, medium `1-7`, low `<1` (deployments/week) | [deployment-frequency.md](./docs/metrics/deployment-frequency.md) |
| `dora.medianLeadTimeForChanges` | `dora.medianLeadTimeForChanges` | elite `<24`, medium `24-168`, low `>168` (hours) | [median-lead-time-for-changes.md](./docs/metrics/median-lead-time-for-changes.md) |
| `dora.meanTimeToRestore` | `dora.meanTimeToRestore` | elite `<1`, medium `1-24`, low `>24` (hours) | [mean-time-to-restore.md](./docs/metrics/mean-time-to-restore.md) |
| `dora.changeFailureRate` | `dora.changeFailureRate` | elite `<5`, medium `5-15`, low `>15` (%) | [change-failure-rate.md](./docs/metrics/change-failure-rate.md) |

## Threshold customization

Thresholds map metric values to visual categories. DORA defaults use `elite`, `medium`, and `low` (see [Available Metrics](#available-metrics)).

You can customize them in two ways (highest priority first):

1. **Entity annotations** — merge with existing rules (same keys only)
2. **App configuration** — replace provider defaults for that metric

See [threshold configuration](../scorecard-backend/docs/thresholds.md) for details.

**App configuration example**:

```yaml
# app-config.yaml
scorecard:
metricProviders:
dora:
deploymentFrequency:
thresholds:
rules:
- key: elite
expression: '>=5'
- key: medium
expression: '1-5'
- key: low
expression: '<1'
```

Paths follow `scorecard.metricProviders.dora.<metricProviderName>.thresholds` (update `metricProviderName` to `deploymentFrequency`, `medianLeadTimeForChanges`, `meanTimeToRestore` or `changeFailureRate`).

**Entity annotation example** (overrides selected keys; others keep app-config or defaults):

```yaml
# catalog-info.yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: my-service
annotations:
scorecard.io/dora: 'true'
# Format: scorecard.io/{metricId}.thresholds.rules.{key}: '{expression}'
scorecard.io/dora.deploymentFrequency.thresholds.rules.elite: '>=8'
scorecard.io/dora.deploymentFrequency.thresholds.rules.medium: '1-8'
scorecard.io/dora.changeFailureRate.thresholds.rules.elite: '<10'
scorecard.io/dora.changeFailureRate.thresholds.rules.medium: '10-20'
scorecard.io/dora.changeFailureRate.thresholds.rules.low: '>20'
spec:
type: service
lifecycle: production
owner: team-a
```

## Use your own collectors

You can replace default collector IDs via `app-config.yaml` as long as your collectors implement the schema contracts expected by each metric:

- `dora.deploymentFrequency` [collector contracts](./docs/metrics/deployment-frequency.md#collectors)
- `dora.medianLeadTimeForChanges` [collector contracts](./docs/metrics/median-lead-time-for-changes.md#collectors)
- `dora.meanTimeToRestore` [collector contracts](./docs/metrics/mean-time-to-restore.md#collectors)
- `dora.changeFailureRate` [collector contracts](./docs/metrics/change-failure-rate.md#collectors)

Collector inputs are merged with provider-generated required inputs. This lets you pass extra collector-specific fields (for example `workflowName` when using a workflow-runs based collector) as long as required contract fields are still supported.

```yaml
scorecard:
metricProviders:
dora:
deploymentFrequency:
options:
productionEnvironments: [production, prod]
collectors:
deployments:
id: customDatasource:deployments
input:
# merged with generated from/to window
# your collector-specific options
medianLeadTimeForChanges:
options:
productionEnvironments: [production, prod]
collectors:
deployments:
id: customDatasource:deployments
input:
# merged with generated from/to window
deploymentPullRequests:
id: customDatasource:deploymentPullRequests
input:
# merged with generated baseCommitSha/headCommitSha
```

## Scheduling

DORA providers follow Scorecard scheduling settings under their metric keys:

- `scorecard.metricProviders.dora.deploymentFrequency.schedule`
- `scorecard.metricProviders.dora.medianLeadTimeForChanges.schedule`
- `scorecard.metricProviders.dora.meanTimeToRestore.schedule`
- `scorecard.metricProviders.dora.changeFailureRate.schedule`

See [providers.md](../scorecard-backend/docs/providers.md#metric-collection-scheduling) for schedule schema and defaults.
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { SchedulerServiceTaskScheduleDefinitionConfig } from '@backstage/backend-plugin-api';
import {
CollectorConfig,
ThresholdConfig,
} from '@red-hat-developer-hub/backstage-plugin-scorecard-common';

export interface Config {
/** Configuration for scorecard dora plugin */
scorecard?: {
metricProviders?: {
dora?: {
deploymentFrequency?: {
/**
* Provider-specific options.
*/
options?: {
/**
* Environment names treated as production (case-insensitive).
* Missing/unknown deployment environments still count as production.
* @default ['production']
*/
productionEnvironments?: string[];
collectors?: {
deployments?: CollectorConfig;
};
};
thresholds?: ThresholdConfig;
schedule?: SchedulerServiceTaskScheduleDefinitionConfig;
};
medianLeadTimeForChanges?: {
/**
* Provider-specific options.
*/
options?: {
/**
* Environment names treated as production (case-insensitive).
* Missing/unknown deployment environments still count as production.
* @default ['production']
*/
productionEnvironments?: string[];
collectors?: {
deployments?: CollectorConfig;
deploymentPullRequests?: CollectorConfig;
};
};
thresholds?: ThresholdConfig;
schedule?: SchedulerServiceTaskScheduleDefinitionConfig;
};
meanTimeToRestore?: {
/**
* Provider-specific options.
*/
options?: {
collectors?: {
incidents?: CollectorConfig;
};
};
thresholds?: ThresholdConfig;
schedule?: SchedulerServiceTaskScheduleDefinitionConfig;
};
changeFailureRate?: {
/**
* Provider-specific options.
*/
options?: {
/**
* Environment names treated as production (case-insensitive).
* Missing/unknown deployment environments still count as production.
* @default ['production']
*/
productionEnvironments?: string[];
collectors?: {
deployments?: CollectorConfig;
incidents?: CollectorConfig;
};
};
thresholds?: ThresholdConfig;
schedule?: SchedulerServiceTaskScheduleDefinitionConfig;
};
};
};
};
}
Loading
Loading