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/unify-metric-ids-camel-case.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
'@red-hat-developer-hub/backstage-plugin-scorecard': major
'@red-hat-developer-hub/backstage-plugin-scorecard-backend': major
'@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-github': major
'@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-jira': major
'@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-sonarqube': major
'@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-dependabot': major
'@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-openssf': major
---

**BREAKING**: Standardize all metric and provider IDs from `snake_case` to `lowerCamelCase`.

This aligns metric IDs with the naming convention used in `app-config.yaml` and the planned Scorecard design. For example, `github.open_prs` is now `github.openPrs`, `sonarqube.quality_gate` is now `sonarqube.qualityGate`, and `dependabot.alerts_critical` is now `dependabot.alertsCritical`.

If you reference metric IDs in your `app-config.yaml` (e.g., in `metricId` fields or plugin schedule config keys), update them to use `lowerCamelCase`.
6 changes: 3 additions & 3 deletions workspaces/scorecard/app-config.local.EXAMPLE.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ scorecard:
title: GitHub Open PRs (weighted health)
type: average
description: Weighted health average for open PRs by threshold status across your entities.
metricId: github.open_prs
metricId: github.openPrs
options:
statusScores:
success: 100
Expand All @@ -78,7 +78,7 @@ scorecard:
color: '#be1ec7' # purple
plugins:
jira:
open_issues:
openIssues:
schedule:
frequency: { days: 1 }
timeout: { minutes: 2 }
Expand All @@ -88,7 +88,7 @@ scorecard:
# mandatoryFilter: type = Story
# customFilter: priority = High
github:
open_prs:
openPrs:
# Example threshold overrides; remove to use provider defaults.
thresholds:
rules:
Expand Down
4 changes: 2 additions & 2 deletions workspaces/scorecard/app-config.production.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ catalog:
# title: GitHub open PRs
# description: Open PRs across owned entities, grouped by status.
# type: statusGrouped
# metricId: github.open_prs
# metricId: github.openPrs
# plugins:
# github:
# open_prs:
# openPrs:
# schedule:
# frequency: { hours: 1 }
# timeout: { minutes: 15 }
Expand Down
10 changes: 5 additions & 5 deletions workspaces/scorecard/app-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -243,12 +243,12 @@ scorecard:
title: GitHub Open PRs KPI
type: statusGrouped
description: This KPI is provide information about GitHub open PRs grouped by status.
metricId: github.open_prs
metricId: github.openPrs
openPrsWeightedKpi:
title: GitHub Open PRs (weighted health)
type: average
description: Weighted health average for open PRs by threshold status across your entities.
metricId: github.open_prs
metricId: github.openPrs
options:
statusScores:
success: 100
Expand All @@ -269,21 +269,21 @@ scorecard:
title: Jira Open Issues KPI
type: statusGrouped
description: This KPI is provide information about Jira open issues grouped by status.
metricId: jira.open_issues
metricId: jira.openIssues
licenseFileExistsKpi:
title: License File Exists KPI
type: statusGrouped
description: This KPI is provide information about whether the license file exists in the repository.
metricId: filecheck.license
plugins:
jira:
open_issues:
openIssues:
schedule:
frequency: { minutes: 5 }
timeout: { minutes: 10 }
initialDelay: { seconds: 10 }
github:
open_prs:
openPrs:
schedule:
frequency: { minutes: 5 }
timeout: { minutes: 10 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
*/

export const AGGREGATED_CARDS_METRIC_IDS = {
jiraMetricId: 'jira.open_issues',
githubMetricId: 'github.open_prs',
jiraMetricId: 'jira.openIssues',
githubMetricId: 'github.openPrs',
githubOpenPrsKpi: 'openPrsKpi',
jiraOpenIssuesKpi: 'openIssuesKpi',
gitHubOpenPrsWeightedKpi: 'openPrsWeightedKpi',
Expand All @@ -35,26 +35,26 @@ export const AGGREGATED_CARDS_METADATA = {
jiraDeprecatedMetricId: {
id: AGGREGATED_CARDS_METRIC_IDS.jiraMetricId,
title: 'Scorecard: With deprecated metricId property (Jira)',
metricId: 'jira.open_issues',
metricId: 'jira.openIssues',
},
githubDefaultAggregation: {
id: AGGREGATED_CARDS_METRIC_IDS.githubMetricId,
title: 'Scorecard: With default aggregation config (GitHub)',
metricId: 'github.open_prs',
metricId: 'github.openPrs',
},
jiraOpenIssuesKpi: {
id: AGGREGATED_CARDS_METRIC_IDS.jiraOpenIssuesKpi,
title: 'Scorecard: Jira open blocking tickets',
metricId: 'jira.open_issues',
metricId: 'jira.openIssues',
},
githubOpenPrsKpi: {
id: AGGREGATED_CARDS_METRIC_IDS.githubOpenPrsKpi,
title: 'Scorecard: GitHub open PRs',
metricId: 'github.open_prs',
metricId: 'github.openPrs',
},
githubOpenPrsWeightedKpi: {
id: AGGREGATED_CARDS_METRIC_IDS.gitHubOpenPrsWeightedKpi,
title: 'Scorecard: GitHub open PRs (weighted health)',
metricId: 'github.open_prs',
metricId: 'github.openPrs',
},
} as const;
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const ScorecardRoutes = {
'**/api/scorecard/aggregations/openIssuesKpi',
/** Default aggregation when aggregationId is the metric id (no KPI entry). */
JIRA_OPEN_ISSUES_METRIC_AGGREGATION_ROUTE:
'**/api/scorecard/aggregations/jira.open_issues',
'**/api/scorecard/aggregations/jira.openIssues',
GITHUB_OPEN_PRS_METRIC_AGGREGATION_ROUTE:
'**/api/scorecard/aggregations/github.open_prs',
'**/api/scorecard/aggregations/github.openPrs',
} as const;
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
getSomeEntitiesNotReportingTooltip,
} from '../utils/translationUtils';

type MetricId = 'github.open_prs' | 'jira.open_issues';
type MetricId = 'github.openPrs' | 'jira.openIssues';

export type DrillDownCardLocatorOptions = {
aggregationId?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ export class ScorecardPage {
get scorecardMetrics() {
return [
{
title: this.translations.metric['github.open_prs'].title,
description: this.translations.metric['github.open_prs'].description,
title: this.translations.metric['github.openPrs'].title,
description: this.translations.metric['github.openPrs'].description,
},
{
title: this.translations.metric['jira.open_issues'].title,
description: this.translations.metric['jira.open_issues'].description,
title: this.translations.metric['jira.openIssues'].title,
description: this.translations.metric['jira.openIssues'].description,
},
];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ test.describe('Scorecard Plugin Tests', () => {
await catalogPage.openComponent('Red Hat Developer Hub');
await scorecardPage.openTab();
await scorecardPage.verifyScorecardValues({
[translations.metric['github.open_prs'].title]: '9',
[translations.metric['jira.open_issues'].title]: '8',
[translations.metric['github.openPrs'].title]: '9',
[translations.metric['jira.openIssues'].title]: '8',
});

for (const metric of scorecardPage.scorecardMetrics) {
Expand Down Expand Up @@ -351,21 +351,21 @@ test.describe('Scorecard Plugin Tests', () => {
await page.getByText('Scorecard', { exact: true }).click();

await expect(
page.getByText(translations.metric['sonarqube.quality_gate'].title),
page.getByText(translations.metric['sonarqube.qualityGate'].title),
).toBeVisible({ timeout: 10000 });

const expectedValues: Record<string, string> = {
[translations.metric['sonarqube.open_issues'].title]: '3',
[translations.metric['sonarqube.security_rating'].title]: '1',
[translations.metric['sonarqube.security_issues'].title]: '0',
[translations.metric['sonarqube.security_review_rating'].title]: '1',
[translations.metric['sonarqube.security_hotspots'].title]: '2',
[translations.metric['sonarqube.reliability_rating'].title]: '1',
[translations.metric['sonarqube.reliability_issues'].title]: '0',
[translations.metric['sonarqube.maintainability_rating'].title]: '1',
[translations.metric['sonarqube.maintainability_issues'].title]: '12',
[translations.metric['sonarqube.code_coverage'].title]: '82.5',
[translations.metric['sonarqube.code_duplications'].title]: '3.2',
[translations.metric['sonarqube.openIssues'].title]: '3',
[translations.metric['sonarqube.securityRating'].title]: '1',
[translations.metric['sonarqube.securityIssues'].title]: '0',
[translations.metric['sonarqube.securityReviewRating'].title]: '1',
[translations.metric['sonarqube.securityHotspots'].title]: '2',
[translations.metric['sonarqube.reliabilityRating'].title]: '1',
[translations.metric['sonarqube.reliabilityIssues'].title]: '0',
[translations.metric['sonarqube.maintainabilityRating'].title]: '1',
[translations.metric['sonarqube.maintainabilityIssues'].title]: '12',
[translations.metric['sonarqube.codeCoverage'].title]: '82.5',
[translations.metric['sonarqube.codeDuplications'].title]: '3.2',
};

for (const [title, value] of Object.entries(expectedValues)) {
Expand All @@ -379,7 +379,7 @@ test.describe('Scorecard Plugin Tests', () => {
const qualityGateCard = page
.locator('[role="article"]')
.filter({
hasText: translations.metric['sonarqube.quality_gate'].title,
hasText: translations.metric['sonarqube.qualityGate'].title,
})
.first();
await expect(
Expand All @@ -398,13 +398,13 @@ test.describe('Scorecard Plugin Tests', () => {
await page.getByText('Scorecard', { exact: true }).click();

await expect(
page.getByText(translations.metric['sonarqube.quality_gate'].title),
page.getByText(translations.metric['sonarqube.qualityGate'].title),
).toBeVisible({ timeout: 10000 });

const qualityGateCard = page
.locator('[role="article"]')
.filter({
hasText: translations.metric['sonarqube.quality_gate'].description,
hasText: translations.metric['sonarqube.qualityGate'].description,
})
.first();
await expect(
Expand Down Expand Up @@ -526,16 +526,16 @@ test.describe('Scorecard Plugin Tests', () => {
await expect(card).toBeVisible();
await homePage.clickDrillDownLink(card);

await scorecardDrillDownPage.expectOnPage('jira.open_issues', {
await scorecardDrillDownPage.expectOnPage('jira.openIssues', {
aggregationId: aggregationMetadata.id,
});

const jiraOpenIssuesTitle = evaluateMessage(
translations.metric['jira.open_issues'].title,
'jira.open_issues',
translations.metric['jira.openIssues'].title,
'jira.openIssues',
);
await scorecardDrillDownPage.expectPageTitle(
'jira.open_issues',
'jira.openIssues',
jiraOpenIssuesTitle,
);
});
Expand Down Expand Up @@ -599,16 +599,16 @@ test.describe('Scorecard Plugin Tests', () => {
await expect(card).toBeVisible();
await homePage.clickDrillDownLink(card);

await scorecardDrillDownPage.expectOnPage('github.open_prs', {
await scorecardDrillDownPage.expectOnPage('github.openPrs', {
aggregationId: aggregationMetadata.id,
});

const githubOpenPrsTitle = evaluateMessage(
translations.metric['github.open_prs'].title,
'github.open_prs',
translations.metric['github.openPrs'].title,
'github.openPrs',
);
await scorecardDrillDownPage.expectPageTitle(
'github.open_prs',
'github.openPrs',
githubOpenPrsTitle,
);
});
Expand Down Expand Up @@ -676,11 +676,11 @@ test.describe('Scorecard Plugin Tests', () => {
await expect(card).toBeVisible();
await homePage.clickDrillDownLink(card, { healthy: '8', total: '8' });

await scorecardDrillDownPage.expectOnPage('github.open_prs', {
await scorecardDrillDownPage.expectOnPage('github.openPrs', {
aggregationId: aggregationMetadata.id,
});
await scorecardDrillDownPage.expectPageTitle(
'github.open_prs',
'github.openPrs',
aggregatedResponse.metadata.title,
);
});
Expand Down Expand Up @@ -779,11 +779,11 @@ test.describe('Scorecard Plugin Tests', () => {
await expect(card).toBeVisible();
await homePage.clickDrillDownLink(card);

await scorecardDrillDownPage.expectOnPage('github.open_prs', {
await scorecardDrillDownPage.expectOnPage('github.openPrs', {
aggregationId: aggregationMetadata.id,
});
await scorecardDrillDownPage.expectPageTitle(
'github.open_prs',
'github.openPrs',
openPrsWeightedAggregatedResponse.metadata.title,
);
});
Expand Down Expand Up @@ -959,7 +959,7 @@ test.describe('Scorecard Plugin Tests', () => {
await mockScorecardEntitiesDrillDownWithSort(
page,
jiraEntitiesDrillDownResponse,
'jira.open_issues',
'jira.openIssues',
);

await setupHomepageAggregationCard(page, homePage, {
Expand Down Expand Up @@ -998,15 +998,15 @@ test.describe('Scorecard Plugin Tests', () => {
await homePage.clickDrillDownLink(
homePage.getCard(aggregationMetadata.id),
);
await scorecardDrillDownPage.expectOnPage('jira.open_issues', {
await scorecardDrillDownPage.expectOnPage('jira.openIssues', {
aggregationId: aggregationMetadata.id,
});
await scorecardDrillDownPage.expectPageTitle(
'jira.open_issues',
'jira.openIssues',
jiraAggregatedResponse.metadata.title,
);
await scorecardDrillDownPage.expectDrillDownCardSnapshot(
'jira.open_issues',
'jira.openIssues',
{
aggregationId: aggregationMetadata.id,
cardTitle: jiraAggregatedResponse.metadata.title,
Expand Down Expand Up @@ -1042,13 +1042,13 @@ test.describe('Scorecard Plugin Tests', () => {
jiraMetricMetadataResponse,
);
await page.goto(
'/scorecard/aggregations/jira.open_issues/metrics/jira.open_issues',
'/scorecard/aggregations/jira.openIssues/metrics/jira.openIssues',
);
await scorecardDrillDownPage.expectOnPage('jira.open_issues');
await scorecardDrillDownPage.expectPageTitle('jira.open_issues');
await scorecardDrillDownPage.expectOnPage('jira.openIssues');
await scorecardDrillDownPage.expectPageTitle('jira.openIssues');
await scorecardDrillDownPage.expectTableHeadersVisible();
await scorecardDrillDownPage.expectCardHasMissingPermission(
'jira.open_issues',
'jira.openIssues',
);
await scorecardDrillDownPage.expectTableHasMissingPermission();
});
Expand All @@ -1059,17 +1059,17 @@ test.describe('Scorecard Plugin Tests', () => {
await mockScorecardEntitiesDrillDown(
page,
jiraEntitiesDrillDownNoDataResponse,
'jira.open_issues',
'jira.openIssues',
);
await page.goto(
'/scorecard/aggregations/jira.open_issues/metrics/jira.open_issues',
'/scorecard/aggregations/jira.openIssues/metrics/jira.openIssues',
);
await scorecardDrillDownPage.expectOnPage('jira.open_issues');
await scorecardDrillDownPage.expectPageTitle('jira.open_issues');
await scorecardDrillDownPage.expectOnPage('jira.openIssues');
await scorecardDrillDownPage.expectPageTitle('jira.openIssues');
await scorecardDrillDownPage.expectTableHeadersVisible();
await scorecardDrillDownPage.expectTableNoDataFound();
await scorecardDrillDownPage.expectCardHasNoDataFound(
'jira.open_issues',
'jira.openIssues',
);
});
});
Expand Down
Loading
Loading